You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@juneau.apache.org by ja...@apache.org on 2018/01/07 18:00:38 UTC
juneau git commit: Update javadocs.
Repository: juneau
Updated Branches:
refs/heads/master 5c21b4caa -> 34c9be07d
Update javadocs.
Project: http://git-wip-us.apache.org/repos/asf/juneau/repo
Commit: http://git-wip-us.apache.org/repos/asf/juneau/commit/34c9be07
Tree: http://git-wip-us.apache.org/repos/asf/juneau/tree/34c9be07
Diff: http://git-wip-us.apache.org/repos/asf/juneau/diff/34c9be07
Branch: refs/heads/master
Commit: 34c9be07dd6341b161b90af8f1e6c34dd04cf722
Parents: 5c21b4c
Author: JamesBognar <ja...@apache.org>
Authored: Sun Jan 7 13:00:33 2018 -0500
Committer: JamesBognar <ja...@apache.org>
Committed: Sun Jan 7 13:00:33 2018 -0500
----------------------------------------------------------------------
.../org/apache/juneau/rest/RestJavaMethod.java | 23 +-
.../juneau/rest/annotation/RestMethod.java | 1085 ++++++++----------
2 files changed, 506 insertions(+), 602 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/juneau/blob/34c9be07/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestJavaMethod.java
----------------------------------------------------------------------
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestJavaMethod.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestJavaMethod.java
index 3f0374a..55af351 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestJavaMethod.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestJavaMethod.java
@@ -144,6 +144,8 @@ public class RestJavaMethod implements Comparable<RestJavaMethod> {
RestMethod m = method.getAnnotation(RestMethod.class);
if (m == null)
throw new RestServletException("@RestMethod annotation not found on method ''{0}''", sig);
+
+ VarResolver vr = context.getVarResolver();
if (! m.description().isEmpty())
description = m.description();
@@ -168,9 +170,9 @@ public class RestJavaMethod implements Comparable<RestJavaMethod> {
maxInput = context.getMaxInput();
if (! m.defaultCharset().isEmpty())
- defaultCharset = context.getVarResolver().resolve(m.defaultCharset());
+ defaultCharset = vr.resolve(m.defaultCharset());
if (! m.maxInput().isEmpty())
- maxInput = StringUtils.parseLongWithSuffix(context.getVarResolver().resolve(m.maxInput()));
+ maxInput = StringUtils.parseLongWithSuffix(vr.resolve(m.maxInput()));
HtmlDocBuilder hdb = new HtmlDocBuilder(properties);
@@ -349,7 +351,7 @@ public class RestJavaMethod implements Comparable<RestJavaMethod> {
defaultRequestHeaders = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
for (String s : m.defaultRequestHeaders()) {
- String[] h = RestUtils.parseKeyValuePair(s);
+ String[] h = RestUtils.parseKeyValuePair(vr.resolve(s));
if (h == null)
throw new RestServletException(
"Invalid default request header specified on method ''{0}'': ''{1}''. Must be in the format: ''name[:=]value''", sig, s);
@@ -358,7 +360,7 @@ public class RestJavaMethod implements Comparable<RestJavaMethod> {
defaultQuery = new LinkedHashMap<>();
for (String s : m.defaultQuery()) {
- String[] h = RestUtils.parseKeyValuePair(s);
+ String[] h = RestUtils.parseKeyValuePair(vr.resolve(s));
if (h == null)
throw new RestServletException(
"Invalid default query parameter specified on method ''{0}'': ''{1}''. Must be in the format: ''name[:=]value''", sig, s);
@@ -367,7 +369,7 @@ public class RestJavaMethod implements Comparable<RestJavaMethod> {
defaultFormData = new LinkedHashMap<>();
for (String s : m.defaultFormData()) {
- String[] h = RestUtils.parseKeyValuePair(s);
+ String[] h = RestUtils.parseKeyValuePair(vr.resolve(s));
if (h == null)
throw new RestServletException(
"Invalid default form data parameter specified on method ''{0}'': ''{1}''. Must be in the format: ''name[:=]value''", sig, s);
@@ -409,11 +411,11 @@ public class RestJavaMethod implements Comparable<RestJavaMethod> {
supportedAcceptTypes =
m.supportedAcceptTypes().length > 0
- ? Collections.unmodifiableList(new ArrayList<>(Arrays.asList(MediaType.forStrings(m.supportedAcceptTypes()))))
+ ? Collections.unmodifiableList(new ArrayList<>(Arrays.asList(MediaType.forStrings(resolveVars(vr, m.supportedAcceptTypes())))))
: serializers.getSupportedMediaTypes();
supportedContentTypes =
m.supportedContentTypes().length > 0
- ? Collections.unmodifiableList(new ArrayList<>(Arrays.asList(MediaType.forStrings(m.supportedContentTypes()))))
+ ? Collections.unmodifiableList(new ArrayList<>(Arrays.asList(MediaType.forStrings(resolveVars(vr, m.supportedContentTypes())))))
: parsers.getSupportedMediaTypes();
params = context.findParams(method, pathPattern, false);
@@ -922,4 +924,11 @@ public class RestJavaMethod implements Comparable<RestJavaMethod> {
public int hashCode() {
return super.hashCode();
}
+
+ static String[] resolveVars(VarResolver vr, String[] in) {
+ String[] out = new String[in.length];
+ for (int i = 0; i < in.length; i++)
+ out[i] = vr.resolve(in[i]);
+ return out;
+ }
}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/juneau/blob/34c9be07/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestMethod.java
----------------------------------------------------------------------
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestMethod.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestMethod.java
index fc8a494..765ef25 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestMethod.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestMethod.java
@@ -18,12 +18,14 @@ import static java.lang.annotation.RetentionPolicy.*;
import java.lang.annotation.*;
import org.apache.juneau.*;
-import org.apache.juneau.encoders.*;
-import org.apache.juneau.http.*;
+import org.apache.juneau.encoders.Encoder;
+import org.apache.juneau.ini.*;
import org.apache.juneau.parser.*;
import org.apache.juneau.remoteable.*;
import org.apache.juneau.rest.*;
+import org.apache.juneau.rest.vars.*;
import org.apache.juneau.serializer.*;
+import org.apache.juneau.svl.vars.*;
/**
* Identifies a REST Java method on a {@link RestServlet} implementation class.
@@ -37,272 +39,392 @@ import org.apache.juneau.serializer.*;
public @interface RestMethod {
/**
- * REST method name.
+ * Appends the specified bean filters to all serializers and parsers used by this method.
+ *
+ * <p>
+ * See {@link BeanContext#BEAN_beanFilters} for more information.
+ */
+ Class<?>[] beanFilters() default {};
+
+ /**
+ * Shortcut for specifying the {@link BeanContext#BEAN_includeProperties} property on all serializers.
*
* <p>
- * Typically <js>"GET"</js>, <js>"PUT"</js>, <js>"POST"</js>, <js>"DELETE"</js>, or <js>"OPTIONS"</js>.
+ * The typical use case is when you're rendering summary and details views of the same bean in a resource and
+ * you want to expose or hide specific properties depending on the level of detail you want.
*
* <p>
- * Method names are case-insensitive (always folded to upper-case).
+ * In the example below, our 'summary' view is a list of beans where we only want to show the ID property,
+ * and our detail view is a single bean where we want to expose different fields:
+ * <p class='bcode'>
+ * <jc>// Our bean</jc>
+ * <jk>public class</jk> MyBean {
+ *
+ * <jc>// Summary properties</jc>
+ * <ja>@Html</ja>(link=<js>"servlet:/mybeans/{id}"</js>)
+ * <jk>public</jk> String <jf>id</jf>;
+ *
+ * <jc>// Detail properties</jc>
+ * <jk>public</jk> String <jf>a</jf>, <jf>b</jf>;
+ * }
+ *
+ * <jc>// Only render "id" property.</jc>
+ * <ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/mybeans"</js>, bpi=<js>"MyBean: id"</js>)
+ * <jk>public</jk> List<MyBean> getBeanSummary();
+ *
+ * <jc>// Only render "a" and "b" properties.</jc>
+ * <ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/mybeans/{id}"</js>, bpi=<js>"MyBean: a,b"</js>)
+ * <jk>public</jk> MyBean getBeanDetails(<ja>@Path</ja> String id);
+ * </p>
*
* <p>
- * Note that you can use {@link org.apache.juneau.http.HttpMethodName} for constant values.
+ * The format of each value is: <js>"Key: comma-delimited-tokens"</js>.
+ * <br>Keys can be fully-qualified or short class names or <js>"*"</js> to represent all classes.
+ * <br>Values are comma-delimited lists of bean property names.
+ * <br>Properties apply to specified class and all subclasses.
*
* <p>
- * Besides the standard HTTP method names, the following can also be specified:
- * <ul class='spaced-list'>
- * <li>
- * <js>"*"</js>
- * - Denotes any method.
- * <br>Use this if you want to capture any HTTP methods in a single Java method.
- * <br>The {@link Method @Method} annotation and/or {@link RestRequest#getMethod()} method can be used to
- * distinguish the actual HTTP method name.
- * <li>
- * <js>""</js>
- * - Auto-detect.
- * <br>The method name is determined based on the Java method name.
- * <br>For example, if the method is <code>doPost(...)</code>, then the method name is automatically detected
- * as <js>"POST"</js>.
- * <br>Otherwise, defaults to <js>"GET"</js>.
- * <li>
- * <js>"PROXY"</js>
- * - Remote-proxy interface.
- * <br>This denotes a Java method that returns an object (usually an interface, often annotated with the
- * {@link Remoteable @Remoteable} annotation) to be used as a remote proxy using
- * <code>RestClient.getRemoteableProxy(Class<T> interfaceClass, String url)</code>.
- * <br>This allows you to construct client-side interface proxies using REST as a transport medium.
- * <br>Conceptually, this is simply a fancy <code>POST</code> against the url <js>"/{path}/{javaMethodName}"</js>
- * where the arguments are marshalled from the client to the server as an HTTP body containing an array of
- * objects, passed to the method as arguments, and then the resulting object is marshalled back to the client.
- * <li>
- * Anything else
- * - Overloaded non-HTTP-standard names that are passed in through a <code>&method=methodName</code> URL
- * parameter.
- * </ul>
+ * Semicolons can be used as an additional separator for multiple values:
+ * <p class='bcode'>
+ * <jc>// Equivalent</jc>
+ * bpi={<js>"Bean1: foo"</js>,<js>"Bean2: bar,baz"</js>}
+ * bpi=<js>"Bean1: foo; Bean2: bar,baz"</js>
+ * </p>
*/
- String name() default "";
+ String[] bpi() default {};
/**
- * Optional path pattern for the specified method.
+ * Shortcut for specifying the {@link BeanContext#BEAN_excludeProperties} property on all serializers.
*
* <p>
- * Appending <js>"/*"</js> to the end of the path pattern will make it match any remainder too.
- * <br>Not appending <js>"/*"</js> to the end of the pattern will cause a 404 (Not found) error to occur if the exact
- * pattern is not found.
+ * Same as {@link #bpi()} except you specify a list of bean property names that you want to exclude from
+ * serialization.
*
* <p>
- * The path can contain variables that get resolved to {@link Path @Path} parameters:
+ * In the example below, our 'summary' view is a list of beans where we want to exclude some properties:
* <p class='bcode'>
- * <jc>// Example 1</jc>
- * <ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/myurl/{foo}/{bar}/{baz}/*"</js>)
+ * <jc>// Our bean</jc>
+ * <jk>public class</jk> MyBean {
*
- * <jc>// Example 2</jc>
- * <ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/myurl/{0}/{1}/{2}/*"</js>)
+ * <jc>// Summary properties</jc>
+ * <ja>@Html</ja>(link=<js>"servlet:/mybeans/{id}"</js>)
+ * <jk>public</jk> String <jf>id</jf>;
+ *
+ * <jc>// Detail properties</jc>
+ * <jk>public</jk> String <jf>a</jf>, <jf>b</jf>;
+ * }
+ *
+ * <jc>// Don't show "a" and "b" properties.</jc>
+ * <ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/mybeans"</js>, bpx=<js>"MyBean: a,b"</js>)
+ * <jk>public</jk> List<MyBean> getBeanSummary();
+ *
+ * <jc>// Render all properties.</jc>
+ * <ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/mybeans/{id}"</js>)
+ * <jk>public</jk> MyBean getBeanDetails(<ja>@Path</ja> String id);
* </p>
*
* <p>
- * Refer to {@link Path @Path} on how path variables get resolved.
+ * The format of each value is: <js>"Key: comma-delimited-tokens"</js>.
+ * <br>Keys can be fully-qualified or short class names or <js>"*"</js> to represent all classes.
+ * <br>Values are comma-delimited lists of bean property names.
+ * <br>Properties apply to specified class and all subclasses.
+ *
+ * <p>
+ * Semicolons can be used as an additional separator for multiple values:
+ * <p class='bcode'>
+ * <jc>// Equivalent</jc>
+ * bpx={<js>"Bean1: foo"</js>,<js>"Bean2: bar,baz"</js>}
+ * bpx=<js>"Bean1: foo; Bean2: bar,baz"</js>
+ * </p>
*/
- String path() default "/*";
+ String[] bpx() default {};
/**
- * URL path pattern priority.
+ * Specifies whether this method can be called based on the client version.
*
* <p>
- * To force path patterns to be checked before other path patterns, use a higher priority number.
+ * The client version is identified via the HTTP request header identified by
+ * {@link RestResource#clientVersionHeader()} which by default is <js>"X-Client-Version"</js>.
*
* <p>
- * By default, it's <code>0</code>, which means it will use an internal heuristic to determine a best match.
- */
- int priority() default 0;
-
- /**
- * Method-level guards.
+ * This is a specialized kind of {@link RestMatcher} that allows you to invoke different Java methods for the same
+ * method/path based on the client version.
*
* <p>
- * Associates one or more {@link RestGuard RestGuards} with all REST methods defined in this class.
- * These guards get called immediately before execution of any REST method in this class.
+ * The format of the client version range is similar to that of OSGi versions.
*
* <p>
- * Typically, guards will be used for permissions checking on the user making the request, but it can also be used
- * for other purposes like pre-call validation of a request.
+ * In the following example, the Java methods are mapped to the same HTTP method and URL <js>"/foobar"</js>.
+ * <p class='bcode'>
+ * <jc>// Call this method if X-Client-Version is at least 2.0.
+ * // Note that this also matches 2.0.1.</jc>
+ * <ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/foobar"</js>, clientVersion=<js>"2.0"</js>)
+ * <jk>public</jk> Object method1() {
+ * ...
+ * }
*
- * <h5 class='section'>Notes:</h5>
- * <ul class='spaced-list'>
- * <li>Property: {@link RestContext#REST_guards}
- * <li>Annotations:
- * <ul>
- * <li>{@link RestResource#guards()}
- * <li>{@link RestMethod#guards()}
- * </ul>
- * <li>Methods:
- * <ul>
- * <li>{@link RestContextBuilder#guards(Class...)}
- * <li>{@link RestContextBuilder#guards(RestGuard...)}
- * </ul>
- * <li>{@link RestGuard} classes must have either a no-arg or {@link PropertyStore} argument constructors.
- * <li>Values are added AFTER those found in the annotation and therefore take precedence over those defined via the
- * annotation.
- * </ul>
+ * <jc>// Call this method if X-Client-Version is at least 1.1, but less than 2.0.</jc>
+ * <ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/foobar"</js>, clientVersion=<js>"[1.1,2.0)"</js>)
+ * <jk>public</jk> Object method2() {
+ * ...
+ * }
+ *
+ * <jc>// Call this method if X-Client-Version is less than 1.1.</jc>
+ * <ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/foobar"</js>, clientVersion=<js>"[0,1.1)"</js>)
+ * <jk>public</jk> Object method3() {
+ * ...
+ * }
+ * </p>
+ *
+ * <p>
+ * It's common to combine the client version with transforms that will convert new POJOs into older POJOs for
+ * backwards compatibility.
+ * <p class='bcode'>
+ * <jc>// Call this method if X-Client-Version is at least 2.0.</jc>
+ * <ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/foobar"</js>, clientVersion=<js>"2.0"</js>)
+ * <jk>public</jk> NewPojo newMethod() {
+ * ...
+ * }
+ *
+ * <jc>// Call this method if X-Client-Version is at least 1.1, but less than 2.0.</jc>
+ * <ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/foobar"</js>, clientVersion=<js>"[1.1,2.0)"</js>, transforms={NewToOldPojoSwap.<jk>class</jk>})
+ * <jk>public</jk> NewPojo oldMethod() {
+ * <jk>return</jk> newMethod()
+ * }
+ *
+ * <p>
+ * Note that in the previous example, we're returning the exact same POJO, but using a transform to convert it into
+ * an older form.
+ * The old method could also just return back a completely different object.
+ * The range can be any of the following:
+ * <ul>
+ * <li><js>"[0,1.0)"</js> = Less than 1.0. 1.0 and 1.0.0 does not match.
+ * <li><js>"[0,1.0]"</js> = Less than or equal to 1.0. Note that 1.0.1 will match.
+ * <li><js>"1.0"</js> = At least 1.0. 1.0 and 2.0 will match.
+ * </ul>
*/
- Class<? extends RestGuard>[] guards() default {};
+ String clientVersion() default "";
/**
* Class-level response converters.
*
* <p>
- * Associates one or more {@link RestConverter converters} with a resource class.
- * These converters get called immediately after execution of the REST method in the same order specified in the
- * annotation.
- *
+ * Associates one or more {@link RestConverter converters} with this method.
+ *
* <p>
- * Can be used for performing post-processing on the response object before serialization.
- *
- * <h5 class='section'>Notes:</h5>
- * <ul class='spaced-list'>
- * <li>Property: {@link RestContext#REST_converters}
- * <li>Annotations:
- * <ul>
- * <li>{@link RestResource#converters()}
- * <li>{@link RestMethod#converters()}
- * </ul>
- * <li>Methods:
- * <ul>
- * <li>{@link RestContextBuilder#converters(Class...)}
- * <li>{@link RestContextBuilder#converters(RestConverter...)}
- * </ul>
- * </ul>
- *
- * <h5 class='section'>Documentation:</h5>
- * <ul>
- * <li><a class="doclink" href="../package-summary.html#RestResources.Converters">Converters</a>
- * </ul>
+ * See {@link RestContext#REST_converters} for more information.
*/
Class<? extends RestConverter>[] converters() default {};
/**
- * Method matchers.
+ * Default character encoding.
+ *
+ * <p>
+ * The default character encoding for the request and response if not specified on the request.
*
* <p>
- * Associates one more more {@link RestMatcher RestMatchers} with this method.
+ * Value can contain any of the following variables:
+ * {@link ConfigFileVar $C}
+ * {@link CoalesceVar $CO}
+ * {@link CoalesceAndRecurseVar $CR}
+ * {@link EnvVariablesVar $E}
+ * {@link IfVar $IF}
+ * {@link SystemPropertiesVar $S}
+ * {@link SwitchVar $SW}
+ *
+ * <p>
+ * See {@link RestContext#REST_defaultCharset} for more information.
+ */
+ String defaultCharset() default "";
+
+ /**
+ * Specifies default values for form-data parameters.
*
* <p>
- * Matchers are used to allow multiple Java methods to handle requests assigned to the same URL path pattern, but
- * differing based on some request attribute, such as a specific header value.
+ * Strings are of the format <js>"name=value"</js>.
*
* <p>
- * See {@link RestMatcher} for details.
+ * Affects values returned by {@link RestRequest#getFormData(String)} when the parameter is not present on the
+ * request.
+ *
+ * <h5 class='section'>Example:</h5>
+ * <p class='bcode'>
+ * <ja>@RestMethod</ja>(name=<jsf>POST</jsf>, path=<js>"/*"</js>, defaultFormData={<js>"foo=bar"</js>})
+ * <jk>public</jk> String doGet(<ja>@FormData</ja>(<js>"foo"</js>) String foo) {
+ * ...
+ * }
+ * </p>
+ *
+ * <p>
+ * You can use either <js>':'</js> or <js>'='</js> as the key/value delimiter.
+ * Key and value is trimmed of whitespace.
+ *
+ * <p>
+ * Values can contain any of the following variables:
+ * {@link ConfigFileVar $C}
+ * {@link CoalesceVar $CO}
+ * {@link CoalesceAndRecurseVar $CR}
+ * {@link EnvVariablesVar $E}
+ * {@link IfVar $IF}
+ * {@link SystemPropertiesVar $S}
+ * {@link SwitchVar $SW}
*/
- Class<? extends RestMatcher>[] matchers() default {};
+ String[] defaultFormData() default {};
/**
- * Serializers.
+ * Specifies default values for query parameters.
*
* <p>
- * Overrides the list of serializers assigned at the method level.
+ * Strings are of the format <js>"name=value"</js>.
*
* <p>
- * Use this annotation when the list of serializers assigned to a method differs from the list of serializers
- * assigned at the servlet level.
+ * Affects values returned by {@link RestRequest#getQuery(String)} when the parameter is not present on the request.
+ *
+ * <h5 class='section'>Example:</h5>
+ * <p class='bcode'>
+ * <ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/*"</js>, defaultQuery={<js>"foo=bar"</js>})
+ * <jk>public</jk> String doGet(<ja>@Query</ja>(<js>"foo"</js>) String foo) {
+ * ...
+ * }
+ * </p>
+ *
+ * <p>
+ * You can use either <js>':'</js> or <js>'='</js> as the key/value delimiter.
+ * Key and value is trimmed of whitespace.
*
* <p>
- * To append to the list of serializers assigned at the servlet level, use <code>inherit=<js>"SERIALIZERS"</js></code>.
+ * Values can contain any of the following variables:
+ * {@link ConfigFileVar $C}
+ * {@link CoalesceVar $CO}
+ * {@link CoalesceAndRecurseVar $CR}
+ * {@link EnvVariablesVar $E}
+ * {@link IfVar $IF}
+ * {@link SystemPropertiesVar $S}
+ * {@link SwitchVar $SW}
+ */
+ String[] defaultQuery() default {};
+
+ /**
+ * Default request headers.
+ *
+ * <p>
+ * Specifies default values for request headers.
*
+ * <h5 class='section'>Example:</h5>
* <p class='bcode'>
- * <jk>public class</jk> MyResource <jk>extends</jk> RestServlet {
- *
- * <ja>@RestMethod</ja>(
- * name=<jsf>GET</jsf>,
- * path=<js>"/foo"</js>,
- * serializers=MySpecialSerializer.<jk>class</jk>,
- * inherit=<js>"SERIALIZERS"</js>
- * )
- * <jk>public</jk> Object doGetWithSpecialAcceptType() {
- * <jc>// Handle request for special Accept type</jc>
- * }
+ * <jc>// Assume "text/json" Accept value when Accept not specified</jc>
+ * <ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/*"</js>, defaultRequestHeaders={<js>"Accept: text/json"</js>})
+ * <jk>public</jk> String doGet() {
+ * ...
* }
* </p>
*
- * <h5 class='section'>Notes:</h5>
+ * <p>
+ * Values can contain any of the following variables:
+ * {@link ConfigFileVar $C}
+ * {@link CoalesceVar $CO}
+ * {@link CoalesceAndRecurseVar $CR}
+ * {@link EnvVariablesVar $E}
+ * {@link IfVar $IF}
+ * {@link SystemPropertiesVar $S}
+ * {@link SwitchVar $SW}
+ *
+ * <p>
+ * See {@link RestContext#REST_defaultRequestHeaders} for more information.
+ */
+ String[] defaultRequestHeaders() default {};
+
+ /**
+ * Optional description for the exposed API.
+ *
+ * <p>
+ * This description is used in the following locations:
* <ul class='spaced-list'>
- * <li>Property: {@link RestContext#REST_serializers}
- * <li>Annotations:
- * <ul>
- * <li>{@link RestResource#serializers()}
- * <li>{@link RestMethod#serializers()}
- * </ul>
- * <li>Methods:
- * <ul>
- * <li>{@link RestContextBuilder#serializers(Object...)}
- * <li>{@link RestContextBuilder#serializers(Class...)}
- * <li>{@link RestContextBuilder#serializers(boolean,Object...)}
- * </ul>
- * <li>When defined as a class, properties/transforms defined on the resource/method are inherited.
- * <li>When defined as an instance, properties/transforms defined on the resource/method are NOT inherited.
+ * <li>
+ * The value returned by {@link RestRequest#getMethodDescription()}.
+ * <li>
+ * The <js>"$R{methodDescription}"</js> variable.
+ * <li>
+ * The description of the method in the Swagger page.
* </ul>
*
- * <h5 class='section'>Documentation:</h5>
- * <ul>
- * <li><a class="doclink" href="../package-summary.html#RestResources.Serializers">Serializers</a>
- * </ul>
+ * <p>
+ * The default value pulls the description from the <code>(className.?)[javaMethodName].description</code> entry in
+ * the servlet resource bundle. (e.g. <js>"MyClass.myMethod.description = foo"</js> or
+ * <js>"myMethod.description = foo"</js>).
+ *
+ * <p>
+ * Value can contain any of the following variables:
+ * {@link ConfigFileVar $C}
+ * {@link CoalesceVar $CO}
+ * {@link CoalesceAndRecurseVar $CR}
+ * {@link EnvVariablesVar $E}
+ * {@link FileVar $F}
+ * {@link ServletInitParamVar $I},
+ * {@link IfVar $IF}
+ * {@link LocalizationVar $L}
+ * {@link RequestAttributeVar $RA}
+ * {@link RequestFormDataVar $RF}
+ * {@link RequestHeaderVar $RH}
+ * {@link RequestPathVar $RP}
+ * {@link RequestQueryVar $RQ}
+ * {@link RequestVar $R}
+ * {@link SystemPropertiesVar $S}
+ * {@link SerializedRequestAttrVar $SA}
+ * {@link SwitchVar $SW}
+ * {@link UrlVar $U}
+ * {@link UrlEncodeVar $UE}
+ * {@link WidgetVar $W}
+ *
+ * <p>
+ * Corresponds to the swagger field <code>/paths/{path}/{method}/description</code>.
*/
- Class<? extends Serializer>[] serializers() default {};
+ String description() default "";
/**
- * Parsers.
- *
- * <p>
- * Overrides the list of parsers assigned at the method level.
+ * Compression encoders.
*
* <p>
- * Use this annotation when the list of parsers assigned to a method differs from the list of parsers assigned at
+ * Use this annotation when the list of encoders assigned to a method differs from the list of encoders assigned at
* the servlet level.
- *
+ *
* <p>
- * To append to the list of parsers assigned at the servlet level, use
- * <code>inherit=<js>"PARSERS"</js></code>.
+ * These can be used to enable various kinds of compression (e.g. <js>"gzip"</js>) on requests and responses.
+ *
+ * <p>
+ * Use <code>inherit={<js>"ENCODERS"</js>}</code> to inherit encoders from the resource class.
+ *
+ * <p>
+ * See {@link RestContext#REST_encoders} for more information.
+ */
+ Class<? extends Encoder>[] encoders() default {};
+
+ /**
+ * Shortcut for setting {@link #properties()} of simple boolean types.
*
- * <p class='bcode'>
- * <jk>public class</jk> MyResource <jk>extends</jk> RestServlet {
+ * <p>
+ * Setting a flag is equivalent to setting the same property to <js>"true"</js>.
+ */
+ String[] flags() default {};
+
+ /**
+ * Method-level guards.
*
- * <ja>@RestMethod</ja>(
- * name=<jsf>PUT</jsf>,
- * path=<js>"/foo"</js>,
- * parsers=MySpecialParser.<jk>class</jk>,
- * inherit=<js>"PARSERS"</js>
- * )
- * <jk>public</jk> Object doGetWithSpecialAcceptType() {
- * <jc>// Handle request for special Accept type</jc>
- * }
- * }
- * </p>
+ * <p>
+ * Associates one or more {@link RestGuard RestGuards} with this method.
*
- * <h5 class='section'>Notes:</h5>
- * <ul class='spaced-list'>
- * <li>Property: {@link RestContext#REST_parsers}
- * <li>Annotations:
- * <ul>
- * <li>{@link RestResource#parsers()}
- * <li>{@link RestMethod#parsers()}
- * </ul>
- * <li>Methods:
- * <ul>
- * <li>{@link RestContextBuilder#parsers(Object...)}
- * <li>{@link RestContextBuilder#parsers(Class...)}
- * <li>{@link RestContextBuilder#parsers(boolean,Object...)}
- * </ul>
- * <li>When defined as a class, properties/transforms defined on the resource/method are inherited.
- * <li>When defined as an instance, properties/transforms defined on the resource/method are NOT inherited.
- * <li>Values are added AFTER those found in the annotation and therefore take precedence over those defined via the
- * annotation.
- * </ul>
+ * <p>
+ * See {@link RestContext#REST_guards} for more information.
+ */
+ Class<? extends RestGuard>[] guards() default {};
+
+ /**
+ * Provides HTML-doc-specific metadata on this method.
*
- * <h5 class='section'>Documentation:</h5>
- * <ul>
- * <li><a class="doclink" href="../package-summary.html#RestResources.Parsers">Parsers</a>
- * </ul>
+ * <p>
+ * Information provided here overrides information provided in the servlet-level annotation.
*/
- Class<? extends Parser>[] parsers() default {};
+ HtmlDoc htmldoc() default @HtmlDoc;
/**
* Identifies what class-level properties are inherited by the serializers and parsers defined on the method.
@@ -331,340 +453,212 @@ public @interface RestMethod {
String inherit() default "";
/**
- * Supported accept media types.
- *
- * <p>
- * Overrides the media types inferred from the serializers that identify what media types can be produced by the resource.
- *
- * <p>
- * This affects the values returned by {@link RestRequest#getSupportedAcceptTypes()} and the supported accept
- * types shown in {@link RestInfoProvider#getSwagger(RestRequest)}.
+ * Method matchers.
*
* <p>
- * <h5 class='section'>Notes:</h5>
- * <ul class='spaced-list'>
- * <li>Property: {@link RestContext#REST_supportedAcceptTypes}
- * <li>Annotations:
- * <ul>
- * <li>{@link RestResource#supportedAcceptTypes()}
- * <li>{@link RestMethod#supportedAcceptTypes()}
- * </ul>
- * <li>Methods:
- * <ul>
- * <li>{@link RestContextBuilder#supportedAcceptTypes(boolean,String...)}
- * <li>{@link RestContextBuilder#supportedAcceptTypes(boolean,MediaType...)}
- * </ul>
- * </ul>
- */
- String[] supportedAcceptTypes() default {};
-
- /**
- * Supported content media types.
+ * Associates one more more {@link RestMatcher RestMatchers} with this method.
*
* <p>
- * Overrides the media types inferred from the parsers that identify what media types can be consumed by the resource.
+ * Matchers are used to allow multiple Java methods to handle requests assigned to the same URL path pattern, but
+ * differing based on some request attribute, such as a specific header value.
*
* <p>
- * This affects the values returned by {@link RestRequest#getSupportedContentTypes()} and the supported content
- * types shown in {@link RestInfoProvider#getSwagger(RestRequest)}.
- *
- * <p>
- * <h5 class='section'>Notes:</h5>
- * <ul class='spaced-list'>
- * <li>Property: {@link RestContext#REST_supportedContentTypes}
- * <li>Annotations:
- * <ul>
- * <li>{@link RestResource#supportedContentTypes()}
- * <li>{@link RestMethod#supportedContentTypes()}
- * </ul>
- * <li>Methods:
- * <ul>
- * <li>{@link RestContextBuilder#supportedContentTypes(boolean,String...)}
- * <li>{@link RestContextBuilder#supportedContentTypes(boolean,MediaType...)}
- * </ul>
- * </ul>
+ * See {@link RestMatcher} for more information.
*/
- String[] supportedContentTypes() default {};
+ Class<? extends RestMatcher>[] matchers() default {};
/**
- * Compression encoders.
+ * The maximum allowed input size (in bytes) on HTTP requests.
*
* <p>
- * Use this annotation when the list of encoders assigned to a method differs from the list of encoders assigned at
- * the servlet level.
+ * Useful for alleviating DoS attacks by throwing an exception when too much input is received instead of resulting
+ * in out-of-memory errors which could affect system stability.
*
- * <p>
- * These can be used to enable various kinds of compression (e.g. <js>"gzip"</js>) on requests and responses.
- *
* <h5 class='section'>Example:</h5>
* <p class='bcode'>
- * <jc>// Servlet with automated support for GZIP compression</jc>
- * <ja>@RestResource</ja>(encoders={GzipEncoder.<jk>class</jk>})
- * <jk>public</jk> MyRestServlet <jk>extends</jk> RestServlet {
- * ...
- * }
+ * <ja>@RestMethod</ja>(
+ * maxInput=<js>"100M"</js>
+ * )
* </p>
*
- * <h5 class='section'>Notes:</h5>
- * <ul class='spaced-list'>
- * <li>Property: {@link RestContext#REST_encoders}
- * <li>Annotations:
- * <ul>
- * <li>{@link RestResource#encoders()}
- * <li>{@link RestMethod#encoders()}
- * </ul>
- * <li>Methods:
- * <ul>
- * <li>{@link RestContextBuilder#encoders(Class...)}
- * <li>{@link RestContextBuilder#encoders(Encoder...)}
- * </ul>
- * <li>Instance classes must provide a public no-arg constructor, or a public constructor that takes in a
- * {@link PropertyStore} object.
- * <li>Instance class can be defined as an inner class of the REST resource class.
- * <li>Use <code>inherit={<js>"ENCODERS"</js>}</code> to inherit encoders from the resource class.
- * </ul>
+ * <p>
+ * Value can contain any of the following variables:
+ * {@link ConfigFileVar $C}
+ * {@link CoalesceVar $CO}
+ * {@link CoalesceAndRecurseVar $CR}
+ * {@link EnvVariablesVar $E}
+ * {@link IfVar $IF}
+ * {@link SystemPropertiesVar $S}
+ * {@link SwitchVar $SW}
+ *
+ * <p>
+ * See {@link RestContext#REST_maxInput} for more information.
*/
- Class<? extends Encoder>[] encoders() default {};
+ String maxInput() default "";
/**
- * Same as {@link RestResource#properties()}, except defines property values by default when this method is called.
+ * REST method name.
*
* <p>
- * This is equivalent to simply calling <code>res.addProperties()</code> in the Java method, but is provided for
- * convenience.
- */
- Property[] properties() default {};
-
- /**
- * Shortcut for setting {@link #properties()} of simple boolean types.
+ * Typically <js>"GET"</js>, <js>"PUT"</js>, <js>"POST"</js>, <js>"DELETE"</js>, or <js>"OPTIONS"</js>.
*
* <p>
- * Setting a flag is equivalent to setting the same property to <js>"true"</js>.
- */
- String[] flags() default {};
-
- /**
- * Appends the specified bean filters to all serializers and parsers used by this method.
+ * Method names are case-insensitive (always folded to upper-case).
*
- * <h5 class='section'>Notes:</h5>
- * <ul class='spaced-list'>
- * <li>Property: {@link BeanContext#BEAN_beanFilters}
- * <li>Annotations:
- * <ul>
- * <li>{@link RestResource#beanFilters()}
- * <li>{@link RestMethod#beanFilters()}
- * </ul>
- * <li>Methods:
- * <ul>
- * <li>{@link RestContextBuilder#beanFilters(Object...)}
- * <li>{@link RestContextBuilder#beanFilters(boolean, Object...)}
- * <li>{@link RestContextBuilder#beanFiltersRemove(Object...)}
- * </ul>
- * </ul>
- */
- Class<?>[] beanFilters() default {};
-
- /**
- * Appends the specified POJO swaps to all serializers and parsers used by this method.
+ * <p>
+ * Note that you can use {@link org.apache.juneau.http.HttpMethodName} for constant values.
*
- * <h5 class='section'>Notes:</h5>
+ * <p>
+ * Besides the standard HTTP method names, the following can also be specified:
* <ul class='spaced-list'>
- * <li>Property: {@link BeanContext#BEAN_pojoSwaps}
- * <li>Annotations:
- * <ul>
- * <li>{@link RestResource#pojoSwaps()}
- * <li>{@link RestMethod#pojoSwaps()}
- * </ul>
- * <li>Methods:
- * <ul>
- * <li>{@link RestContextBuilder#pojoSwaps(Object...)}
- * <li>{@link RestContextBuilder#pojoSwaps(Class...)}
- * <li>{@link RestContextBuilder#pojoSwaps(boolean, Object...)}
- * <li>{@link RestContextBuilder#pojoSwapsRemove(Object...)}
- * </ul>
- * </ul>
+ * <li>
+ * <js>"*"</js>
+ * - Denotes any method.
+ * <br>Use this if you want to capture any HTTP methods in a single Java method.
+ * <br>The {@link Method @Method} annotation and/or {@link RestRequest#getMethod()} method can be used to
+ * distinguish the actual HTTP method name.
+ * <li>
+ * <js>""</js>
+ * - Auto-detect.
+ * <br>The method name is determined based on the Java method name.
+ * <br>For example, if the method is <code>doPost(...)</code>, then the method name is automatically detected
+ * as <js>"POST"</js>.
+ * <br>Otherwise, defaults to <js>"GET"</js>.
+ * <li>
+ * <js>"PROXY"</js>
+ * - Remote-proxy interface.
+ * <br>This denotes a Java method that returns an object (usually an interface, often annotated with the
+ * {@link Remoteable @Remoteable} annotation) to be used as a remote proxy using
+ * <code>RestClient.getRemoteableProxy(Class<T> interfaceClass, String url)</code>.
+ * <br>This allows you to construct client-side interface proxies using REST as a transport medium.
+ * <br>Conceptually, this is simply a fancy <code>POST</code> against the url <js>"/{path}/{javaMethodName}"</js>
+ * where the arguments are marshalled from the client to the server as an HTTP body containing an array of
+ * objects, passed to the method as arguments, and then the resulting object is marshalled back to the client.
+ * <li>
+ * Anything else
+ * - Overloaded non-HTTP-standard names that are passed in through a <code>&method=methodName</code> URL
+ * parameter.
+ * </ul>
*/
- Class<?>[] pojoSwaps() default {};
+ String name() default "";
/**
- * Shortcut for specifying the {@link BeanContext#BEAN_includeProperties} property on all serializers.
+ * Parsers.
*
* <p>
- * The typical use case is when you're rendering summary and details views of the same bean in a resource and
- * you want to expose or hide specific properties depending on the level of detail you want.
+ * Overrides the list of parsers assigned at the method level.
*
* <p>
- * In the example below, our 'summary' view is a list of beans where we only want to show the ID property,
- * and our detail view is a single bean where we want to expose different fields:
- * <p class='bcode'>
- * <jc>// Our bean</jc>
- * <jk>public class</jk> MyBean {
- *
- * <jc>// Summary properties</jc>
- * <ja>@Html</ja>(link=<js>"servlet:/mybeans/{id}"</js>)
- * <jk>public</jk> String <jf>id</jf>;
- *
- * <jc>// Detail properties</jc>
- * <jk>public</jk> String <jf>a</jf>, <jf>b</jf>;
- * }
- *
- * <jc>// Only render "id" property.</jc>
- * <ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/mybeans"</js>, bpi=<js>"MyBean: id"</js>)
- * <jk>public</jk> List<MyBean> getBeanSummary();
- *
- * <jc>// Only render "a" and "b" properties.</jc>
- * <ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/mybeans/{id}"</js>, bpi=<js>"MyBean: a,b"</js>)
- * <jk>public</jk> MyBean getBeanDetails(<ja>@Path</ja> String id);
- * </p>
+ * Use this annotation when the list of parsers assigned to a method differs from the list of parsers assigned at
+ * the servlet level.
*
* <p>
- * The format of each value is: <js>"Key: comma-delimited-tokens"</js>.
- * <br>Keys can be fully-qualified or short class names or <js>"*"</js> to represent all classes.
- * <br>Values are comma-delimited lists of bean property names.
- * <br>Properties apply to specified class and all subclasses.
+ * To append to the list of parsers assigned at the servlet level, use <code>inherit=<js>"PARSERS"</js></code>.
*
- * <p>
- * Semicolons can be used as an additional separator for multiple values:
* <p class='bcode'>
- * <jc>// Equivalent</jc>
- * bpi={<js>"Bean1: foo"</js>,<js>"Bean2: bar,baz"</js>}
- * bpi=<js>"Bean1: foo; Bean2: bar,baz"</js>
+ * <jk>public class</jk> MyResource <jk>extends</jk> RestServlet {
+ *
+ * <ja>@RestMethod</ja>(
+ * name=<jsf>PUT</jsf>,
+ * path=<js>"/foo"</js>,
+ * parsers=MySpecialParser.<jk>class</jk>,
+ * inherit=<js>"PARSERS"</js>
+ * )
+ * <jk>public</jk> Object doGetWithSpecialAcceptType() {
+ * <jc>// Handle request for special Accept type</jc>
+ * }
+ * }
* </p>
+ *
+ * <p>
+ * See {@link RestContext#REST_parsers} for more information.
*/
- String[] bpi() default {};
+ Class<? extends Parser>[] parsers() default {};
/**
- * Shortcut for specifying the {@link BeanContext#BEAN_excludeProperties} property on all serializers.
+ * Optional path pattern for the specified method.
*
* <p>
- * Same as {@link #bpi()} except you specify a list of bean property names that you want to exclude from
- * serialization.
+ * Appending <js>"/*"</js> to the end of the path pattern will make it match any remainder too.
+ * <br>Not appending <js>"/*"</js> to the end of the pattern will cause a 404 (Not found) error to occur if the exact
+ * pattern is not found.
*
* <p>
- * In the example below, our 'summary' view is a list of beans where we want to exclude some properties:
+ * The path can contain variables that get resolved to {@link Path @Path} parameters:
* <p class='bcode'>
- * <jc>// Our bean</jc>
- * <jk>public class</jk> MyBean {
- *
- * <jc>// Summary properties</jc>
- * <ja>@Html</ja>(link=<js>"servlet:/mybeans/{id}"</js>)
- * <jk>public</jk> String <jf>id</jf>;
- *
- * <jc>// Detail properties</jc>
- * <jk>public</jk> String <jf>a</jf>, <jf>b</jf>;
- * }
- *
- * <jc>// Don't show "a" and "b" properties.</jc>
- * <ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/mybeans"</js>, bpx=<js>"MyBean: a,b"</js>)
- * <jk>public</jk> List<MyBean> getBeanSummary();
+ * <jc>// Example 1</jc>
+ * <ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/myurl/{foo}/{bar}/{baz}/*"</js>)
*
- * <jc>// Render all properties.</jc>
- * <ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/mybeans/{id}"</js>)
- * <jk>public</jk> MyBean getBeanDetails(<ja>@Path</ja> String id);
+ * <jc>// Example 2</jc>
+ * <ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/myurl/{0}/{1}/{2}/*"</js>)
* </p>
*
* <p>
- * The format of each value is: <js>"Key: comma-delimited-tokens"</js>.
- * <br>Keys can be fully-qualified or short class names or <js>"*"</js> to represent all classes.
- * <br>Values are comma-delimited lists of bean property names.
- * <br>Properties apply to specified class and all subclasses.
- *
- * <p>
- * Semicolons can be used as an additional separator for multiple values:
- * <p class='bcode'>
- * <jc>// Equivalent</jc>
- * bpx={<js>"Bean1: foo"</js>,<js>"Bean2: bar,baz"</js>}
- * bpx=<js>"Bean1: foo; Bean2: bar,baz"</js>
- * </p>
+ * Refer to {@link Path @Path} on how path variables get resolved.
*/
- String[] bpx() default {};
+ String path() default "/*";
/**
- * Default request headers.
- *
- * <p>
- * Specifies default values for request headers.
+ * Appends the specified POJO swaps to all serializers and parsers used by this method.
*
- * <h5 class='section'>Example:</h5>
- * <p class='bcode'>
- * <jc>// Assume "text/json" Accept value when Accept not specified</jc>
- * <ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/*"</js>, defaultRequestHeaders={<js>"Accept: text/json"</js>})
- * <jk>public</jk> String doGet() {
- * ...
- * }
- * </p>
- *
* <p>
- * <h5 class='section'>Notes:</h5>
- * <ul class='spaced-list'>
- * <li>Property: {@link RestContext#REST_defaultRequestHeaders}
- * <li>Annotations:
- * <ul>
- * <li>{@link RestResource#defaultRequestHeaders()}
- * <li>{@link RestMethod#defaultRequestHeaders()}
- * </ul>
- * <li>Methods:
- * <ul>
- * <li>{@link RestContextBuilder#defaultRequestHeader(String,Object)}
- * <li>{@link RestContextBuilder#defaultRequestHeaders(String...)}
- * </ul>
- * <li>Strings are of the format <js>"Header-Name: header-value"</js>.
- * <li>You can use either <js>':'</js> or <js>'='</js> as the key/value delimiter.
- * <li>Key and value is trimmed of whitespace.
- * <li>Only one header value can be specified per entry (i.e. it's not a delimited list of header entries).
- * <li>Affects values returned by {@link RestRequest#getHeader(String)} when the header is not present on the request.
- * <li>The most useful reason for this annotation is to provide a default <code>Accept</code> header when one is not
- * specified so that a particular default {@link Serializer} is picked.
- * </ul>
+ * See {@link BeanContext#BEAN_pojoSwaps} for more information.
*/
- String[] defaultRequestHeaders() default {};
+ Class<?>[] pojoSwaps() default {};
/**
- * Specifies default values for query parameters.
+ * URL path pattern priority.
*
* <p>
- * Strings are of the format <js>"name=value"</js>.
+ * To force path patterns to be checked before other path patterns, use a higher priority number.
*
* <p>
- * Affects values returned by {@link RestRequest#getQuery(String)} when the parameter is not present on the request.
- *
- * <h5 class='section'>Example:</h5>
- * <p class='bcode'>
- * <ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/*"</js>, defaultQuery={<js>"foo=bar"</js>})
- * <jk>public</jk> String doGet(<ja>@Query</ja>(<js>"foo"</js>) String foo) {
- * ...
- * }
- * </p>
+ * By default, it's <code>0</code>, which means it will use an internal heuristic to determine a best match.
+ */
+ int priority() default 0;
+
+ /**
+ * Same as {@link RestResource#properties()}, except defines property values by default when this method is called.
*
* <p>
- * You can use either <js>':'</js> or <js>'='</js> as the key/value delimiter.
- * Key and value is trimmed of whitespace.
+ * This is equivalent to simply calling <code>res.addProperties()</code> in the Java method, but is provided for
+ * convenience.
*/
- String[] defaultQuery() default {};
+ Property[] properties() default {};
/**
- * Specifies default values for form-data parameters.
+ * Serializers.
*
* <p>
- * Strings are of the format <js>"name=value"</js>.
+ * Overrides the list of serializers assigned at the method level.
*
* <p>
- * Affects values returned by {@link RestRequest#getFormData(String)} when the parameter is not present on the
- * request.
+ * Use this annotation when the list of serializers assigned to a method differs from the list of serializers
+ * assigned at the servlet level.
+ *
+ * <p>
+ * To append to the list of serializers assigned at the servlet level, use <code>inherit=<js>"SERIALIZERS"</js></code>.
*
* <h5 class='section'>Example:</h5>
* <p class='bcode'>
- * <ja>@RestMethod</ja>(name=<jsf>POST</jsf>, path=<js>"/*"</js>, defaultFormData={<js>"foo=bar"</js>})
- * <jk>public</jk> String doGet(<ja>@FormData</ja>(<js>"foo"</js>) String foo) {
- * ...
+ * <jk>public class</jk> MyResource <jk>extends</jk> RestServlet {
+ *
+ * <ja>@RestMethod</ja>(
+ * name=<jsf>GET</jsf>,
+ * path=<js>"/foo"</js>,
+ * serializers=MySpecialSerializer.<jk>class</jk>,
+ * inherit=<js>"SERIALIZERS"</js>
+ * )
+ * <jk>public</jk> Object doGetWithSpecialAcceptType() {
+ * <jc>// Handle request for special Accept type</jc>
+ * }
* }
* </p>
- *
+ *
* <p>
- * You can use either <js>':'</js> or <js>'='</js> as the key/value delimiter.
- * Key and value is trimmed of whitespace.
+ * See {@link RestContext#REST_serializers} for more information.
*/
- String[] defaultFormData() default {};
+ Class<? extends Serializer>[] serializers() default {};
/**
* Optional summary for the exposed API.
@@ -685,8 +679,27 @@ public @interface RestMethod {
* servlet resource bundle. (e.g. <js>"MyClass.myMethod.summary = foo"</js> or <js>"myMethod.summary = foo"</js>).
*
* <p>
- * This field can contain variables (e.g. <js>"$L{my.localized.variable}"</js>).
- * <br>See {@link RestContext#getVarResolver()} for the list of supported variables.
+ * Value can contain any of the following variables:
+ * {@link ConfigFileVar $C}
+ * {@link CoalesceVar $CO}
+ * {@link CoalesceAndRecurseVar $CR}
+ * {@link EnvVariablesVar $E}
+ * {@link FileVar $F}
+ * {@link ServletInitParamVar $I},
+ * {@link IfVar $IF}
+ * {@link LocalizationVar $L}
+ * {@link RequestAttributeVar $RA}
+ * {@link RequestFormDataVar $RF}
+ * {@link RequestHeaderVar $RH}
+ * {@link RequestPathVar $RP}
+ * {@link RequestQueryVar $RQ}
+ * {@link RequestVar $R}
+ * {@link SystemPropertiesVar $S}
+ * {@link SerializedRequestAttrVar $SA}
+ * {@link SwitchVar $SW}
+ * {@link UrlVar $U}
+ * {@link UrlEncodeVar $UE}
+ * {@link WidgetVar $W}
*
* <p>
* Corresponds to the swagger field <code>/paths/{path}/{method}/summary</code>.
@@ -694,167 +707,49 @@ public @interface RestMethod {
String summary() default "";
/**
- * Optional description for the exposed API.
- *
- * <p>
- * This description is used in the following locations:
- * <ul class='spaced-list'>
- * <li>
- * The value returned by {@link RestRequest#getMethodDescription()}.
- * <li>
- * The <js>"$R{methodDescription}"</js> variable.
- * <li>
- * The description of the method in the Swagger page.
- * </ul>
+ * Supported accept media types.
*
* <p>
- * The default value pulls the description from the <code>(className.?)[javaMethodName].description</code> entry in
- * the servlet resource bundle. (e.g. <js>"MyClass.myMethod.description = foo"</js> or
- * <js>"myMethod.description = foo"</js>).
- *
+ * Overrides the media types inferred from the serializers that identify what media types can be produced by the resource.
+ *
* <p>
- * This field can contain variables (e.g. <js>"$L{my.localized.variable}"</js>).
- * <br>See {@link RestContext#getVarResolver()} for the list of supported variables.
- *
+ * Values can contain any of the following variables:
+ * {@link ConfigFileVar $C}
+ * {@link CoalesceVar $CO}
+ * {@link CoalesceAndRecurseVar $CR}
+ * {@link EnvVariablesVar $E}
+ * {@link IfVar $IF}
+ * {@link SystemPropertiesVar $S}
+ * {@link SwitchVar $SW}
+ *
* <p>
- * Corresponds to the swagger field <code>/paths/{path}/{method}/description</code>.
+ * See {@link RestContext#REST_supportedAcceptTypes} for more information.
*/
- String description() default "";
-
+ String[] supportedAcceptTypes() default {};
+
/**
- * Specifies whether this method can be called based on the client version.
- *
- * <p>
- * The client version is identified via the HTTP request header identified by
- * {@link RestResource#clientVersionHeader()} which by default is <js>"X-Client-Version"</js>.
- *
- * <p>
- * This is a specialized kind of {@link RestMatcher} that allows you to invoke different Java methods for the same
- * method/path based on the client version.
- *
- * <p>
- * The format of the client version range is similar to that of OSGi versions.
+ * Supported content media types.
*
* <p>
- * In the following example, the Java methods are mapped to the same HTTP method and URL <js>"/foobar"</js>.
- * <p class='bcode'>
- * <jc>// Call this method if X-Client-Version is at least 2.0.
- * // Note that this also matches 2.0.1.</jc>
- * <ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/foobar"</js>, clientVersion=<js>"2.0"</js>)
- * <jk>public</jk> Object method1() {
- * ...
- * }
- *
- * <jc>// Call this method if X-Client-Version is at least 1.1, but less than 2.0.</jc>
- * <ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/foobar"</js>, clientVersion=<js>"[1.1,2.0)"</js>)
- * <jk>public</jk> Object method2() {
- * ...
- * }
- *
- * <jc>// Call this method if X-Client-Version is less than 1.1.</jc>
- * <ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/foobar"</js>, clientVersion=<js>"[0,1.1)"</js>)
- * <jk>public</jk> Object method3() {
- * ...
- * }
- * </p>
- *
+ * Overrides the media types inferred from the parsers that identify what media types can be consumed by the resource.
+ *
* <p>
- * It's common to combine the client version with transforms that will convert new POJOs into older POJOs for
- * backwards compatibility.
- * <p class='bcode'>
- * <jc>// Call this method if X-Client-Version is at least 2.0.</jc>
- * <ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/foobar"</js>, clientVersion=<js>"2.0"</js>)
- * <jk>public</jk> NewPojo newMethod() {
- * ...
- * }
- *
- * <jc>// Call this method if X-Client-Version is at least 1.1, but less than 2.0.</jc>
- * <ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/foobar"</js>, clientVersion=<js>"[1.1,2.0)"</js>, transforms={NewToOldPojoSwap.<jk>class</jk>})
- * <jk>public</jk> NewPojo oldMethod() {
- * <jk>return</jk> newMethod()
- * }
- *
+ * Values can contain any of the following variables:
+ * {@link ConfigFileVar $C}
+ * {@link CoalesceVar $CO}
+ * {@link CoalesceAndRecurseVar $CR}
+ * {@link EnvVariablesVar $E}
+ * {@link IfVar $IF}
+ * {@link SystemPropertiesVar $S}
+ * {@link SwitchVar $SW}
+ *
* <p>
- * Note that in the previous example, we're returning the exact same POJO, but using a transform to convert it into
- * an older form.
- * The old method could also just return back a completely different object.
- * The range can be any of the following:
- * <ul>
- * <li><js>"[0,1.0)"</js> = Less than 1.0. 1.0 and 1.0.0 does not match.
- * <li><js>"[0,1.0]"</js> = Less than or equal to 1.0. Note that 1.0.1 will match.
- * <li><js>"1.0"</js> = At least 1.0. 1.0 and 2.0 will match.
- * </ul>
+ * See {@link RestContext#REST_supportedContentTypes} for more information.
*/
- String clientVersion() default "";
+ String[] supportedContentTypes() default {};
/**
* Provides swagger-specific metadata on this method.
*/
MethodSwagger swagger() default @MethodSwagger;
-
- /**
- * Provides HTML-doc-specific metadata on this method.
- *
- * <p>
- * Information provided here overrides information provided in the servlet-level annotation.
- */
- HtmlDoc htmldoc() default @HtmlDoc;
-
- /**
- * Default character encoding.
- *
- * <p>
- * The default character encoding for the request and response if not specified on the request.
- *
- * <h5 class='section'>Notes:</h5>
- * <ul class='spaced-list'>
- * <li>Property: {@link RestContext#REST_defaultCharset}
- * <li>Annotations:
- * <ul>
- * <li>{@link RestResource#defaultCharset()}
- * <li>{@link RestMethod#defaultCharset()}
- * </ul>
- * <li>Methods:
- * <ul>
- * <li>{@link RestContextBuilder#defaultCharset(String)}
- * </ul>
- * <li>String value.
- * <li>Can contain variables.
- * </ul>
- */
- String defaultCharset() default "";
- /**
- * The maximum allowed input size (in bytes) on HTTP requests.
- *
- * <p>
- * Useful for alleviating DoS attacks by throwing an exception when too much input is received instead of resulting
- * in out-of-memory errors which could affect system stability.
- *
- * <h5 class='section'>Example:</h5>
- * <p class='bcode'>
- * <ja>@RestMethod</ja>(
- * maxInput=<js>"100M"</js>
- * )
- * </p>
- *
- * <h5 class='section'>Notes:</h5>
- * <ul class='spaced-list'>
- * <li>Property: {@link RestContext#REST_maxInput}
- * <li>Annotations:
- * <ul>
- * <li>{@link RestResource#maxInput()}
- * <li>{@link RestMethod#maxInput()}
- * </ul>
- * <li>Methods:
- * <ul>
- * <li>{@link RestContextBuilder#maxInput(String)}
- * </ul>
- * <li>String value that gets resolved to a <jk>long</jk>.
- * <li>Can contain variables.
- * <li>Can be suffixed with any of the following representing kilobytes, megabytes, and gigabytes:
- * <js>'K'</js>, <js>'M'</js>, <js>'G'</js>.
- * <li>A value of <js>"-1"</js> can be used to represent no limit.
- * </ul>
- */
- String maxInput() default "";
}