REST refactoring.
diff --git a/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/utils/MethodInvokerTest.java b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/utils/MethodInvokerTest.java
index 608e808..bad0383 100644
--- a/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/utils/MethodInvokerTest.java
+++ b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/utils/MethodInvokerTest.java
@@ -83,7 +83,7 @@
assertEquals(m, mi.inner().inner());
assertEquals("A", mi.getDeclaringClass().getSimpleName());
- assertEquals("foo", mi.getName());
+ assertEquals(A.class.getName() + ".foo()", mi.getFullName());
}
}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/StringUtils.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/StringUtils.java
index f87d395..9e035fa 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/StringUtils.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/StringUtils.java
@@ -2428,7 +2428,13 @@
Object[] args2 = new Object[args.length];
for (int i = 0; i < args.length; i++)
args2[i] = convertToReadable(args[i]);
- return MessageFormat.format(pattern, args2);
+
+ int c = countChars(pattern, '\'');
+ if (c % 2 != 0)
+ throw new AssertionError("Dangling single quote found in pattern: " + pattern);
+
+ String msg = MessageFormat.format(pattern, args2);
+ return msg;
}
private static String convertToReadable(Object o) {
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/ClassInfo.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/ClassInfo.java
index ac5e52b..7a4cdaa 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/ClassInfo.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/ClassInfo.java
@@ -2353,6 +2353,15 @@
return c != null && c.isAnnotation();
}
+ /**
+ * Returns <jk>true</jk> if this class is a {@link Collection} or an array.
+ *
+ * @return <jk>true</jk> if this class is a {@link Collection} or an array.
+ */
+ public boolean isCollectionOrArray() {
+ return c != null && (Collection.class.isAssignableFrom(c) || c.isArray());
+ }
+
//-----------------------------------------------------------------------------------------------------------------
// Instantiation
//-----------------------------------------------------------------------------------------------------------------
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/ParamInfo.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/ParamInfo.java
index 3d95f76..8d92627 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/ParamInfo.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/ParamInfo.java
@@ -234,6 +234,16 @@
//-----------------------------------------------------------------------------------------------------------------
/**
+ * Returns <jk>true</jk> if the parameter type is an exact match for the specified class.
+ *
+ * @param c The type to check.
+ * @return <jk>true</jk> if the parameter type is an exact match for the specified class.
+ */
+ public boolean isType(Class<?> c) {
+ return getParameterType().is(c);
+ }
+
+ /**
* Returns <jk>true</jk> if the parameter has a name provided by the class file.
*
* @return <jk>true</jk> if the parameter has a name provided by the class file.
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/utils/MethodInvoker.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/utils/MethodInvoker.java
index 91006cd..af0ae2c 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/utils/MethodInvoker.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/utils/MethodInvoker.java
@@ -85,7 +85,7 @@
missing = beanFactory.getMissingParamTypes(m.getParamTypes());
if (missing.isEmpty())
return invoke(o, beanFactory.getParams(m.getParamTypes()));
- throw new ExecutableException("Could not find prerequisites to invoke method ''{0}'': {1}", m.getFullName(), missing.stream().map(x->x.getSimpleName()).collect(Collectors.joining(",")));
+ throw new ExecutableException("Could not find prerequisites to invoke method ''{0}'': {1}", getFullName(), missing.stream().map(x->x.getSimpleName()).collect(Collectors.joining(",")));
}
/**
@@ -102,7 +102,7 @@
*
* @return The name of the method.
*/
- public String getName() {
- return m.getName();
+ public String getFullName() {
+ return m.getFullName();
}
}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/utils/ThrowingFunction.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/utils/ThrowingFunction.java
new file mode 100644
index 0000000..f57ca9c
--- /dev/null
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/utils/ThrowingFunction.java
@@ -0,0 +1,45 @@
+// ***************************************************************************************************************************
+// * 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.utils;
+
+import java.util.function.*;
+
+/**
+ * A subclass of {@link Function} that allows for thrown exceptions.
+ *
+ * @param <T> the type of the input to the function.
+ * @param <R> the type of the result of the function.
+ */
+@FunctionalInterface
+public interface ThrowingFunction<T,R> extends Function<T,R> {
+
+ @Override
+ default R apply(T t) {
+ try {
+ return applyThrows(t);
+ } catch (RuntimeException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * The functional method to implement.
+ *
+ * @param t The type of the input to the function.
+ * @return The type of the result of the function.
+ * @throws Exception
+ */
+ R applyThrows(T t) throws Exception;
+}
diff --git a/juneau-rest/juneau-rest-server-utest/src/test/java/org/apache/juneau/rest/RestMethod_Params_Test.java b/juneau-rest/juneau-rest-server-utest/src/test/java/org/apache/juneau/rest/RestMethod_Params_Test.java
index 5a86bf2..00bdaf8 100644
--- a/juneau-rest/juneau-rest-server-utest/src/test/java/org/apache/juneau/rest/RestMethod_Params_Test.java
+++ b/juneau-rest/juneau-rest-server-utest/src/test/java/org/apache/juneau/rest/RestMethod_Params_Test.java
@@ -30,6 +30,7 @@
import org.apache.juneau.json.*;
import org.apache.juneau.parser.*;
import org.apache.juneau.plaintext.*;
+import org.apache.juneau.reflect.*;
import org.apache.juneau.rest.annotation.*;
import org.apache.juneau.rest.client.*;
import org.apache.juneau.rest.mock.*;
@@ -366,7 +367,7 @@
//------------------------------------------------------------------------------------------------------------------
@Rest(
- paramResolvers=B2a.class,
+ restParams=B2a.class,
allowedHeaderParams="Custom"
)
public static class B2 {
@@ -376,10 +377,14 @@
}
}
- public static class B2a extends RestMethodParam {
- public B2a() {
- super(RestParamType.HEADER, "Custom", B2b.class);
+ public static class B2a implements RestParam {
+
+ public static B2a create(ParamInfo pi) {
+ if (pi.isType(B2b.class))
+ return new B2a();
+ return null;
}
+
@Override
public Object resolve(RestCall call) throws Exception {
return new B2b(call.getRestRequest().getHeader("Custom"));
diff --git a/juneau-rest/juneau-rest-server-utest/src/test/java/org/apache/juneau/rest/annotation/RestAnnotation_Test.java b/juneau-rest/juneau-rest-server-utest/src/test/java/org/apache/juneau/rest/annotation/RestAnnotation_Test.java
index 5a3bcfd..67fb3ab 100644
--- a/juneau-rest/juneau-rest-server-utest/src/test/java/org/apache/juneau/rest/annotation/RestAnnotation_Test.java
+++ b/juneau-rest/juneau-rest-server-utest/src/test/java/org/apache/juneau/rest/annotation/RestAnnotation_Test.java
@@ -66,7 +66,6 @@
.messages("messages")
.on("on")
.onClass(RestAnnotation_Test.class)
- .paramResolvers(RestMethodParam.class)
.parsers(Parser.class)
.partParser(HttpPartParser.class)
.partSerializer(HttpPartSerializer.class)
@@ -74,6 +73,7 @@
.produces("produces")
.renderResponseStackTraces("renderResponseStackTraces")
.responseHandlers(ResponseHandler.class)
+ .restParams(RestParam.class)
.roleGuard("roleGuard")
.rolesDeclared("rolesDeclared")
.serializers(Serializer.class)
@@ -117,7 +117,6 @@
.messages("messages")
.on("on")
.onClass(RestAnnotation_Test.class)
- .paramResolvers(RestMethodParam.class)
.parsers(Parser.class)
.partParser(HttpPartParser.class)
.partSerializer(HttpPartSerializer.class)
@@ -125,6 +124,7 @@
.produces("produces")
.renderResponseStackTraces("renderResponseStackTraces")
.responseHandlers(ResponseHandler.class)
+ .restParams(RestParam.class)
.roleGuard("roleGuard")
.rolesDeclared("rolesDeclared")
.serializers(Serializer.class)
@@ -171,7 +171,6 @@
+ "messages:'messages',"
+ "on:['on'],"
+ "onClass:['"+CNAME+"'],"
- + "paramResolvers:['org.apache.juneau.rest.RestMethodParam'],"
+ "parsers:['org.apache.juneau.parser.Parser'],"
+ "partParser:'org.apache.juneau.httppart.HttpPartParser',"
+ "partSerializer:'org.apache.juneau.httppart.HttpPartSerializer',"
@@ -179,6 +178,7 @@
+ "produces:['produces'],"
+ "renderResponseStackTraces:'renderResponseStackTraces',"
+ "responseHandlers:['org.apache.juneau.rest.ResponseHandler'],"
+ + "restParams:['org.apache.juneau.rest.RestParam'],"
+ "roleGuard:'roleGuard',"
+ "rolesDeclared:'rolesDeclared',"
+ "serializers:['org.apache.juneau.serializer.Serializer'],"
@@ -267,7 +267,6 @@
messages="messages",
on="on",
onClass=RestAnnotation_Test.class,
- paramResolvers=RestMethodParam.class,
parsers=Parser.class,
partParser=HttpPartParser.class,
partSerializer=HttpPartSerializer.class,
@@ -275,6 +274,7 @@
produces="produces",
renderResponseStackTraces="renderResponseStackTraces",
responseHandlers=ResponseHandler.class,
+ restParams=RestParam.class,
roleGuard="roleGuard",
rolesDeclared="rolesDeclared",
serializers=Serializer.class,
@@ -320,7 +320,6 @@
messages="messages",
on="on",
onClass=RestAnnotation_Test.class,
- paramResolvers=RestMethodParam.class,
parsers=Parser.class,
partParser=HttpPartParser.class,
partSerializer=HttpPartSerializer.class,
@@ -328,6 +327,7 @@
produces="produces",
renderResponseStackTraces="renderResponseStackTraces",
responseHandlers=ResponseHandler.class,
+ restParams=RestParam.class,
roleGuard="roleGuard",
rolesDeclared="rolesDeclared",
serializers=Serializer.class,
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RequestBody.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RequestBody.java
index 61645c7..73dfae0 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RequestBody.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RequestBody.java
@@ -68,7 +68,13 @@
return this;
}
- RequestBody schema(HttpPartSchema schema) {
+ /**
+ * Sets the schema for this body.
+ *
+ * @param schema The new schema for this body.
+ * @return This object (for method chaining).
+ */
+ public RequestBody schema(HttpPartSchema schema) {
this.schema = schema;
return this;
}
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 8e44a99..160fdea 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
@@ -47,14 +47,6 @@
import org.apache.juneau.html.*;
import org.apache.juneau.html.annotation.*;
import org.apache.juneau.http.*;
-import org.apache.juneau.http.annotation.*;
-import org.apache.juneau.http.annotation.Body;
-import org.apache.juneau.http.annotation.FormData;
-import org.apache.juneau.http.annotation.HasFormData;
-import org.apache.juneau.http.annotation.HasQuery;
-import org.apache.juneau.http.annotation.Header;
-import org.apache.juneau.http.annotation.Path;
-import org.apache.juneau.http.annotation.Query;
import org.apache.juneau.http.annotation.Response;
import org.apache.juneau.httppart.*;
import org.apache.juneau.httppart.bean.*;
@@ -69,6 +61,7 @@
import org.apache.juneau.rest.annotation.*;
import org.apache.juneau.rest.converters.*;
import org.apache.juneau.rest.logging.*;
+import org.apache.juneau.rest.params.*;
import org.apache.juneau.http.exception.*;
import org.apache.juneau.http.remote.*;
import org.apache.juneau.rest.reshandlers.*;
@@ -1482,98 +1475,6 @@
public static final String REST_messages = PREFIX + ".messages.lo";
/**
- * Configuration property: Java method parameter resolvers.
- *
- * <h5 class='section'>Property:</h5>
- * <ul class='spaced-list'>
- * <li><b>ID:</b> {@link org.apache.juneau.rest.RestContext#REST_paramResolvers REST_paramResolvers}
- * <li><b>Name:</b> <js>"RestContext.paramResolvers.lo"</js>
- * <li><b>Data type:</b> <c>List<{@link org.apache.juneau.rest.RestMethodParam}|Class<{@link org.apache.juneau.rest.RestMethodParam}>></c>
- * <li><b>Default:</b> empty list
- * <li><b>Session property:</b> <jk>false</jk>
- * <li><b>Annotations:</b>
- * <ul>
- * <li class='ja'>{@link org.apache.juneau.rest.annotation.Rest#paramResolvers()}
- * </ul>
- * <li><b>Methods:</b>
- * <ul>
- * <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#paramResolvers(Class...)}
- * <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#paramResolvers(RestMethodParam...)}
- * </ul>
- * </ul>
- *
- * <h5 class='section'>Description:</h5>
- * <p>
- * By default, the Juneau framework will automatically Java method parameters of various types (e.g.
- * <c>RestRequest</c>, <c>Accept</c>, <c>Reader</c>).
- * This setting allows you to provide your own resolvers for your own class types that you want resolved.
- *
- * <p>
- * For example, if you want to pass in instances of <c>MySpecialObject</c> to your Java method, define
- * the following resolver:
- * <p class='bcode w800'>
- * <jc>// Define a parameter resolver for resolving MySpecialObject objects.</jc>
- * <jk>public class</jk> MyRestParam <jk>extends</jk> RestMethodParam {
- *
- * <jc>// Must have no-arg constructor!</jc>
- * <jk>public</jk> MyRestParam() {
- * <jc>// First two parameters help with Swagger doc generation.</jc>
- * <jk>super</jk>(<jsf>QUERY</jsf>, <js>"myparam"</js>, MySpecialObject.<jk>class</jk>);
- * }
- *
- * <jc>// The method that creates our object.
- * // In this case, we're taking in a query parameter and converting it to our object.</jc>
- * <jk>public</jk> Object resolve(RestRequest req, RestResponse res) <jk>throws</jk> Exception {
- * <jk>return new</jk> MySpecialObject(req.getQuery().get(<js>"myparam"</js>));
- * }
- * }
- *
- * <jc>// Option #1 - Registered via annotation.</jc>
- * <ja>@Rest</ja>(paramResolvers=MyRestParam.<jk>class</jk>)
- * <jk>public class</jk> MyResource {
- *
- * <jc>// Option #2 - Registered via builder passed in through resource constructor.</jc>
- * <jk>public</jk> MyResource(RestContextBuilder builder) <jk>throws</jk> Exception {
- *
- * <jc>// Using method on builder.</jc>
- * builder.paramResolvers(MyRestParam.<jk>class</jk>);
- *
- * <jc>// Same, but using property.</jc>
- * builder.addTo(<jsf>REST_paramResolver</jsf>, MyRestParam.<jk>class</jk>);
- * }
- *
- * <jc>// Option #3 - Registered via builder passed in through init method.</jc>
- * <ja>@RestHook</ja>(<jsf>INIT</jsf>)
- * <jk>public void</jk> init(RestContextBuilder builder) <jk>throws</jk> Exception {
- * builder.paramResolvers(MyRestParam.<jk>class</jk>);
- * }
- *
- * <jc>// Now pass it into your method.</jc>
- * <ja>@RestMethod</ja>(...)
- * <jk>public</jk> Object doMyMethod(MySpecialObject mySpeciaObject) {
- * <jc>// Do something with it.</jc>
- * }
- * }
- * </p>
- *
- * <ul class='notes'>
- * <li>
- * When defined as a class, the implementation must have one of the following constructors:
- * <ul>
- * <li><code><jk>public</jk> T(BeanContext)</code>
- * <li><code><jk>public</jk> T()</code>
- * <li><code><jk>public static</jk> T <jsm>create</jsm>(RestContext)</code>
- * <li><code><jk>public static</jk> T <jsm>create</jsm>()</code>
- * </ul>
- * <li>
- * Inner classes of the REST resource class are allowed.
- * <li>
- * Refer to {@link RestMethodParam} for the list of predefined parameter resolvers.
- * </ul>
- */
- public static final String REST_paramResolvers = PREFIX + ".paramResolvers.lo";
-
- /**
* Configuration property: Parsers.
*
* <h5 class='section'>Property:</h5>
@@ -2325,6 +2226,94 @@
public static final String REST_responseHandlers = PREFIX + ".responseHandlers.lo";
/**
+ * Configuration property: Java REST method parameter resolvers.
+ *
+ * <h5 class='section'>Property:</h5>
+ * <ul class='spaced-list'>
+ * <li><b>ID:</b> {@link org.apache.juneau.rest.RestContext#REST_restParams REST_restParams}
+ * <li><b>Name:</b> <js>"RestContext.restParams.lo"</js>
+ * <li><b>Data type:</b> <c>List<Class<{@link org.apache.juneau.rest.RestParam}>></c>
+ * <li><b>Default:</b> empty list
+ * <li><b>Session property:</b> <jk>false</jk>
+ * <li><b>Annotations:</b>
+ * <ul>
+ * <li class='ja'>{@link org.apache.juneau.rest.annotation.Rest#restParams()}
+ * </ul>
+ * <li><b>Methods:</b>
+ * <ul>
+ * <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#restParams(Class...)}
+ * </ul>
+ * </ul>
+ *
+ * <h5 class='section'>Description:</h5>
+ * <p>
+ * By default, the Juneau framework will automatically Java method parameters of various types (e.g.
+ * <c>RestRequest</c>, <c>Accept</c>, <c>Reader</c>).
+ * This setting allows you to provide your own resolvers for your own class types that you want resolved.
+ *
+ * <p>
+ * For example, if you want to pass in instances of <c>MySpecialObject</c> to your Java method, define
+ * the following resolver:
+ * <p class='bcode w800'>
+ * <jc>// Define a parameter resolver for resolving MySpecialObject objects.</jc>
+ * <jk>public class</jk> MyRestParam <jk>implements</jk> RestParam {
+ *
+ * <jc>// Must implement a static creator method that takes in a ParamInfo that describes the parameter
+ * // being checked. If the parameter isn't of type MySpecialObject, then it should return null.</jc>
+ * <jk>public static</jk> MyRestParam <jsm>create</jsm>(ParamInfo <jv>paramInfo</jv>) {
+ * <jk>if</jk> (<jv>paramInfo</jv>.isType(MySpecialObject.<jk>class</jk>)
+ * <jk>return new</jk> MyRestParam();
+ * <jk>return null</jk>;
+ * }
+ *
+ * <jk>public</jk> MyRestParam() {}
+ *
+ * <jc>// The method that creates our object.
+ * // In this case, we're taking in a query parameter and converting it to our object.</jc>
+ * <ja>@Override</ja>
+ * <jk>public</jk> Object resolve(RestCall <jv>call</jv>) <jk>throws</jk> Exception {
+ * <jk>return new</jk> MySpecialObject(<jv>call</jv>.getRestRequest().getQuery().get(<js>"myparam"</js>));
+ * }
+ * }
+ *
+ * <jc>// Option #1 - Registered via annotation.</jc>
+ * <ja>@Rest</ja>(restParams=MyRestParam.<jk>class</jk>)
+ * <jk>public class</jk> MyResource {
+ *
+ * <jc>// Option #2 - Registered via builder passed in through resource constructor.</jc>
+ * <jk>public</jk> MyResource(RestContextBuilder <jv>builder</jv>) <jk>throws</jk> Exception {
+ *
+ * <jc>// Using method on builder.</jc>
+ * <jv>builder</jv>.restParams(MyRestParam.<jk>class</jk>);
+ *
+ * <jc>// Same, but using property.</jc>
+ * <jv>builder</jv>.addTo(<jsf>REST_restParams</jsf>, MyRestParam.<jk>class</jk>);
+ * }
+ *
+ * <jc>// Option #3 - Registered via builder passed in through init method.</jc>
+ * <ja>@RestHook</ja>(<jsf>INIT</jsf>)
+ * <jk>public void</jk> init(RestContextBuilder <jv>builder</jv>) <jk>throws</jk> Exception {
+ * <jv>builder</jv>.restParams(MyRestParam.<jk>class</jk>);
+ * }
+ *
+ * <jc>// Now pass it into your method.</jc>
+ * <ja>@RestMethod</ja>(...)
+ * <jk>public</jk> Object doMyMethod(MySpecialObject <jv>mySpecialObject</jv>) {
+ * <jc>// Do something with it.</jc>
+ * }
+ * }
+ * </p>
+ *
+ * <ul class='notes'>
+ * <li>
+ * Inner classes of the REST resource class are allowed.
+ * <li>
+ * Refer to {@link RestParam} for the list of predefined parameter resolvers.
+ * </ul>
+ */
+ public static final String REST_restParams = PREFIX + ".restParams.lo";
+
+ /**
* Configuration property: Declared roles.
*
* <h5 class='section'>Property:</h5>
@@ -3179,7 +3168,7 @@
private final Set<String> allowedMethodParams, allowedHeaderParams, allowedMethodHeaders;
- private final Map<Class<?>,RestMethodParam> paramResolvers;
+ private final Class<? extends RestParam>[] restParams, hookMethodParams;
private final SerializerGroup serializers;
private final ParserGroup parsers;
private final HttpPartSerializer partSerializer;
@@ -3334,12 +3323,8 @@
defaultResponseHeaders = createDefaultResponseHeaders(r, beanFactory);
defaultRequestAttributes = createDefaultRequestAttributes(r, beanFactory);
- RestMethodParam[] _paramResolvers = createParamResolvers(r, beanFactory);
- beanFactory.addBean(RestMethodParam[].class, _paramResolvers);
- AMap<Class<?>,RestMethodParam> _paramResolvers2 = AMap.of();
- for (RestMethodParam rp : _paramResolvers)
- _paramResolvers2.put(rp.forClass(), rp);
- paramResolvers = _paramResolvers2.unmodifiable();
+ restParams = createRestParams(r, beanFactory);
+ hookMethodParams = createHookMethodParams(r, beanFactory);
uriContext = nullIfEmpty(getStringProperty(REST_uriContext));
uriAuthority = nullIfEmpty(getStringProperty(REST_uriAuthority));
@@ -3561,7 +3546,7 @@
}
private MethodInvoker toRestMethodInvoker(Method m) {
- return new RestMethodInvoker(m, findParams(m, true, null), getMethodExecStats(m));
+ return new RestMethodInvoker(m, findHookMethodParams(m, getBeanFactory()), getMethodExecStats(m));
}
/**
@@ -4191,20 +4176,14 @@
* <p>
* Instantiates based on the following logic:
* <ul>
- * <li>Looks for {@link #REST_paramResolvers} value set via any of the following:
+ * <li>Looks for {@link #REST_restParams} value set via any of the following:
* <ul>
- * <li>{@link RestContextBuilder#paramResolvers(Class...)}/{@link RestContextBuilder#paramResolvers(RestMethodParam...)}
- * <li>{@link Rest#paramResolvers()}.
+ * <li>{@link RestContextBuilder#restParams(Class...)}/{@link RestContextBuilder#restParams(Class...)}
+ * <li>{@link Rest#restParams()}.
* </ul>
- * <li>Looks for a static or non-static <c>createParamResolvers()</> method that returns <c>{@link RestMethodParam}[]</c> on the
- * resource class with any of the following arguments:
- * <ul>
- * <li>{@link RestContext}
- * <li>{@link BeanFactory}
- * <li>Any {@doc RestInjection injected beans}.
- * </ul>
+ * <li>Looks for a static or non-static <c>createRestParams()</> method that returns <c>{@link Class}[]</c>.
* <li>Resolves it via the bean factory registered in this context.
- * <li>Instantiates a <c>RestMethodParam[0]</c>.
+ * <li>Instantiates a default set of parameters.
* </ul>
*
* @param resource The REST resource object.
@@ -4213,24 +4192,114 @@
* @throws Exception If parameter resolvers could not be instantiated.
* @seealso #REST_paramResolvers
*/
- protected RestMethodParam[] createParamResolvers(Object resource, BeanFactory beanFactory) throws Exception {
- RestMethodParam[] x = getInstanceArrayProperty(REST_paramResolvers, RestMethodParam.class, null, beanFactory);
+ @SuppressWarnings("unchecked")
+ protected Class<? extends RestParam>[] createRestParams(Object resource, BeanFactory beanFactory) throws Exception {
+ @SuppressWarnings("rawtypes")
+ AList<Class> x = AList.of(getListProperty(REST_restParams, Class.class, AList.of()));
- if (x == null)
- x = beanFactory.getBean(RestMethodParam[].class).orElse(null);
+ x.a(
+ AttributeParam.class,
+ BodyParam.class,
+ ConfigParam.class,
+ FormDataParam.class,
+ HasFormDataParam.class,
+ HasQueryParam.class,
+ HeaderParam.class,
+ HttpServletRequestParam.class,
+ HttpServletResponseParam.class,
+ InputStreamParam.class,
+ InputStreamParserParam.class,
+ LocaleParam.class,
+ MessagesParam.class,
+ MethodParam.class,
+ OutputStreamParam.class,
+ ParserParam.class,
+ PathParam.class,
+ QueryParam.class,
+ ReaderParam.class,
+ ReaderParserParam.class,
+ RequestAttributesParam.class,
+ RequestBeanParam.class,
+ RequestBodyParam.class,
+ RequestFormDataParam.class,
+ RequestHeadersParam.class,
+ RequestPathParam.class,
+ RequestQueryParam.class,
+ ResourceBundleParam.class,
+ ResponseBeanParam.class,
+ ResponseHeaderParam.class,
+ ResponseStatusParam.class,
+ RestContextParam.class,
+ RestRequestParam.class,
+ ServetInputStreamParam.class,
+ ServletOutputStreamParam.class,
+ SwaggerParam.class,
+ TimeZoneParam.class,
+ UriContextParam.class,
+ UriResolverParam.class,
+ WriterParam.class,
+ DefaultParam.class
+ );
- if (x == null)
- x = new RestMethodParam[0];
+ Class<?>[] x2 = x.toArray(new Class[x.size()]);
- x = BeanFactory
+ x2 = BeanFactory
.of(beanFactory, resource)
- .addBean(RestMethodParam[].class, x)
- .beanCreateMethodFinder(RestMethodParam[].class, resource)
- .find("createParamResolvers")
- .withDefault(x)
+ .addBean(Class[].class, x2)
+ .beanCreateMethodFinder(Class[].class, resource)
+ .find("createRestParams")
+ .withDefault(x2)
.run();
- return x;
+ return (Class<? extends RestParam>[])x2;
+ }
+
+ /**
+ * Instantiates the hook method parameter resolvers for this REST resource.
+ *
+ * @param resource The REST resource object.
+ * @param beanFactory The bean factory to use for retrieving and creating beans.
+ * @return The REST method parameter resolvers for this REST resource.
+ * @throws Exception If parameter resolvers could not be instantiated.
+ * @seealso #REST_paramResolvers
+ */
+ @SuppressWarnings("unchecked")
+ protected Class<? extends RestParam>[] createHookMethodParams(Object resource, BeanFactory beanFactory) throws Exception {
+ @SuppressWarnings("rawtypes")
+ AList<Class> x = AList.of();
+
+ x.a(
+ ConfigParam.class,
+ HeaderParam.class,
+ HttpServletRequestParam.class,
+ HttpServletResponseParam.class,
+ InputStreamParam.class,
+ LocaleParam.class,
+ MessagesParam.class,
+ MethodParam.class,
+ OutputStreamParam.class,
+ ReaderParam.class,
+ ResourceBundleParam.class,
+ RestContextParam.class,
+ RestRequestParam.class,
+ ServetInputStreamParam.class,
+ ServletOutputStreamParam.class,
+ TimeZoneParam.class,
+ WriterParam.class,
+ DefaultParam.class
+ );
+
+ Class<?>[] x2 = x.toArray(new Class[x.size()]);
+
+ x2 = BeanFactory
+ .of(beanFactory, resource)
+ .addBean(Class[].class, x2)
+ .beanCreateMethodFinder(Class[].class, resource)
+ .find("createHookMethodParams")
+ .withDefault(x2)
+ .run();
+
+ return (Class<? extends RestParam>[])x2;
}
/**
@@ -5264,66 +5333,71 @@
}
/**
- * Finds the {@link RestMethodParam} instances to handle resolving objects on the calls to the specified Java method.
+ * Finds the {@link RestParam} instances to handle resolving objects on the calls to the specified Java method.
*
* @param m The Java method being called.
- * @param isPreOrPost Whether this is a {@link HookEvent#PRE_CALL} or {@link HookEvent#POST_CALL}.
- * @param urlPathMatcher The path pattern to match against.
+ * @param beanFactory The method context bean factory.
* @return The array of resolvers.
*/
- protected RestMethodParam[] findParams(Method m, boolean isPreOrPost, UrlPathMatcher urlPathMatcher) {
+ protected RestParam[] findRestMethodParams(Method m, BeanFactory beanFactory) {
MethodInfo mi = MethodInfo.of(m);
List<ClassInfo> pt = mi.getParamTypes();
- RestMethodParam[] rp = new RestMethodParam[pt.size()];
- PropertyStore ps = getPropertyStore();
+ RestParam[] rp = new RestParam[pt.size()];
+
+ beanFactory = new BeanFactory(beanFactory, getResource());
for (int i = 0; i < pt.size(); i++) {
-
- ClassInfo t = pt.get(i);
- if (t.inner() != null) {
- Class<?> c = t.inner();
- rp[i] = paramResolvers.get(c);
- if (rp[i] == null)
- rp[i] = RestParamDefaults.STANDARD_RESOLVERS.get(c);
+ ParamInfo pi = mi.getParam(i);
+ beanFactory.addBean(ParamInfo.class, pi);
+ for (Class<? extends RestParam> c : restParams) {
+ try {
+ rp[i] = beanFactory.createBean(c);
+ if (rp[i] != null)
+ break;
+ } catch (ExecutableException e) {
+ throw new InternalServerError(e.unwrap(), "Could not resolve parameter {0} on method {1}.", i, mi.getFullName());
+ }
}
-
- ParamInfo mpi = mi.getParam(i);
-
- if (mpi.hasAnnotation(Header.class)) {
- rp[i] = new RestParamDefaults.HeaderObject(mpi, ps);
- } else if (mpi.hasAnnotation(Attr.class)) {
- rp[i] = new RestParamDefaults.AttributeObject(mpi, ps);
- } else if (mpi.hasAnnotation(Query.class)) {
- rp[i] = new RestParamDefaults.QueryObject(mpi, ps);
- } else if (mpi.hasAnnotation(FormData.class)) {
- rp[i] = new RestParamDefaults.FormDataObject(mpi, ps);
- } else if (mpi.hasAnnotation(Path.class)) {
- rp[i] = new RestParamDefaults.PathObject(mpi, ps, urlPathMatcher);
- } else if (mpi.hasAnnotation(Body.class)) {
- rp[i] = new RestParamDefaults.BodyObject(mpi, ps);
- } else if (mpi.hasAnnotation(Request.class)) {
- rp[i] = new RestParamDefaults.RequestObject(mpi, ps);
- } else if (mpi.hasAnnotation(Response.class)) {
- rp[i] = new RestParamDefaults.ResponseObject(mpi, ps);
- } else if (mpi.hasAnnotation(ResponseHeader.class)) {
- rp[i] = new RestParamDefaults.ResponseHeaderObject(mpi, ps);
- } else if (mpi.hasAnnotation(ResponseStatus.class)) {
- rp[i] = new RestParamDefaults.ResponseStatusObject(t);
- } else if (mpi.hasAnnotation(HasFormData.class)) {
- rp[i] = new RestParamDefaults.HasFormDataObject(mpi);
- } else if (mpi.hasAnnotation(HasQuery.class)) {
- rp[i] = new RestParamDefaults.HasQueryObject(mpi);
- } else if (mpi.hasAnnotation(org.apache.juneau.rest.annotation.Method.class)) {
- rp[i] = new RestParamDefaults.MethodObject(mi, t, mpi);
- } else if (rp[i] == null) {
- rp[i] = new RestParamDefaults.BeanFactoryObject(mi, t, mpi);
- }
+ if (rp[i] == null)
+ throw new InternalServerError("Could not resolve parameter {0} on method {1}.", i, mi.getFullName());
}
return rp;
}
+ /**
+ * Finds the {@link RestParam} instances to handle resolving objects on pre-call and post-call Java methods.
+ *
+ * @param m The Java method being called.
+ * @param beanFactory The method context bean factory.
+ * @return The array of resolvers.
+ */
+ protected RestParam[] findHookMethodParams(Method m, BeanFactory beanFactory) {
+ MethodInfo mi = MethodInfo.of(m);
+ List<ClassInfo> pt = mi.getParamTypes();
+ RestParam[] rp = new RestParam[pt.size()];
+
+ beanFactory = new BeanFactory(beanFactory, getResource());
+
+ for (int i = 0; i < pt.size(); i++) {
+ ParamInfo pi = mi.getParam(i);
+ beanFactory.addBean(ParamInfo.class, pi);
+ for (Class<? extends RestParam> c : hookMethodParams) {
+ try {
+ rp[i] = beanFactory.createBean(c);
+ if (rp[i] != null)
+ break;
+ } catch (ExecutableException e) {
+ throw new InternalServerError(e.unwrap(), "Could not resolve parameter {0} on method {1}.", i, mi.getFullName());
+ }
+ }
+ if (rp[i] == null)
+ throw new InternalServerError("Could not resolve parameter {0} on method {1}.", i, mi.getFullName());
+ }
+
+ return rp;
+ }
//------------------------------------------------------------------------------------------------------------------
// Call handling
@@ -5765,7 +5839,7 @@
try {
x.invokeUsingFactory(call.getBeanFactory(), call.getResource());
} catch (ExecutableException e) {
- logger.log(Level.WARNING, e.unwrap(), ()->format("Error occurred invoking finish-call method ''{0}''.", x.getName()));
+ logger.log(Level.WARNING, e.unwrap(), ()->format("Error occurred invoking finish-call method ''{0}''.", x.getFullName()));
}
}
}
@@ -5830,7 +5904,7 @@
try {
x.invokeUsingFactory(beanFactory, getResource());
} catch (ExecutableException e) {
- getLogger().log(Level.WARNING, e.unwrap(), ()->format("Error occurred invoking servlet-destroy method ''{0}''.", x.getName()));
+ getLogger().log(Level.WARNING, e.unwrap(), ()->format("Error occurred invoking servlet-destroy method ''{0}''.", x.getFullName()));
}
}
@@ -5928,13 +6002,13 @@
.a("defaultResponseHeaders", defaultResponseHeaders)
.a("fileFinder", fileFinder)
.a("infoProvider", infoProvider)
- .a("paramResolvers", paramResolvers)
.a("parsers", parsers)
.a("partParser", partParser)
.a("partSerializer", partSerializer)
.a("produces", produces)
.a("renderResponseStackTraces", renderResponseStackTraces)
.a("responseHandlers", responseHandlers)
+ .a("restParams", restParams)
.a("serializers", serializers)
.a("staticFiles", staticFiles)
.a("uriAuthority", uriAuthority)
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 225e442..9079e9d 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
@@ -1372,45 +1372,6 @@
}
/**
- * <i><l>RestContext</l> configuration property: </i> Java method parameter resolvers.
- *
- * <p>
- * By default, the Juneau framework will automatically Java method parameters of various types (e.g.
- * <c>RestRequest</c>, <c>Accept</c>, <c>Reader</c>).
- * This annotation allows you to provide your own resolvers for your own class types that you want resolved.
- *
- * <ul class='seealso'>
- * <li class='jf'>{@link RestContext#REST_paramResolvers}
- * </ul>
- *
- * @param values The values to add to this setting.
- * @return This object (for method chaining).
- */
- @FluentSetter
- @SuppressWarnings("unchecked")
- public RestContextBuilder paramResolvers(Class<? extends RestMethodParam>...values) {
- return prependTo(REST_paramResolvers, values);
- }
-
- /**
- * <i><l>RestContext</l> configuration property: </i> Java method parameter resolvers.
- *
- * <p>
- * Same as {@link #paramResolvers(Class...)} except input is pre-constructed instances.
- *
- * <ul class='seealso'>
- * <li class='jf'>{@link RestContext#REST_paramResolvers}
- * </ul>
- *
- * @param values The values to add to this setting.
- * @return This object (for method chaining).
- */
- @FluentSetter
- public RestContextBuilder paramResolvers(RestMethodParam...values) {
- return prependTo(REST_paramResolvers, values);
- }
-
- /**
* <i><l>RestContext</l> configuration property: </i> Parser listener.
*
* <p>
@@ -1668,6 +1629,27 @@
}
/**
+ * <i><l>RestContext</l> configuration property: </i> Java method parameter resolvers.
+ *
+ * <p>
+ * By default, the Juneau framework will automatically Java method parameters of various types (e.g.
+ * <c>RestRequest</c>, <c>Accept</c>, <c>Reader</c>).
+ * This annotation allows you to provide your own resolvers for your own class types that you want resolved.
+ *
+ * <ul class='seealso'>
+ * <li class='jf'>{@link RestContext#REST_restParams}
+ * </ul>
+ *
+ * @param values The values to add to this setting.
+ * @return This object (for method chaining).
+ */
+ @FluentSetter
+ @SuppressWarnings("unchecked")
+ public RestContextBuilder restParams(Class<? extends RestParam>...values) {
+ return prependTo(REST_restParams, values);
+ }
+
+ /**
* <i><l>RestContext</l> configuration property: </i> Declared roles.
*
* <p>
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 1e95f74..0f4329d 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
@@ -599,7 +599,7 @@
private final String httpMethod;
private final UrlPathMatcher[] pathMatchers;
- final RestMethodParam[] methodParams;
+ final RestParam[] methodParams;
private final RestGuard[] guards;
private final RestMatcher[] optionalMatchers;
private final RestMatcher[] requiredMatchers;
@@ -649,7 +649,8 @@
beanFactory = new BeanFactory(context.rootBeanFactory, r)
.addBean(RestMethodContext.class, this)
- .addBean(Method.class, method);
+ .addBean(Method.class, method)
+ .addBean(PropertyStore.class, ps);
beanFactory.addBean(BeanFactory.class, beanFactory);
serializers = createSerializers(r, beanFactory, ps);
@@ -676,6 +677,7 @@
pathMatchers = createPathMatchers(r, beanFactory, b.dotAll);
beanFactory.addBean(UrlPathMatcher[].class, pathMatchers);
+ beanFactory.addBean(UrlPathMatcher.class, pathMatchers.length > 0 ? pathMatchers[0] : null);
encoders = createEncoders(r, beanFactory);
beanFactory.addBean(EncoderGroup.class, encoders);
@@ -713,7 +715,7 @@
responseMeta = ResponseBeanMeta.create(mi, ps);
- methodParams = context.findParams(mi.inner(), false, pathMatchers[this.pathMatchers.length-1]);
+ methodParams = context.findRestMethodParams(mi.inner(), beanFactory);
this.priority = getIntegerProperty(RESTMETHOD_priority, 0);
@@ -1680,10 +1682,11 @@
Object[] args = new Object[methodParams.length];
for (int i = 0; i < methodParams.length; i++) {
+ ParamInfo pi = methodInvoker.inner().getParam(i);
try {
args[i] = methodParams[i].resolve(call);
} catch (Exception e) {
- throw toHttpException(e, BadRequest.class, "Invalid data conversion. Could not convert {0} ''{1}'' to type ''{2}'' on method ''{3}.{4}''.", methodParams[i].getParamType().name(), methodParams[i].getName(), methodParams[i].getType(), mi.getDeclaringClass().getFullName(), mi.getSimpleName());
+ throw toHttpException(e, BadRequest.class, "Could not convert resolve parameter {0} of type ''{1}'' on method ''{2}''.", i, pi.getParameterType(), mi.getFullName());
}
}
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestMethodInvoker.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestMethodInvoker.java
index c77bb39..01fff11 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestMethodInvoker.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestMethodInvoker.java
@@ -19,6 +19,7 @@
import org.apache.juneau.*;
import org.apache.juneau.http.exception.*;
import org.apache.juneau.mstat.*;
+import org.apache.juneau.reflect.*;
import org.apache.juneau.utils.*;
/**
@@ -26,7 +27,7 @@
*/
public class RestMethodInvoker extends MethodInvoker {
- private final RestMethodParam[] params;
+ private final RestParam[] params;
/**
* Constructor.
@@ -35,7 +36,7 @@
* @param params The parameter resolvers.
* @param stats The instrumentor.
*/
- public RestMethodInvoker(Method m, RestMethodParam[] params, MethodExecStats stats) {
+ public RestMethodInvoker(Method m, RestParam[] params, MethodExecStats stats) {
super(m, stats);
this.params = params;
}
@@ -51,16 +52,17 @@
public Object invokeFromCall(RestCall call, Object resource) throws HttpException {
Object[] args = new Object[params.length];
for (int i = 0; i < params.length; i++) {
+ ParamInfo pi = inner().getParam(i);
try {
args[i] = params[i].resolve(call);
} catch (Exception e) {
- throw toHttpException(e, BadRequest.class, "Could not resolve parameter {0} of type ''{1}'' on method ''{2}.{3}''.", i, params[i].getParamType(), getDeclaringClass().getName(), getName());
+ throw toHttpException(e, BadRequest.class, "Could not resolve parameter {0} of type ''{1}'' on method ''{2}''.", i, pi.getParameterType(), getFullName());
}
}
try {
return invoke(resource, args);
} catch (ExecutableException e) {
- throw toHttpException(e.unwrap(), InternalServerError.class, "Method ''{0}.{1}'' threw an unexpected exception.", getDeclaringClass().getName(), getName());
+ throw toHttpException(e.unwrap(), InternalServerError.class, "Method ''{0}'' threw an unexpected exception.", getFullName());
}
}
}
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestMethodParam.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestMethodParam.java
deleted file mode 100644
index f7c7eb7..0000000
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestMethodParam.java
+++ /dev/null
@@ -1,258 +0,0 @@
-// ***************************************************************************************************************************
-// * 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.rest;
-
-import java.io.*;
-import java.lang.reflect.*;
-import java.util.*;
-
-import javax.servlet.*;
-import javax.servlet.http.*;
-
-import org.apache.juneau.*;
-import org.apache.juneau.config.*;
-import org.apache.juneau.cp.Messages;
-import org.apache.juneau.dto.swagger.*;
-import org.apache.juneau.http.header.*;
-import org.apache.juneau.http.header.Date;
-import org.apache.juneau.parser.*;
-import org.apache.juneau.reflect.*;
-
-/**
- * REST java method parameter resolver.
- *
- * <p>
- * Used to resolve instances of classes being passed to Java REST methods.
- *
- * <p>
- * By default, the following parameter types can be passed into Java methods in any order:
- *
- * <h5 class='topic'>Standard top-level objects</h5>
- * <ul>
- * <li><b>Standard top-level objects</b>
- * <ul>
- * <li class='jc'>{@link HttpServletRequest}
- * <li class='jc'>{@link RestRequest}
- * <li class='jc'>{@link HttpServletResponse}
- * <li class='jc'>{@link RestResponse}
- * </ul>
- * <li><b>Headers</b>
- * <ul>
- * <li class='jc'>{@link Accept}
- * <li class='jc'>{@link AcceptCharset}
- * <li class='jc'>{@link AcceptEncoding}
- * <li class='jc'>{@link AcceptLanguage}
- * <li class='jc'>{@link Authorization}
- * <li class='jc'>{@link CacheControl}
- * <li class='jc'>{@link Connection}
- * <li class='jc'>{@link ContentLength}
- * <li class='jc'>{@link ContentType}
- * <li class='jc'>{@link Date}
- * <li class='jc'>{@link Expect}
- * <li class='jc'>{@link From}
- * <li class='jc'>{@link Host}
- * <li class='jc'>{@link IfMatch}
- * <li class='jc'>{@link IfModifiedSince}
- * <li class='jc'>{@link IfNoneMatch}
- * <li class='jc'>{@link IfRange}
- * <li class='jc'>{@link IfUnmodifiedSince}
- * <li class='jc'>{@link MaxForwards}
- * <li class='jc'>{@link Pragma}
- * <li class='jc'>{@link ProxyAuthorization}
- * <li class='jc'>{@link Range}
- * <li class='jc'>{@link Referer}
- * <li class='jc'>{@link TE}
- * <li class='jc'>{@link TimeZone}
- * <li class='jc'>{@link UserAgent}
- * <li class='jc'>{@link Upgrade}
- * <li class='jc'>{@link Via}
- * <li class='jc'>{@link Warning}
- * </ul>
- * <li><b>Other objects</b>
- * <ul>
- * <li class='jc'>{@link Config}
- * <li class='jc'>{@link InputStream}
- * <li class='jc'>{@link Locale}
- * <li class='jc'>{@link Messages}
- * <li class='jc'>{@link OutputStream}
- * <li class='jc'>{@link Parser}
- * <li class='jc'>{@link Reader}
- * <li class='jc'>{@link RequestBody}
- * <li class='jc'>{@link RequestFormData}
- * <li class='jc'>{@link RequestHeaders}
- * <li class='jc'>{@link RequestAttributes}
- * <li class='jc'>{@link RequestPath}
- * <li class='jc'>{@link RequestQuery}
- * <li class='jc'>{@link ResourceBundle}
- * <li class='jc'>{@link RestContext}
- * <li class='jc'>{@link ServletInputStream}
- * <li class='jc'>{@link ServletOutputStream}
- * <li class='jc'>{@link Swagger}
- * <li class='jc'>{@link UriContext}
- * <li class='jc'>{@link UriResolver}
- * <li class='jc'>{@link Writer}
- * </ul>
- * </ul>
- *
- * <ul class='seealso'>
- * <li class='jf'>{@link RestContext#REST_paramResolvers}
- * <li class='link'>{@doc RestmParameters}
- * </ul>
- */
-public abstract class RestMethodParam {
-
- final RestParamType paramType;
- final ParamInfo mpi;
- final String name;
- final Type type;
- final Class<?> c;
-
- /**
- * Resolves the parameter object.
- *
- * @param call The rest call.
- * @return The resolved object.
- * @throws Exception Generic error occurred.
- */
- public abstract Object resolve(RestCall call) throws Exception;
-
- /**
- * Constructor.
- *
- * @param paramType The Swagger parameter type.
- * @param mpi The method parameter.
- * @param name
- * The parameter name.
- * Can be <jk>null</jk> if parameter doesn't have a name (e.g. the request body).
- * @param type The object type to convert the parameter to.
- */
- protected RestMethodParam(RestParamType paramType, ParamInfo mpi, String name, Type type) {
- this.paramType = paramType;
- this.mpi = mpi;
- this.name = name;
- this.type = type;
- this.c = type instanceof Class ? (Class<?>)type : type instanceof ParameterizedType ? (Class<?>)((ParameterizedType)type).getRawType() : null;
- }
-
- /**
- * Constructor.
- *
- * @param paramType The Swagger parameter type.
- * @param mpi The method parameter.
- * @param name
- * The parameter name.
- * Can be <jk>null</jk> if parameter doesn't have a name (e.g. the request body).
- */
- protected RestMethodParam(RestParamType paramType, ParamInfo mpi, String name) {
- this(paramType, mpi, name, mpi.getParameterType().innerType());
- }
-
- /**
- * Constructor.
- *
- * @param paramType The Swagger parameter type.
- * @param mpi The method parameter.
- */
- protected RestMethodParam(RestParamType paramType, ParamInfo mpi) {
- this(paramType, mpi, null, mpi.getParameterType().innerType());
- }
-
- /**
- * Constructor.
- *
- * @param paramType The Swagger parameter type.
- * @param type The object type to convert the parameter to.
- */
- protected RestMethodParam(RestParamType paramType, Type type) {
- this(paramType, null, null, type);
- }
-
- /**
- * Constructor.
- *
- * @param paramType The Swagger parameter type.
- * @param type The object type to convert the parameter to.
- */
- protected RestMethodParam(RestParamType paramType, ClassInfo type) {
- this(paramType, null, null, type.innerType());
- }
-
- /**
- * Constructor.
- *
- * @param paramType The Swagger parameter type.
- * @param name
- * The parameter name.
- * Can be <jk>null</jk> if parameter doesn't have a name (e.g. the request body).
- * @param type The object type to convert the parameter to.
- */
- protected RestMethodParam(RestParamType paramType, String name, Type type) {
- this(paramType, null, name, type);
- }
-
- /**
- * Returns the parameter class type that this parameter resolver is meant for.
- *
- * @return The parameter class type, or <jk>null</jk> if the type passed in isn't an instance of {@link Class}.
- */
- protected Class<?> forClass() {
- if (type instanceof Class)
- return (Class<?>)type;
- return null;
- }
-
- /**
- * Returns the swagger parameter type for this parameter as shown in the Swagger doc.
- *
- * @return the swagger parameter type for this parameter.
- */
- protected RestParamType getParamType() {
- return paramType;
- }
-
- /**
- * Returns the parameter info.
- *
- * @return The parameter info.
- */
- public ParamInfo getMethodParamInfo() {
- return mpi;
- }
-
- /**
- * Returns the parameter name for this parameter as shown in the Swagger doc.
- *
- * @return the parameter name for this parameter.
- */
- protected String getName() {
- return name;
- }
-
- /**
- * Returns the parameter class type.
- *
- * @return the parameter class type.
- */
- public Type getType() {
- return type;
- }
-
- /**
- * Returns the parameter class type.
- *
- * @return the parameter class type.
- */
- public Class<?> getTypeClass() {
- return c;
- }
-}
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestParam.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestParam.java
new file mode 100644
index 0000000..d870407
--- /dev/null
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestParam.java
@@ -0,0 +1,60 @@
+// ***************************************************************************************************************************
+// * 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.rest;
+
+import org.apache.juneau.rest.annotation.*;
+
+/**
+ * REST java method parameter resolver.
+ *
+ * <p>
+ * Used to resolve parameter values when invoking {@link RestMethod}-annotated methods.
+ *
+ * <h5 class='figure'>Example:</h5>
+ * <p class='bcode w800'>
+ * <jc>// A simple parameter resolver that resolves TimeZone parameters.</jc>
+ * <jk>public class</jk> TimeZoneParam <jk>implements</jk> RestParam {
+ *
+ * <jc>// Implementers must provide a static creator method that returns a RestParam if it's
+ * // applicable to the specified parameter.</jc>
+ * <jk>public static</jk> TimeZoneParam <jsm>create</jsm>(ParamInfo <jv>paramInfo</jv>) {
+ * <jk>if</jk> (<jv>paramInfo</jv>.isType(TimeZone.<jk>class</jk>))
+ * <jk>return new</jk> TimeZoneParam();
+ * <jk>return null</jk>;
+ * }
+ *
+ * <jk>protected</jk> TimeZoneParam() {}
+ *
+ * <ja>@Override</ja>
+ * <jk>public</jk> Object resolve(RestCall <jv>call</jv>) <jk>throws</jk> Exception {
+ * <jk>return</jk> <jv>call</jv>.getRestRequest().getHeaders().getTimeZone();
+ * }
+ * }
+ * </p>
+ *
+ * <ul class='seealso'>
+ * <li class='jf'>{@link RestContext#REST_restParams}
+ * <li class='link'>{@doc RestmParameters}
+ * </ul>
+ */
+public interface RestParam {
+
+ /**
+ * Resolves the parameter object.
+ *
+ * @param call The rest call.
+ * @return The resolved object.
+ * @throws Exception Generic error occurred.
+ */
+ public Object resolve(RestCall call) throws Exception;
+}
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestParamDefaults.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestParamDefaults.java
deleted file mode 100644
index 69dc6aa..0000000
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestParamDefaults.java
+++ /dev/null
@@ -1,872 +0,0 @@
-// ***************************************************************************************************************************
-// * 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.rest;
-
-import static org.apache.juneau.internal.ClassUtils.*;
-import static org.apache.juneau.internal.StringUtils.*;
-import static org.apache.juneau.rest.RestParamType.*;
-
-import java.io.*;
-import java.lang.reflect.*;
-import java.util.*;
-
-import javax.servlet.*;
-import javax.servlet.http.*;
-
-import org.apache.juneau.*;
-import org.apache.juneau.config.*;
-import org.apache.juneau.cp.*;
-import org.apache.juneau.dto.swagger.*;
-import org.apache.juneau.http.annotation.*;
-import org.apache.juneau.http.annotation.Body;
-import org.apache.juneau.http.annotation.FormData;
-import org.apache.juneau.http.annotation.HasFormData;
-import org.apache.juneau.http.annotation.HasQuery;
-import org.apache.juneau.http.annotation.Header;
-import org.apache.juneau.http.annotation.Path;
-import org.apache.juneau.http.annotation.Query;
-import org.apache.juneau.httppart.*;
-import org.apache.juneau.httppart.bean.*;
-import org.apache.juneau.internal.*;
-import org.apache.juneau.parser.*;
-import org.apache.juneau.reflect.*;
-import org.apache.juneau.rest.annotation.*;
-import org.apache.juneau.http.exception.*;
-import org.apache.juneau.rest.util.UrlPathMatcher;
-import org.apache.juneau.serializer.*;
-
-/**
- * Default REST method parameter resolvers.
- *
- * <p>
- * Contains the default set of parameter resolvers for REST resource methods (i.e methods annotated with {@link RestResource @RestResource}).
- *
- * <ul class='seealso'>
- * <li class='link'>{@doc RestmParameters}
- * </ul>
- */
-class RestParamDefaults {
-
- /**
- * Standard set of method parameter resolvers.
- */
- static final Map<Class<?>,RestMethodParam> STANDARD_RESOLVERS;
-
- static {
- Map<Class<?>,RestMethodParam> m = new HashMap<>();
-
- @SuppressWarnings("rawtypes")
- Class[] r = new Class[] {
-
- // Standard top-level objects
- HttpServletRequestObject.class,
- RestRequestObject.class,
- HttpServletResponseObject.class,
- RestResponseObject.class,
-
- // Headers
- TimeZoneHeader.class,
-
- // Other objects
- ResourceBundleObject.class,
- MessageBundleObject.class,
- InputStreamObject.class,
- ServletInputStreamObject.class,
- ReaderObject.class,
- OutputStreamObject.class,
- ServletOutputStreamObject.class,
- WriterObject.class,
- RequestHeadersObject.class,
- RequestAttributesObject.class,
- RequestQueryObject.class,
- RequestFormDataObject.class,
- RestContextObject.class,
- ParserObject.class,
- ReaderParserObject.class,
- InputStreamParserObject.class,
- LocaleObject.class,
- SwaggerObject.class,
- RequestPathMatchObject.class,
- RequestBodyObject.class,
- ConfigObject.class,
- UriContextObject.class,
- UriResolverObject.class
- };
-
- for (Class<?> c : r) {
- try {
- RestMethodParam mpr = (RestMethodParam)c.newInstance();
- m.put(mpr.forClass(), mpr);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
- STANDARD_RESOLVERS = Collections.unmodifiableMap(m);
- }
-
- //-------------------------------------------------------------------------------------------------------------------
- // Request / Response retrievers
- //-------------------------------------------------------------------------------------------------------------------
-
- static final class HttpServletRequestObject extends RestMethodParam {
-
- protected HttpServletRequestObject() {
- super(OTHER, HttpServletRequest.class);
- }
-
- @Override /* RestMethodParam */
- public Object resolve(RestCall call) {
- return call.getRequest();
- }
- }
-
- static final class HttpServletResponseObject extends RestMethodParam {
-
- protected HttpServletResponseObject() {
- super(OTHER, HttpServletResponse.class);
- }
-
- @Override /* RestMethodParam */
- public Object resolve(RestCall call) {
- return call.getResponse();
- }
- }
-
- static final class RestRequestObject extends RestMethodParam {
-
- protected RestRequestObject() {
- super(OTHER, RestRequest.class);
- }
-
- @Override /* RestMethodParam */
- public Object resolve(RestCall call) {
- return call.getRestRequest();
- }
- }
-
- static final class RestResponseObject extends RestMethodParam {
-
- protected RestResponseObject() {
- super(OTHER, RestResponse.class);
- }
-
- @Override /* RestMethodParam */
- public Object resolve(RestCall call) {
- return call.getRestResponse();
- }
- }
-
- //-------------------------------------------------------------------------------------------------------------------
- // Header retrievers
- //-------------------------------------------------------------------------------------------------------------------
-
- static final class TimeZoneHeader extends RestMethodParam {
-
- protected TimeZoneHeader() {
- super(HEADER, "Time-Zone", TimeZone.class);
- }
-
- @Override
- public TimeZone resolve(RestCall call) {
- return call.getRestRequest().getHeaders().getTimeZone();
- }
- }
-
- //-------------------------------------------------------------------------------------------------------------------
- // Annotated retrievers
- //-------------------------------------------------------------------------------------------------------------------
-
- static final class PathObject extends RestMethodParam {
- private final HttpPartParser partParser;
- private final HttpPartSchema schema;
-
- protected PathObject(ParamInfo mpi, PropertyStore ps, UrlPathMatcher pathMatcher) {
- super(PATH, mpi, getName(mpi, pathMatcher));
- this.schema = HttpPartSchema.create(Path.class, mpi);
- this.partParser = createPartParser(schema.getParser(), ps);
- }
-
- private static String getName(ParamInfo mpi, UrlPathMatcher pathMatcher) {
- String p = null;
- for (Path h : mpi.getAnnotations(Path.class))
- p = firstNonEmpty(h.name(), h.n(), h.value(), p);
- if (p != null)
- return p;
- if (pathMatcher != null) {
- int idx = 0;
- int i = mpi.getIndex();
- MethodInfo mi = mpi.getMethod();
-
- for (int j = 0; j < i; j++)
- if (mi.getParam(i).getLastAnnotation(Path.class) != null)
- idx++;
-
- String[] vars = pathMatcher.getVars();
- if (vars.length <= idx)
- throw new InternalServerError("Number of attribute parameters in method ''{0}'' exceeds the number of URL pattern variables.", mi.getFullName());
-
- // Check for {#} variables.
- String idxs = String.valueOf(idx);
- for (int j = 0; j < vars.length; j++)
- if (StringUtils.isNumeric(vars[j]) && vars[j].equals(idxs))
- return vars[j];
-
- return pathMatcher.getVars()[idx];
- }
- throw new InternalServerError("@Path used without name or value on method parameter ''{0}''.", mpi);
- }
-
- @Override /* RestMethodParam */
- public Object resolve(RestCall call) throws Exception {
- RestRequest req = call.getRestRequest();
- HttpPartParserSession ps = partParser == null ? req.getPartParser() : partParser.createPartSession(req.getParserSessionArgs());
- return call.getRestRequest().getPathMatch().get(ps, schema, name, type);
- }
- }
-
- static final class BodyObject extends RestMethodParam {
- private final HttpPartSchema schema;
-
- protected BodyObject(ParamInfo mpi, PropertyStore ps) {
- super(BODY, mpi);
- this.schema = HttpPartSchema.create(Body.class, mpi);
- }
-
- @Override /* RestMethodParam */
- public Object resolve(RestCall call) throws Exception {
- return call.getRestRequest().getBody().schema(schema).asType(type);
- }
- }
-
- static final class HeaderObject extends RestMethodParam {
- private final HttpPartParser partParser;
- private final HttpPartSchema schema;
- private final boolean multi;
-
- protected HeaderObject(ParamInfo mpi, PropertyStore ps) {
- super(HEADER, mpi, getName(mpi));
- this.schema = HttpPartSchema.create(Header.class, mpi);
- this.partParser = createPartParser(schema.getParser(), ps);
- this.multi = getMulti(mpi);
-
- if (multi && ! isCollection(type))
- throw new InternalServerError("Use of multipart flag on @Header parameter that's not an array or Collection on method ''{0}''", mpi.getMethod());
- }
-
- private static String getName(ParamInfo mpi) {
- String n = null;
- for (Header h : mpi.getAnnotations(Header.class))
- n = firstNonEmpty(h.name(), h.n(), h.value(), n);
- if (n == null)
- throw new InternalServerError("@Header used without name or value on method parameter ''{0}''.", mpi);
- return n;
- }
-
- private static boolean getMulti(ParamInfo mpi) {
- for (Header h : mpi.getAnnotations(Header.class))
- if (h.multi())
- return true;
- return false;
- }
-
- @Override /* RestMethodParam */
- public Object resolve(RestCall call) throws Exception {
- RestRequest req = call.getRestRequest();
- HttpPartParserSession ps = partParser == null ? req.getPartParser() : partParser.createPartSession(req.getParserSessionArgs());
- RequestHeaders rh = call.getRestRequest().getHeaders();
- return multi ? rh.getAll(ps, schema, name, type) : rh.get(ps, schema, name, type);
- }
- }
-
- static final class AttributeObject extends RestMethodParam {
-
- protected AttributeObject(ParamInfo mpi, PropertyStore ps) {
- super(OTHER, mpi, getName(mpi));
- }
-
- private static String getName(ParamInfo mpi) {
- String n = null;
- for (Attr h : mpi.getAnnotations(Attr.class))
- n = firstNonEmpty(h.name(), h.value(), n);
- if (n == null)
- throw new InternalServerError("@Attr used without name or value on method parameter ''{0}''.", mpi);
- return n;
- }
-
- @Override /* RestMethodParam */
- public Object resolve(RestCall call) throws Exception {
- return call.getRestRequest().getAttributes().get(name, type);
- }
- }
-
- static final class RequestObject extends RestMethodParam {
- private final RequestBeanMeta meta;
-
- protected RequestObject(ParamInfo mpi, PropertyStore ps) {
- super(RESPONSE_BODY, mpi);
- this.meta = RequestBeanMeta.create(mpi, ps);
- }
-
- @Override /* RestMethodParam */
- public Object resolve(RestCall call) throws Exception {
- return call.getRestRequest().getRequest(meta);
- }
- }
-
- static final class ResponseHeaderObject extends RestMethodParam {
- final ResponsePartMeta meta;
-
- protected ResponseHeaderObject(ParamInfo mpi, PropertyStore ps) {
- super(RESPONSE_HEADER, mpi, getName(mpi));
- HttpPartSchema schema = HttpPartSchema.create(ResponseHeader.class, mpi);
- this.meta = new ResponsePartMeta(HttpPartType.HEADER, schema, createPartSerializer(schema.getSerializer(), ps));
-
- if (getTypeClass() != Value.class)
- throw new InternalServerError("Invalid type {0} specified with @ResponseHeader annotation. It must be Value.", type);
- }
-
- private static String getName(ParamInfo mpi) {
- String n = null;
- for (ResponseHeader h : mpi.getAnnotations(ResponseHeader.class))
- n = firstNonEmpty(h.name(), h.n(), h.value(), n);
- if (n == null)
- throw new InternalServerError("@ResponseHeader used without name or value on method parameter ''{0}''.", mpi);
- return n;
- }
-
- @SuppressWarnings({ "unchecked", "rawtypes" })
- @Override /* RestMethodParam */
- public Object resolve(final RestCall call) throws Exception {
- Value<Object> v = (Value<Object>)getTypeClass().newInstance();
- v.listener(new ValueListener() {
- @Override
- public void onSet(Object o) {
- try {
- RestRequest req = call.getRestRequest();
- RestResponse res = call.getRestResponse();
- ResponsePartMeta rpm = req.getResponseHeaderMeta(o);
- if (rpm == null)
- rpm = ResponseHeaderObject.this.meta;
- HttpPartSerializerSession pss = rpm.getSerializer() == null ? req.getPartSerializer() : rpm.getSerializer().createPartSession(req.getSerializerSessionArgs());
- res.setHeader(new HttpPart(name, HttpPartType.HEADER, rpm.getSchema(), pss, o));
- } catch (SerializeException | SchemaValidationException e) {
- throw new RuntimeException(e);
- }
- }
- });
- return v;
- }
- }
-
- static final class ResponseObject extends RestMethodParam {
- final ResponseBeanMeta meta;
-
- protected ResponseObject(ParamInfo mpi, PropertyStore ps) {
- super(RESPONSE, mpi);
- this.meta = ResponseBeanMeta.create(mpi, ps);
- if (getTypeClass() != Value.class)
- throw new InternalServerError("Invalid type {0} specified with @Response annotation. It must be Value.", type);
- }
-
- @SuppressWarnings({ "unchecked", "rawtypes" })
- @Override /* RestMethodParam */
- public Object resolve(final RestCall call) throws Exception {
- Value<Object> v = (Value<Object>)c.newInstance();
- v.listener(new ValueListener() {
- @Override
- public void onSet(Object o) {
- RestRequest req = call.getRestRequest();
- RestResponse res = call.getRestResponse();
- ResponseBeanMeta meta = req.getResponseBeanMeta(o);
- if (meta == null)
- meta = ResponseObject.this.meta;
- res.setResponseMeta(meta);
- res.setOutput(o);
- }
- });
- return v;
- }
- }
-
- static class ResponseStatusObject extends RestMethodParam {
-
- protected ResponseStatusObject(ClassInfo t) {
- super(RESPONSE_STATUS, t);
- if (getTypeClass() != Value.class || Value.getParameterType(t.innerType()) != Integer.class)
- throw new InternalServerError("Invalid type {0} specified with @ResponseStatus annotation. It must Value<Integer>.", type);
- }
-
- @SuppressWarnings({ "unchecked", "rawtypes" })
- @Override /* RestMethodParam */
- public Object resolve(final RestCall call) throws Exception {
- Value<Object> v = (Value<Object>)c.newInstance();
- v.listener(new ValueListener() {
- @Override
- public void onSet(Object o) {
- call.getRestResponse().setStatus(Integer.parseInt(o.toString()));
- }
- });
- return v;
- }
- }
-
- static final class MethodObject extends RestMethodParam {
-
- protected MethodObject(MethodInfo m, ClassInfo t, ParamInfo mpi) {
- super(OTHER, mpi);
- }
-
- @Override /* RestMethodParam */
- public Object resolve(RestCall call) throws Exception {
- return call.getRestRequest().getMethod();
- }
- }
-
- static final class BeanFactoryObject extends RestMethodParam {
-
- private final ClassInfo type;
-
- protected BeanFactoryObject(MethodInfo m, ClassInfo t, ParamInfo mpi) {
- super(OTHER, mpi);
- this.type = t;
- }
-
- @Override /* RestMethodParam */
- public Object resolve(RestCall call) throws Exception {
- return call.getBeanFactory().getBean(type.inner()).orElseThrow(()->new ServletException("Could not resolve bean type: " + type.inner().getName()));
- }
- }
-
- static final class FormDataObject extends RestMethodParam {
- private final boolean multi;
- private final HttpPartParser partParser;
- private final HttpPartSchema schema;
-
- protected FormDataObject(ParamInfo mpi, PropertyStore ps) {
- super(FORM_DATA, mpi, getName(mpi));
- this.schema = HttpPartSchema.create(FormData.class, mpi);
- this.partParser = createPartParser(schema.getParser(), ps);
- this.multi = getMulti(mpi) || schema.getCollectionFormat() == HttpPartCollectionFormat.MULTI;
-
- if (multi && ! isCollection(type))
- throw new InternalServerError("Use of multipart flag on @FormData parameter that's not an array or Collection on method ''{0}''", mpi.getMethod());
- }
-
- private static String getName(ParamInfo mpi) {
- String n = null;
- for (FormData h : mpi.getAnnotations(FormData.class))
- n = firstNonEmpty(h.name(), h.n(), h.value(), n);
- if (n == null)
- throw new InternalServerError("@FormData used without name or value on method parameter ''{0}''.", mpi);
- return n;
- }
-
- private static boolean getMulti(ParamInfo mpi) {
- for (FormData f : mpi.getAnnotations(FormData.class))
- if (f.multi())
- return true;
- return false;
- }
-
- @Override /* RestMethodParam */
- public Object resolve(RestCall call) throws Exception {
- RestRequest req = call.getRestRequest();
- HttpPartParserSession ps = partParser == null ? req.getPartParser() : partParser.createPartSession(req.getParserSessionArgs());
- RequestFormData fd = req.getFormData();
- return multi ? fd.getAll(ps, schema, name, type) : fd.get(ps, schema, name, type);
- }
- }
-
- static final class QueryObject extends RestMethodParam {
- private final boolean multi;
- private final HttpPartParser partParser;
- private final HttpPartSchema schema;
-
- protected QueryObject(ParamInfo mpi, PropertyStore ps) {
- super(QUERY, mpi, getName(mpi));
- this.schema = HttpPartSchema.create(Query.class, mpi);
- this.partParser = createPartParser(schema.getParser(), ps);
- this.multi = getMulti(mpi) || schema.getCollectionFormat() == HttpPartCollectionFormat.MULTI;
-
- if (multi && ! isCollection(type))
- throw new InternalServerError("Use of multipart flag on @Query parameter that's not an array or Collection on method ''{0}''", mpi.getMethod());
- }
-
- private static String getName(ParamInfo mpi) {
- String n = null;
- for (Query h : mpi.getAnnotations(Query.class))
- n = firstNonEmpty(h.name(), h.n(), h.value(), n);
- if (n == null)
- throw new InternalServerError("@Query used without name or value on method param ''{0}''.", mpi);
- return n;
- }
-
- private static boolean getMulti(ParamInfo mpi) {
- for (Query q : mpi.getAnnotations(Query.class))
- if (q.multi())
- return true;
- return false;
- }
-
- @Override /* RestMethodParam */
- public Object resolve(RestCall call) throws Exception {
- RestRequest req = call.getRestRequest();
- HttpPartParserSession ps = partParser == null ? req.getPartParser() : partParser.createPartSession(req.getParserSessionArgs());
- RequestQuery rq = req.getQuery();
- return multi ? rq.getAll(ps, schema, name, type) : rq.get(ps, schema, name, type);
- }
- }
-
- static final class HasFormDataObject extends RestMethodParam {
-
- protected HasFormDataObject(ParamInfo mpi) {
- super(FORM_DATA, mpi, getName(mpi));
- }
-
- private static String getName(ParamInfo mpi) {
- String n = null;
- for (HasFormData h : mpi.getAnnotations(HasFormData.class))
- n = firstNonEmpty(h.name(), h.n(), h.value(), n);
- if (n == null)
- throw new InternalServerError("@HasFormData used without name or value on method parameter ''{o}''.", mpi);
- return n;
- }
-
- @Override /* RestMethodParam */
- public Object resolve(RestCall call) throws Exception {
- RestRequest req = call.getRestRequest();
- BeanSession bs = req.getBeanSession();
- return bs.convertToType(req.getFormData().containsKey(name), bs.getClassMeta(type));
- }
- }
-
- static final class HasQueryObject extends RestMethodParam {
-
- protected HasQueryObject(ParamInfo mpi) {
- super(QUERY, mpi, getName(mpi));
- }
-
- private static String getName(ParamInfo mpi) {
- String n = null;
- for (HasQuery h : mpi.getAnnotations(HasQuery.class))
- n = firstNonEmpty(h.name(), h.n(), h.value(), n);
- if (n == null)
- throw new InternalServerError("@HasQuery used without name or value on method parameter ''{0}''.", mpi);
- return n;
- }
-
- @Override /* RestMethodParam */
- public Object resolve(RestCall call) throws Exception {
- RestRequest req = call.getRestRequest();
- BeanSession bs = req.getBeanSession();
- return bs.convertToType(req.getQuery().containsKey(name), bs.getClassMeta(type));
- }
- }
-
- //-------------------------------------------------------------------------------------------------------------------
- // Other retrievers
- //-------------------------------------------------------------------------------------------------------------------
-
- static final class ResourceBundleObject extends RestMethodParam {
-
- protected ResourceBundleObject() {
- super(OTHER, ResourceBundle.class);
- }
-
- @Override /* RestMethodParam */
- public Object resolve(RestCall call) throws Exception {
- return call.getRestRequest().getMessages();
- }
- }
-
- static final class MessageBundleObject extends RestMethodParam {
-
- protected MessageBundleObject() {
- super(OTHER, Messages.class);
- }
-
- @Override /* RestMethodParam */
- public Object resolve(RestCall call) throws Exception {
- return call.getRestRequest().getMessages();
- }
- }
-
- static final class InputStreamObject extends RestMethodParam {
-
- protected InputStreamObject() {
- super(OTHER, InputStream.class);
- }
-
- @Override /* RestMethodParam */
- public Object resolve(RestCall call) throws Exception {
- return call.getRestRequest().getInputStream();
- }
- }
-
- static final class ServletInputStreamObject extends RestMethodParam {
-
- protected ServletInputStreamObject() {
- super(OTHER, ServletInputStream.class);
- }
-
- @Override /* RestMethodParam */
- public Object resolve(RestCall call) throws Exception {
- return call.getRestRequest().getInputStream();
- }
- }
-
- static final class ReaderObject extends RestMethodParam {
-
- protected ReaderObject() {
- super(OTHER, Reader.class);
- }
-
- @Override /* RestMethodParam */
- public Object resolve(RestCall call) throws Exception {
- return call.getRestRequest().getReader();
- }
- }
-
- static final class OutputStreamObject extends RestMethodParam {
-
- protected OutputStreamObject() {
- super(OTHER, OutputStream.class);
- }
-
- @Override /* RestMethodParam */
- public Object resolve(RestCall call) throws Exception {
- return call.getRestResponse().getOutputStream();
- }
- }
-
- static final class ServletOutputStreamObject extends RestMethodParam {
-
- protected ServletOutputStreamObject() {
- super(OTHER, ServletOutputStream.class);
- }
-
- @Override /* RestMethodParam */
- public Object resolve(RestCall call) throws Exception {
- return call.getRestResponse().getOutputStream();
- }
- }
-
- static final class WriterObject extends RestMethodParam {
-
- protected WriterObject() {
- super(OTHER, Writer.class);
- }
-
- @Override /* RestMethodParam */
- public Object resolve(RestCall call) throws Exception {
- return call.getRestResponse().getWriter();
- }
- }
-
- static final class RequestHeadersObject extends RestMethodParam {
-
- protected RequestHeadersObject() {
- super(OTHER, RequestHeaders.class);
- }
-
- @Override /* RestMethodParam */
- public Object resolve(RestCall call) throws Exception {
- return call.getRestRequest().getHeaders();
- }
- }
-
- static final class RequestAttributesObject extends RestMethodParam {
-
- protected RequestAttributesObject() {
- super(OTHER, RequestAttributes.class);
- }
-
- @Override /* RestMethodParam */
- public Object resolve(RestCall call) throws Exception {
- return call.getRestRequest().getAttributes();
- }
- }
-
- static final class RequestQueryObject extends RestMethodParam {
-
- protected RequestQueryObject() {
- super(OTHER, RequestQuery.class);
- }
-
- @Override /* RestMethodParam */
- public Object resolve(RestCall call) throws Exception {
- return call.getRestRequest().getQuery();
- }
- }
-
- static final class RequestFormDataObject extends RestMethodParam {
-
- protected RequestFormDataObject() {
- super(OTHER, RequestFormData.class);
- }
-
- @Override /* RestMethodParam */
- public Object resolve(RestCall call) throws Exception {
- return call.getRestRequest().getFormData();
- }
- }
-
- static final class RestContextObject extends RestMethodParam {
-
- protected RestContextObject() {
- super(OTHER, RestContext.class);
- }
-
- @Override /* RestMethodParam */
- public Object resolve(RestCall call) throws Exception {
- return call.getRestRequest().getContext();
- }
- }
-
- static final class ParserObject extends RestMethodParam {
-
- protected ParserObject() {
- super(OTHER, Parser.class);
- }
-
- @Override /* RestMethodParam */
- public Object resolve(RestCall call) throws Exception {
- return call.getRestRequest().getBody().getParser();
- }
- }
-
- static final class ReaderParserObject extends RestMethodParam {
-
- protected ReaderParserObject() {
- super(OTHER, ReaderParser.class);
- }
-
- @Override /* RestMethodParam */
- public Object resolve(RestCall call) throws Exception {
- return call.getRestRequest().getBody().getReaderParser();
- }
- }
-
- static final class InputStreamParserObject extends RestMethodParam {
-
- protected InputStreamParserObject() {
- super(OTHER, InputStreamParser.class);
- }
-
- @Override /* RestMethodParam */
- public Object resolve(RestCall call) throws Exception {
- return call.getRestRequest().getBody().getInputStreamParser();
- }
- }
-
- static final class LocaleObject extends RestMethodParam {
-
- protected LocaleObject() {
- super(OTHER, Locale.class);
- }
-
- @Override /* RestMethodParam */
- public Object resolve(RestCall call) throws Exception {
- return call.getRestRequest().getLocale();
- }
- }
-
- static final class SwaggerObject extends RestMethodParam {
-
- protected SwaggerObject() {
- super(OTHER, Swagger.class);
- }
-
- @Override /* RestMethodParam */
- public Object resolve(RestCall call) throws Exception {
- return call.getRestRequest().getSwagger();
- }
- }
-
- static final class RequestPathMatchObject extends RestMethodParam {
-
- protected RequestPathMatchObject() {
- super(OTHER, RequestPath.class);
- }
-
- @Override /* RestMethodParam */
- public Object resolve(RestCall call) throws Exception {
- return call.getRestRequest().getPathMatch();
- }
- }
-
- static final class RequestBodyObject extends RestMethodParam {
-
- protected RequestBodyObject() {
- super(OTHER, RequestBody.class);
- }
-
- @Override /* RestMethodParam */
- public Object resolve(RestCall call) throws Exception {
- return call.getRestRequest().getBody();
- }
- }
-
- static final class ConfigObject extends RestMethodParam {
-
- protected ConfigObject() {
- super(OTHER, Config.class);
- }
-
- @Override /* RestMethodParam */
- public Object resolve(RestCall call) throws Exception {
- return call.getRestRequest().getConfig();
- }
- }
-
- static final class UriContextObject extends RestMethodParam {
-
- protected UriContextObject() {
- super(OTHER, UriContext.class);
- }
-
- @Override /* RestMethodParam */
- public Object resolve(RestCall call) throws Exception {
- return call.getRestRequest().getUriContext();
- }
- }
-
- static final class UriResolverObject extends RestMethodParam {
-
- protected UriResolverObject() {
- super(OTHER, UriResolver.class);
- }
-
- @Override /* RestMethodParam */
- public Object resolve(RestCall call) throws Exception {
- return call.getRestRequest().getUriResolver();
- }
- }
-
- //=================================================================================================================
- // Utility methods
- //=================================================================================================================
-
- static final boolean isCollection(Type t) {
- return BeanContext.DEFAULT.getClassMeta(t).isCollectionOrArray();
- }
-
- static final HttpPartParser createPartParser(Class<? extends HttpPartParser> p, PropertyStore ps) {
- return castOrCreate(HttpPartParser.class, p, true, ps);
- }
-
- static final HttpPartSerializer createPartSerializer(Class<? extends HttpPartSerializer> s, PropertyStore ps) {
- return castOrCreate(HttpPartSerializer.class, s, true, ps);
- }
-}
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/SwaggerGenerator.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/SwaggerGenerator.java
index 69e9e3f..cdec671 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/SwaggerGenerator.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/SwaggerGenerator.java
@@ -322,56 +322,77 @@
paramMap.put(param.getString("in") + '.' + ("body".equals(param.getString("in")) ? "body" : param.getString("name")), param);
// Finally, look for parameters defined on method.
- for (RestMethodParam mp : sm.methodParams) {
+ for (ParamInfo mpi : mi.getParams()) {
- RestParamType in = mp.getParamType();
- ParamInfo mpi = mp.getMethodParamInfo();
+ ClassInfo pt = mpi.getParameterType();
+ Type type = pt.innerType();
- if (in.isAny(BODY, QUERY, FORM_DATA, HEADER, PATH)) {
+ if (mpi.hasAnnotation(Body.class) || pt.hasAnnotation(Body.class)) {
+ OMap param = paramMap.getMap(BODY + ".body", true).a("in", BODY);
+ for (Body a : mpi.getAnnotations(Body.class))
+ merge(param, a);
+ for (Body a : pt.getAnnotations(Body.class))
+ merge(param, a);
+ param.putIfAbsent("required", true);
+ param.ase("schema", getSchema(param.getMap("schema"), type, bs));
+ addBodyExamples(sm, param, false, type);
- String key = in.toString() + '.' + (in == BODY ? "body" : mp.getName());
+ } else if (mpi.hasAnnotation(Query.class) || pt.hasAnnotation(Query.class)) {
+ String name = null;
+ for (Query a : mpi.getAnnotations(Query.class))
+ name = firstNonEmpty(a.name(), a.n(), a.value(), name);
+ for (Query a : pt.getAnnotations(Query.class))
+ name = firstNonEmpty(a.name(), a.n(), a.value(), name);
+ OMap param = paramMap.getMap(QUERY + "." + name, true).a("name", name).a("in", QUERY);
+ for (Query a : mpi.getAnnotations(Query.class))
+ merge(param, a);
+ for (Query a : pt.getAnnotations(Query.class))
+ merge(param, a);
+ mergePartSchema(param, getSchema(param.getMap("schema"), type, bs));
+ addParamExample(sm, param, QUERY, type);
- OMap param = paramMap.getMap(key, true);
+ } else if (mpi.hasAnnotation(FormData.class) || pt.hasAnnotation(FormData.class)) {
+ String name = null;
+ for (FormData a : mpi.getAnnotations(FormData.class))
+ name = firstNonEmpty(a.name(), a.n(), a.value(), name);
+ for (FormData a : pt.getAnnotations(FormData.class))
+ name = firstNonEmpty(a.name(), a.n(), a.value(), name);
+ OMap param = paramMap.getMap(FORM_DATA + "." + name, true).a("name", name).a("in", FORM_DATA);
+ for (FormData a : mpi.getAnnotations(FormData.class))
+ merge(param, a);
+ for (FormData a : pt.getAnnotations(FormData.class))
+ merge(param, a);
+ mergePartSchema(param, getSchema(param.getMap("schema"), type, bs));
+ addParamExample(sm, param, FORM_DATA, type);
- param.append("in", in);
+ } else if (mpi.hasAnnotation(Header.class) || pt.hasAnnotation(Header.class)) {
+ String name = null;
+ for (Header a : mpi.getAnnotations(Header.class))
+ name = firstNonEmpty(a.name(), a.n(), a.value(), name);
+ for (Header a : pt.getAnnotations(Header.class))
+ name = firstNonEmpty(a.name(), a.n(), a.value(), name);
+ OMap param = paramMap.getMap(HEADER + "." + name, true).a("name", name).a("in", HEADER);
+ for (Header a : mpi.getAnnotations(Header.class))
+ merge(param, a);
+ for (Header a : pt.getAnnotations(Header.class))
+ merge(param, a);
+ mergePartSchema(param, getSchema(param.getMap("schema"), type, bs));
+ addParamExample(sm, param, HEADER, type);
- if (in != BODY)
- param.append("name", mp.name);
-
- try {
- if (mpi != null) {
- if (in == BODY) {
- for (Body a : mpi.getAnnotations(Body.class))
- merge(param, a);
- } else if (in == QUERY) {
- for (Query a : mpi.getAnnotations(Query.class))
- merge(param, a);
- } else if (in == FORM_DATA) {
- for (FormData a : mpi.getAnnotations(FormData.class))
- merge(param, a);
- } else if (in == HEADER) {
- for (Header a : mpi.getAnnotations(Header.class))
- merge(param, a);
- } else if (in == PATH) {
- for (Path a : mpi.getAnnotations(Path.class))
- merge(param, a);
- }
- }
- } catch (ParseException e) {
- throw new SwaggerException(e, "Malformed swagger JSON object encountered in {0} class {1} method parameter {2}", in, c, mpi);
- }
-
-
- if ((in == BODY || in == PATH) && ! param.containsKeyNotEmpty("required"))
- param.put("required", true);
-
- if (in == BODY) {
- param.ase("schema", getSchema(param.getMap("schema"), mp.getType(), bs));
- addBodyExamples(sm, param, false, mp.getType());
- } else {
- mergePartSchema(param, getSchema(param.getMap("schema"), mp.getType(), bs));
- addParamExample(sm, param, in, mp.getType());
- }
+ } else if (mpi.hasAnnotation(Path.class) || pt.hasAnnotation(Path.class)) {
+ String name = null;
+ for (Path a : mpi.getAnnotations(Path.class))
+ name = firstNonEmpty(a.name(), a.n(), a.value(), name);
+ for (Path a : pt.getAnnotations(Path.class))
+ name = firstNonEmpty(a.name(), a.n(), a.value(), name);
+ OMap param = paramMap.getMap(PATH + "." + name, true).a("name", name).a("in", PATH);
+ for (Path a : mpi.getAnnotations(Path.class))
+ merge(param, a);
+ for (Path a : pt.getAnnotations(Path.class))
+ merge(param, a);
+ mergePartSchema(param, getSchema(param.getMap("schema"), type, bs));
+ addParamExample(sm, param, PATH, type);
+ param.putIfAbsent("required", true);
}
}
@@ -443,34 +464,38 @@
}
// Finally, look for @ResponseHeader parameters defined on method.
- for (RestMethodParam mp : sm.methodParams) {
+ for (ParamInfo mpi : mi.getParams()) {
- RestParamType in = mp.getParamType();
- ParamInfo mpi = mp.getMethodParamInfo();
+ ClassInfo pt = mpi.getParameterType();
- if (in == RESPONSE_HEADER) {
- List<ResponseHeader> la = mpi.getAnnotations(ResponseHeader.class);
+ if (mpi.hasAnnotation(ResponseHeader.class) || pt.hasAnnotation(ResponseHeader.class)) {
+ List<ResponseHeader> la = AList.of(mpi.getAnnotations(ResponseHeader.class)).aa(pt.getAnnotations(ResponseHeader.class));
Set<Integer> codes = getCodes2(la, 200);
+ String name = null;
+ for (ResponseHeader a : la)
+ name = firstNonEmpty(a.name(), a.n(), a.value(), name);
+ Type type = mpi.getParameterType().innerType();
for (ResponseHeader a : la) {
if (! isMulti(a)) {
for (Integer code : codes) {
- OMap header = responses.getMap(String.valueOf(code), true).getMap("headers", true).getMap(mp.name, true);
+ OMap header = responses.getMap(String.valueOf(code), true).getMap("headers", true).getMap(name, true);
merge(header, a);
- mergePartSchema(header, getSchema(header, Value.getParameterType(mp.type), bs));
+ mergePartSchema(header, getSchema(header, Value.getParameterType(type), bs));
}
}
}
- } else if (in == RESPONSE) {
- List<Response> la = mpi.getAnnotations(Response.class);
+ } else if (mpi.hasAnnotation(Response.class) || pt.hasAnnotation(Response.class)) {
+ List<Response> la = AList.of(mpi.getAnnotations(Response.class)).aa(pt.getAnnotations(Response.class));
Set<Integer> codes = getCodes(la, 200);
+ Type type = mpi.getParameterType().innerType();
for (Response a : la) {
for (Integer code : codes) {
OMap response = responses.getMap(String.valueOf(code), true);
merge(response, a);
}
}
- Type type = Value.getParameterType(mp.type);
+ type = Value.getParameterType(type);
if (type != null) {
for (String code : responses.keySet()) {
OMap om = responses.getMap(code);
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/Attr.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/Attr.java
index 00a03ca..293ba99 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/Attr.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/Attr.java
@@ -46,7 +46,7 @@
* </p>
*/
@Documented
-@Target({PARAMETER})
+@Target({PARAMETER,TYPE})
@Retention(RUNTIME)
@Inherited
public @interface Attr {
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/Rest.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/Rest.java
index b20f061..283006b 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/Rest.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/Rest.java
@@ -731,20 +731,6 @@
Class<?>[] onClass() default {};
/**
- * Java method parameter resolvers.
- *
- * <p>
- * By default, the Juneau framework will automatically Java method parameters of various types (e.g.
- * <c>RestRequest</c>, <c>Accept</c>, <c>Reader</c>).
- * <br>This setting allows you to provide your own resolvers for your own class types that you want resolved.
- *
- * <ul class='seealso'>
- * <li class='jf'>{@link RestContext#REST_paramResolvers}
- * </ul>
- */
- Class<? extends RestMethodParam>[] paramResolvers() default {};
-
- /**
* Parsers.
*
* <p>
@@ -968,6 +954,20 @@
Class<? extends ResponseHandler>[] responseHandlers() default {};
/**
+ * Java method parameter resolvers.
+ *
+ * <p>
+ * By default, the Juneau framework will automatically Java method parameters of various types (e.g.
+ * <c>RestRequest</c>, <c>Accept</c>, <c>Reader</c>).
+ * <br>This setting allows you to provide your own resolvers for your own class types that you want resolved.
+ *
+ * <ul class='seealso'>
+ * <li class='jf'>{@link RestContext#REST_restParams}
+ * </ul>
+ */
+ Class<? extends RestParam>[] restParams() default {};
+
+ /**
* Role guard.
*
* <p>
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestAnnotation.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestAnnotation.java
index 7a1a8d0..8e7f88b 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestAnnotation.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestAnnotation.java
@@ -94,7 +94,7 @@
Class<? extends RestConverter>[] converters = new Class[0];
Class<? extends RestGuard>[] guards = new Class[0];
Class<? extends RestInfoProvider> infoProvider=RestInfoProvider.Null.class;
- Class<? extends RestMethodParam>[] paramResolvers = new Class[0];
+ Class<? extends RestParam>[] restParams = new Class[0];
Class<? extends BeanFactory> beanFactory = BeanFactory.Null.class;
Class<?>[] children={}, parsers={}, serializers={};
ResourceSwagger swagger = ResourceSwaggerAnnotation.DEFAULT;
@@ -415,17 +415,6 @@
}
/**
- * Sets the {@link Rest#paramResolvers()} property on this annotation.
- *
- * @param value The new value for this property.
- * @return This object (for method chaining).
- */
- public Builder paramResolvers(Class<? extends RestMethodParam>...value) {
- this.paramResolvers = value;
- return this;
- }
-
- /**
* Sets the {@link Rest#parsers()} property on this annotation.
*
* @param value The new value for this property.
@@ -503,6 +492,17 @@
}
/**
+ * Sets the {@link Rest#restParams()} property on this annotation.
+ *
+ * @param value The new value for this property.
+ * @return This object (for method chaining).
+ */
+ public Builder restParams(Class<? extends RestParam>...value) {
+ this.restParams = value;
+ return this;
+ }
+
+ /**
* Sets the {@link Rest#roleGuard()} property on this annotation.
*
* @param value The new value for this property.
@@ -659,7 +659,7 @@
private final Class<? extends RestConverter>[] converters;
private final Class<? extends RestGuard>[] guards;
private final Class<? extends RestInfoProvider> infoProvider;
- private final Class<? extends RestMethodParam>[] paramResolvers;
+ private final Class<? extends RestParam>[] restParams;
private final Class<? extends BeanFactory> beanFactory;
private final Class<?>[] children, parsers, serializers;
private final ResourceSwagger swagger;
@@ -695,7 +695,7 @@
this.infoProvider = b.infoProvider;
this.maxInput = b.maxInput;
this.messages = b.messages;
- this.paramResolvers = copyOf(b.paramResolvers);
+ this.restParams = copyOf(b.restParams);
this.parsers = copyOf(b.parsers);
this.partParser = b.partParser;
this.partSerializer = b.partSerializer;
@@ -853,11 +853,6 @@
}
@Override /* Rest */
- public Class<? extends RestMethodParam>[] paramResolvers() {
- return paramResolvers;
- }
-
- @Override /* Rest */
public Class<?>[] parsers() {
return parsers;
}
@@ -893,6 +888,11 @@
}
@Override /* Rest */
+ public Class<? extends RestParam>[] restParams() {
+ return restParams;
+ }
+
+ @Override /* Rest */
public String roleGuard() {
return roleGuard;
}
@@ -984,7 +984,7 @@
psb.prependTo(REST_converters, a.converters());
psb.prependTo(REST_guards, reverse(a.guards()));
psb.prependTo(REST_children, a.children());
- psb.prependTo(REST_paramResolvers, a.paramResolvers());
+ psb.prependTo(REST_restParams, a.restParams());
psb.setIf(a.context() != RestContext.Null.class, REST_context, a.context());
psb.setIfNotEmpty(REST_uriContext, string(a.uriContext()));
psb.setIfNotEmpty(REST_uriAuthority, string(a.uriAuthority()));
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/AttributeParam.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/AttributeParam.java
new file mode 100644
index 0000000..fd4162c
--- /dev/null
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/AttributeParam.java
@@ -0,0 +1,71 @@
+// ***************************************************************************************************************************
+// * 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.rest.params;
+
+import static org.apache.juneau.internal.StringUtils.*;
+
+import java.lang.reflect.*;
+
+import org.apache.juneau.reflect.*;
+import org.apache.juneau.rest.*;
+import org.apache.juneau.rest.annotation.*;
+
+/**
+ * Resolves method parameters annotated with {@link Attr} on {@link RestMethod}-annotated Java methods.
+ *
+ * <p>
+ * The parameter value is resolved using <c><jv>call</jv>.{@link RestCall#getRestRequest() getRestRequest}().{@link RestRequest#getAttributes() getAttributes}().{@link RequestAttributes#get(String,Type,Type...) get}(<jv>name</jv>,<jv>type</jv>)</c>.
+ */
+public class AttributeParam implements RestParam {
+
+ private final String name;
+ private final Type type;
+
+ /**
+ * Static creator.
+ *
+ * @param paramInfo The Java method parameter being resolved.
+ * @return A new {@link AttributeParam}, or <jk>null</jk> if the parameter is not annotated with {@link Attr}.
+ */
+ public static AttributeParam create(ParamInfo paramInfo) {
+ if (paramInfo.hasAnnotation(Attr.class) || paramInfo.getParameterType().hasAnnotation(Attr.class))
+ return new AttributeParam(paramInfo);
+ return null;
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param paramInfo The Java method parameter being resolved.
+ */
+ protected AttributeParam(ParamInfo paramInfo) {
+ this.name = getName(paramInfo);
+ this.type = paramInfo.getParameterType().innerType();
+ }
+
+ private String getName(ParamInfo paramInfo) {
+ String n = null;
+ for (Attr h : paramInfo.getAnnotations(Attr.class))
+ n = firstNonEmpty(h.name(), h.value(), n);
+ for (Attr h : paramInfo.getParameterType().getAnnotations(Attr.class))
+ n = firstNonEmpty(h.name(), h.value(), n);
+ if (n == null)
+ throw new ParameterException(paramInfo, "@Attr used without name or value");
+ return n;
+ }
+
+ @Override /* RestMethodParam */
+ public Object resolve(RestCall call) throws Exception {
+ return call.getRestRequest().getAttributes().get(name, type);
+ }
+}
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/BodyParam.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/BodyParam.java
new file mode 100644
index 0000000..0908f2f
--- /dev/null
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/BodyParam.java
@@ -0,0 +1,61 @@
+// ***************************************************************************************************************************
+// * 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.rest.params;
+
+import java.lang.reflect.*;
+
+import org.apache.juneau.http.annotation.*;
+import org.apache.juneau.httppart.*;
+import org.apache.juneau.reflect.*;
+import org.apache.juneau.rest.*;
+import org.apache.juneau.rest.annotation.*;
+
+/**
+ * Resolves method parameters and parameter types annotated with {@link Body} on {@link RestMethod}-annotated Java methods.
+ *
+ * <p>
+ * The parameter value is resolved using <c><jv>call</jv>.{@link RestCall#getRestRequest() getRestRequest}().{@link RestRequest#getBody() getBody}().{@link RequestBody#schema(HttpPartSchema) schema}(<jv>schema</jv>).{@link RequestBody#asType(Type,Type...) asType}(<jv>type</jv>)</c>.
+ * with a {@link HttpPartSchema schema} derived from the {@link Body} annotation.
+ */
+public class BodyParam implements RestParam {
+
+ private final HttpPartSchema schema;
+ private final Type type;
+
+ /**
+ * Static creator.
+ *
+ * @param paramInfo The Java method parameter being resolved.
+ * @return A new {@link BodyParam}, or <jk>null</jk> if the parameter is not annotated with {@link Body}.
+ */
+ public static BodyParam create(ParamInfo paramInfo) {
+ if (paramInfo.hasAnnotation(Body.class) || paramInfo.getParameterType().hasAnnotation(Body.class))
+ return new BodyParam(paramInfo);
+ return null;
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param paramInfo The Java method parameter being resolved.
+ */
+ protected BodyParam(ParamInfo paramInfo) {
+ this.type = paramInfo.getParameterType().innerType();
+ this.schema = HttpPartSchema.create(Body.class, paramInfo);
+ }
+
+ @Override /* RestMethodParam */
+ public Object resolve(RestCall call) throws Exception {
+ return call.getRestRequest().getBody().schema(schema).asType(type);
+ }
+}
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/ConfigParam.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/ConfigParam.java
new file mode 100644
index 0000000..fd68315
--- /dev/null
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/ConfigParam.java
@@ -0,0 +1,46 @@
+// ***************************************************************************************************************************
+// * 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.rest.params;
+
+import org.apache.juneau.config.*;
+import org.apache.juneau.reflect.*;
+import org.apache.juneau.rest.*;
+import org.apache.juneau.rest.annotation.*;
+
+/**
+ * Resolves method parameters of type {@link Config} on {@link RestMethod}-annotated Java methods.
+ *
+ * <p>
+ * The parameter value is resolved using <c><jv>call</jv>.{@link RestCall#getContext() getContext}().{@link RestContext#getConfig() getConfig}()</c>.
+ */
+public class ConfigParam extends SimpleRestParam {
+
+ /**
+ * Static creator.
+ *
+ * @param paramInfo The Java method parameter being resolved.
+ * @return A new {@link ConfigParam}, or <jk>null</jk> if the parameter type is not {@link Config}.
+ */
+ public static ConfigParam create(ParamInfo paramInfo) {
+ if (paramInfo.isType(Config.class))
+ return new ConfigParam();
+ return null;
+ }
+
+ /**
+ * Constructor.
+ */
+ protected ConfigParam() {
+ super((c)->c.getContext().getConfig());
+ }
+}
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/DefaultParam.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/DefaultParam.java
new file mode 100644
index 0000000..8dab057
--- /dev/null
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/DefaultParam.java
@@ -0,0 +1,59 @@
+// ***************************************************************************************************************************
+// * 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.rest.params;
+
+import org.apache.juneau.cp.*;
+import org.apache.juneau.reflect.*;
+import org.apache.juneau.rest.*;
+import org.apache.juneau.rest.annotation.*;
+
+/**
+ * Resolves method parameters on {@link RestMethod}-annotated Java methods by retrieving them by type from the REST object bean factory.
+ *
+ * <p>
+ * The parameter value is resolved using <c><jv>call</jv>.{@link RestCall#getBeanFactory() getBeanFactory}().{@link BeanFactory#getBean(Class) getBean}(<jv>type</jv>)</c>
+ * which resolves the object from the registered bean factory (e.g. Spring-injected beans available in the application).
+ *
+ * <p>
+ * This is the default parameter resolver if no other applicable parameter resolvers could be found.
+ */
+public class DefaultParam implements RestParam {
+
+ private final Class<?> type;
+ private final ParamInfo paramInfo;
+
+ /**
+ * Static creator.
+ *
+ * @param paramInfo The Java method parameter being resolved.
+ * @return A new {@link DefaultParam}, never <jk>null</jk>.
+ */
+ public static DefaultParam create(ParamInfo paramInfo) {
+ return new DefaultParam(paramInfo);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param paramInfo The Java method parameter being resolved.
+ */
+ protected DefaultParam(ParamInfo paramInfo) {
+ this.type = paramInfo.getParameterType().inner();
+ this.paramInfo = paramInfo;
+ }
+
+ @Override /* RestMethodParam */
+ public Object resolve(RestCall call) throws Exception {
+ return call.getBeanFactory().getBean(type).orElseThrow(()->new ParameterException(paramInfo, "Could not resolve bean type {0}", type.getName()));
+ }
+}
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/FormDataParam.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/FormDataParam.java
new file mode 100644
index 0000000..f052209
--- /dev/null
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/FormDataParam.java
@@ -0,0 +1,103 @@
+// ***************************************************************************************************************************
+// * 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.rest.params;
+
+import static org.apache.juneau.internal.ClassUtils.*;
+import static org.apache.juneau.internal.StringUtils.*;
+
+import java.lang.reflect.*;
+import java.util.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.http.annotation.*;
+import org.apache.juneau.httppart.*;
+import org.apache.juneau.reflect.*;
+import org.apache.juneau.rest.*;
+import org.apache.juneau.rest.annotation.*;
+
+/**
+ * Resolves method parameters and parameter types annotated with {@link FormData} on {@link RestMethod}-annotated Java methods.
+ *
+ * <p>
+ * The parameter value is resolved using <c><jv>call</jv>.{@link RestCall#getRestRequest() getRestRequest}().{@link RestRequest#getFormData() getFormData}().{@link RequestFormData#get(HttpPartParserSession,HttpPartSchema,String,Type,Type...) get}(<jv>parserSession<jv>, <jv>schema</jv>, <jv>name</jv>, <jv>type</jv>)</c>
+ * with a {@link HttpPartSchema schema} derived from the {@link FormData} annotation.
+ *
+ * <p>
+ * If the {@link FormData#multi()} flag is set, then the data type can be a {@link Collection} or array.
+ */
+public class FormDataParam implements RestParam {
+ private final boolean multi;
+ private final HttpPartParser partParser;
+ private final HttpPartSchema schema;
+ private final String name;
+ private final ClassInfo type;
+
+ /**
+ * Static creator.
+ *
+ * @param paramInfo The Java method parameter being resolved.
+ * @param ps The configuration properties of the {@link RestContext}.
+ * @return A new {@link FormDataParam}, or <jk>null</jk> if the parameter is not annotated with {@link FormData}.
+ */
+ public static FormDataParam create(ParamInfo paramInfo, PropertyStore ps) {
+ if (paramInfo.hasAnnotation(FormData.class) || paramInfo.getParameterType().hasAnnotation(FormData.class))
+ return new FormDataParam(paramInfo, ps);
+ return null;
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param paramInfo The Java method parameter being resolved.
+ * @param ps The configuration properties of the {@link RestContext}.
+ */
+ protected FormDataParam(ParamInfo paramInfo, PropertyStore ps) {
+ this.name = getName(paramInfo);
+ this.type = paramInfo.getParameterType();
+ this.schema = HttpPartSchema.create(FormData.class, paramInfo);
+ this.partParser = castOrCreate(HttpPartParser.class, schema.getParser(), true, ps);
+ this.multi = getMulti(paramInfo) || schema.getCollectionFormat() == HttpPartCollectionFormat.MULTI;
+
+ if (multi && ! type.isCollectionOrArray())
+ throw new ParameterException(paramInfo, "Use of multipart flag on @FormData parameter that is not an array or Collection");
+ }
+
+ private String getName(ParamInfo paramInfo) {
+ String n = null;
+ for (FormData h : paramInfo.getAnnotations(FormData.class))
+ n = firstNonEmpty(h.name(), h.n(), h.value(), n);
+ for (FormData h : paramInfo.getParameterType().getAnnotations(FormData.class))
+ n = firstNonEmpty(h.name(), h.n(), h.value(), n);
+ if (n == null)
+ throw new ParameterException(paramInfo, "@FormData used without name or value");
+ return n;
+ }
+
+ private boolean getMulti(ParamInfo paramInfo) {
+ for (FormData f : paramInfo.getAnnotations(FormData.class))
+ if (f.multi())
+ return true;
+ for (FormData f : paramInfo.getParameterType().getAnnotations(FormData.class))
+ if (f.multi())
+ return true;
+ return false;
+ }
+
+ @Override /* RestMethodParam */
+ public Object resolve(RestCall call) throws Exception {
+ RestRequest req = call.getRestRequest();
+ HttpPartParserSession ps = partParser == null ? req.getPartParser() : partParser.createPartSession(req.getParserSessionArgs());
+ RequestFormData fd = req.getFormData();
+ return multi ? fd.getAll(ps, schema, name, type.innerType()) : fd.get(ps, schema, name, type.innerType());
+ }
+}
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/HasFormDataParam.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/HasFormDataParam.java
new file mode 100644
index 0000000..8828743
--- /dev/null
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/HasFormDataParam.java
@@ -0,0 +1,76 @@
+// ***************************************************************************************************************************
+// * 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.rest.params;
+
+import static org.apache.juneau.internal.StringUtils.*;
+
+import java.lang.reflect.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.http.annotation.*;
+import org.apache.juneau.reflect.*;
+import org.apache.juneau.rest.*;
+import org.apache.juneau.rest.annotation.*;
+
+/**
+ * Resolves method parameters annotated with {@link HasFormData} on {@link RestMethod}-annotated Java methods.
+ *
+ * <p>
+ * The parameter value is resolved using <c><jv>call</jv>.{@link RestCall#getRestRequest() getRestRequest}().{@link RestRequest#getFormData() getFormData}().{@link RequestFormData#containsKey(Object) containsKey}(<jv>name</jv>)</c>
+ *
+ * <p>
+ * The parameter type can be a <jk>boolean</jk> or anything convertible from a <jk>boolean</jk>.
+ */
+public class HasFormDataParam implements RestParam {
+
+ private final String name;
+ private final Type type;
+
+ /**
+ * Static creator.
+ *
+ * @param paramInfo The Java method parameter being resolved.
+ * @return A new {@link HasFormDataParam}, or <jk>null</jk> if the parameter is not annotated with {@link HasFormData}.
+ */
+ public static HasFormDataParam create(ParamInfo paramInfo) {
+ if (paramInfo.hasAnnotation(HasFormData.class))
+ return new HasFormDataParam(paramInfo);
+ return null;
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param paramInfo The Java method parameter being resolved.
+ */
+ protected HasFormDataParam(ParamInfo paramInfo) {
+ this.name = getName(paramInfo);
+ this.type = paramInfo.getParameterType().innerType();
+ }
+
+ private String getName(ParamInfo paramInfo) {
+ String n = null;
+ for (HasFormData h : paramInfo.getAnnotations(HasFormData.class))
+ n = firstNonEmpty(h.name(), h.n(), h.value(), n);
+ if (n == null)
+ throw new ParameterException(paramInfo, "@HasFormData used without name or value");
+ return n;
+ }
+
+ @Override /* RestMethodParam */
+ public Object resolve(RestCall call) throws Exception {
+ RestRequest req = call.getRestRequest();
+ BeanSession bs = req.getBeanSession();
+ return bs.convertToType(req.getFormData().containsKey(name), bs.getClassMeta(type));
+ }
+}
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/HasQueryParam.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/HasQueryParam.java
new file mode 100644
index 0000000..109f878
--- /dev/null
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/HasQueryParam.java
@@ -0,0 +1,76 @@
+// ***************************************************************************************************************************
+// * 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.rest.params;
+
+import static org.apache.juneau.internal.StringUtils.*;
+
+import java.lang.reflect.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.http.annotation.*;
+import org.apache.juneau.reflect.*;
+import org.apache.juneau.rest.*;
+import org.apache.juneau.rest.annotation.*;
+
+/**
+ * Resolves method parameters annotated with {@link HasQuery} on {@link RestMethod}-annotated Java methods.
+ *
+ * <p>
+ * The parameter value is resolved using <c><jv>call</jv>.{@link RestCall#getRestRequest() getRestRequest}().{@link RestRequest#getQuery() getQuery}().{@link RequestQuery#containsKey(Object) containsKey}(<jv>name</jv>)</c>
+ *
+ * <p>
+ * The parameter type can be a <jk>boolean</jk> or anything convertible from a <jk>boolean</jk>.
+ */
+public class HasQueryParam implements RestParam {
+
+ private final String name;
+ private final Type type;
+
+ /**
+ * Static creator.
+ *
+ * @param paramInfo The Java method parameter being resolved.
+ * @return A new {@link HasQueryParam}, or <jk>null</jk> if the parameter is not annotated with {@link HasQuery}.
+ */
+ public static HasQueryParam create(ParamInfo paramInfo) {
+ if (paramInfo.hasAnnotation(HasQuery.class))
+ return new HasQueryParam(paramInfo);
+ return null;
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param paramInfo The Java method parameter being resolved.
+ */
+ protected HasQueryParam(ParamInfo paramInfo) {
+ this.name = getName(paramInfo);
+ this.type = paramInfo.getParameterType().innerType();
+ }
+
+ private String getName(ParamInfo paramInfo) {
+ String n = null;
+ for (HasQuery h : paramInfo.getAnnotations(HasQuery.class))
+ n = firstNonEmpty(h.name(), h.n(), h.value(), n);
+ if (n == null)
+ throw new ParameterException(paramInfo, "@HasQuery used without name or value");
+ return n;
+ }
+
+ @Override /* RestMethodParam */
+ public Object resolve(RestCall call) throws Exception {
+ RestRequest req = call.getRestRequest();
+ BeanSession bs = req.getBeanSession();
+ return bs.convertToType(req.getQuery().containsKey(name), bs.getClassMeta(type));
+ }
+}
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/HeaderParam.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/HeaderParam.java
new file mode 100644
index 0000000..dccfe5d
--- /dev/null
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/HeaderParam.java
@@ -0,0 +1,103 @@
+// ***************************************************************************************************************************
+// * 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.rest.params;
+
+import static org.apache.juneau.internal.ClassUtils.*;
+import static org.apache.juneau.internal.StringUtils.*;
+
+import java.lang.reflect.*;
+import java.util.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.http.annotation.*;
+import org.apache.juneau.httppart.*;
+import org.apache.juneau.reflect.*;
+import org.apache.juneau.rest.*;
+import org.apache.juneau.rest.annotation.*;
+
+/**
+ * Resolves method parameters and parameter types annotated with {@link Header} on {@link RestMethod}-annotated Java methods.
+ *
+ * <p>
+ * The parameter value is resolved using <c><jv>call</jv>.{@link RestCall#getRestRequest() getRestRequest}().{@link RestRequest#getHeaders() getHeaders}().{@link RequestHeaders#get(HttpPartParserSession,HttpPartSchema,String,Type,Type...) get}(<jv>parserSession<jv>, <jv>schema</jv>, <jv>name</jv>, <jv>type</jv>)</c>
+ * with a {@link HttpPartSchema schema} derived from the {@link Header} annotation.
+ *
+ * <p>
+ * If the {@link Header#multi()} flag is set, then the data type can be a {@link Collection} or array.
+ */
+public class HeaderParam implements RestParam {
+ private final HttpPartParser partParser;
+ private final HttpPartSchema schema;
+ private final boolean multi;
+ private final String name;
+ private final ClassInfo type;
+
+ /**
+ * Static creator.
+ *
+ * @param paramInfo The Java method parameter being resolved.
+ * @param ps The configuration properties of the {@link RestContext}.
+ * @return A new {@link HeaderParam}, or <jk>null</jk> if the parameter is not annotated with {@link Header}.
+ */
+ public static HeaderParam create(ParamInfo paramInfo, PropertyStore ps) {
+ if (paramInfo.hasAnnotation(Header.class) || paramInfo.getParameterType().hasAnnotation(Header.class))
+ return new HeaderParam(paramInfo, ps);
+ return null;
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param paramInfo The Java method parameter being resolved.
+ * @param ps The configuration properties of the {@link RestContext}.
+ */
+ protected HeaderParam(ParamInfo paramInfo, PropertyStore ps) {
+ this.name = getName(paramInfo);
+ this.type = paramInfo.getParameterType();
+ this.schema = HttpPartSchema.create(Header.class, paramInfo);
+ this.partParser = castOrCreate(HttpPartParser.class, schema.getParser(), true, ps);
+ this.multi = getMulti(paramInfo);
+
+ if (multi && ! type.isCollectionOrArray())
+ throw new ParameterException(paramInfo, "Use of multipart flag on @Header parameter that is not an array or Collection");
+ }
+
+ private String getName(ParamInfo paramInfo) {
+ String n = null;
+ for (Header h : paramInfo.getAnnotations(Header.class))
+ n = firstNonEmpty(h.name(), h.n(), h.value(), n);
+ for (Header h : paramInfo.getParameterType().getAnnotations(Header.class))
+ n = firstNonEmpty(h.name(), h.n(), h.value(), n);
+ if (n == null)
+ throw new ParameterException(paramInfo, "@Header used without name or value");
+ return n;
+ }
+
+ private boolean getMulti(ParamInfo paramInfo) {
+ for (Header h : paramInfo.getAnnotations(Header.class))
+ if (h.multi())
+ return true;
+ for (Header h : paramInfo.getParameterType().getAnnotations(Header.class))
+ if (h.multi())
+ return true;
+ return false;
+ }
+
+ @Override /* RestMethodParam */
+ public Object resolve(RestCall call) throws Exception {
+ RestRequest req = call.getRestRequest();
+ HttpPartParserSession ps = partParser == null ? req.getPartParser() : partParser.createPartSession(req.getParserSessionArgs());
+ RequestHeaders rh = call.getRestRequest().getHeaders();
+ return multi ? rh.getAll(ps, schema, name, type.innerType()) : rh.get(ps, schema, name, type.innerType());
+ }
+}
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/HttpServletRequestParam.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/HttpServletRequestParam.java
new file mode 100644
index 0000000..e68f5a3
--- /dev/null
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/HttpServletRequestParam.java
@@ -0,0 +1,48 @@
+// ***************************************************************************************************************************
+// * 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.rest.params;
+
+
+import javax.servlet.http.*;
+
+import org.apache.juneau.reflect.*;
+import org.apache.juneau.rest.*;
+import org.apache.juneau.rest.annotation.*;
+
+/**
+ * Resolves method parameters of type {@link HttpServletRequest} on {@link RestMethod}-annotated Java methods.
+ *
+ * <p>
+ * The parameter value is resolved using <c><jv>call</jv>.{@link RestCall#getRequest() getRequest}()</c>.
+ */
+public class HttpServletRequestParam extends SimpleRestParam {
+
+ /**
+ * Static creator.
+ *
+ * @param paramInfo The Java method parameter being resolved.
+ * @return A new {@link HttpServletRequestParam}, or <jk>null</jk> if the parameter type is not {@link HttpServletRequest}.
+ */
+ public static HttpServletRequestParam create(ParamInfo paramInfo) {
+ if (paramInfo.isType(HttpServletRequest.class))
+ return new HttpServletRequestParam();
+ return null;
+ }
+
+ /**
+ * Constructor.
+ */
+ protected HttpServletRequestParam() {
+ super((c)->c.getRequest());
+ }
+}
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/HttpServletResponseParam.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/HttpServletResponseParam.java
new file mode 100644
index 0000000..4628255
--- /dev/null
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/HttpServletResponseParam.java
@@ -0,0 +1,47 @@
+// ***************************************************************************************************************************
+// * 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.rest.params;
+
+import javax.servlet.http.*;
+
+import org.apache.juneau.reflect.*;
+import org.apache.juneau.rest.*;
+import org.apache.juneau.rest.annotation.*;
+
+/**
+ * Resolves method parameters of type {@link HttpServletResponse} on {@link RestMethod}-annotated Java methods.
+ *
+ * <p>
+ * The parameter value is resolved using <c><jv>call</jv>.{@link RestCall#getResponse() getResponse}()</c>.
+ */
+public class HttpServletResponseParam extends SimpleRestParam {
+
+ /**
+ * Static creator.
+ *
+ * @param paramInfo The Java method parameter being resolved.
+ * @return A new {@link HttpServletResponse}, or <jk>null</jk> if the parameter type is not {@link HttpServletResponse}.
+ */
+ public static HttpServletResponseParam create(ParamInfo paramInfo) {
+ if (paramInfo.isType(HttpServletResponse.class))
+ return new HttpServletResponseParam();
+ return null;
+ }
+
+ /**
+ * Constructor.
+ */
+ protected HttpServletResponseParam() {
+ super((c)->c.getResponse());
+ }
+}
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/InputStreamParam.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/InputStreamParam.java
new file mode 100644
index 0000000..666041e
--- /dev/null
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/InputStreamParam.java
@@ -0,0 +1,47 @@
+// ***************************************************************************************************************************
+// * 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.rest.params;
+
+import java.io.*;
+
+import org.apache.juneau.reflect.*;
+import org.apache.juneau.rest.*;
+import org.apache.juneau.rest.annotation.*;
+
+/**
+ * Resolves method parameters of type {@link InputStream} on {@link RestMethod}-annotated Java methods.
+ *
+ * <p>
+ * The parameter value is resolved using <c><jv>call</jv>.{@link RestCall#getRestRequest() getRestRequest}().{@link RestRequest#getInputStream() getInputStream}()</c>.
+ */
+public class InputStreamParam extends SimpleRestParam {
+
+ /**
+ * Static creator.
+ *
+ * @param paramInfo The Java method parameter being resolved.
+ * @return A new {@link InputStreamParam}, or <jk>null</jk> if the parameter type is not {@link InputStream}.
+ */
+ public static InputStreamParam create(ParamInfo paramInfo) {
+ if (paramInfo.isType(InputStream.class))
+ return new InputStreamParam();
+ return null;
+ }
+
+ /**
+ * Constructor.
+ */
+ protected InputStreamParam() {
+ super((c)->c.getRestRequest().getInputStream());
+ }
+}
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/InputStreamParserParam.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/InputStreamParserParam.java
new file mode 100644
index 0000000..6152790
--- /dev/null
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/InputStreamParserParam.java
@@ -0,0 +1,46 @@
+// ***************************************************************************************************************************
+// * 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.rest.params;
+
+import org.apache.juneau.parser.*;
+import org.apache.juneau.reflect.*;
+import org.apache.juneau.rest.*;
+import org.apache.juneau.rest.annotation.*;
+
+/**
+ * Resolves method parameters of type {@link InputStreamParser} on {@link RestMethod}-annotated Java methods.
+ *
+ * <p>
+ * The parameter value is resolved using <c><jv>call</jv>.{@link RestCall#getRestRequest() getRestRequest}().{@link RestRequest#getBody() getBody}().{@link RequestBody#getInputStreamParser() getInputStreamParser}()</c>.
+ */
+public class InputStreamParserParam extends SimpleRestParam {
+
+ /**
+ * Static creator.
+ *
+ * @param paramInfo The Java method parameter being resolved.
+ * @return A new {@link InputStreamParserParam}, or <jk>null</jk> if the parameter type is not {@link InputStreamParser}.
+ */
+ public static InputStreamParserParam create(ParamInfo paramInfo) {
+ if (paramInfo.isType(InputStreamParser.class))
+ return new InputStreamParserParam();
+ return null;
+ }
+
+ /**
+ * Constructor.
+ */
+ protected InputStreamParserParam() {
+ super((c)->c.getRestRequest().getBody().getInputStreamParser());
+ }
+}
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/LocaleParam.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/LocaleParam.java
new file mode 100644
index 0000000..569f218
--- /dev/null
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/LocaleParam.java
@@ -0,0 +1,47 @@
+// ***************************************************************************************************************************
+// * 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.rest.params;
+
+import java.util.*;
+
+import org.apache.juneau.reflect.*;
+import org.apache.juneau.rest.*;
+import org.apache.juneau.rest.annotation.*;
+
+/**
+ * Resolves method parameters of type {@link Locale} on {@link RestMethod}-annotated Java methods.
+ *
+ * <p>
+ * The parameter value is resolved using <c><jv>call</jv>.{@link RestCall#getRestRequest() getRestRequest}().{@link RestRequest#getLocale() getLocale}()</c>.
+ */
+public class LocaleParam extends SimpleRestParam {
+
+ /**
+ * Static creator.
+ *
+ * @param paramInfo The Java method parameter being resolved.
+ * @return A new {@link LocaleParam}, or <jk>null</jk> if the parameter type is not {@link Locale}.
+ */
+ public static LocaleParam create(ParamInfo paramInfo) {
+ if (paramInfo.isType(Locale.class))
+ return new LocaleParam();
+ return null;
+ }
+
+ /**
+ * Constructor.
+ */
+ protected LocaleParam() {
+ super((c)->c.getRestRequest().getLocale());
+ }
+}
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/MessagesParam.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/MessagesParam.java
new file mode 100644
index 0000000..daa6c0c
--- /dev/null
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/MessagesParam.java
@@ -0,0 +1,46 @@
+// ***************************************************************************************************************************
+// * 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.rest.params;
+
+import org.apache.juneau.cp.*;
+import org.apache.juneau.reflect.*;
+import org.apache.juneau.rest.*;
+import org.apache.juneau.rest.annotation.*;
+
+/**
+ * Resolves method parameters of type {@link Messages} on {@link RestMethod}-annotated Java methods.
+ *
+ * <p>
+ * The parameter value is resolved using <c><jv>call</jv>.{@link RestCall#getRestRequest() getRestRequest}().{@link RestRequest#getMessages() getMessages}()</c>.
+ */
+public class MessagesParam extends SimpleRestParam {
+
+ /**
+ * Static creator.
+ *
+ * @param paramInfo The Java method parameter being resolved.
+ * @return A new {@link MessagesParam}, or <jk>null</jk> if the parameter type is not {@link Messages}.
+ */
+ public static MessagesParam create(ParamInfo paramInfo) {
+ if (paramInfo.isType(Messages.class))
+ return new MessagesParam();
+ return null;
+ }
+
+ /**
+ * Constructor.
+ */
+ protected MessagesParam() {
+ super((c)->c.getRestRequest().getMessages());
+ }
+}
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/MethodParam.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/MethodParam.java
new file mode 100644
index 0000000..adf315c
--- /dev/null
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/MethodParam.java
@@ -0,0 +1,52 @@
+// ***************************************************************************************************************************
+// * 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.rest.params;
+
+import org.apache.juneau.reflect.*;
+import org.apache.juneau.rest.*;
+import org.apache.juneau.rest.annotation.*;
+
+/**
+ * Resolves method parameters annotated with {@link Method} on {@link RestMethod}-annotated Java methods.
+ *
+ * <p>
+ * The parameter value is resolved using <c><jv>call</jv>.{@link RestCall#getRestRequest() getRestRequest}().{@link RestRequest#getMethod() getMethod}()</c>.
+ *
+ * <p>
+ * The parameter type must be {@link String}.
+ */
+public class MethodParam implements RestParam {
+
+ /**
+ * Static creator.
+ *
+ * @param paramInfo The Java method parameter being resolved.
+ * @return A new {@link MethodParam}, or <jk>null</jk> if the parameter isn't annotated with {@link Method}.
+ */
+ public static MethodParam create(ParamInfo paramInfo) {
+ if (paramInfo.hasAnnotation(Method.class))
+ return new MethodParam();
+ return null;
+ }
+
+ /**
+ * Constructor.
+ */
+ protected MethodParam() {
+ }
+
+ @Override /* RestMethodParam */
+ public Object resolve(RestCall call) throws Exception {
+ return call.getRestRequest().getMethod();
+ }
+}
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/OutputStreamParam.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/OutputStreamParam.java
new file mode 100644
index 0000000..af4dcee
--- /dev/null
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/OutputStreamParam.java
@@ -0,0 +1,47 @@
+// ***************************************************************************************************************************
+// * 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.rest.params;
+
+import java.io.*;
+
+import org.apache.juneau.reflect.*;
+import org.apache.juneau.rest.*;
+import org.apache.juneau.rest.annotation.*;
+
+/**
+ * Resolves method parameters of type {@link OutputStream} on {@link RestMethod}-annotated Java methods.
+ *
+ * <p>
+ * The parameter value is resolved using <c><jv>call</jv>.{@link RestCall#getRestResponse() getRestResponse}().{@link RestResponse#getOutputStream() getOutputStream}()</c>.
+ */
+public class OutputStreamParam extends SimpleRestParam {
+
+ /**
+ * Static creator.
+ *
+ * @param paramInfo The Java method parameter being resolved.
+ * @return A new {@link OutputStreamParam}, or <jk>null</jk> if the parameter type is not {@link OutputStream}.
+ */
+ public static OutputStreamParam create(ParamInfo paramInfo) {
+ if (paramInfo.isType(OutputStream.class))
+ return new OutputStreamParam();
+ return null;
+ }
+
+ /**
+ * Constructor.
+ */
+ protected OutputStreamParam() {
+ super((c)->c.getRestResponse().getOutputStream());
+ }
+}
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/ParameterException.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/ParameterException.java
new file mode 100644
index 0000000..c812612
--- /dev/null
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/ParameterException.java
@@ -0,0 +1,37 @@
+// ***************************************************************************************************************************
+// * 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.rest.params;
+
+import static org.apache.juneau.internal.StringUtils.*;
+
+import org.apache.juneau.http.exception.*;
+import org.apache.juneau.reflect.*;
+
+/**
+ * General exception due to a malformed Java parameter.
+ */
+public class ParameterException extends InternalServerError {
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Constructor.
+ *
+ * @param pi The parameter with the issue.
+ * @param msg The message.
+ * @param args The message args.
+ */
+ public ParameterException(ParamInfo pi, String msg, Object...args) {
+ super(format(msg, args) + " on parameter "+pi.getIndex()+" of method "+pi.getMethod().getFullName()+".");
+ }
+
+}
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/ParserParam.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/ParserParam.java
new file mode 100644
index 0000000..01e4ce5
--- /dev/null
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/ParserParam.java
@@ -0,0 +1,46 @@
+// ***************************************************************************************************************************
+// * 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.rest.params;
+
+import org.apache.juneau.parser.*;
+import org.apache.juneau.reflect.*;
+import org.apache.juneau.rest.*;
+import org.apache.juneau.rest.annotation.*;
+
+/**
+ * Resolves method parameters of type {@link Parser} on {@link RestMethod}-annotated Java methods.
+ *
+ * <p>
+ * The parameter value is resolved using <c><jv>call</jv>.{@link RestCall#getRestRequest() getRestRequest}().{@link RestRequest#getBody() getBody}().{@link RequestBody#getParser() getParser}()</c>.
+ */
+public class ParserParam extends SimpleRestParam {
+
+ /**
+ * Static creator.
+ *
+ * @param paramInfo The Java method parameter being resolved.
+ * @return A new {@link ParserParam}, or <jk>null</jk> if the parameter type is not {@link Parser}.
+ */
+ public static ParserParam create(ParamInfo paramInfo) {
+ if (paramInfo.isType(Parser.class))
+ return new ParserParam();
+ return null;
+ }
+
+ /**
+ * Constructor.
+ */
+ protected ParserParam() {
+ super((c)->c.getRestRequest().getBody().getParser());
+ }
+}
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/PathParam.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/PathParam.java
new file mode 100644
index 0000000..14f6a8f
--- /dev/null
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/PathParam.java
@@ -0,0 +1,108 @@
+// ***************************************************************************************************************************
+// * 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.rest.params;
+
+import static org.apache.juneau.internal.ClassUtils.*;
+import static org.apache.juneau.internal.StringUtils.*;
+
+import java.lang.reflect.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.http.annotation.*;
+import org.apache.juneau.httppart.*;
+import org.apache.juneau.internal.*;
+import org.apache.juneau.reflect.*;
+import org.apache.juneau.rest.*;
+import org.apache.juneau.rest.annotation.*;
+import org.apache.juneau.rest.util.*;
+
+/**
+ * Resolves method parameters and parameter types annotated with {@link Path} on {@link RestMethod}-annotated Java methods.
+ *
+ * <p>
+ * The parameter value is resolved using <c><jv>call</jv>.{@link RestCall#getRestRequest() getRestRequest}().{@link RestRequest#getPathMatch() getPathMatch}().{@link RequestPath#get(HttpPartParserSession,HttpPartSchema,String,Type,Type...) get}(<jv>parserSession<jv>, <jv>schema</jv>, <jv>name</jv>, <jv>type</jv>)</c>
+ * with a {@link HttpPartSchema schema} derived from the {@link Path} annotation.
+ */
+public class PathParam implements RestParam {
+ private final HttpPartParser partParser;
+ private final HttpPartSchema schema;
+ private final String name;
+ private final Type type;
+
+ /**
+ * Static creator.
+ *
+ * @param paramInfo The Java method parameter being resolved.
+ * @param ps The configuration properties of the {@link RestContext}.
+ * @param pathMatcher Path matcher for the specified method.
+ * @return A new {@link PathParam}, or <jk>null</jk> if the parameter is not annotated with {@link Path}.
+ */
+ public static PathParam create(ParamInfo paramInfo, PropertyStore ps, UrlPathMatcher pathMatcher) {
+ if (paramInfo.hasAnnotation(Path.class) || paramInfo.getParameterType().hasAnnotation(Path.class))
+ return new PathParam(paramInfo, ps, pathMatcher);
+ return null;
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param paramInfo The Java method parameter being resolved.
+ * @param ps The configuration properties of the {@link RestContext}.
+ * @param pathMatcher Path matcher for the specified method.
+ */
+ protected PathParam(ParamInfo paramInfo, PropertyStore ps, UrlPathMatcher pathMatcher) {
+ this.name = getName(paramInfo, pathMatcher);
+ this.type = paramInfo.getParameterType().innerType();
+ this.schema = HttpPartSchema.create(Path.class, paramInfo);
+ this.partParser = castOrCreate(HttpPartParser.class, schema.getParser(), true, ps);
+ }
+
+ private String getName(ParamInfo paramInfo, UrlPathMatcher pathMatcher) {
+ String p = null;
+ for (Path h : paramInfo.getAnnotations(Path.class))
+ p = firstNonEmpty(h.name(), h.n(), h.value(), p);
+ for (Path h : paramInfo.getParameterType().getAnnotations(Path.class))
+ p = firstNonEmpty(h.name(), h.n(), h.value(), p);
+ if (p != null)
+ return p;
+ if (pathMatcher != null) {
+ int idx = 0;
+ int i = paramInfo.getIndex();
+ MethodInfo mi = paramInfo.getMethod();
+
+ for (int j = 0; j < i; j++)
+ if (mi.getParam(i).getLastAnnotation(Path.class) != null)
+ idx++;
+
+ String[] vars = pathMatcher.getVars();
+ if (vars.length <= idx)
+ throw new ParameterException(paramInfo, "Number of attribute parameters exceeds the number of URL pattern variables");
+
+ // Check for {#} variables.
+ String idxs = String.valueOf(idx);
+ for (int j = 0; j < vars.length; j++)
+ if (StringUtils.isNumeric(vars[j]) && vars[j].equals(idxs))
+ return vars[j];
+
+ return pathMatcher.getVars()[idx];
+ }
+ throw new ParameterException(paramInfo, "@Path used without name or value");
+ }
+
+ @Override /* RestMethodParam */
+ public Object resolve(RestCall call) throws Exception {
+ RestRequest req = call.getRestRequest();
+ HttpPartParserSession ps = partParser == null ? req.getPartParser() : partParser.createPartSession(req.getParserSessionArgs());
+ return call.getRestRequest().getPathMatch().get(ps, schema, name, type);
+ }
+}
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/QueryParam.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/QueryParam.java
new file mode 100644
index 0000000..230f529
--- /dev/null
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/QueryParam.java
@@ -0,0 +1,99 @@
+// ***************************************************************************************************************************
+// * 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.rest.params;
+
+import static org.apache.juneau.internal.ClassUtils.*;
+import static org.apache.juneau.internal.StringUtils.*;
+
+import java.lang.reflect.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.http.annotation.*;
+import org.apache.juneau.httppart.*;
+import org.apache.juneau.reflect.*;
+import org.apache.juneau.rest.*;
+import org.apache.juneau.rest.annotation.*;
+
+/**
+ * Resolves method parameters and parameter types annotated with {@link Query} on {@link RestMethod}-annotated Java methods.
+ *
+ * <p>
+ * The parameter value is resolved using <c><jv>call</jv>.{@link RestCall#getRestRequest() getRestRequest}().{@link RestRequest#getQuery() getQuery}().{@link RequestQuery#get(HttpPartParserSession,HttpPartSchema,String,Type,Type...) get}(<jv>parserSession<jv>, <jv>schema</jv>, <jv>name</jv>, <jv>type</jv>)</c>
+ * with a {@link HttpPartSchema schema} derived from the {@link Query} annotation.
+ */
+public class QueryParam implements RestParam {
+ private final boolean multi;
+ private final HttpPartParser partParser;
+ private final HttpPartSchema schema;
+ private final String name;
+ private final ClassInfo type;
+
+ /**
+ * Static creator.
+ *
+ * @param paramInfo The Java method parameter being resolved.
+ * @param ps The configuration properties of the {@link RestContext}.
+ * @return A new {@link QueryParam}, or <jk>null</jk> if the parameter is not annotated with {@link Query}.
+ */
+ public static QueryParam create(ParamInfo paramInfo, PropertyStore ps) {
+ if (paramInfo.hasAnnotation(Query.class) || paramInfo.getParameterType().hasAnnotation(Query.class))
+ return new QueryParam(paramInfo, ps);
+ return null;
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param paramInfo The Java method parameter being resolved.
+ * @param ps The configuration properties of the {@link RestContext}.
+ */
+ protected QueryParam(ParamInfo paramInfo, PropertyStore ps) {
+ this.name = getName(paramInfo);
+ this.type = paramInfo.getParameterType();
+ this.schema = HttpPartSchema.create(Query.class, paramInfo);
+ this.partParser = castOrCreate(HttpPartParser.class, schema.getParser(), true, ps);
+ this.multi = getMulti(paramInfo) || schema.getCollectionFormat() == HttpPartCollectionFormat.MULTI;
+
+ if (multi && ! type.isCollectionOrArray())
+ throw new ParameterException(paramInfo, "Use of multipart flag on @Query parameter that is not an array or Collection");
+ }
+
+ private String getName(ParamInfo paramInfo) {
+ String n = null;
+ for (Query h : paramInfo.getAnnotations(Query.class))
+ n = firstNonEmpty(h.name(), h.n(), h.value(), n);
+ for (Query h : paramInfo.getParameterType().getAnnotations(Query.class))
+ n = firstNonEmpty(h.name(), h.n(), h.value(), n);
+ if (n == null)
+ throw new ParameterException(paramInfo, "@Query used without name or value");
+ return n;
+ }
+
+ private boolean getMulti(ParamInfo paramInfo) {
+ for (Query q : paramInfo.getAnnotations(Query.class))
+ if (q.multi())
+ return true;
+ for (Query q : paramInfo.getParameterType().getAnnotations(Query.class))
+ if (q.multi())
+ return true;
+ return false;
+ }
+
+ @Override /* RestMethodParam */
+ public Object resolve(RestCall call) throws Exception {
+ RestRequest req = call.getRestRequest();
+ HttpPartParserSession ps = partParser == null ? req.getPartParser() : partParser.createPartSession(req.getParserSessionArgs());
+ RequestQuery rq = req.getQuery();
+ return multi ? rq.getAll(ps, schema, name, type.innerType()) : rq.get(ps, schema, name, type.innerType());
+ }
+}
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/ReaderParam.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/ReaderParam.java
new file mode 100644
index 0000000..d2782ca
--- /dev/null
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/ReaderParam.java
@@ -0,0 +1,47 @@
+// ***************************************************************************************************************************
+// * 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.rest.params;
+
+import java.io.*;
+
+import org.apache.juneau.reflect.*;
+import org.apache.juneau.rest.*;
+import org.apache.juneau.rest.annotation.*;
+
+/**
+ * Resolves method parameters of type {@link Reader} on {@link RestMethod}-annotated Java methods.
+ *
+ * <p>
+ * The parameter value is resolved using <c><jv>call</jv>.{@link RestCall#getRestRequest() getRestRequest}().{@link RestRequest#getReader() getReader}()</c>.
+ */
+public class ReaderParam extends SimpleRestParam {
+
+ /**
+ * Static creator.
+ *
+ * @param paramInfo The Java method parameter being resolved.
+ * @return A new {@link ReaderParam}, or <jk>null</jk> if the parameter type is not {@link Reader}.
+ */
+ public static ReaderParam create(ParamInfo paramInfo) {
+ if (paramInfo.isType(Reader.class))
+ return new ReaderParam();
+ return null;
+ }
+
+ /**
+ * Constructor.
+ */
+ protected ReaderParam() {
+ super((c)->c.getRestRequest().getReader());
+ }
+}
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/ReaderParserParam.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/ReaderParserParam.java
new file mode 100644
index 0000000..8c35d39
--- /dev/null
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/ReaderParserParam.java
@@ -0,0 +1,46 @@
+// ***************************************************************************************************************************
+// * 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.rest.params;
+
+import org.apache.juneau.parser.*;
+import org.apache.juneau.reflect.*;
+import org.apache.juneau.rest.*;
+import org.apache.juneau.rest.annotation.*;
+
+/**
+ * Resolves method parameters of type {@link ReaderParser} on {@link RestMethod}-annotated Java methods.
+ *
+ * <p>
+ * The parameter value is resolved using <c><jv>call</jv>.{@link RestCall#getRestRequest() getRestRequest}().{@link RestRequest#getBody() getBody}().{@link RequestBody#getReaderParser() getReaderParser}()</c>.
+ */
+public class ReaderParserParam extends SimpleRestParam {
+
+ /**
+ * Static creator.
+ *
+ * @param paramInfo The Java method parameter being resolved.
+ * @return A new {@link ReaderParserParam}, or <jk>null</jk> if the parameter type is not {@link ReaderParser}.
+ */
+ public static ReaderParserParam create(ParamInfo paramInfo) {
+ if (paramInfo.isType(ReaderParser.class))
+ return new ReaderParserParam();
+ return null;
+ }
+
+ /**
+ * Constructor.
+ */
+ protected ReaderParserParam() {
+ super((c)->c.getRestRequest().getBody().getReaderParser());
+ }
+}
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/RequestAttributesParam.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/RequestAttributesParam.java
new file mode 100644
index 0000000..0f61d75
--- /dev/null
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/RequestAttributesParam.java
@@ -0,0 +1,45 @@
+// ***************************************************************************************************************************
+// * 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.rest.params;
+
+import org.apache.juneau.reflect.*;
+import org.apache.juneau.rest.*;
+import org.apache.juneau.rest.annotation.*;
+
+/**
+ * Resolves method parameters of type {@link RequestAttributes} on {@link RestMethod}-annotated Java methods.
+ *
+ * <p>
+ * The parameter value is resolved using <c><jv>call</jv>.{@link RestCall#getRestRequest() getRestRequest}().{@link RestRequest#getAttributes() getAttributes}()</c>.
+ */
+public class RequestAttributesParam extends SimpleRestParam {
+
+ /**
+ * Static creator.
+ *
+ * @param paramInfo The Java method parameter being resolved.
+ * @return A new {@link RequestAttributesParam}, or <jk>null</jk> if the parameter type is not {@link RequestAttributes}.
+ */
+ public static RequestAttributesParam create(ParamInfo paramInfo) {
+ if (paramInfo.isType(RequestAttributes.class))
+ return new RequestAttributesParam();
+ return null;
+ }
+
+ /**
+ * Constructor.
+ */
+ protected RequestAttributesParam() {
+ super((c)->c.getRestRequest().getAttributes());
+ }
+}
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/RequestBeanParam.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/RequestBeanParam.java
new file mode 100644
index 0000000..9e7c734
--- /dev/null
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/RequestBeanParam.java
@@ -0,0 +1,59 @@
+// ***************************************************************************************************************************
+// * 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.rest.params;
+
+import org.apache.juneau.*;
+import org.apache.juneau.http.annotation.*;
+import org.apache.juneau.httppart.bean.*;
+import org.apache.juneau.reflect.*;
+import org.apache.juneau.rest.*;
+import org.apache.juneau.rest.annotation.*;
+
+/**
+ * Resolves method parameters annotated with {@link Request} on {@link RestMethod}-annotated Java methods.
+ *
+ * <p>
+ * The parameter value is resolved using <c><jv>call</jv>.{@link RestCall#getRestRequest() getRestRequest}().{@link RestRequest#getRequest(RequestBeanMeta) getRequest}(<jv>requestBeanMeta</jv>)</c>
+ * with a {@link RequestBeanMeta meta} derived from the {@link Request} annotation and context configuration.
+ */
+public class RequestBeanParam implements RestParam {
+ private final RequestBeanMeta meta;
+
+ /**
+ * Static creator.
+ *
+ * @param paramInfo The Java method parameter being resolved.
+ * @param ps The configuration properties of the {@link RestContext}.
+ * @return A new {@link RequestBeanParam}, or <jk>null</jk> if the parameter is not annotated with {@link Request}.
+ */
+ public static RequestBeanParam create(ParamInfo paramInfo, PropertyStore ps) {
+ if (paramInfo.hasAnnotation(Request.class))
+ return new RequestBeanParam(paramInfo, ps);
+ return null;
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param paramInfo The Java method parameter being resolved.
+ * @param ps The configuration properties of the {@link RestContext}.
+ */
+ protected RequestBeanParam(ParamInfo paramInfo, PropertyStore ps) {
+ this.meta = RequestBeanMeta.create(paramInfo, ps);
+ }
+
+ @Override /* RestMethodParam */
+ public Object resolve(RestCall call) throws Exception {
+ return call.getRestRequest().getRequest(meta);
+ }
+}
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/RequestBodyParam.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/RequestBodyParam.java
new file mode 100644
index 0000000..09f44ab
--- /dev/null
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/RequestBodyParam.java
@@ -0,0 +1,45 @@
+// ***************************************************************************************************************************
+// * 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.rest.params;
+
+import org.apache.juneau.reflect.*;
+import org.apache.juneau.rest.*;
+import org.apache.juneau.rest.annotation.*;
+
+/**
+ * Resolves method parameters of type {@link RequestBody} on {@link RestMethod}-annotated Java methods.
+ *
+ * <p>
+ * The parameter value is resolved using <c><jv>call</jv>.{@link RestCall#getRestRequest() getRestRequest}().{@link RestRequest#getBody() getBody}()</c>.
+ */
+public class RequestBodyParam extends SimpleRestParam {
+
+ /**
+ * Static creator.
+ *
+ * @param paramInfo The Java method parameter being resolved.
+ * @return A new {@link RequestBodyParam}, or <jk>null</jk> if the parameter type is not {@link RequestBody}.
+ */
+ public static RequestBodyParam create(ParamInfo paramInfo) {
+ if (paramInfo.isType(RequestBody.class))
+ return new RequestBodyParam();
+ return null;
+ }
+
+ /**
+ * Constructor.
+ */
+ protected RequestBodyParam() {
+ super((c)->c.getRestRequest().getBody());
+ }
+}
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/RequestFormDataParam.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/RequestFormDataParam.java
new file mode 100644
index 0000000..841132f
--- /dev/null
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/RequestFormDataParam.java
@@ -0,0 +1,45 @@
+// ***************************************************************************************************************************
+// * 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.rest.params;
+
+import org.apache.juneau.reflect.*;
+import org.apache.juneau.rest.*;
+import org.apache.juneau.rest.annotation.*;
+
+/**
+ * Resolves method parameters of type {@link RequestFormData} on {@link RestMethod}-annotated Java methods.
+ *
+ * <p>
+ * The parameter value is resolved using <c><jv>call</jv>.{@link RestCall#getRestRequest() getRestRequest}().{@link RestRequest#getFormData() getFormData}()</c>.
+ */
+public class RequestFormDataParam extends SimpleRestParam {
+
+ /**
+ * Static creator.
+ *
+ * @param paramInfo The Java method parameter being resolved.
+ * @return A new {@link RequestFormDataParam}, or <jk>null</jk> if the parameter type is not {@link RequestFormData}.
+ */
+ public static RequestFormDataParam create(ParamInfo paramInfo) {
+ if (paramInfo.isType(RequestFormData.class))
+ return new RequestFormDataParam();
+ return null;
+ }
+
+ /**
+ * Constructor.
+ */
+ protected RequestFormDataParam() {
+ super((c)->c.getRestRequest().getFormData());
+ }
+}
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/RequestHeadersParam.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/RequestHeadersParam.java
new file mode 100644
index 0000000..6056655
--- /dev/null
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/RequestHeadersParam.java
@@ -0,0 +1,45 @@
+// ***************************************************************************************************************************
+// * 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.rest.params;
+
+import org.apache.juneau.reflect.*;
+import org.apache.juneau.rest.*;
+import org.apache.juneau.rest.annotation.*;
+
+/**
+ * Resolves method parameters of type {@link RequestHeaders} on {@link RestMethod}-annotated Java methods.
+ *
+ * <p>
+ * The parameter value is resolved using <c><jv>call</jv>.{@link RestCall#getRestRequest() getRestRequest}().{@link RestRequest#getHeaders() getHeaders}()</c>.
+ */
+public class RequestHeadersParam extends SimpleRestParam {
+
+ /**
+ * Static creator.
+ *
+ * @param paramInfo The Java method parameter being resolved.
+ * @return A new {@link RequestHeadersParam}, or <jk>null</jk> if the parameter type is not {@link RequestHeaders}.
+ */
+ public static RequestHeadersParam create(ParamInfo paramInfo) {
+ if (paramInfo.isType(RequestHeaders.class))
+ return new RequestHeadersParam();
+ return null;
+ }
+
+ /**
+ * Constructor.
+ */
+ protected RequestHeadersParam() {
+ super((c)->c.getRestRequest().getHeaders());
+ }
+}
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/RequestPathParam.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/RequestPathParam.java
new file mode 100644
index 0000000..17b95f9
--- /dev/null
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/RequestPathParam.java
@@ -0,0 +1,45 @@
+// ***************************************************************************************************************************
+// * 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.rest.params;
+
+import org.apache.juneau.reflect.*;
+import org.apache.juneau.rest.*;
+import org.apache.juneau.rest.annotation.*;
+
+/**
+ * Resolves method of type with {@link RequestPath} on {@link RestMethod}-annotated Java methods.
+ *
+ * <p>
+ * The parameter value is resolved using <c><jv>call</jv>.{@link RestCall#getRestRequest() getRestRequest}().{@link RestRequest#getPathMatch() getPathMatch}()</c>.
+ */
+public class RequestPathParam extends SimpleRestParam {
+
+ /**
+ * Static creator.
+ *
+ * @param paramInfo The Java method parameter being resolved.
+ * @return A new {@link RequestPathParam}, or <jk>null</jk> if the parameter type is not {@link RequestPath}.
+ */
+ public static RequestPathParam create(ParamInfo paramInfo) {
+ if (paramInfo.isType(RequestPath.class))
+ return new RequestPathParam();
+ return null;
+ }
+
+ /**
+ * Constructor.
+ */
+ protected RequestPathParam() {
+ super((c)->c.getRestRequest().getPathMatch());
+ }
+}
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/RequestQueryParam.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/RequestQueryParam.java
new file mode 100644
index 0000000..68d949c
--- /dev/null
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/RequestQueryParam.java
@@ -0,0 +1,45 @@
+// ***************************************************************************************************************************
+// * 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.rest.params;
+
+import org.apache.juneau.reflect.*;
+import org.apache.juneau.rest.*;
+import org.apache.juneau.rest.annotation.*;
+
+/**
+ * Resolves method parameters of type {@link RequestQuery} on {@link RestMethod}-annotated Java methods.
+ *
+ * <p>
+ * The parameter value is resolved using <c><jv>call</jv>.{@link RestCall#getRestRequest() getRestRequest}().{@link RestRequest#getQuery() getQuery}()</c>.
+ */
+public class RequestQueryParam extends SimpleRestParam {
+
+ /**
+ * Static creator.
+ *
+ * @param paramInfo The Java method parameter being resolved.
+ * @return A new {@link RequestQueryParam}, or <jk>null</jk> if the parameter type is not {@link RequestQuery}.
+ */
+ public static RequestQueryParam create(ParamInfo paramInfo) {
+ if (paramInfo.isType(RequestQuery.class))
+ return new RequestQueryParam();
+ return null;
+ }
+
+ /**
+ * Constructor.
+ */
+ protected RequestQueryParam() {
+ super((c)->c.getRestRequest().getQuery());
+ }
+}
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/ResourceBundleParam.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/ResourceBundleParam.java
new file mode 100644
index 0000000..5ddd42b
--- /dev/null
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/ResourceBundleParam.java
@@ -0,0 +1,47 @@
+// ***************************************************************************************************************************
+// * 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.rest.params;
+
+import java.util.*;
+
+import org.apache.juneau.reflect.*;
+import org.apache.juneau.rest.*;
+import org.apache.juneau.rest.annotation.*;
+
+/**
+ * Resolves method parameters of type {@link ResourceBundle} on {@link RestMethod}-annotated Java methods.
+ *
+ * <p>
+ * The parameter value is resolved using <c><jv>call</jv>.{@link RestCall#getRestRequest() getRestRequest}().{@link RestRequest#getMessages() getMessages}()</c>.
+ */
+public class ResourceBundleParam extends SimpleRestParam {
+
+ /**
+ * Static creator.
+ *
+ * @param paramInfo The Java method parameter being resolved.
+ * @return A new {@link ResourceBundleParam}, or <jk>null</jk> if the parameter type is not {@link ResourceBundle}.
+ */
+ public static ResourceBundleParam create(ParamInfo paramInfo) {
+ if (paramInfo.isType(ResourceBundle.class))
+ return new ResourceBundleParam();
+ return null;
+ }
+
+ /**
+ * Constructor.
+ */
+ protected ResourceBundleParam() {
+ super((c)->c.getRestRequest().getMessages());
+ }
+}
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/ResponseBeanParam.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/ResponseBeanParam.java
new file mode 100644
index 0000000..e05ca32
--- /dev/null
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/ResponseBeanParam.java
@@ -0,0 +1,80 @@
+// ***************************************************************************************************************************
+// * 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.rest.params;
+
+import java.lang.reflect.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.http.annotation.*;
+import org.apache.juneau.httppart.bean.*;
+import org.apache.juneau.reflect.*;
+import org.apache.juneau.rest.*;
+import org.apache.juneau.rest.annotation.*;
+
+/**
+ * Resolves method parameters and parameter types annotated with {@link Response} on {@link RestMethod}-annotated Java methods.
+ *
+ * <p>
+ * The parameter value must be of type {@link Value} that accepts a value that is then set via
+ * <c><jv>call</jv>.{@link RestCall#getRestResponse() getRestResponse}().{@link RestResponse#setOutput(Object) setOutput}(<jv>value</jv>)</c>.
+ */
+public class ResponseBeanParam implements RestParam {
+ final ResponseBeanMeta meta;
+ private final Type type;
+
+ /**
+ * Static creator.
+ *
+ * @param paramInfo The Java method parameter being resolved.
+ * @param ps The configuration properties of the {@link RestContext}.
+ * @return A new {@link ResponseBeanParam}, or <jk>null</jk> if the parameter is not annotated with {@link Response}.
+ */
+ public static ResponseBeanParam create(ParamInfo paramInfo, PropertyStore ps) {
+ if (paramInfo.hasAnnotation(Response.class) || paramInfo.getParameterType().hasAnnotation(Response.class))
+ return new ResponseBeanParam(paramInfo, ps);
+ return null;
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param paramInfo The Java method parameter being resolved.
+ * @param ps The configuration properties of the {@link RestContext}.
+ */
+ protected ResponseBeanParam(ParamInfo paramInfo, PropertyStore ps) {
+ this.type = paramInfo.getParameterType().innerType();
+ this.meta = ResponseBeanMeta.create(paramInfo, ps);
+ Class<?> c = type instanceof Class ? (Class<?>)type : type instanceof ParameterizedType ? (Class<?>)((ParameterizedType)type).getRawType() : null;
+ if (c != Value.class)
+ throw new ParameterException(paramInfo, "Type must be Value<?> on parameter annotated with @Response annotation");
+ }
+
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ @Override /* RestMethodParam */
+ public Object resolve(final RestCall call) throws Exception {
+ Value<Object> v = new Value();
+ v.listener(new ValueListener() {
+ @Override
+ public void onSet(Object o) {
+ RestRequest req = call.getRestRequest();
+ RestResponse res = call.getRestResponse();
+ ResponseBeanMeta meta = req.getResponseBeanMeta(o);
+ if (meta == null)
+ meta = ResponseBeanParam.this.meta;
+ res.setResponseMeta(meta);
+ res.setOutput(o);
+ }
+ });
+ return v;
+ }
+}
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/ResponseHeaderParam.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/ResponseHeaderParam.java
new file mode 100644
index 0000000..95d11bd
--- /dev/null
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/ResponseHeaderParam.java
@@ -0,0 +1,103 @@
+// ***************************************************************************************************************************
+// * 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.rest.params;
+
+import static org.apache.juneau.internal.ClassUtils.*;
+import static org.apache.juneau.internal.StringUtils.*;
+
+import java.lang.reflect.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.http.annotation.*;
+import org.apache.juneau.httppart.*;
+import org.apache.juneau.reflect.*;
+import org.apache.juneau.rest.*;
+import org.apache.juneau.rest.annotation.*;
+import org.apache.juneau.serializer.*;
+
+/**
+ * Resolves method parameters annotated with {@link ResponseHeader} on {@link RestMethod}-annotated Java methods.
+ *
+ * <p>
+ * The parameter value must be of type {@link Value} that accepts a value that is then set via
+ * <c><jv>call</jv>.{@link RestCall#getRestResponse() getRestResponse}().{@link RestResponse#setHeader(String,String) setOutput}(<jv>name</jv>,<jv>value</jv>)</c>.
+ */
+public class ResponseHeaderParam implements RestParam {
+ final ResponsePartMeta meta;
+ final String name;
+ private final Type type;
+
+ /**
+ * Static creator.
+ *
+ * @param paramInfo The Java method parameter being resolved.
+ * @param ps The configuration properties of the {@link RestContext}.
+ * @return A new {@link ResponseHeaderParam}, or <jk>null</jk> if the parameter is not annotated with {@link ResponseHeader}.
+ */
+ public static ResponseHeaderParam create(ParamInfo paramInfo, PropertyStore ps) {
+ if (paramInfo.hasAnnotation(ResponseHeader.class) || paramInfo.getParameterType().hasAnnotation(ResponseHeader.class))
+ return new ResponseHeaderParam(paramInfo, ps);
+ return null;
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param paramInfo The Java method parameter being resolved.
+ * @param ps The configuration properties of the {@link RestContext}.
+ */
+ protected ResponseHeaderParam(ParamInfo paramInfo, PropertyStore ps) {
+ this.name = getName(paramInfo);
+ this.type = paramInfo.getParameterType().innerType();
+ HttpPartSchema schema = HttpPartSchema.create(ResponseHeader.class, paramInfo);
+ this.meta = new ResponsePartMeta(HttpPartType.HEADER, schema, castOrCreate(HttpPartSerializer.class, schema.getSerializer(), true, ps));
+
+ Class<?> c = type instanceof Class ? (Class<?>)type : type instanceof ParameterizedType ? (Class<?>)((ParameterizedType)type).getRawType() : null;
+ if (c != Value.class)
+ throw new ParameterException(paramInfo, "Type must be Value<?> on parameter annotated with @ResponseHeader annotation");
+ }
+
+ private static String getName(ParamInfo paramInfo) {
+ String n = null;
+ for (ResponseHeader h : paramInfo.getAnnotations(ResponseHeader.class))
+ n = firstNonEmpty(h.name(), h.n(), h.value(), n);
+ for (ResponseHeader h : paramInfo.getParameterType().getAnnotations(ResponseHeader.class))
+ n = firstNonEmpty(h.name(), h.n(), h.value(), n);
+ if (n == null)
+ throw new ParameterException(paramInfo, "@ResponseHeader used without name or value");
+ return n;
+ }
+
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ @Override /* RestMethodParam */
+ public Object resolve(final RestCall call) throws Exception {
+ Value<Object> v = new Value();
+ v.listener(new ValueListener() {
+ @Override
+ public void onSet(Object o) {
+ try {
+ RestRequest req = call.getRestRequest();
+ RestResponse res = call.getRestResponse();
+ ResponsePartMeta rpm = req.getResponseHeaderMeta(o);
+ if (rpm == null)
+ rpm = ResponseHeaderParam.this.meta;
+ HttpPartSerializerSession pss = rpm.getSerializer() == null ? req.getPartSerializer() : rpm.getSerializer().createPartSession(req.getSerializerSessionArgs());
+ res.setHeader(new HttpPart(name, HttpPartType.HEADER, rpm.getSchema(), pss, o));
+ } catch (SerializeException | SchemaValidationException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ });
+ return v;
+ }
+}
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/ResponseStatusParam.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/ResponseStatusParam.java
new file mode 100644
index 0000000..59d8a10
--- /dev/null
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/ResponseStatusParam.java
@@ -0,0 +1,66 @@
+// ***************************************************************************************************************************
+// * 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.rest.params;
+
+import java.lang.reflect.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.http.annotation.*;
+import org.apache.juneau.reflect.*;
+import org.apache.juneau.rest.*;
+import org.apache.juneau.rest.annotation.*;
+
+/**
+ * Resolves method parameters annotated with {@link ResponseStatus} on {@link RestMethod}-annotated Java methods.
+ */
+public class ResponseStatusParam implements RestParam {
+
+ private final Type type;
+
+ /**
+ * Static creator.
+ *
+ * @param paramInfo The Java method parameter being resolved.
+ * @return A new {@link ResponseStatusParam}, or <jk>null</jk> if the parameter is not annotated with {@link ResponseStatus}.
+ */
+ public static ResponseStatusParam create(ParamInfo paramInfo) {
+ if (paramInfo.hasAnnotation(ResponseStatus.class) || paramInfo.getParameterType().hasAnnotation(ResponseStatus.class))
+ return new ResponseStatusParam(paramInfo);
+ return null;
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param paramInfo The Java method parameter being resolved.
+ */
+ protected ResponseStatusParam(ParamInfo paramInfo) {
+ this.type = paramInfo.getParameterType().innerType();
+ Class<?> c = type instanceof Class ? (Class<?>)type : type instanceof ParameterizedType ? (Class<?>)((ParameterizedType)type).getRawType() : null;
+ if (c != Value.class || Value.getParameterType(type) != Integer.class)
+ throw new ParameterException(paramInfo, "Type must be Value<Integer> on parameter annotated with @ResponseStatus annotation");
+ }
+
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ @Override /* RestMethodParam */
+ public Object resolve(final RestCall call) throws Exception {
+ Value<Object> v = new Value();
+ v.listener(new ValueListener() {
+ @Override
+ public void onSet(Object o) {
+ call.getRestResponse().setStatus(Integer.parseInt(o.toString()));
+ }
+ });
+ return v;
+ }
+}
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/RestContextParam.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/RestContextParam.java
new file mode 100644
index 0000000..5829883
--- /dev/null
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/RestContextParam.java
@@ -0,0 +1,45 @@
+// ***************************************************************************************************************************
+// * 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.rest.params;
+
+import org.apache.juneau.reflect.*;
+import org.apache.juneau.rest.*;
+import org.apache.juneau.rest.annotation.*;
+
+/**
+ * Resolves method parameters of type {@link RestContext} on {@link RestMethod}-annotated Java methods.
+ *
+ * <p>
+ * The parameter value is resolved using <c><jv>call</jv>.{@link RestCall#getContext() getContext}()</c>.
+ */
+public class RestContextParam extends SimpleRestParam {
+
+ /**
+ * Static creator.
+ *
+ * @param paramInfo The Java method parameter being resolved.
+ * @return A new {@link RestContextParam}, or <jk>null</jk> if the parameter type is not {@link RestContext}.
+ */
+ public static RestContextParam create(ParamInfo paramInfo) {
+ if (paramInfo.isType(RestContext.class))
+ return new RestContextParam();
+ return null;
+ }
+
+ /**
+ * Constructor.
+ */
+ protected RestContextParam() {
+ super((c)->c.getContext());
+ }
+}
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/RestRequestParam.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/RestRequestParam.java
new file mode 100644
index 0000000..3b5752c
--- /dev/null
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/RestRequestParam.java
@@ -0,0 +1,45 @@
+// ***************************************************************************************************************************
+// * 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.rest.params;
+
+import org.apache.juneau.reflect.*;
+import org.apache.juneau.rest.*;
+import org.apache.juneau.rest.annotation.*;
+
+/**
+ * Resolves method parameters of type {@link RestRequest} on {@link RestMethod}-annotated Java methods.
+ *
+ * <p>
+ * The parameter value is resolved using <c><jv>call</jv>.{@link RestCall#getRestRequest() getRestRequest}()</c>.
+ */
+public class RestRequestParam extends SimpleRestParam {
+
+ /**
+ * Static creator.
+ *
+ * @param paramInfo The Java method parameter being resolved.
+ * @return A new {@link RestRequestParam}, or <jk>null</jk> if the parameter type is not {@link RestRequest}.
+ */
+ public static RestRequestParam create(ParamInfo paramInfo) {
+ if (paramInfo.isType(RestRequest.class))
+ return new RestRequestParam();
+ return null;
+ }
+
+ /**
+ * Constructor.
+ */
+ protected RestRequestParam() {
+ super((c)->c.getRestRequest());
+ }
+}
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/ServetInputStreamParam.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/ServetInputStreamParam.java
new file mode 100644
index 0000000..cadcad6
--- /dev/null
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/ServetInputStreamParam.java
@@ -0,0 +1,47 @@
+// ***************************************************************************************************************************
+// * 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.rest.params;
+
+import javax.servlet.*;
+
+import org.apache.juneau.reflect.*;
+import org.apache.juneau.rest.*;
+import org.apache.juneau.rest.annotation.*;
+
+/**
+ * Resolves method parameters of type {@link ServletInputStream} on {@link RestMethod}-annotated Java methods.
+ *
+ * <p>
+ * The parameter value is resolved using <c><jv>call</jv>.{@link RestCall#getRestRequest() getRestRequest}().{@link RestRequest#getInputStream() getInputStream}()</c>.
+ */
+public class ServetInputStreamParam extends SimpleRestParam {
+
+ /**
+ * Static creator.
+ *
+ * @param paramInfo The Java method parameter being resolved.
+ * @return A new {@link ServetInputStreamParam}, or <jk>null</jk> if the parameter type is not {@link ServletInputStream}.
+ */
+ public static ServetInputStreamParam create(ParamInfo paramInfo) {
+ if (paramInfo.isType(ServletInputStream.class))
+ return new ServetInputStreamParam();
+ return null;
+ }
+
+ /**
+ * Constructor.
+ */
+ protected ServetInputStreamParam() {
+ super((c)->c.getRestRequest().getInputStream());
+ }
+}
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/ServletOutputStreamParam.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/ServletOutputStreamParam.java
new file mode 100644
index 0000000..677a1b7
--- /dev/null
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/ServletOutputStreamParam.java
@@ -0,0 +1,47 @@
+// ***************************************************************************************************************************
+// * 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.rest.params;
+
+import javax.servlet.*;
+
+import org.apache.juneau.reflect.*;
+import org.apache.juneau.rest.*;
+import org.apache.juneau.rest.annotation.*;
+
+/**
+ * Resolves method parameters of type {@link ServletOutputStream} on {@link RestMethod}-annotated Java methods.
+ *
+ * <p>
+ * The parameter value is resolved using <c><jv>call</jv>.{@link RestCall#getRestResponse() getRestResponse}().{@link RestResponse#getOutputStream() getOutputStream}()</c>.
+ */
+public class ServletOutputStreamParam extends SimpleRestParam {
+
+ /**
+ * Static creator.
+ *
+ * @param paramInfo The Java method parameter being resolved.
+ * @return A new {@link ServletOutputStreamParam}, or <jk>null</jk> if the parameter type is not {@link ServletOutputStream}.
+ */
+ public static ServletOutputStreamParam create(ParamInfo paramInfo) {
+ if (paramInfo.isType(ServletOutputStream.class))
+ return new ServletOutputStreamParam();
+ return null;
+ }
+
+ /**
+ * Constructor.
+ */
+ protected ServletOutputStreamParam() {
+ super((c)->c.getRestResponse().getOutputStream());
+ }
+}
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/SimpleRestParam.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/SimpleRestParam.java
new file mode 100644
index 0000000..4cdac27
--- /dev/null
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/SimpleRestParam.java
@@ -0,0 +1,41 @@
+// ***************************************************************************************************************************
+// * 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.rest.params;
+
+import java.util.function.*;
+
+import org.apache.juneau.rest.*;
+import org.apache.juneau.utils.*;
+
+/**
+ * An implementation of a {@link RestParam} that takes in a {@link ThrowingFunction} for resolving a parameter value.
+ */
+public class SimpleRestParam implements RestParam {
+
+ private final Function<RestCall,Object> function;
+
+ /**
+ * Constructor.
+ *
+ * @param function The function to use to retrieve the parameter value from the {@link RestCall}.
+ */
+ @SuppressWarnings("unchecked")
+ protected <T> SimpleRestParam(ThrowingFunction<RestCall,T> function) {
+ this.function = (Function<RestCall,Object>)function;
+ }
+
+ @Override /* RestMethodParam */
+ public Object resolve(RestCall call) throws Exception {
+ return function.apply(call);
+ }
+}
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/SwaggerParam.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/SwaggerParam.java
new file mode 100644
index 0000000..f263cd4
--- /dev/null
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/SwaggerParam.java
@@ -0,0 +1,46 @@
+// ***************************************************************************************************************************
+// * 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.rest.params;
+
+import org.apache.juneau.dto.swagger.*;
+import org.apache.juneau.reflect.*;
+import org.apache.juneau.rest.*;
+import org.apache.juneau.rest.annotation.*;
+
+/**
+ * Resolves method parameters of type {@link Swagger} on {@link RestMethod}-annotated Java methods.
+ *
+ * <p>
+ * The parameter value is resolved using <c><jv>call</jv>.{@link RestCall#getRestRequest() getRestRequest}().{@link RestRequest#getSwagger() getSwagger}()</c>.
+ */
+public class SwaggerParam extends SimpleRestParam {
+
+ /**
+ * Static creator.
+ *
+ * @param paramInfo The Java method parameter being resolved.
+ * @return A new {@link SwaggerParam}, or <jk>null</jk> if the parameter type is not {@link Swagger}.
+ */
+ public static SwaggerParam create(ParamInfo paramInfo) {
+ if (paramInfo.isType(Swagger.class))
+ return new SwaggerParam();
+ return null;
+ }
+
+ /**
+ * Constructor.
+ */
+ protected SwaggerParam() {
+ super((c)->c.getRestRequest().getSwagger());
+ }
+}
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/TimeZoneParam.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/TimeZoneParam.java
new file mode 100644
index 0000000..1924f16
--- /dev/null
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/TimeZoneParam.java
@@ -0,0 +1,47 @@
+// ***************************************************************************************************************************
+// * 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.rest.params;
+
+import java.util.*;
+
+import org.apache.juneau.reflect.*;
+import org.apache.juneau.rest.*;
+import org.apache.juneau.rest.annotation.*;
+
+/**
+ * Resolves method parameters of type {@link TimeZone} on {@link RestMethod}-annotated Java methods.
+ *
+ * <p>
+ * The parameter value is resolved using <c><jv>call</jv>.{@link RestCall#getRestRequest() getRestRequest}().{@link RestRequest#getHeaders() getHeaders}().{@link RequestHeaders#getTimeZone() getTimeZone}()</c>.
+ */
+public class TimeZoneParam extends SimpleRestParam {
+
+ /**
+ * Static creator.
+ *
+ * @param paramInfo The Java method parameter being resolved.
+ * @return A new {@link TimeZoneParam}, or <jk>null</jk> if the parameter type is not {@link TimeZone}.
+ */
+ public static TimeZoneParam create(ParamInfo paramInfo) {
+ if (paramInfo.isType(TimeZone.class))
+ return new TimeZoneParam();
+ return null;
+ }
+
+ /**
+ * Constructor.
+ */
+ protected TimeZoneParam() {
+ super((c)->c.getRestRequest().getHeaders().getTimeZone());
+ }
+}
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/UriContextParam.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/UriContextParam.java
new file mode 100644
index 0000000..d1215f7
--- /dev/null
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/UriContextParam.java
@@ -0,0 +1,46 @@
+// ***************************************************************************************************************************
+// * 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.rest.params;
+
+import org.apache.juneau.*;
+import org.apache.juneau.reflect.*;
+import org.apache.juneau.rest.*;
+import org.apache.juneau.rest.annotation.*;
+
+/**
+ * Resolves method parameters of type {@link UriContext} on {@link RestMethod}-annotated Java methods.
+ *
+ * <p>
+ * The parameter value is resolved using <c><jv>call</jv>.{@link RestCall#getRestRequest() getRestRequest}().{@link RestRequest#getUriContext() getUriContext}()</c>.
+ */
+public class UriContextParam extends SimpleRestParam {
+
+ /**
+ * Static creator.
+ *
+ * @param paramInfo The Java method parameter being resolved.
+ * @return A new {@link UriContextParam}, or <jk>null</jk> if the parameter type is not {@link UriContext}.
+ */
+ public static UriContextParam create(ParamInfo paramInfo) {
+ if (paramInfo.isType(UriContext.class))
+ return new UriContextParam();
+ return null;
+ }
+
+ /**
+ * Constructor.
+ */
+ protected UriContextParam() {
+ super((c)->c.getRestRequest().getUriContext());
+ }
+}
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/UriResolverParam.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/UriResolverParam.java
new file mode 100644
index 0000000..1ea4b1e
--- /dev/null
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/UriResolverParam.java
@@ -0,0 +1,46 @@
+// ***************************************************************************************************************************
+// * 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.rest.params;
+
+import org.apache.juneau.*;
+import org.apache.juneau.reflect.*;
+import org.apache.juneau.rest.*;
+import org.apache.juneau.rest.annotation.*;
+
+/**
+ * Resolves method parameters of type {@link UriResolver} on {@link RestMethod}-annotated Java methods.
+ *
+ * <p>
+ * The parameter value is resolved using <c><jv>call</jv>.{@link RestCall#getRestRequest() getRestRequest}().{@link RestRequest#getUriResolver() getUriResolver}()</c>.
+ */
+public class UriResolverParam extends SimpleRestParam {
+
+ /**
+ * Static creator.
+ *
+ * @param paramInfo The Java method parameter being resolved.
+ * @return A new {@link UriResolverParam}, or <jk>null</jk> if the parameter type is not {@link UriResolver}.
+ */
+ public static UriResolverParam create(ParamInfo paramInfo) {
+ if (paramInfo.isType(UriResolver.class))
+ return new UriResolverParam();
+ return null;
+ }
+
+ /**
+ * Constructor.
+ */
+ protected UriResolverParam() {
+ super((c)->c.getRestRequest().getUriResolver());
+ }
+}
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/WriterParam.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/WriterParam.java
new file mode 100644
index 0000000..37d95cf
--- /dev/null
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/params/WriterParam.java
@@ -0,0 +1,47 @@
+// ***************************************************************************************************************************
+// * 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.rest.params;
+
+import java.io.*;
+
+import org.apache.juneau.reflect.*;
+import org.apache.juneau.rest.*;
+import org.apache.juneau.rest.annotation.*;
+
+/**
+ * Resolves method parameters of type {@link Writer} on {@link RestMethod}-annotated Java methods.
+ *
+ * <p>
+ * The parameter value is resolved using <c><jv>call</jv>.{@link RestCall#getRestResponse() getRestResponse}().{@link RestResponse#getWriter() getWriter}()</c>.
+ */
+public class WriterParam extends SimpleRestParam {
+
+ /**
+ * Static creator.
+ *
+ * @param paramInfo The Java method parameter being resolved.
+ * @return A new {@link WriterParam}, or <jk>null</jk> if the parameter type is not {@link Writer}.
+ */
+ public static WriterParam create(ParamInfo paramInfo) {
+ if (paramInfo.isType(Writer.class))
+ return new WriterParam();
+ return null;
+ }
+
+ /**
+ * Constructor.
+ */
+ protected WriterParam() {
+ super((c)->c.getRestResponse().getWriter());
+ }
+}