Java Method Parameters
Java methods can contain any of the following parameters in any order:
AsyncContextDispatcherTypeHttpServletRequestServletInputStreamHttpServletResponseServletOutputStreamHttpSessionIn Spring Boot environments, any available Spring Beans can also be passed in as parameters.
@RestGet("/example1/{a1}/{a2}/{a3}/*")
public String doGetExample1(
RestRequest req,
RestResponse res,
@Method String method,
@Path("a1") String a1,
@Path("a2") int a2,
@Path("a3") UUID a3,
@Query("p1") int p1,
@Query("p2") String p2,
@Query("p3") UUID p3,
@HasQuery("p3") boolean hasP3,
@Path("/*") String remainder,
@Header("Accept-Language") String lang,
@Header("Accept") String accept,
@Header("DNT") int doNotTrack,
RequestAttributes attributes,
ResourceBundle nls
) {
// Do something with all of those
}
Additional parameter types can be defined via the annotation Rest.restOpArgs() or by supplying a named bean via @Bean.
@Rest(
restOpArgs={ MyOpArg.class } // Option #1 - Via annotation
)
public class MyResource extends BasicRestResource {
}
@Attr and @Method
Two annotations in org.apache.juneau.rest.server are specific to operation parameters.
@Attr retrieves a value from the request attributes map.
Its name (or value) selects the attribute.
A blank name on a Map, NameValuePairs or bean parameter is equivalent to "*" and returns all attributes as name/value pairs.
A parser can be supplied to override the part parser used to convert the attribute value.
@RestGet
public Person getPerson(@Attr("ETag") UUID etag) {...}
// Equivalent to:
@RestGet
public Person getPerson(RestRequest req) {
UUID etag = req.getAttributes().get(UUID.class, "ETag");
...
}
@Method supplies the HTTP method name as a String.
It is mainly useful on operations declared with method="*", which match every HTTP method.
@RestOp(method="*")
public void doAnything(RestRequest req, RestResponse res, @Method String method) {
// method is "GET", "POST", etc.
}
Parameter resolver matrix
Each parameter of an operation method is matched to a RestOpArg
resolver when the resource starts.
Resolvers are tried in order and the first one that recognizes the parameter wins.
A parameter that no resolver can handle causes an error at startup (Could not resolve parameter N on method ...).
The framework's default resolver list is shown below in the order in which it is consulted.
Resolvers registered through @Rest(restOpArgs) are placed ahead of this list (child class entries first, then parent entries), so they can override the defaults.
A @Bean method returning a RestOpArgList replaces the entire list.
| # | Resolver | Matches a parameter that is... | Resolved value |
|---|---|---|---|
| 1 | AttributeArg | annotated with @Attr | Request attribute (converted to the parameter type). |
| 2 | AuthArg | annotated with @Auth, or any Principal subtype | The principal stored on the request by an upstream authentication guard (null if none). |
| 3 | ContentArg | annotated with @Content | The request body, parsed to the parameter type. |
| 4 | FormDataArg | annotated with @FormData | Form-data parameter. |
| 5 | HasFormDataArg | annotated with @HasFormData | boolean: whether the form-data parameter is present. |
| 6 | HasQueryArg | annotated with @HasQuery | boolean: whether the query parameter is present. |
| 7 | HeaderArg | annotated with @Header (and not a Holder), or a typed header class that has a static NAME field (e.g. Accept, Host) | Request header. |
| 8 | HttpServletRequestArgs | AsyncContext, CookieList, DispatcherType, HttpServletRequest, Principal | Servlet request facets. |
| 9 | HttpServletResponseArgs | HttpServletResponse | The servlet response. |
| 10 | HttpSessionArgs | HttpSession | The servlet session. |
| 11 | InputStreamParserArg | InputStreamParser | The parser matched to the request Content-Type, if it is an InputStreamParser. |
| 12 | MethodArg | annotated with @Method | The HTTP method name. |
| 13 | ParserArg | Parser | The parser matched to the request Content-Type. |
| 14 | PathArg | annotated with @Path | Path variable. |
| 15 | PathRemainderArg | annotated with @PathRemainder | The path remainder (the /* portion). |
| 16 | QueryArg | annotated with @Query | Query parameter. |
| 17 | ReaderParserArg | ReaderParser | The parser matched to the request Content-Type, if it is a ReaderParser. |
| 18 | RecordReaderArg | subtype of RecordReader (but not TokenReader) | Record cursor over the request body (see Record Streaming). |
| 19 | RecordWriterArg | subtype of RecordWriter (but not TokenWriter) | Record writer for the response (see Record Streaming). |
| 20 | RequestBeanArg | annotated with @Request | A request bean. |
| 21 | ResponseBeanArg | annotated with @Response (must be a Holder) | A Holder whose value becomes the response body. See Response Beans. |
| 22 | ResponseHeaderArg | a Holder annotated with @Header | A Holder whose value is set as a response header. |
| 23 | ResponseCodeArg | annotated with @StatusCode (must be Holder<Integer>) | A Holder whose value sets the response status code. |
| 24 | RestContextArgs | MarshallingContext, Config, EncoderSet, Logger, MethodExecStore, RestChildren, RestContext, RestContextStats, RestOperations, StaticFiles, ThrownStore | Resource-level objects. |
| 25 | RestSessionArgs | RestSession, UrlPath, UrlPathMatch | Per-call session objects. |
| 26 | RestOpContextArgs | JsonSchemaGenerator, ParserSet, RestOpContext, SerializerSet | Operation-level objects. |
| 27 | RestOpSessionArgs | RestOpSession, BeanStore (or WritableBeanStore) | Per-operation-call session objects. |
| 28 | RestRequestArgs | RestRequest, RequestContent, RequestHeaderList, RequestQueryParamList, RequestFormParamList, RequestPathParamList, RequestAttributes, InputStream, ServletInputStream, Reader, Locale, TimeZone, ResourceBundle, Messages, Swagger, UriContext, UriResolver, VarResolverSession, HttpPartParserSession, HttpPartSerializerSession | Request-level objects. |
| 29 | RestResponseArgs | RestResponse, OutputStream, ServletOutputStream, Writer | Response-level objects. |
| 30 | SseBroadcasterArg | SseBroadcaster | The shared broadcaster bean (created on first use). See Server-Sent Events. |
| 31 | SseSubscriptionArg | SseSubscription | A new subscription on the shared broadcaster. |
| 32 | TokenReaderArg | subtype of TokenReader | Token cursor over the request body (see Token Streaming). |
| 33 | TokenWriterArg | subtype of TokenWriter | Token writer for the response. |
| 34 | DefaultArg | anything else (fallback) | A bean of the parameter type looked up in the resource bean store (by qualifier, if any). |
Notes:
- Where a resolver is listed by parameter type (for example
ParserorLocale), the parameter type must match exactly; aReaderParserparameter is therefore handled byReaderParserArg, notParserArg. The exceptions areAuthArg(anyPrincipalsubtype),RecordReaderArg,RecordWriterArg,TokenReaderArgandTokenWriterArg(subtypes). - Because
AuthArgprecedesHttpServletRequestArgs, a barePrincipalparameter is resolved from the authenticated principal stored on the request by the guard chain, rather than fromHttpServletRequest.getUserPrincipal(). @Headeron aHolderparameter sets a response header;@Headeron any other type reads a request header.- Because
DefaultArgis the final fallback, any bean registered in the resource bean store (including Spring beans in Spring Boot environments) can be declared as an operation parameter.
Writing a custom resolver
A resolver implements RestOpArg and exposes a static create(...) (or getInstance(...)) factory.
The factory may declare a ParameterInfo parameter (and other injectable beans) and must return null if the resolver does not apply to the given parameter.
RestOpArg.resolve(RestOpSession) is then called for each request to produce the value.
// A simple value type populated from a request header.
public record CallerId(String value) {}
public class CallerIdArg implements RestOpArg {
public static CallerIdArg create(ParameterInfo paramInfo) {
if (paramInfo.isType(CallerId.class))
return new CallerIdArg();
return null;
}
protected CallerIdArg() {}
@Override
public Object resolve(RestOpSession opSession) throws Exception {
return new CallerId(opSession.getRequest().getHeaders().getFirst("X-Caller-Id").asString().orElse("anonymous"));
}
}
Register it with @Rest(restOpArgs=CallerIdArg.class), after which any operation can declare a CallerId parameter.