org.apache.juneau.rest.annotation.RestMethod Maven / Gradle / Ivy
// ***************************************************************************************************************************
// * 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.annotation;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.*;
import java.lang.annotation.*;
import org.apache.juneau.*;
import org.apache.juneau.encoders.*;
import org.apache.juneau.parser.*;
import org.apache.juneau.remoteable.*;
import org.apache.juneau.rest.*;
import org.apache.juneau.serializer.*;
/**
* Identifies a REST Java method on a {@link RestServlet} implementation class.
*
* Refer to org.apache.juneau.rest doc for information on using this class.
*/
@Documented
@Target(METHOD)
@Retention(RUNTIME)
@Inherited
public @interface RestMethod {
/**
* REST method name.
*
*
* Typically "GET" , "PUT" , "POST" , "DELETE" , or "OPTIONS" .
*
*
* Method names are case-insensitive (always folded to upper-case).
*
*
* Note that you can use {@link org.apache.juneau.http.HttpMethodName} for constant values.
*
*
* Besides the standard HTTP method names, the following can also be specified:
*
* -
*
"*"
* - Denotes any method.
*
Use this if you want to capture any HTTP methods in a single Java method.
*
The {@link Method @Method} annotation and/or {@link RestRequest#getMethod()} method can be used to
* distinguish the actual HTTP method name.
* -
*
""
* - Auto-detect.
*
The method name is determined based on the Java method name.
*
For example, if the method is doPost(...)
, then the method name is automatically detected
* as "POST" .
*
Otherwise, defaults to "GET" .
* -
*
"PROXY"
* - Remote-proxy interface.
*
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
* RestClient.getRemoteableProxy(Class<T> interfaceClass, String url)
.
*
This allows you to construct client-side interface proxies using REST as a transport medium.
*
Conceptually, this is simply a fancy POST
against the url "/{path}/{javaMethodName}"
* 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.
* -
* Anything else
* - Overloaded non-HTTP-standard names that are passed in through a
&method=methodName
URL
* parameter.
*
*/
String name() default "";
/**
* Optional path pattern for the specified method.
*
*
* Appending "/*" to the end of the path pattern will make it match any remainder too.
*
Not appending "/*" to the end of the pattern will cause a 404 (Not found) error to occur if the exact
* pattern is not found.
*
*
* The path can contain variables that get resolved to {@link Path @Path} parameters:
*
* // Example 1
* @RestMethod (name=GET , path="/myurl/{foo}/{bar}/{baz}/*" )
*
* // Example 2
* @RestMethod (name=GET , path="/myurl/{0}/{1}/{2}/*" )
*
*
*
* Refer to {@link Path @Path} on how path variables get resolved.
*/
String path() default "/*";
/**
* URL path pattern priority.
*
*
* To force path patterns to be checked before other path patterns, use a higher priority number.
*
*
* By default, it's 0
, which means it will use an internal heuristic to determine a best match.
*/
int priority() default 0;
/**
* Method guards.
*
*
* Associates one or more {@link RestGuard RestGuards} with a method call.
* These guards get called immediately before execution of the REST method.
*
*
* 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.
*/
Class extends RestGuard>[] guards() default {};
/**
* Method response converters.
*
*
* Associates one or more {@link RestConverter RestConverters} with a method call.
* These converters get called immediately after execution of the REST method in the same order specified in the
* annotation.
*
*
* Can be used for performing post-processing on the response object before serialization.
*
*
* Default converters are available in the org.apache.juneau.rest.converters package.
*/
Class extends RestConverter>[] converters() default {};
/**
* Method matchers.
*
*
* Associates one more more {@link RestMatcher RestMatchers} with this method.
*
*
* 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.
*
*
* See {@link RestMatcher} for details.
*/
Class extends RestMatcher>[] matchers() default {};
/**
* Overrides the list of serializers assigned at the method level.
*
*
* Use this annotation when the list of serializers assigned to a method differs from the list of serializers
* assigned at the servlet level.
*
*
* To append to the list of serializers assigned at the servlet level, use
* serializersInherit=SERIALIZERS
.
*
*
* public class MyResource extends RestServlet {
*
* @RestMethod (
* name=GET ,
* path="/foo" ,
* serializers=MySpecialSerializer.class ,
* serializersInherit=SERIALIZERS
* )
* public Object doGetWithSpecialAcceptType() {
* // Handle request for special Accept type
* }
* }
*
*/
Class extends Serializer>[] serializers() default {};
/**
* Used in conjunction with {@link #serializers()} to identify what class-level settings are inherited by the method
* serializer group.
*
*
* Possible values:
*
* - {@link Inherit#SERIALIZERS} - Inherit class-level serializers.
*
- {@link Inherit#PROPERTIES} - Inherit class-level properties.
*
- {@link Inherit#TRANSFORMS} - Inherit class-level transforms.
*
*
*
* For example, to inherit all serializers, properties, and transforms from the servlet class:
*
* @RestMethod (
* path="/foo" ,
* serializers=MySpecialSerializer.class ,
* serializersInherit={SERIALIZERS ,PROPERTIES ,TRANSFORMS }
* )
*
*/
Inherit[] serializersInherit() default {};
/**
* Overrides the list of parsers assigned at the method level.
*
*
* Use this annotation when the list of parsers assigned to a method differs from the list of parsers assigned at
* the servlet level.
*
*
* To append to the list of serializers assigned at the servlet level, use
* serializersInherit=SERIALIZERS
.
*
*
* public class MyResource extends RestServlet {
*
* @RestMethod (
* name=PUT ,
* path="/foo" ,
* parsers=MySpecialParser.class ,
* parsersInherit=PARSERS
* )
* public Object doGetWithSpecialAcceptType() {
* // Handle request for special Accept type
* }
* }
*
*/
Class extends Parser>[] parsers() default {};
/**
* Used in conjunction with {@link #parsers()} to identify what class-level settings are inherited by the method
* parser group.
*
*
* Possible values:
*
* - {@link Inherit#PARSERS} - Inherit class-level parsers.
*
- {@link Inherit#PROPERTIES} - Inherit class-level properties.
*
- {@link Inherit#TRANSFORMS} - Inherit class-level transforms.
*
*
*
* For example, to inherit all parsers, properties, and transforms from the servlet class:
*
* @RestMethod (
* path="/foo" ,
* parsers=MySpecialParser.class ,
* parsersInherit={PARSERS ,PROPERTIES ,TRANSFORMS }
* )
*
*/
Inherit[] parsersInherit() default {};
/**
* Appends to the list of {@link Encoder encoders} specified on the servlet.
*
*
* Use this annotation when the list of encoders assigned to a method differs from the list of encoders assigned at
* the servlet level.
*
*
* These can be used to enable various kinds of compression (e.g. "gzip" ) on requests and responses.
*
*
* public class MyResource extends RestServlet {
*
* @RestMethod (
* name=PUT ,
* path="/foo" ,
* encoders={GzipEncoder.class }
* )
* public Object doGetWithSpecialEncoding() {
* // Handle request with special encoding
* }
* }
*
*
*
* If you want to OVERRIDE the set of encoders specified by the servlet, combine this annotation with
* @RestMethod (inheritEncoders=false )
.
*/
Class extends Encoder>[] encoders() default {};
/**
* Specifies whether the method should inherit encoders from the servlet.
*/
boolean inheritEncoders() default true;
/**
* Same as {@link RestResource#properties()}, except defines property values by default when this method is called.
*
*
* This is equivalent to simply calling res.addProperties()
in the Java method, but is provided for
* convenience.
*/
Property[] properties() default {};
/**
* Shortcut for setting {@link #properties()} of simple boolean types.
*
*
* Setting a flag is equivalent to setting the same property to "true" .
*/
String[] flags() default {};
/**
* Appends the specified bean filters to all serializers and parsers used by this method.
*/
Class>[] beanFilters() default {};
/**
* Appends the specified POJO swaps to all serializers and parsers used by this method.
*/
Class>[] pojoSwaps() default {};
/**
* Shortcut for specifying the {@link BeanContext#BEAN_includeProperties} property on all serializers.
*
*
* 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.
*
*
* 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:
*
* // Our bean
* public class MyBean {
*
* // Summary properties
* @Html (link="servlet:/mybeans/{id}" )
* public String id ;
*
* // Detail properties
* public String a , b ;
* }
*
* // Only render "id" property.
* @RestMethod (name=GET , path="/mybeans" , bpi="MyBean: id" )
* public List<MyBean> getBeanSummary();
*
* // Only render "a" and "b" properties.
* @RestMethod (name=GET , path="/mybeans/{id}" , bpi="MyBean: a,b" )
* public MyBean getBeanDetails(@Path String id);
*
*
*
* The format of each value is: "Key: comma-delimited-tokens" .
*
Keys can be fully-qualified or short class names or "*" to represent all classes.
*
Values are comma-delimited lists of bean property names.
*
Properties apply to specified class and all subclasses.
*
*
* Semicolons can be used as an additional separator for multiple values:
*
* // Equivalent
* bpi={"Bean1: foo" ,"Bean2: bar,baz" }
* bpi="Bean1: foo; Bean2: bar,baz"
*
*/
String[] bpi() default {};
/**
* Shortcut for specifying the {@link BeanContext#BEAN_excludeProperties} property on all serializers.
*
*
* Same as {@link #bpi()} except you specify a list of bean property names that you want to exclude from
* serialization.
*
*
* In the example below, our 'summary' view is a list of beans where we want to exclude some properties:
*
* // Our bean
* public class MyBean {
*
* // Summary properties
* @Html (link="servlet:/mybeans/{id}" )
* public String id ;
*
* // Detail properties
* public String a , b ;
* }
*
* // Don't show "a" and "b" properties.
* @RestMethod (name=GET , path="/mybeans" , bpx="MyBean: a,b" )
* public List<MyBean> getBeanSummary();
*
* // Render all properties.
* @RestMethod (name=GET , path="/mybeans/{id}" )
* public MyBean getBeanDetails(@Path String id);
*
*
*
* The format of each value is: "Key: comma-delimited-tokens" .
*
Keys can be fully-qualified or short class names or "*" to represent all classes.
*
Values are comma-delimited lists of bean property names.
*
Properties apply to specified class and all subclasses.
*
*
* Semicolons can be used as an additional separator for multiple values:
*
* // Equivalent
* bpx={"Bean1: foo" ,"Bean2: bar,baz" }
* bpx="Bean1: foo; Bean2: bar,baz"
*
*/
String[] bpx() default {};
/**
* Specifies default values for request headers.
*
*
* Strings are of the format "Header-Name: header-value" .
*
*
* Affects values returned by {@link RestRequest#getHeader(String)} when the header is not present on the request.
*
*
* The most useful reason for this annotation is to provide a default Accept
header when one is not
* specified so that a particular default {@link Serializer} is picked.
*
*
* Only one header value can be specified per entry (i.e. it's not a delimited list of header entries).
*
*
* Header values specified at the method level override header values specified at the servlet level.
*
*
Example:
*
* // Assume "text/json" Accept value when Accept not specified
* @RestMethod (name=GET , path="/*" , defaultRequestHeaders={"Accept: text/json" })
* public String doGet() {
* ...
* }
*
*
*
* You can use either ':' or '=' as the key/value delimiter.
* Key and value is trimmed of whitespace.
*/
String[] defaultRequestHeaders() default {};
/**
* Specifies default values for query parameters.
*
*
* Strings are of the format "name=value" .
*
*
* Affects values returned by {@link RestRequest#getQuery(String)} when the parameter is not present on the request.
*
*
Example:
*
* @RestMethod (name=GET , path="/*" , defaultQuery={"foo=bar" })
* public String doGet(@Query ("foo" ) String foo) {
* ...
* }
*
*
*
* You can use either ':' or '=' as the key/value delimiter.
* Key and value is trimmed of whitespace.
*/
String[] defaultQuery() default {};
/**
* Specifies default values for form-data parameters.
*
*
* Strings are of the format "name=value" .
*
*
* Affects values returned by {@link RestRequest#getFormData(String)} when the parameter is not present on the
* request.
*
*
Example:
*
* @RestMethod (name=POST , path="/*" , defaultFormData={"foo=bar" })
* public String doGet(@FormData ("foo" ) String foo) {
* ...
* }
*
*
*
* You can use either ':' or '=' as the key/value delimiter.
* Key and value is trimmed of whitespace.
*/
String[] defaultFormData() default {};
/**
* Optional summary for the exposed API.
*
*
* This summary is used in the following locations:
*
* -
* The value returned by {@link RestRequest#getMethodSummary()}.
*
-
* The
"$R{methodSummary}" variable.
* -
* The summary of the method in the Swagger page.
*
*
*
* The default value pulls the description from the (className.?)[javaMethodName].summary
entry in the
* servlet resource bundle. (e.g. "MyClass.myMethod.summary = foo" or "myMethod.summary = foo" ).
*
*
* This field can contain variables (e.g. "$L{my.localized.variable}" ).
*
See {@link RestContext#getVarResolver()} for the list of supported variables.
*
*
* Corresponds to the swagger field /paths/{path}/{method}/summary
.
*/
String summary() default "";
/**
* Optional description for the exposed API.
*
*
* This description is used in the following locations:
*
* -
* The value returned by {@link RestRequest#getMethodDescription()}.
*
-
* The
"$R{methodDescription}" variable.
* -
* The description of the method in the Swagger page.
*
*
*
* The default value pulls the description from the (className.?)[javaMethodName].description
entry in
* the servlet resource bundle. (e.g. "MyClass.myMethod.description = foo" or
* "myMethod.description = foo" ).
*
*
* This field can contain variables (e.g. "$L{my.localized.variable}" ).
*
See {@link RestContext#getVarResolver()} for the list of supported variables.
*
*
* Corresponds to the swagger field /paths/{path}/{method}/description
.
*/
String description() default "";
/**
* Specifies whether this method can be called based on the client version.
*
*
* The client version is identified via the HTTP request header identified by
* {@link RestResource#clientVersionHeader()} which by default is "X-Client-Version" .
*
*
* 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.
*
*
* The format of the client version range is similar to that of OSGi versions.
*
*
* In the following example, the Java methods are mapped to the same HTTP method and URL "/foobar" .
*
* // Call this method if X-Client-Version is at least 2.0.
* // Note that this also matches 2.0.1.
* @RestMethod (name=GET , path="/foobar" , clientVersion="2.0" )
* public Object method1() {
* ...
* }
*
* // Call this method if X-Client-Version is at least 1.1, but less than 2.0.
* @RestMethod (name=GET , path="/foobar" , clientVersion="[1.1,2.0)" )
* public Object method2() {
* ...
* }
*
* // Call this method if X-Client-Version is less than 1.1.
* @RestMethod (name=GET , path="/foobar" , clientVersion="[0,1.1)" )
* public Object method3() {
* ...
* }
*
*
*
* It's common to combine the client version with transforms that will convert new POJOs into older POJOs for
* backwards compatibility.
*
* // Call this method if X-Client-Version is at least 2.0.
* @RestMethod (name=GET , path="/foobar" , clientVersion="2.0" )
* public NewPojo newMethod() {
* ...
* }
*
* // Call this method if X-Client-Version is at least 1.1, but less than 2.0.
* @RestMethod (name=GET , path="/foobar" , clientVersion="[1.1,2.0)" , transforms={NewToOldPojoSwap.class })
* public NewPojo oldMethod() {
* return newMethod()
* }
*
*
* 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:
*
* "[0,1.0)" = Less than 1.0. 1.0 and 1.0.0 does not match.
* "[0,1.0]" = Less than or equal to 1.0. Note that 1.0.1 will match.
* "1.0" = At least 1.0. 1.0 and 2.0 will match.
*
*/
String clientVersion() default "";
/**
* Provides swagger-specific metadata on this method.
*/
MethodSwagger swagger() default @MethodSwagger;
/**
* Provides HTML-doc-specific metadata on this method.
*
*
* Information provided here overrides information provided in the servlet-level annotation.
*/
HtmlDoc htmldoc() default @HtmlDoc;
/**
* Default character encoding.
*
*
* The default character encoding for the request and response if not specified on the request.
*
*
* - String value.
*
- Defaults to system property
"juneau.defaultCharset" , or "utf-8" if not specified.
* - Can contain variables.
*
- Overrides the value at the class level via {@link RestResource#defaultCharset() @RestResource.defaultCharset()}.
*
*/
String defaultCharset() default "";
/**
* Expected format of request parameters.
*
* Possible values:
*
* -
*
"UON" - URL-Encoded Object Notation.
*
This notation allows for request parameters to contain arbitrarily complex POJOs.
* -
*
"PLAIN" - Plain text.
*
This treats request parameters as plain text.
*
Only POJOs directly convertible from Strings can be represented in parameters when using this
* mode.
*
*
*
* Note that the parameter value "(foo)" is interpreted as "(foo)" when using plain mode, but
* "foo" when using UON mode.
*
*
* The format can also be specified per-parameter using the {@link FormData#format() @FormData.format()} and
* {@link Query#format() @Query.format()} annotations.
*
*
* - String value.
*
- Defaults to system property
"juneau.paramFormat" , or "UON" if not specified.
* - Can contain variables.
*
- Overrides the value at the class level via {@link RestResource#paramFormat() @RestResource.paramFormat()}.
*
*/
String paramFormat() default "";
}