This is an automated email from the ASF dual-hosted git repository.

jamesbognar pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/juneau.git


The following commit(s) were added to refs/heads/master by this push:
     new 576597a  REST refactoring.
576597a is described below

commit 576597ad03d343e34c12596ce39e31c61575b332
Author: JamesBognar <[email protected]>
AuthorDate: Wed Jan 13 16:41:29 2021 -0500

    REST refactoring.
---
 .../org/apache/juneau/cp/BeanFactory_Test.java     |  85 ++++--
 .../apache/juneau/cp/BeanCreateMethodFinder.java   | 135 +++++++++
 .../java/org/apache/juneau/cp/BeanFactory.java     |  65 ++--
 .../org/apache/juneau/internal/ObjectUtils.java    |   4 +-
 .../org/apache/juneau/rest/RequestFormData.java    |  24 +-
 .../org/apache/juneau/rest/RequestHeaders.java     |  25 +-
 .../java/org/apache/juneau/rest/RequestQuery.java  |  25 +-
 .../java/org/apache/juneau/rest/RestContext.java   | 217 +++++++++++---
 .../org/apache/juneau/rest/RestContextBuilder.java |   7 +-
 .../org/apache/juneau/rest/RestMethodContext.java  | 329 +++++++++++++++------
 .../java/org/apache/juneau/rest/RestRequest.java   |   8 +-
 11 files changed, 736 insertions(+), 188 deletions(-)

diff --git 
a/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/cp/BeanFactory_Test.java
 
b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/cp/BeanFactory_Test.java
index 3e09892..1ddd4a7 100644
--- 
a/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/cp/BeanFactory_Test.java
+++ 
b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/cp/BeanFactory_Test.java
@@ -351,36 +351,65 @@ public class BeanFactory_Test {
        }
 
        @Test
-       public void e01_createBeanViaMethod_noArgs() throws Exception {
-               BeanFactory bf = new BeanFactory();
+       public void e01_beanCreateMethodFinder() throws Exception {
+               BeanFactory bf = BeanFactory.create();
                E1 x = new E1();
 
-               assertObject(bf.createBeanViaMethod(E.class, x, "createA0", 
null)).doesNotExist();
-               assertObject(bf.createBeanViaMethod(E.class, x, "createA1", 
null)).exists();
-               assertObject(bf.createBeanViaMethod(E.class, x, "createA2", 
null)).doesNotExist();
-               assertObject(bf.createBeanViaMethod(E.class, x, "createA3", 
null)).doesNotExist();
-               assertObject(bf.createBeanViaMethod(E.class, x, "createA4", 
null)).doesNotExist();
-               assertObject(bf.createBeanViaMethod(E.class, x, "createA5", 
null)).doesNotExist();
-               assertObject(bf.createBeanViaMethod(E.class, x, "createA6", 
null)).doesNotExist();
-               assertThrown(()->bf.createBeanViaMethod(E.class, x, "createA7", 
null)).contains("foo");
-
-               assertObject(bf.createBeanViaMethod(E.class, x, "createB0", 
null)).doesNotExist();
-               assertObject(bf.createBeanViaMethod(E.class, x, "createB1", 
null)).exists();
-               assertObject(bf.createBeanViaMethod(E.class, x, "createB2", 
null)).doesNotExist();
-               assertObject(bf.createBeanViaMethod(E.class, x, "createB3", 
null)).doesNotExist();
-               assertObject(bf.createBeanViaMethod(E.class, x, "createB4", 
null)).doesNotExist();
-               assertObject(bf.createBeanViaMethod(E.class, x, "createB5", 
null)).doesNotExist();
-               assertObject(bf.createBeanViaMethod(E.class, x, "createB6", 
null)).doesNotExist();
-               assertThrown(()->bf.createBeanViaMethod(E.class, x, "createB7", 
null)).contains("foo");
-
-               assertObject(bf.createBeanViaMethod(E.class, x, "createC1", 
null)).doesNotExist();
-               assertObject(bf.createBeanViaMethod(E.class, x, "createC2", 
null)).doesNotExist();
-               assertObject(bf.createBeanViaMethod(E.class, x, "createC3", 
null)).exists();
-               assertObject(bf.createBeanViaMethod(E.class, x, "createC3", 
null).a).doesNotExist();
+               assertObject(bf.beanCreateMethodFinder(E.class, 
x).find("createA0").run()).doesNotExist();
+               assertObject(bf.beanCreateMethodFinder(E.class, 
x).find("createA1").run()).exists();
+               assertObject(bf.beanCreateMethodFinder(E.class, 
x).find("createA2").run()).doesNotExist();
+               assertObject(bf.beanCreateMethodFinder(E.class, 
x).find("createA3").run()).doesNotExist();
+               assertObject(bf.beanCreateMethodFinder(E.class, 
x).find("createA4").run()).doesNotExist();
+               assertObject(bf.beanCreateMethodFinder(E.class, 
x).find("createA5").run()).doesNotExist();
+               assertObject(bf.beanCreateMethodFinder(E.class, 
x).find("createA6").run()).doesNotExist();
+               assertThrown(()->bf.beanCreateMethodFinder(E.class, 
x).find("createA7").run()).contains("foo");
+
+               assertObject(bf.beanCreateMethodFinder(E.class, 
x).find("createB0").run()).doesNotExist();
+               assertObject(bf.beanCreateMethodFinder(E.class, 
x).find("createB1").run()).exists();
+               assertObject(bf.beanCreateMethodFinder(E.class, 
x).find("createB2").run()).doesNotExist();
+               assertObject(bf.beanCreateMethodFinder(E.class, 
x).find("createB3").run()).doesNotExist();
+               assertObject(bf.beanCreateMethodFinder(E.class, 
x).find("createB4").run()).doesNotExist();
+               assertObject(bf.beanCreateMethodFinder(E.class, 
x).find("createB5").run()).doesNotExist();
+               assertObject(bf.beanCreateMethodFinder(E.class, 
x).find("createB6").run()).doesNotExist();
+               assertThrown(()->bf.beanCreateMethodFinder(E.class, 
x).find("createB7").run()).contains("foo");
+
+               assertObject(bf.beanCreateMethodFinder(E.class, 
x).find("createC1").run()).doesNotExist();
+               assertObject(bf.beanCreateMethodFinder(E.class, 
x).find("createC2").run()).doesNotExist();
+               assertObject(bf.beanCreateMethodFinder(E.class, 
x).find("createC3").run()).exists();
+               assertObject(bf.beanCreateMethodFinder(E.class, 
x).find("createC3").run().a).doesNotExist();
                bf.addBean(A.class, new A());
-               assertObject(bf.createBeanViaMethod(E.class, x, "createC1", 
null)).exists();
-               assertObject(bf.createBeanViaMethod(E.class, x, "createC2", 
null)).exists();
-               assertObject(bf.createBeanViaMethod(E.class, x, "createC3", 
null)).exists();
-               assertObject(bf.createBeanViaMethod(E.class, x, "createC3", 
null).a).exists();
+               assertObject(bf.beanCreateMethodFinder(E.class, 
x).find("createC1").run()).exists();
+               assertObject(bf.beanCreateMethodFinder(E.class, 
x).find("createC2").run()).exists();
+               assertObject(bf.beanCreateMethodFinder(E.class, 
x).find("createC3").run()).exists();
+               assertObject(bf.beanCreateMethodFinder(E.class, 
x).find("createC3").run().a).exists();
+               bf.addBean(A.class, null);
+               assertObject(bf.beanCreateMethodFinder(E.class, 
x).find("createC1").run()).doesNotExist();
+               assertObject(bf.beanCreateMethodFinder(E.class, 
x).find("createC2").run()).doesNotExist();
+               assertObject(bf.beanCreateMethodFinder(E.class, 
x).find("createC3").run()).exists();
+               assertObject(bf.beanCreateMethodFinder(E.class, 
x).find("createC3").run().a).doesNotExist();
+               bf.addBeanSupplier(A.class, ()->new A());
+               assertObject(bf.beanCreateMethodFinder(E.class, 
x).find("createC1").run()).exists();
+               assertObject(bf.beanCreateMethodFinder(E.class, 
x).find("createC2").run()).exists();
+               assertObject(bf.beanCreateMethodFinder(E.class, 
x).find("createC3").run()).exists();
+               assertObject(bf.beanCreateMethodFinder(E.class, 
x).find("createC3").run().a).exists();
+               bf.addBeanSupplier(A.class, null);
+               assertObject(bf.beanCreateMethodFinder(E.class, 
x).find("createC1").run()).doesNotExist();
+               assertObject(bf.beanCreateMethodFinder(E.class, 
x).find("createC2").run()).doesNotExist();
+               assertObject(bf.beanCreateMethodFinder(E.class, 
x).find("createC3").run()).exists();
+               assertObject(bf.beanCreateMethodFinder(E.class, 
x).find("createC3").run().a).doesNotExist();
+
+               assertObject(bf.beanCreateMethodFinder(E.class, 
x).find("createAx").thenFind("createA1").run()).exists();
+               assertObject(bf.beanCreateMethodFinder(E.class, 
x).find("createA1").thenFind("createAx").run()).exists();
+               assertObject(bf.beanCreateMethodFinder(E.class, 
x).find("createA1", A.class).thenFind("createA2", 
A.class).run()).doesNotExist();
+               assertObject(bf.beanCreateMethodFinder(E.class, 
x).find("createA1", A.class).thenFind("createA1").run()).exists();
+               assertObject(bf.beanCreateMethodFinder(E.class, 
x).find("createA1", A.class).withDefault(new E()).run()).exists();
+
+               bf.addBeanSupplier(A.class, ()->new A());
+               assertObject(bf.createBean(A.class)).exists();
+
+               BeanFactory bf2 = BeanFactory.of(bf, null);
+               assertObject(bf2.beanCreateMethodFinder(E.class, 
x).find("createA1").run()).exists();
+
+               
assertString(bf2.toString()).is("{beanMap:[],parent:{beanMap:['A']}}");
        }
 }
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/cp/BeanCreateMethodFinder.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/cp/BeanCreateMethodFinder.java
new file mode 100644
index 0000000..d0fc615
--- /dev/null
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/cp/BeanCreateMethodFinder.java
@@ -0,0 +1,135 @@
+// 
***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license agreements.  See the NOTICE file *
+// * distributed with this work for additional information regarding copyright 
ownership.  The ASF licenses this file        *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not 
use this file except in compliance            *
+// * with the License.  You may obtain a copy of the License at                
                                              *
+// *                                                                           
                                              *
+// *  http://www.apache.org/licenses/LICENSE-2.0                               
                                              *
+// *                                                                           
                                              *
+// * Unless required by applicable law or agreed to in writing, software 
distributed under the License is distributed on an  *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 
express or implied.  See the License for the        *
+// * specific language governing permissions and limitations under the 
License.                                              *
+// 
***************************************************************************************************************************
+package org.apache.juneau.cp;
+
+import static org.apache.juneau.assertions.Assertions.*;
+import static org.apache.juneau.reflect.ReflectFlags.*;
+
+import java.util.*;
+import java.util.function.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.annotation.*;
+import org.apache.juneau.reflect.*;
+
+/**
+ * Used for finding methods on an object that take in arbitrary parameters and 
returns bean instances.
+ *
+ * See {@link BeanFactory#beanCreateMethodFinder(Class, Object)} for usage.
+ *
+ * @param <T> The bean type being created.
+ */
+public class BeanCreateMethodFinder<T> {
+
+       private Class<T> beanType;
+       private final Object resource;
+       private final BeanFactory beanFactory;
+
+       private MethodInfo method;
+       private Object[] args;
+
+       private Supplier<T> def = ()->null;
+
+       BeanCreateMethodFinder(Class<T> beanType, Object resource, BeanFactory 
beanFactory) {
+               this.beanType = beanType;
+               this.resource = resource;
+               this.beanFactory = beanFactory;
+       }
+
+       /**
+        * Find the method matching the specified name and optionally having 
the specified required parameters present.
+        *
+        * <p>
+        * In order for the method to be used, it must adhere to the following 
restrictions:
+        * <ul>
+        *      <li>The method must be public.
+        *      <li>The method can be static.
+        *      <li>The method name must match exactly.
+        *      <li>The method must not be deprecated or annotated with {@link 
BeanIgnore}.
+        *      <li>The method must have all parameter types specified in 
<c>requiredParams</c>.
+        *      <li>The bean factory must contain beans for all parameter types.
+        *      <li>The bean factory may contain beans for all {@link Optional} 
parameter types.
+        * </ul>
+        *
+        * <p>
+        * This method can be called multiple times with different method names 
or required parameters until a match is found.
+        * <br>Once a method is found, subsequent calls to this method will be 
no-ops.
+        *
+        * See {@link BeanFactory#beanCreateMethodFinder(Class, Object)} for 
usage.
+        *
+        * @param methodName The method name.
+        * @param requiredParams Optional required parameters.
+        * @return This object (for method chaining).
+        */
+       public BeanCreateMethodFinder<T> find(String methodName, 
Class<?>...requiredParams) {
+               if (method == null) {
+                       ClassInfo ci = ClassInfo.of(resource);
+                       for (MethodInfo m : ci.getPublicMethods()) {
+                               if (m.isAll(NOT_DEPRECATED) && 
m.hasReturnType(beanType) && m.getSimpleName().equals(methodName) && 
(!m.hasAnnotation(BeanIgnore.class))) {
+                                       List<ClassInfo> missing = 
beanFactory.getMissingParamTypes(m.getParamTypes());
+                                       if (missing.isEmpty() && 
m.hasAllArgs(requiredParams)) {
+                                               this.method = m;
+                                               this.args = 
beanFactory.getParams(m.getParamTypes());
+                                       }
+                               }
+                       }
+               }
+               return this;
+       }
+
+       /**
+        * Identical to {@link #find(String, Class...)} but named for 
fluent-style calls.
+        *
+        * @param methodName The method name.
+        * @param requiredParams Optional required parameters.
+        * @return This object (for method chaining).
+        */
+       public BeanCreateMethodFinder<T> thenFind(String methodName, 
Class<?>...requiredParams) {
+               return find(methodName, requiredParams);
+       }
+
+       /**
+        * A default value to return if no matching methods were found.
+        *
+        * @param def The default value.  Can be <jk>null</jk>.
+        * @return This object (for method chaining).
+        */
+       public BeanCreateMethodFinder<T> withDefault(T def) {
+               return withDefault(()->def);
+       }
+
+       /**
+        * A default value to return if no matching methods were found.
+        *
+        * @param def The default value.
+        * @return This object (for method chaining).
+        */
+       public BeanCreateMethodFinder<T> withDefault(Supplier<T> def) {
+               assertArgNotNull("def", def);
+               this.def = def;
+               return this;
+       }
+
+       /**
+        * Executes the matched method and returns the result.
+        *
+        * @return The object returned by the method invocation, or the default 
value if method was not found.
+        * @throws ExecutableException If method invocation threw an exception.
+        */
+       @SuppressWarnings("unchecked")
+       public T run() throws ExecutableException  {
+               if (method != null)
+                       return (T)method.invoke(resource, args);
+               return def.get();
+       }
+}
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/cp/BeanFactory.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/cp/BeanFactory.java
index 247ee46..b8e7c98 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/cp/BeanFactory.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/cp/BeanFactory.java
@@ -42,16 +42,16 @@ public class BeanFactory {
 
        /**
         * Static creator.
-        * 
+        *
         * @return A new {@link BeanFactory} object.
         */
-       public static BeanFactory of() {
+       public static BeanFactory create() {
                return new BeanFactory();
        }
 
        /**
         * Static creator.
-        * 
+        *
         * @param parent Parent bean factory.  Can be <jk>null</jk> if this is 
the root resource.
         * @param outer Outer bean context to use when instantiating local 
classes.  Can be <jk>null</jk>.
         * @return A new {@link BeanFactory} object.
@@ -138,7 +138,7 @@ public class BeanFactory {
         * @param t The bean supplier.
         * @return This object (for method chaining).
         */
-       public <T> BeanFactory addBean(Class<T> c, Supplier<T> t) {
+       public <T> BeanFactory addBeanSupplier(Class<T> c, Supplier<T> t) {
                if (t == null)
                        beanMap.remove(c);
                else
@@ -214,29 +214,46 @@ public class BeanFactory {
                throw new ExecutableException("Could not instantiate class {0}: 
{1}.", c.getName(), msg.get());
        }
 
-
        /**
-        * Creates a bean via a static or non-static method defined on the 
specified class.
+        * Create a method finder for finding bean creation methods.
+        *
+        * <h5 class='section'>Example:</h5>
+        * <p class='bcode w800'>
+        *      <jc>// The bean we want to create.</jc>
+        *      <jk>public class</jk> A {}
+        *
+        *      <jc>// The bean that has a creator method for the bean 
above.</jc>
+        *      <jk>public class</jk> B {
+        *
+        *              <jc>// Creator method.</jc>
+        *              <jc>// Bean factory must have a C bean and optionally a 
D bean.</jc>
+        *              <jk>public</jk> A createA(C <mv>c</mv>, 
Optional&lt;D&gt; <mv>d</mv>) {
+        *                      <jk>return new</jk> A(<mv>c</mv>, 
<mv>d</mv>.orElse(<jk>null</jk>));
+        *              }
+        *      }
+        *
+        *      <jc>// Instantiate the bean with the creator method.</jc>
+        *      B <mv>b</mv> = <jk>new</jk> B();
+        *
+        *  <jc>// Create a bean factory with some mapped beans.</jc>
+        *      BeanFactory <mv>beanFactory</mv> = 
BeanFactory.<jsm>create</jsm>().addBean(C.<jk>class</jk>, <jk>new</jk> C());
+        *
+        *      <jc>// Instantiate the bean using the creator method.</jc>
+        *      A <mv>a</mv> = <mv>beanFactory</mv>
+        *              .beanCreateMethodFinder(A.<jk>class</jk>, <mv>b</mv>)  
<jc>// Looking for creator for A on b object.</jc>
+        *              .find(<js>"createA"</js>)                         
<jc>// Look for method called "createA".</jc>
+        *              .thenFind(<js>"createA2"</js>)                    
<jc>// Then look for method called "createA2".</jc>
+        *              .withDefault(()-&gt;<jk>new</jk> A())                   
     <jc>// Optionally supply a default value if method not found.</jc>
+        *              .run();                                  <jc>// 
Execute.</jc>
+        * </p>
         *
         * @param <T> The bean type to create.
         * @param c The bean type to create.
-        * @param resource The object where the method is defined.
-        * @param methodName The method name on the object to call.
-        * @param def The default value to return if method doesn't exist.
-        * @param requiredParams The parameter types that must be present on 
the method.
-        * @return A newly-created bean or <jk>null</jk> if method not found or 
it returns <jk>null</jk>.
-        * @throws ExecutableException If bean could not be created.
+        * @param resource The class containing the bean creator method.
+        * @return The created bean or the default value if method could not be 
found.
         */
-       public <T> T createBeanViaMethod(Class<T> c, Object resource, String 
methodName, T def, Class<?>...requiredParams) throws ExecutableException {
-               ClassInfo ci = ClassInfo.of(resource);
-               for (MethodInfo m : ci.getPublicMethods()) {
-                       if (m.isAll(NOT_DEPRECATED) && m.hasReturnType(c) && 
m.getSimpleName().equals(methodName) && (!m.hasAnnotation(BeanIgnore.class))) {
-                               List<ClassInfo> missing = 
getMissingParamTypes(m.getParamTypes());
-                               if (missing.isEmpty() && 
m.hasAllArgs(requiredParams))
-                                       return m.invoke(resource, 
getParams(m.getParamTypes()));
-                       }
-               }
-               return def;
+       public <T> BeanCreateMethodFinder<T> beanCreateMethodFinder(Class<T> c, 
Object resource) {
+               return new BeanCreateMethodFinder<>(c, resource, this);
        }
 
        /**
@@ -291,8 +308,8 @@ public class BeanFactory {
        public OMap toMap() {
                return OMap.of()
                        .a("beanMap", beanMap.keySet().stream().map(x -> 
x.getSimpleName()).collect(Collectors.toList()))
-                       .a("outer", ObjectUtils.identity(outer))
-                       .a("parent", ObjectUtils.identity(parent));
+                       .asn("outer", ObjectUtils.identity(outer))
+                       .asn("parent", parent.orElse(null));
        }
 
        @Override /* Object */
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/ObjectUtils.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/ObjectUtils.java
index 0798158..41654b0 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/ObjectUtils.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/ObjectUtils.java
@@ -321,10 +321,10 @@ public class ObjectUtils {
         * @return An identity string.
         */
        public static String identity(Object o) {
+               if (o instanceof Optional)
+                       o = ((Optional<?>)o).orElse(null);
                if (o == null)
                        return null;
-               if (o instanceof Optional)
-                       o = ((Optional<?>)o).get();
                return ClassInfo.of(o).getShortName() + "@" + 
System.identityHashCode(o);
        }
 }
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RequestFormData.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RequestFormData.java
index d72db38..c92a9ee 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RequestFormData.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RequestFormData.java
@@ -21,6 +21,7 @@ import java.util.*;
 
 import javax.servlet.http.*;
 
+import org.apache.http.*;
 import org.apache.juneau.*;
 import org.apache.juneau.collections.*;
 import org.apache.juneau.http.annotation.*;
@@ -28,7 +29,7 @@ import org.apache.juneau.httppart.*;
 import org.apache.juneau.internal.*;
 import org.apache.juneau.json.*;
 import org.apache.juneau.oapi.*;
-import org.apache.juneau.parser.*;
+import org.apache.juneau.parser.ParseException;
 import org.apache.juneau.http.exception.*;
 
 /**
@@ -91,6 +92,25 @@ public class RequestFormData extends 
LinkedHashMap<String,String[]> {
        }
 
        /**
+        * Adds default entries to these form-data parameters.
+        *
+        * @param pairs
+        *      The default entries.
+        *      <br>Can be <jk>null</jk>.
+        * @return This object (for method chaining).
+        */
+       public RequestFormData addDefault(NameValuePair...pairs) {
+               for (NameValuePair p : pairs) {
+                       String key = p.getName();
+                       Object value = p.getValue();
+                       String[] v = get(key);
+                       if (v == null || v.length == 0 || 
StringUtils.isEmpty(v[0]))
+                               put(key, stringifyAll(value));
+               }
+               return this;
+       }
+
+       /**
         * Adds a default entries to these form-data parameters.
         *
         * <p>
@@ -562,7 +582,7 @@ public class RequestFormData extends 
LinkedHashMap<String,String[]> {
        public <T> T get(String name, Type type, Type...args) throws 
BadRequest, InternalServerError {
                return getInner(null, null, name, null, 
this.<T>getClassMeta(type, args));
        }
-       
+
        /**
         * Same as {@link #get(String, Type, Type...)} but allows you to 
override the part parser.
         *
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RequestHeaders.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RequestHeaders.java
index 75fe74e..979122b 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RequestHeaders.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RequestHeaders.java
@@ -18,13 +18,14 @@ import static org.apache.juneau.internal.StringUtils.*;
 import java.lang.reflect.*;
 import java.util.*;
 
+import org.apache.http.*;
 import org.apache.juneau.*;
 import org.apache.juneau.collections.*;
 import org.apache.juneau.httppart.*;
 import org.apache.juneau.internal.*;
 import org.apache.juneau.json.*;
 import org.apache.juneau.oapi.*;
-import org.apache.juneau.parser.*;
+import org.apache.juneau.parser.ParseException;
 import org.apache.juneau.http.exception.*;
 import org.apache.juneau.http.header.*;
 import org.apache.juneau.http.header.Date;
@@ -88,6 +89,28 @@ public class RequestHeaders extends TreeMap<String,String[]> 
{
        }
 
        /**
+        * Adds default entries to these headers.
+        *
+        * <p>
+        * Similar to {@link #put(String, Object)} but doesn't override 
existing values.
+        *
+        * @param pairs
+        *      The default entries.
+        *      <br>Can be <jk>null</jk>.
+        * @return This object (for method chaining).
+        */
+       public RequestHeaders addDefault(Header...pairs) {
+               for (Header p : pairs) {
+                       String key = p.getName();
+                       Object value = p.getValue();
+                       String[] v = get(key);
+                       if (v == null || v.length == 0 || 
StringUtils.isEmpty(v[0]))
+                               put(key, stringifyAll(value));
+               }
+               return this;
+       }
+
+       /**
         * Adds a default header value on this request.
         *
         * <p>
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RequestQuery.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RequestQuery.java
index 4ea89c9..1f55775 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RequestQuery.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RequestQuery.java
@@ -20,13 +20,14 @@ import java.util.*;
 
 import javax.servlet.http.*;
 
+import org.apache.http.*;
 import org.apache.juneau.*;
 import org.apache.juneau.collections.*;
 import org.apache.juneau.httppart.*;
 import org.apache.juneau.internal.*;
 import org.apache.juneau.json.*;
 import org.apache.juneau.oapi.*;
-import org.apache.juneau.parser.*;
+import org.apache.juneau.parser.ParseException;
 import org.apache.juneau.http.exception.*;
 import org.apache.juneau.utils.*;
 
@@ -92,6 +93,28 @@ public final class RequestQuery extends 
LinkedHashMap<String,String[]> {
        }
 
        /**
+        * Adds default entries to these query parameters.
+        *
+        * <p>
+        * This includes the default queries defined at the resource and method 
levels.
+        *
+        * @param pairs
+        *      The default entries.
+        *      <br>Can be <jk>null</jk>.
+        * @return This object (for method chaining).
+        */
+       public RequestQuery addDefault(NameValuePair...pairs) {
+               for (NameValuePair p : pairs) {
+                       String key = p.getName();
+                       Object value = p.getValue();
+                       String[] v = get(key);
+                       if (v == null || v.length == 0 || 
StringUtils.isEmpty(v[0]))
+                               put(key, stringifyAll(value));
+               }
+               return this;
+       }
+
+       /**
         * Adds a default entries to these query parameters.
         *
         * <p>
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java
index 621f508..4fddaea 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java
@@ -3689,19 +3689,30 @@ public class RestContext extends BeanContext {
         */
        protected FileFinder createFileFinder(Object resource, BeanFactory 
beanFactory) throws Exception {
                FileFinder x = null;
+
                if (resource instanceof FileFinder)
                        x = (FileFinder)resource;
+
                if (x == null)
                        x = getInstanceProperty(REST_fileFinder, 
FileFinder.class, null, beanFactory);
+
                if (x == null)
                        x = beanFactory.getBean(FileFinder.class).orElse(null);
+
                if (x == null)
                        x = getInstanceProperty(REST_fileFinderDefault, 
FileFinder.class, null, beanFactory);
+
                if (x == null)
                        x = new BasicFileFinder(this);
-               x = BeanFactory.of(beanFactory, resource)
+
+               x = BeanFactory
+                       .of(beanFactory, resource)
                        .addBean(FileFinder.class, x)
-                       .createBeanViaMethod(FileFinder.class, resource, 
"createFileFinder", x);
+                       .beanCreateMethodFinder(FileFinder.class, resource)
+                       .find("createFileFinder")
+                       .withDefault(x)
+                       .run();
+
                return x;
        }
 
@@ -3736,17 +3747,27 @@ public class RestContext extends BeanContext {
         */
        protected RestInfoProvider createInfoProvider(Object resource, 
BeanFactory beanFactory) throws Exception {
                RestInfoProvider x = null;
+
                if (resource instanceof RestInfoProvider)
                        x = (RestInfoProvider)resource;
+
                if (x == null)
                        x = getInstanceProperty(REST_infoProvider, 
RestInfoProvider.class, null, beanFactory);
+
                if (x == null)
                        x = 
beanFactory.getBean(RestInfoProvider.class).orElse(null);
+
                if (x == null)
                        x = new BasicRestInfoProvider(this);
-               x = BeanFactory.of(beanFactory, resource)
+
+               x = BeanFactory
+                       .of(beanFactory, resource)
                        .addBean(RestInfoProvider.class, x)
-                       .createBeanViaMethod(RestInfoProvider.class, resource, 
"createInfoProvider", x);
+                       .beanCreateMethodFinder(RestInfoProvider.class, 
resource)
+                       .find("createInfoProvider")
+                       .withDefault(x)
+                       .run();
+
                return x;
        }
 
@@ -3783,19 +3804,30 @@ public class RestContext extends BeanContext {
         */
        protected StaticFiles createStaticFiles(Object resource, BeanFactory 
beanFactory) throws Exception {
                StaticFiles x = null;
+
                if (resource instanceof StaticFiles)
                        x = (StaticFiles)resource;
+
                if (x == null)
                        x = getInstanceProperty(REST_staticFiles, 
StaticFiles.class, null, beanFactory);
+
                if (x == null)
                        x = beanFactory.getBean(StaticFiles.class).orElse(null);
+
                if (x == null)
                        x = getInstanceProperty(REST_staticFilesDefault, 
StaticFiles.class, null, beanFactory);
+
                if (x == null)
                        x = new BasicStaticFiles(this);
-               x = BeanFactory.of(beanFactory, resource)
+
+               x = BeanFactory
+                       .of(beanFactory, resource)
                        .addBean(StaticFiles.class, x)
-                       .createBeanViaMethod(StaticFiles.class, resource, 
"createStaticFiles", x);
+                       .beanCreateMethodFinder(StaticFiles.class, resource)
+                       .find("createStaticFiles")
+                       .withDefault(x)
+                       .run();
+
                return x;
        }
 
@@ -3832,19 +3864,30 @@ public class RestContext extends BeanContext {
         */
        protected RestLogger createCallLogger(Object resource, BeanFactory 
beanFactory) throws Exception {
                RestLogger x = null;
+
                if (resource instanceof RestLogger)
                        x = (RestLogger)resource;
+
                if (x == null)
                        x = getInstanceProperty(REST_callLogger, 
RestLogger.class, null, beanFactory);
+
                if (x == null)
                        x = beanFactory.getBean(RestLogger.class).orElse(null);
+
                if (x == null)
                        x = getInstanceProperty(REST_callLoggerDefault, 
RestLogger.class, null, beanFactory);
+
                if (x == null)
                        x = new BasicRestLogger(this);
-               x = BeanFactory.of(beanFactory, resource)
+
+               x = BeanFactory
+                       .of(beanFactory, resource)
                        .addBean(RestLogger.class, x)
-                       .createBeanViaMethod(RestLogger.class, resource, 
"createCallLogger", x);
+                       .beanCreateMethodFinder(RestLogger.class, resource)
+                       .find("createCallLogger")
+                       .withDefault(x)
+                       .run();
+
                return x;
        }
 
@@ -3878,18 +3921,28 @@ public class RestContext extends BeanContext {
         */
        protected BeanFactory createBeanFactory(Object resource) throws 
Exception {
                BeanFactory x = null;
+
                if (resource instanceof BeanFactory)
                        x = (BeanFactory)resource;
+
                BeanFactory bf = createRootBeanFactory(resource)
                        .addBean(RestContext.class, this)
                        .addBean(BeanFactory.class, parentContext == null ? 
null : parentContext.rootBeanFactory)
                        .addBean(PropertyStore.class, getPropertyStore())
                        .addBean(Object.class, resource);
+
                if (x == null)
                        x = getInstanceProperty(REST_beanFactory, 
BeanFactory.class, null, bf);
+
                if (x == null)
                        x = bf;
-               x = bf.createBeanViaMethod(BeanFactory.class, resource, 
"createBeanFactory", x);
+
+               x = bf
+                       .beanCreateMethodFinder(BeanFactory.class, resource)
+                       .find("createBeanFactory")
+                       .withDefault(x)
+                       .run();
+
                return x;
        }
 
@@ -3926,16 +3979,26 @@ public class RestContext extends BeanContext {
         */
        protected BeanFactory createRootBeanFactory(Object resource) throws 
Exception {
                BeanFactory x = null;
+
                if (resource instanceof BeanFactory)
                        x = (BeanFactory)resource;
+
                BeanFactory parent = parentContext == null ? null : 
parentContext.rootBeanFactory;
                BeanFactory bf = new BeanFactory(parent, resource);
                bf.addBean(BeanFactory.class, bf);
+
                if (x == null)
                        x = getInstanceProperty(REST_beanFactory, 
BeanFactory.class, null, bf);
+
                if (x == null)
                        x = bf;
-               x = bf.createBeanViaMethod(BeanFactory.class, resource, 
"createBeanFactory", x);
+
+               x = bf
+                       .beanCreateMethodFinder(BeanFactory.class, resource)
+                       .find("createBeanFactory")
+                       .withDefault(x)
+                       .run();
+
                return x;
        }
 
@@ -3969,13 +4032,21 @@ public class RestContext extends BeanContext {
         */
        protected ResponseHandler[] createResponseHandlers(Object resource, 
BeanFactory beanFactory) throws Exception {
                ResponseHandler[] x = 
getInstanceArrayProperty(REST_responseHandlers, ResponseHandler.class, null, 
beanFactory);
+
                if (x == null)
                        x = 
beanFactory.getBean(ResponseHandler[].class).orElse(null);
+
                if (x == null)
                        x = new ResponseHandler[0];
-               x = BeanFactory.of(beanFactory, resource)
+
+               x = BeanFactory
+                       .of(beanFactory, resource)
                        .addBean(ResponseHandler[].class, x)
-                       .createBeanViaMethod(ResponseHandler[].class, resource, 
"createResponseHandlers", x);
+                       .beanCreateMethodFinder(ResponseHandler[].class, 
resource)
+                       .find("createResponseHandlers")
+                       .withDefault(x)
+                       .run();
+
                return x;
        }
 
@@ -4013,10 +4084,13 @@ public class RestContext extends BeanContext {
 
                if (g == null) {
                        Object[] x = getArrayProperty(REST_serializers, 
Object.class);
+
                        if (x == null)
                                x = 
beanFactory.getBean(Serializer[].class).orElse(null);
+
                        if (x == null)
                                x = new Serializer[0];
+
                        g = SerializerGroup
                                .create()
                                .append(x)
@@ -4024,9 +4098,13 @@ public class RestContext extends BeanContext {
                                .build();
                }
 
-               g = BeanFactory.of(beanFactory, resource)
+               g = BeanFactory
+                       .of(beanFactory, resource)
                        .addBean(SerializerGroup.class, g)
-                       .createBeanViaMethod(SerializerGroup.class, resource, 
"createSerializers", g);
+                       .beanCreateMethodFinder(SerializerGroup.class, resource)
+                       .find("createSerializers")
+                       .withDefault(g)
+                       .run();
 
                return g;
        }
@@ -4065,10 +4143,13 @@ public class RestContext extends BeanContext {
 
                if (g == null) {
                        Object[] x = getArrayProperty(REST_parsers, 
Object.class);
+
                        if (x == null)
                                x = 
beanFactory.getBean(Parser[].class).orElse(null);
+
                        if (x == null)
                                x = new Parser[0];
+
                        g = ParserGroup
                                .create()
                                .append(x)
@@ -4076,9 +4157,13 @@ public class RestContext extends BeanContext {
                                .build();
                }
 
-               g = BeanFactory.of(beanFactory, resource)
+               g = BeanFactory
+                       .of(beanFactory, resource)
                        .addBean(ParserGroup.class, g)
-                       .createBeanViaMethod(ParserGroup.class, resource, 
"createParsers", g);
+                       .beanCreateMethodFinder(ParserGroup.class, resource)
+                       .find("createParsers")
+                       .withDefault(g)
+                       .run();
 
                return g;
        }
@@ -4114,17 +4199,27 @@ public class RestContext extends BeanContext {
         */
        protected HttpPartSerializer createPartSerializer(Object resource, 
BeanFactory beanFactory) throws Exception {
                HttpPartSerializer x = null;
+
                if (resource instanceof HttpPartSerializer)
                        x = (HttpPartSerializer)resource;
+
                if (x == null)
                        x = getInstanceProperty(REST_partSerializer, 
HttpPartSerializer.class, null, beanFactory);
+
                if (x == null)
                        x = 
beanFactory.getBean(HttpPartSerializer.class).orElse(null);
+
                if (x == null)
                        x = new OpenApiSerializer(getPropertyStore());
-               x = BeanFactory.of(beanFactory, resource)
+
+               x = BeanFactory
+                       .of(beanFactory, resource)
                        .addBean(HttpPartSerializer.class, x)
-                       .createBeanViaMethod(HttpPartSerializer.class, 
resource, "createPartSerializer", x);
+                       .beanCreateMethodFinder(HttpPartSerializer.class, 
resource)
+                       .find("createPartSerializer")
+                       .withDefault(x)
+                       .run();
+
                return x;
        }
 
@@ -4159,17 +4254,27 @@ public class RestContext extends BeanContext {
         */
        protected HttpPartParser createPartParser(Object resource, BeanFactory 
beanFactory) throws Exception {
                HttpPartParser x = null;
+
                if (resource instanceof HttpPartParser)
                        x = (HttpPartParser)resource;
+
                if (x == null)
                        x = getInstanceProperty(REST_partParser, 
HttpPartParser.class, null, beanFactory);
+
                if (x == null)
                        x = 
beanFactory.getBean(HttpPartParser.class).orElse(null);
+
                if (x == null)
                        x = new OpenApiParser(getPropertyStore());
-               x = BeanFactory.of(beanFactory, resource)
+
+               x = BeanFactory
+                       .of(beanFactory, resource)
                        .addBean(HttpPartParser.class, x)
-                       .createBeanViaMethod(HttpPartParser.class, resource, 
"createPartParser", x);
+                       .beanCreateMethodFinder(HttpPartParser.class, resource)
+                       .find("createPartParser")
+                       .withDefault(x)
+                       .run();
+
                return x;
        }
 
@@ -4203,13 +4308,21 @@ public class RestContext extends BeanContext {
         */
        protected RestMethodParam[] createParamResolvers(Object resource, 
BeanFactory beanFactory) throws Exception {
                RestMethodParam[] x = 
getInstanceArrayProperty(REST_paramResolvers, RestMethodParam.class, null, 
beanFactory);
+
                if (x == null)
                        x = 
beanFactory.getBean(RestMethodParam[].class).orElse(null);
+
                if (x == null)
                        x = new RestMethodParam[0];
-               x = BeanFactory.of(beanFactory, resource)
+
+               x = BeanFactory
+                       .of(beanFactory, resource)
                        .addBean(RestMethodParam[].class, x)
-                       .createBeanViaMethod(RestMethodParam[].class, resource, 
"createParamResolvers", x);
+                       .beanCreateMethodFinder(RestMethodParam[].class, 
resource)
+                       .find("createParamResolvers")
+                       .withDefault(x)
+                       .run();
+
                return x;
        }
 
@@ -4237,11 +4350,18 @@ public class RestContext extends BeanContext {
         */
        protected Logger createLogger(Object resource, BeanFactory beanFactory) 
throws Exception {
                Logger x = beanFactory.getBean(Logger.class).orElse(null);
+
                if (x == null)
                        x = Logger.getLogger(resource.getClass().getName());
-               x = BeanFactory.of(beanFactory, resource)
+
+               x = BeanFactory
+                       .of(beanFactory, resource)
                        .addBean(Logger.class, x)
-                       .createBeanViaMethod(Logger.class, resource, 
"createLogger", x);
+                       .beanCreateMethodFinder(Logger.class, resource)
+                       .find("createLogger")
+                       .withDefault(x)
+                       .run();
+
                return x;
        }
 
@@ -4269,14 +4389,21 @@ public class RestContext extends BeanContext {
         */
        protected JsonSchemaGenerator createJsonSchemaGenerator(Object 
resource, BeanFactory beanFactory) throws Exception {
                JsonSchemaGenerator x = 
beanFactory.getBean(JsonSchemaGenerator.class).orElse(null);
+
                if (x == null)
                        x = JsonSchemaGenerator
                                .create()
                                .apply(getPropertyStore())
                                .build();
-               x = BeanFactory.of(beanFactory, resource)
+
+               x = BeanFactory
+                       .of(beanFactory, resource)
                        .addBean(JsonSchemaGenerator.class, x)
-                       .createBeanViaMethod(JsonSchemaGenerator.class, 
resource, "createJsonSchemaGenerator", x);
+                       .beanCreateMethodFinder(JsonSchemaGenerator.class, 
resource)
+                       .find("createJsonSchemaGenerator")
+                       .withDefault(x)
+                       .run();
+
                return x;
        }
 
@@ -4304,14 +4431,18 @@ public class RestContext extends BeanContext {
         */
        protected VarResolver createVarResolver(Object resource, BeanFactory 
beanFactory) throws Exception {
                VarResolver x = 
beanFactory.getBean(VarResolver.class).orElse(null);
+
                if (x == null)
-                       x = builder.varResolverBuilder
-                       .vars(createVars(resource,beanFactory))
-                       .build()
-               ;
-               x = BeanFactory.of(beanFactory, resource)
+                       x = 
builder.varResolverBuilder.vars(createVars(resource,beanFactory)).build();
+
+               x = BeanFactory
+                       .of(beanFactory, resource)
                        .addBean(VarResolver.class, x)
-                       .createBeanViaMethod(VarResolver.class, resource, 
"createVarResolver", x);
+                       .beanCreateMethodFinder(VarResolver.class, resource)
+                       .find("createVarResolver")
+                       .withDefault(x)
+                       .run();
+
                return x;
        }
 
@@ -4340,6 +4471,7 @@ public class RestContext extends BeanContext {
        @SuppressWarnings("unchecked")
        protected VarList createVars(Object resource, BeanFactory beanFactory) 
throws Exception {
                VarList x = beanFactory.getBean(VarList.class).orElse(null);
+
                if (x == null)
                        x = VarList.of(
                                FileVar.class,
@@ -4358,9 +4490,15 @@ public class RestContext extends BeanContext {
                                UrlEncodeVar.class,
                                HtmlWidgetVar.class
                        );
-               x = BeanFactory.of(beanFactory, resource)
+
+               x = BeanFactory
+                       .of(beanFactory, resource)
                        .addBean(VarList.class, x)
-                       .createBeanViaMethod(VarList.class, resource, 
"createVars", x);
+                       .beanCreateMethodFinder(VarList.class, resource)
+                       .find("createVars")
+                       .withDefault(x)
+                       .run();
+
                return x;
        }
 
@@ -4388,11 +4526,18 @@ public class RestContext extends BeanContext {
         */
        protected StackTraceStore createStackTraceStore(Object resource, 
BeanFactory beanFactory) throws Exception {
                StackTraceStore x = 
beanFactory.getBean(StackTraceStore.class).orElse(null);
+
                if (x == null)
                        x = StackTraceStore.GLOBAL;
-               x = BeanFactory.of(beanFactory, resource)
+
+               x = BeanFactory
+                       .of(beanFactory, resource)
                        .addBean(StackTraceStore.class, x)
-                       .createBeanViaMethod(StackTraceStore.class, resource, 
"createStackTraceStore", x);
+                       .beanCreateMethodFinder(StackTraceStore.class, resource)
+                       .find("createStackTraceStore")
+                       .withDefault(x)
+                       .run();
+
                return x;
        }
 
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContextBuilder.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContextBuilder.java
index d42ef49..e26f43f 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContextBuilder.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContextBuilder.java
@@ -203,8 +203,11 @@ public class RestContextBuilder extends BeanContextBuilder 
implements ServletCon
                BeanFactory x = null;
                if (resource.isPresent()) {
                        Object r = resource.get();
-                       BeanFactory bf = new 
BeanFactory(parentContext.isPresent() ? parentContext.get().rootBeanFactory : 
null, r);
-                       x = bf.createBeanViaMethod(BeanFactory.class, r, 
"createBeanFactory", null);
+                       x = BeanFactory
+                               .of(parentContext.isPresent() ? 
parentContext.get().rootBeanFactory : null, r)
+                               .beanCreateMethodFinder(BeanFactory.class, 
resource)
+                               .find("createBeanFactory")
+                               .run();
                }
                if (x == null && parentContext.isPresent()) {
                        x = parentContext.get().rootBeanFactory;
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestMethodContext.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestMethodContext.java
index ab1b125..9fc8663 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestMethodContext.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestMethodContext.java
@@ -32,6 +32,8 @@ import java.util.concurrent.atomic.*;
 import javax.servlet.*;
 import javax.servlet.http.*;
 
+import org.apache.http.*;
+import org.apache.http.ParseException;
 import org.apache.juneau.*;
 import org.apache.juneau.annotation.*;
 import org.apache.juneau.collections.*;
@@ -39,6 +41,7 @@ import org.apache.juneau.cp.*;
 import org.apache.juneau.encoders.*;
 import org.apache.juneau.http.*;
 import org.apache.juneau.http.annotation.*;
+import org.apache.juneau.http.annotation.Header;
 import org.apache.juneau.httppart.*;
 import org.apache.juneau.httppart.bean.*;
 import org.apache.juneau.internal.*;
@@ -529,10 +532,9 @@ public class RestMethodContext extends BeanContext 
implements Comparable<RestMet
        final HttpPartSerializer partSerializer;
        final HttpPartParser partParser;
        final JsonSchemaGenerator jsonSchemaGenerator;
-       final Map<String,Object>
-               reqHeaders,
-               defaultQuery,
-               defaultFormData;
+       final org.apache.http.Header[] defaultRequestHeaders;
+       final NameValuePair[] defaultRequestQuery;
+       final NameValuePair[] defaultRequestFormData;
        final OMap reqAttrs;
        final String defaultCharset;
        final long maxInput;
@@ -624,57 +626,13 @@ public class RestMethodContext extends BeanContext 
implements Comparable<RestMet
 
                        methodParams = context.findParams(mi, false, 
pathMatchers[this.pathMatchers.length-1]);
 
-                       Map<String,Object> _reqHeaders = new 
TreeMap<>(String.CASE_INSENSITIVE_ORDER);
-                       
_reqHeaders.putAll(getMapProperty(RESTMETHOD_reqHeaders, Object.class));
+                       defaultRequestHeaders = createDefaultRequestHeaders(r, 
beanFactory, method);
+                       defaultRequestQuery = createDefaultRequestQuery(r, 
beanFactory, method);
+                       defaultRequestFormData = 
createDefaultRequestFormData(r, beanFactory, method);
 
                        OMap _reqAttrs = new 
OMap(context.getReqAttrs()).appendAll(getMapProperty(RESTMETHOD_reqAttrs, 
Object.class));
 
-                       Map<String,Object> _defaultQuery = new 
LinkedHashMap<>(getMapProperty(RESTMETHOD_defaultQuery, Object.class));
-
-                       Map<String,Object> _defaultFormData = new 
LinkedHashMap<>(getMapProperty(RESTMETHOD_defaultFormData, Object.class));
-
-                       Type[] pt = method.getGenericParameterTypes();
-                       Annotation[][] pa = method.getParameterAnnotations();
-                       for (int i = 0; i < pt.length; i++) {
-                               for (Annotation a : pa[i]) {
-                                       if (a instanceof Header) {
-                                               Header h = (Header)a;
-                                               String def = 
joinnlFirstNonEmptyArray(h._default(), h.df());
-                                               if (def != null) {
-                                                       try {
-                                                               
_reqHeaders.put(firstNonEmpty(h.name(), h.n(), h.value()), parseAnything(def));
-                                                       } catch (ParseException 
e) {
-                                                               throw new 
ConfigException(e, "Malformed @Header annotation");
-                                                       }
-                                               }
-                                       } else if (a instanceof Query) {
-                                               Query q = (Query)a;
-                                               String def = 
joinnlFirstNonEmptyArray(q._default(), q.df());
-                                               if (def != null) {
-                                                       try {
-                                                               
_defaultQuery.put(firstNonEmpty(q.name(), q.n(), q.value()), 
parseAnything(def));
-                                                       } catch (ParseException 
e) {
-                                                               throw new 
ConfigException(e, "Malformed @Query annotation");
-                                                       }
-                                               }
-                                       } else if (a instanceof FormData) {
-                                               FormData f = (FormData)a;
-                                               String def = 
joinnlFirstNonEmptyArray(f._default(), f.df());
-                                               if (def != null) {
-                                                       try {
-                                                               
_defaultFormData.put(firstNonEmpty(f.name(), f.value(), f.n()), 
parseAnything(def));
-                                                       } catch (ParseException 
e) {
-                                                               throw new 
ConfigException(e, "Malformed @FormData annotation");
-                                                       }
-                                               }
-                                       }
-                               }
-                       }
-
-                       this.reqHeaders = 
Collections.unmodifiableMap(_reqHeaders);
                        this.reqAttrs = _reqAttrs.unmodifiable();
-                       this.defaultQuery = 
Collections.unmodifiableMap(_defaultQuery);
-                       this.defaultFormData = 
Collections.unmodifiableMap(_defaultFormData);
 
                        this.priority = getIntegerProperty(RESTMETHOD_priority, 
0);
 
@@ -742,13 +700,22 @@ public class RestMethodContext extends BeanContext 
implements Comparable<RestMet
         */
        protected RestConverter[] createConverters(Object resource, BeanFactory 
beanFactory) throws Exception {
                RestConverter[] x = getInstanceArrayProperty(REST_converters, 
RestConverter.class, null, beanFactory);
+
                if (x == null)
                        x = 
beanFactory.getBean(RestConverter[].class).orElse(null);
+
                if (x == null)
                        x = new RestConverter[0];
-               x = BeanFactory.of(beanFactory, resource)
+
+               x = BeanFactory
+                       .of(beanFactory, resource)
                        .addBean(RestConverter[].class, x)
-                       .createBeanViaMethod(RestConverter[].class, resource, 
"createConverters", x);
+                       .beanCreateMethodFinder(RestConverter[].class, resource)
+                       .find("createConverters", Method.class)
+                       .thenFind("createConverters")
+                       .withDefault(x)
+                       .run();
+
                return x;
        }
 
@@ -784,8 +751,10 @@ public class RestMethodContext extends BeanContext 
implements Comparable<RestMet
         */
        protected RestGuard[] createGuards(Object resource, BeanFactory 
beanFactory) throws Exception {
                RestGuard[] x = getInstanceArrayProperty(REST_guards, 
RestGuard.class, null, beanFactory);
+
                if (x == null)
                        x = beanFactory.getBean(RestGuard[].class).orElse(null);
+
                if (x == null)
                        x = new RestGuard[0];
 
@@ -805,9 +774,14 @@ public class RestMethodContext extends BeanContext 
implements Comparable<RestMet
 
                x = xl.toArray(new RestGuard[xl.size()]);
 
-               x = BeanFactory.of(beanFactory, resource)
+               x = BeanFactory
+                       .of(beanFactory, resource)
                        .addBean(RestGuard[].class, x)
-                       .createBeanViaMethod(RestGuard[].class, resource, 
"createGuards", x);
+                       .beanCreateMethodFinder(RestGuard[].class, resource)
+                       .find("createGuards", Method.class)
+                       .thenFind("createGuards")
+                       .withDefault(x)
+                       .run();
 
                return x;
        }
@@ -842,8 +816,10 @@ public class RestMethodContext extends BeanContext 
implements Comparable<RestMet
         */
        protected RestMatcher[] createMatchers(Object resource, BeanFactory 
beanFactory) throws Exception {
                RestMatcher[] x = getInstanceArrayProperty(RESTMETHOD_matchers, 
RestMatcher.class, null, beanFactory);
+
                if (x == null)
                        x = 
beanFactory.getBean(RestMatcher[].class).orElse(null);
+
                if (x == null)
                        x = new RestMatcher[0];
 
@@ -851,9 +827,13 @@ public class RestMethodContext extends BeanContext 
implements Comparable<RestMet
                if (clientVersion != null)
                        x = ArrayUtils.append(x, new 
ClientVersionMatcher(context.getClientVersionHeader(), mi));
 
-               x = BeanFactory.of(beanFactory, resource)
+               x = BeanFactory
+                       .of(beanFactory, resource)
                        .addBean(RestMatcher[].class, x)
-                       .createBeanViaMethod(RestMatcher[].class, resource, 
"createMatchers", x);
+                       .beanCreateMethodFinder(RestMatcher[].class, resource)
+                       .find("createMatchers", Method.class)
+                       .withDefault(x)
+                       .run();
 
                return x;
        }
@@ -890,8 +870,10 @@ public class RestMethodContext extends BeanContext 
implements Comparable<RestMet
         */
        protected EncoderGroup createEncoders(Object resource, BeanFactory 
beanFactory) throws Exception {
                Encoder[] x = getInstanceArrayProperty(REST_encoders, 
Encoder.class, null, beanFactory);
+
                if (x == null)
                        x = beanFactory.getBean(Encoder[].class).orElse(null);
+
                if (x == null)
                        x = new Encoder[0];
 
@@ -901,9 +883,14 @@ public class RestMethodContext extends BeanContext 
implements Comparable<RestMet
                        .append(x)
                        .build();
 
-               g = BeanFactory.of(beanFactory, resource)
+               g = BeanFactory
+                       .of(beanFactory, resource)
                        .addBean(EncoderGroup.class, g)
-                       .createBeanViaMethod(EncoderGroup.class, resource, 
"createEncoders", g);
+                       .beanCreateMethodFinder(EncoderGroup.class, resource)
+                       .find("createEncoders", Method.class)
+                       .thenFind("createEncoders")
+                       .withDefault(g)
+                       .run();
 
                return g;
        }
@@ -942,10 +929,13 @@ public class RestMethodContext extends BeanContext 
implements Comparable<RestMet
 
                if (g == null) {
                        Object[] x = getArrayProperty(REST_serializers, 
Object.class);
+
                        if (x == null)
                                x = 
beanFactory.getBean(Serializer[].class).orElse(null);
+
                        if (x == null)
                                x = new Serializer[0];
+
                        g = SerializerGroup
                                .create()
                                .append(x)
@@ -953,12 +943,14 @@ public class RestMethodContext extends BeanContext 
implements Comparable<RestMet
                                .build();
                }
 
-               g = BeanFactory.of(beanFactory, resource)
-                       .addBean(SerializerGroup.class, g)
-                       .createBeanViaMethod(SerializerGroup.class, resource, 
"createSerializers", g, Method.class);
-               g = BeanFactory.of(beanFactory, resource)
+               g = BeanFactory
+                       .of(beanFactory, resource)
                        .addBean(SerializerGroup.class, g)
-                       .createBeanViaMethod(SerializerGroup.class, resource, 
"createSerializers", g);
+                       .beanCreateMethodFinder(SerializerGroup.class, resource)
+                       .find("createSerializers", Method.class)
+                       .thenFind("createSerializers")
+                       .withDefault(g)
+                       .run();
 
                return g;
        }
@@ -997,10 +989,13 @@ public class RestMethodContext extends BeanContext 
implements Comparable<RestMet
 
                if (g == null) {
                        Object[] x = getArrayProperty(REST_parsers, 
Object.class);
+
                        if (x == null)
                                x = 
beanFactory.getBean(Parser[].class).orElse(null);
+
                        if (x == null)
                                x = new Parser[0];
+
                        g = ParserGroup
                                .create()
                                .append(x)
@@ -1008,12 +1003,14 @@ public class RestMethodContext extends BeanContext 
implements Comparable<RestMet
                                .build();
                }
 
-               g = BeanFactory.of(beanFactory, resource)
+               g = BeanFactory
+                       .of(beanFactory, resource)
                        .addBean(ParserGroup.class, g)
-                       .createBeanViaMethod(ParserGroup.class, resource, 
"createParsers", g, Method.class);
-               g = BeanFactory.of(beanFactory, resource)
-                       .addBean(ParserGroup.class, g)
-                       .createBeanViaMethod(ParserGroup.class, resource, 
"createParsers", g);
+                       .beanCreateMethodFinder(ParserGroup.class, resource)
+                       .find("createParsers", Method.class)
+                       .thenFind("createParsers")
+                       .withDefault(g)
+                       .run();
 
                return g;
        }
@@ -1050,20 +1047,28 @@ public class RestMethodContext extends BeanContext 
implements Comparable<RestMet
         */
        protected HttpPartSerializer createPartSerializer(Object resource, 
BeanFactory beanFactory, PropertyStore ps) throws Exception {
                HttpPartSerializer x = null;
+
                if (resource instanceof HttpPartSerializer)
                        x = (HttpPartSerializer)resource;
+
                if (x == null)
                        x = getInstanceProperty(REST_partSerializer, 
HttpPartSerializer.class, null, beanFactory);
+
                if (x == null)
                        x = 
beanFactory.getBean(HttpPartSerializer.class).orElse(null);
+
                if (x == null)
                        x = new OpenApiSerializer(ps);
-               x = BeanFactory.of(beanFactory, resource)
-                       .addBean(HttpPartSerializer.class, x)
-                       .createBeanViaMethod(HttpPartSerializer.class, 
resource, "createPartSerializer", x, Method.class);
-               x = BeanFactory.of(beanFactory, resource)
+
+               x = BeanFactory
+                       .of(beanFactory, resource)
                        .addBean(HttpPartSerializer.class, x)
-                       .createBeanViaMethod(HttpPartSerializer.class, 
resource, "createPartSerializer", x);
+                       .beanCreateMethodFinder(HttpPartSerializer.class, 
resource)
+                       .find("createPartSerializer", Method.class)
+                       .thenFind("createPartSerializer")
+                       .withDefault(x)
+                       .run();
+
                return x;
        }
 
@@ -1099,20 +1104,28 @@ public class RestMethodContext extends BeanContext 
implements Comparable<RestMet
         */
        protected HttpPartParser createPartParser(Object resource, BeanFactory 
beanFactory, PropertyStore ps) throws Exception {
                HttpPartParser x = null;
+
                if (resource instanceof HttpPartParser)
                        x = (HttpPartParser)resource;
+
                if (x == null)
                        x = getInstanceProperty(REST_partParser, 
HttpPartParser.class, null, beanFactory);
+
                if (x == null)
                        x = 
beanFactory.getBean(HttpPartParser.class).orElse(null);
+
                if (x == null)
                        x = new OpenApiParser(ps);
-               x = BeanFactory.of(beanFactory, resource)
-                       .addBean(HttpPartParser.class, x)
-                       .createBeanViaMethod(HttpPartParser.class, resource, 
"createPartParser", x, Method.class);
-               x = BeanFactory.of(beanFactory, resource)
+
+               x = BeanFactory
+                       .of(beanFactory, resource)
                        .addBean(HttpPartParser.class, x)
-                       .createBeanViaMethod(HttpPartParser.class, resource, 
"createPartParser", x);
+                       .beanCreateMethodFinder(HttpPartParser.class, resource)
+                       .find("createPartParser", Method.class)
+                       .thenFind("createPartParser")
+                       .withDefault(x)
+                       .run();
+
                return x;
        }
 
@@ -1128,22 +1141,29 @@ public class RestMethodContext extends BeanContext 
implements Comparable<RestMet
         */
        protected UrlPathMatcher[] createPathMatchers(Object resource, 
BeanFactory beanFactory, boolean dotAll) throws Exception {
                List<UrlPathMatcher> x = AList.of();
+
                for (String p : getArrayProperty(RESTMETHOD_paths, 
String.class)) {
                        if (dotAll && ! p.endsWith("/*"))
                                p += "/*";
                        x.add(UrlPathMatcher.of(p));
                }
+
                if (x.isEmpty()) {
                        String p = HttpUtils.detectHttpPath(method, true);
                        if (dotAll && ! p.endsWith("/*"))
                                p += "/*";
                        x.add(UrlPathMatcher.of(p));
                }
+
                UrlPathMatcher[] x2 = x.toArray(new UrlPathMatcher[x.size()]);;
 
-               x2 = BeanFactory.of(beanFactory, resource)
+               x2 = BeanFactory
+                       .of(beanFactory, resource)
                        .addBean(UrlPathMatcher[].class, x2)
-                       .createBeanViaMethod(UrlPathMatcher[].class, resource, 
"createPathMatchers", x2, Method.class);
+                       .beanCreateMethodFinder(UrlPathMatcher[].class, 
resource)
+                       .find("createPathMatchers", Method.class)
+                       .withDefault(x2)
+                       .run();
 
                return x2;
        }
@@ -1159,23 +1179,154 @@ public class RestMethodContext extends BeanContext 
implements Comparable<RestMet
         */
        protected JsonSchemaGenerator createJsonSchemaGenerator(Object 
resource, BeanFactory beanFactory, PropertyStore ps) throws Exception {
                JsonSchemaGenerator x = null;
+
                if (resource instanceof JsonSchemaGenerator)
                        x = (JsonSchemaGenerator)resource;
+
                if (x == null)
                        x = 
beanFactory.getBean(JsonSchemaGenerator.class).orElse(null);
+
                if (x == null)
                        x = JsonSchemaGenerator.create().apply(ps).build();
 
-               x = BeanFactory.of(beanFactory, resource)
+               x = BeanFactory
+                       .of(beanFactory, resource)
                        .addBean(JsonSchemaGenerator.class, x)
-                       .createBeanViaMethod(JsonSchemaGenerator.class, 
resource, "createJsonSchemaGenerator", x, Method.class);
-               x = BeanFactory.of(beanFactory, resource)
-                       .addBean(JsonSchemaGenerator.class, x)
-                       .createBeanViaMethod(JsonSchemaGenerator.class, 
resource, "createJsonSchemaGenerator", x);
+                       .beanCreateMethodFinder(JsonSchemaGenerator.class, 
resource)
+                       .find("createJsonSchemaGenerator", Method.class)
+                       .thenFind("createJsonSchemaGenerator")
+                       .withDefault(x)
+                       .run();
 
                return x;
        }
 
+       /**
+        * Instantiates the default request headers for this method.
+        *
+        * @param resource The REST resource object.
+        * @param beanFactory The bean factory to use for retrieving and 
creating beans.
+        * @param method This Java method.
+        * @return The default request headers for this method.
+        * @throws Exception If default request headers could not be 
instantiated.
+        */
+       protected org.apache.http.Header[] createDefaultRequestHeaders(Object 
resource, BeanFactory beanFactory, Method method) throws Exception {
+               Map<String,Object> x = new 
TreeMap<>(String.CASE_INSENSITIVE_ORDER);
+               x.putAll(getMapProperty(RESTMETHOD_reqHeaders, Object.class));
+
+               for (Annotation[] aa : method.getParameterAnnotations()) {
+                       for (Annotation a : aa) {
+                               if (a instanceof Header) {
+                                       Header h = (Header)a;
+                                       String def = 
joinnlFirstNonEmptyArray(h._default(), h.df());
+                                       if (def != null) {
+                                               try {
+                                                       
x.put(firstNonEmpty(h.name(), h.n(), h.value()), parseAnything(def));
+                                               } catch (ParseException e) {
+                                                       throw new 
ConfigException(e, "Malformed @Header annotation");
+                                               }
+                                       }
+                               }
+                       }
+               }
+
+               org.apache.http.Header[] x2 = 
x.entrySet().stream().map(e->BasicHeader.of(e.getKey(),e.getValue())).toArray(org.apache.http.Header[]::new);
+
+               x2 = BeanFactory
+                       .of(beanFactory, resource)
+                       .addBean(org.apache.http.Header[].class, x2)
+                       .beanCreateMethodFinder(org.apache.http.Header[].class, 
resource)
+                       .find("createDefaultRequestHeaders", Method.class)
+                       .thenFind("createDefaultRequestHeaders")
+                       .withDefault(x2)
+                       .run();
+
+               return x2;
+       }
+
+       /**
+        * Instantiates the default query parameters for this method.
+        *
+        * @param resource The REST resource object.
+        * @param beanFactory The bean factory to use for retrieving and 
creating beans.
+        * @param method This Java method.
+        * @return The default request query parameters for this method.
+        * @throws Exception If default request query parameters could not be 
instantiated.
+        */
+       protected NameValuePair[] createDefaultRequestQuery(Object resource, 
BeanFactory beanFactory, Method method) throws Exception {
+               Map<String,Object> x = new 
LinkedHashMap<>(getMapProperty(RESTMETHOD_defaultQuery, Object.class));
+
+               for (Annotation[] aa : method.getParameterAnnotations()) {
+                       for (Annotation a : aa) {
+                               if (a instanceof Query) {
+                                       Query h = (Query)a;
+                                       String def = 
joinnlFirstNonEmptyArray(h._default(), h.df());
+                                       if (def != null) {
+                                               try {
+                                                       
x.put(firstNonEmpty(h.name(), h.n(), h.value()), parseAnything(def));
+                                               } catch (ParseException e) {
+                                                       throw new 
ConfigException(e, "Malformed @Query annotation");
+                                               }
+                                       }
+                               }
+                       }
+               }
+
+               NameValuePair[] x2 = 
x.entrySet().stream().map(e->BasicNameValuePair.of(e.getKey(),e.getValue())).toArray(NameValuePair[]::new);
+
+               x2 = BeanFactory
+                       .of(beanFactory, resource)
+                       .addBean(NameValuePair[].class, x2)
+                       .beanCreateMethodFinder(NameValuePair[].class, resource)
+                       .find("createDefaultRequestQuery", Method.class)
+                       .thenFind("createDefaultRequestQuery")
+                       .withDefault(x2)
+                       .run();
+
+               return x2;
+       }
+
+       /**
+        * Instantiates the default form-data parameters for this method.
+        *
+        * @param resource The REST resource object.
+        * @param beanFactory The bean factory to use for retrieving and 
creating beans.
+        * @param method This Java method.
+        * @return The default request form-data parameters for this method.
+        * @throws Exception If default request form-data parameters could not 
be instantiated.
+        */
+       protected NameValuePair[] createDefaultRequestFormData(Object resource, 
BeanFactory beanFactory, Method method) throws Exception {
+               Map<String,Object> x = new 
LinkedHashMap<>(getMapProperty(RESTMETHOD_defaultFormData, Object.class));
+
+               for (Annotation[] aa : method.getParameterAnnotations()) {
+                       for (Annotation a : aa) {
+                               if (a instanceof FormData) {
+                                       FormData h = (FormData)a;
+                                       String def = 
joinnlFirstNonEmptyArray(h._default(), h.df());
+                                       if (def != null) {
+                                               try {
+                                                       
x.put(firstNonEmpty(h.name(), h.n(), h.value()), parseAnything(def));
+                                               } catch (ParseException e) {
+                                                       throw new 
ConfigException(e, "Malformed @FormData annotation");
+                                               }
+                                       }
+                               }
+                       }
+               }
+
+               NameValuePair[] x2 = 
x.entrySet().stream().map(e->BasicNameValuePair.of(e.getKey(),e.getValue())).toArray(NameValuePair[]::new);
+
+               x2 = BeanFactory
+                       .of(beanFactory, resource)
+                       .addBean(NameValuePair[].class, x2)
+                       .beanCreateMethodFinder(NameValuePair[].class, resource)
+                       .find("createDefaultRequestFormData", Method.class)
+                       .thenFind("createDefaultRequestFormData")
+                       .withDefault(x2)
+                       .run();
+
+               return x2;
+       }
 
        ResponsePartMeta getResponseHeaderMeta(Object o) {
                if (o == null)
@@ -1568,9 +1719,9 @@ public class RestMethodContext extends BeanContext 
implements Comparable<RestMet
        public OMap toMap() {
                return super.toMap()
                        .a("RestMethodContext", new DefaultFilteringOMap()
-                               .a("defaultFormData", defaultFormData)
-                               .a("defaultQuery", defaultQuery)
-                               .a("reqHeaders", reqHeaders)
+                               .a("defaultRequestFormData", 
defaultRequestFormData)
+                               .a("defaultRequestHeaders", 
defaultRequestHeaders)
+                               .a("defaultRequestQuery", defaultRequestQuery)
                                .a("httpMethod", httpMethod)
                                .a("priority", priority)
                        );
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestRequest.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestRequest.java
index 5f3bc76..c9e325c 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestRequest.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestRequest.java
@@ -34,6 +34,7 @@ import java.util.logging.*;
 import javax.servlet.*;
 import javax.servlet.http.*;
 
+import org.apache.http.*;
 import org.apache.juneau.*;
 import org.apache.juneau.config.*;
 import org.apache.juneau.cp.*;
@@ -202,10 +203,10 @@ public final class RestRequest extends 
HttpServletRequestWrapper {
                this.pathParams
                        .parser(partParserSession);
                this.queryParams
-                       .addDefault(rjm.defaultQuery)
+                       .addDefault(rjm.defaultRequestQuery)
                        .parser(partParserSession);
                this.headers
-                       .addDefault(rjm.reqHeaders)
+                       .addDefault(rjm.defaultRequestHeaders)
                        .addDefault(context.getReqHeaders())
                        .parser(partParserSession);
                this.attrs = new RequestAttributes(this, rjm.reqAttrs);
@@ -605,7 +606,8 @@ public final class RestRequest extends 
HttpServletRequestWrapper {
                                        }
                                }
                        }
-                       formData.addDefault(restJavaMethod == null ? null : 
restJavaMethod.defaultFormData);
+                       if (restJavaMethod != null)
+                               
formData.addDefault(restJavaMethod.defaultRequestFormData);
                        return formData;
                } catch (Exception e) {
                        throw new InternalServerError(e);

Reply via email to