This is an automated email from the ASF dual-hosted git repository.
jamesbognar pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/juneau.git
The following commit(s) were added to refs/heads/master by this push:
new 866b394 Context API refactoring.
866b394 is described below
commit 866b3944de71fd503811fff863bded28bf6af30b
Author: JamesBognar <[email protected]>
AuthorDate: Sun Sep 12 19:26:20 2021 -0400
Context API refactoring.
---
.../java/org/apache/juneau/rest/RestContext.java | 49 +-
.../org/apache/juneau/rest/RestContextBuilder.java | 878 ++++++++++++---------
.../java/org/apache/juneau/rest/RestOpArgList.java | 45 +-
3 files changed, 559 insertions(+), 413 deletions(-)
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 5b14dc5..61d1b94 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
@@ -162,7 +162,7 @@ public class RestContext extends Context {
private final Set<String> allowedMethodParams, allowedHeaderParams,
allowedMethodHeaders;
- private final Class<? extends RestOpArg>[] opArgs, hookMethodArgs;
+ private final Class<? extends RestOpArg>[] restOpArgs, hookMethodArgs;
private final HttpPartSerializer partSerializer;
private final HttpPartParser partParser;
private final JsonSchemaGenerator jsonSchemaGenerator;
@@ -265,10 +265,10 @@ public class RestContext extends Context {
defaultRequestHeaders =
bs.add("RestContext.defaultRequestHeaders",
builder.defaultRequestHeaders().build());
defaultResponseHeaders =
bs.add("RestContext.defaultResponseHeaders",
builder.defaultResponseHeaders().build());
defaultRequestAttributes =
bs.add("RestContext.defaultRequestAttributes",
builder.defaultRequestAttributes());
+ restOpArgs = builder.restOpArgs().build().asArray();
Object r = resource.get();
- opArgs = createOpArgs(r, builder, bs).asArray();
hookMethodArgs = createHookMethodArgs(r, builder,
bs).asArray();
uriContext = builder.uriContext;
@@ -361,47 +361,6 @@ public class RestContext extends Context {
}
/**
- * Instantiates the REST method parameter resolvers for this REST
resource.
- *
- * <p>
- * Instantiates based on the following logic:
- * <ul>
- * <li>Looks for REST op args set via any of the following:
- * <ul>
- * <li>{@link
RestContextBuilder#restOpArgs(Class...)}/{@link
RestContextBuilder#restOpArgs(Class...)}
- * <li>{@link Rest#restOpArgs()}.
- * </ul>
- * <li>Looks for a static or non-static <c>createRestParams()</>
method that returns <c>{@link Class}[]</c>.
- * <li>Resolves it via the bean store registered in this context.
- * <li>Instantiates a default set of parameters.
- * </ul>
- *
- * @param resource
- * The REST servlet or bean that this context defines.
- * @param builder
- * The builder for this object.
- * @param beanStore
- * The factory used for creating beans and retrieving injected
beans.
- * <br>Created by {@link RestContextBuilder#beanStore()}.
- * @return The REST method parameter resolvers for this REST resource.
- * @throws Exception If parameter resolvers could not be instantiated.
- */
- protected RestOpArgList createOpArgs(Object resource,
RestContextBuilder builder, BeanStore beanStore) throws Exception {
-
- RestOpArgList.Builder x = builder.restOpArgs;
-
- x = BeanStore
- .of(beanStore, resource)
- .addBean(RestOpArgList.Builder.class, x)
- .beanCreateMethodFinder(RestOpArgList.Builder.class,
resource)
- .find("createRestOperationArgs")
- .withDefault(x)
- .run();
-
- return x.build();
- }
-
- /**
* Instantiates the hook method parameter resolvers for this REST
resource.
*
* @param resource
@@ -1758,7 +1717,7 @@ public class RestContext extends Context {
for (int i = 0; i < pt.size(); i++) {
ParamInfo pi = mi.getParam(i);
beanStore.addBean(ParamInfo.class, pi);
- for (Class<? extends RestOpArg> c : opArgs) {
+ for (Class<? extends RestOpArg> c : restOpArgs) {
try {
ra[i] = beanStore.createBean(c);
if (ra[i] != null)
@@ -2353,7 +2312,7 @@ public class RestContext extends Context {
.a("defaultRequestHeaders",
defaultRequestHeaders)
.a("defaultResponseHeaders",
defaultResponseHeaders)
.a("fileFinder", fileFinder)
- .a("opArgs", opArgs)
+ .a("restOpArgs", restOpArgs)
.a("partParser", partParser)
.a("partSerializer", partSerializer)
.a("produces", produces)
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 02aa843..989b6dc 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
@@ -140,6 +140,7 @@ public class RestContextBuilder extends ContextBuilder
implements ServletConfig
private HeaderList.Builder defaultRequestHeaders;
private HeaderList.Builder defaultResponseHeaders;
private NamedAttributeList defaultRequestAttributes;
+ private RestOpArgList.Builder restOpArgs;
String
allowedHeaderParams = env("RestContext.allowedHeaderParams",
"Accept,Content-Type"),
@@ -173,50 +174,6 @@ public class RestContextBuilder extends ContextBuilder
implements ServletConfig
List<Object> children = new ArrayList<>();
- RestOpArgList.Builder restOpArgs = RestOpArgList.create().add(
- AttributeArg.class,
- BodyArg.class,
- ConfigArg.class,
- FormDataArg.class,
- HasFormDataArg.class,
- HasQueryArg.class,
- HeaderArg.class,
- HttpServletRequestArg.class,
- HttpServletResponseArg.class,
- InputStreamArg.class,
- InputStreamParserArg.class,
- LocaleArg.class,
- MessagesArg.class,
- MethodArg.class,
- OutputStreamArg.class,
- ParserArg.class,
- PathArg.class,
- QueryArg.class,
- ReaderArg.class,
- ReaderParserArg.class,
- RequestAttributesArg.class,
- RequestBeanArg.class,
- RequestBodyArg.class,
- RequestFormDataArg.class,
- RequestHeadersArg.class,
- RequestPathArg.class,
- RequestQueryArg.class,
- ResourceBundleArg.class,
- ResponseBeanArg.class,
- ResponseHeaderArg.class,
- ResponseStatusArg.class,
- RestContextArg.class,
- RestRequestArg.class,
- ServetInputStreamArg.class,
- ServletOutputStreamArg.class,
- SwaggerArg.class,
- TimeZoneArg.class,
- UriContextArg.class,
- UriResolverArg.class,
- WriterArg.class,
- DefaultArg.class
- );
-
/**
* Constructor.
*
@@ -352,6 +309,10 @@ public class RestContextBuilder extends ContextBuilder
implements ServletConfig
}
}
+
//-----------------------------------------------------------------------------------------------------------------
+ // defaultClasses
+
//-----------------------------------------------------------------------------------------------------------------
+
/**
* Returns access to the default classes list.
*
@@ -375,6 +336,10 @@ public class RestContextBuilder extends ContextBuilder
implements ServletConfig
return this;
}
+
//-----------------------------------------------------------------------------------------------------------------
+ // beanStore
+
//-----------------------------------------------------------------------------------------------------------------
+
/**
* Returns access to the bean store being used by this builder.
*
@@ -477,6 +442,10 @@ public class RestContextBuilder extends ContextBuilder
implements ServletConfig
return v.get();
}
+
//-----------------------------------------------------------------------------------------------------------------
+ // varResolver
+
//-----------------------------------------------------------------------------------------------------------------
+
/**
* Returns access to the variable resolver builder.
*
@@ -646,6 +615,10 @@ public class RestContextBuilder extends ContextBuilder
implements ServletConfig
return v.get();
}
+
//-----------------------------------------------------------------------------------------------------------------
+ // config
+
//-----------------------------------------------------------------------------------------------------------------
+
/**
* Returns the external configuration file for this resource.
*
@@ -734,6 +707,10 @@ public class RestContextBuilder extends ContextBuilder
implements ServletConfig
return v.get();
}
+
//-----------------------------------------------------------------------------------------------------------------
+ // logger
+
//-----------------------------------------------------------------------------------------------------------------
+
/**
* Returns the logger to use for the REST resource.
*
@@ -805,6 +782,10 @@ public class RestContextBuilder extends ContextBuilder
implements ServletConfig
return v.get();
}
+
//-----------------------------------------------------------------------------------------------------------------
+ // thrownStore
+
//-----------------------------------------------------------------------------------------------------------------
+
/**
* Returns the builder for the {@link ThrownStore} object in the REST
context.
*
@@ -881,6 +862,10 @@ public class RestContextBuilder extends ContextBuilder
implements ServletConfig
return v.get();
}
+
//-----------------------------------------------------------------------------------------------------------------
+ // methodExecStore
+
//-----------------------------------------------------------------------------------------------------------------
+
/**
* Returns the builder for the {@link MethodExecStore} object in the
REST context.
*
@@ -938,6 +923,10 @@ public class RestContextBuilder extends ContextBuilder
implements ServletConfig
return v.get();
}
+
//-----------------------------------------------------------------------------------------------------------------
+ // messages
+
//-----------------------------------------------------------------------------------------------------------------
+
/**
* Returns the builder for the {@link Messages} object in the REST
context.
*
@@ -1061,6 +1050,10 @@ public class RestContextBuilder extends ContextBuilder
implements ServletConfig
return v.get();
}
+
//-----------------------------------------------------------------------------------------------------------------
+ // responseProcessors
+
//-----------------------------------------------------------------------------------------------------------------
+
/**
* Returns the builder for the {@link ResponseProcessorList} object in
the REST context.
*
@@ -1228,6 +1221,10 @@ public class RestContextBuilder extends ContextBuilder
implements ServletConfig
return v.get();
}
+
//-----------------------------------------------------------------------------------------------------------------
+ // callLogger
+
//-----------------------------------------------------------------------------------------------------------------
+
/**
* Returns the builder for the {@link RestLogger} object in the REST
context.
*
@@ -1393,6 +1390,10 @@ public class RestContextBuilder extends ContextBuilder
implements ServletConfig
return v.get();
}
+
//-----------------------------------------------------------------------------------------------------------------
+ // partSerializer
+
//-----------------------------------------------------------------------------------------------------------------
+
/**
* Returns the part serializer builder for this context.
*
@@ -1477,6 +1478,10 @@ public class RestContextBuilder extends ContextBuilder
implements ServletConfig
return v.get();
}
+
//-----------------------------------------------------------------------------------------------------------------
+ // partParser
+
//-----------------------------------------------------------------------------------------------------------------
+
/**
* Returns the part parser builder for this context.
*
@@ -1561,6 +1566,10 @@ public class RestContextBuilder extends ContextBuilder
implements ServletConfig
return v.get();
}
+
//-----------------------------------------------------------------------------------------------------------------
+ // jsonSchemaGenerator
+
//-----------------------------------------------------------------------------------------------------------------
+
/**
* Returns the JSON schema generator builder for this context.
*
@@ -1629,6 +1638,10 @@ public class RestContextBuilder extends ContextBuilder
implements ServletConfig
return v.get();
}
+
//-----------------------------------------------------------------------------------------------------------------
+ // fileFinder
+
//-----------------------------------------------------------------------------------------------------------------
+
/**
* Returns the file finder builder for this context.
*
@@ -1814,6 +1827,10 @@ public class RestContextBuilder extends ContextBuilder
implements ServletConfig
return v.get();
}
+
//-----------------------------------------------------------------------------------------------------------------
+ // staticFiles
+
//-----------------------------------------------------------------------------------------------------------------
+
/**
* Returns the static files builder for this context.
*
@@ -1991,6 +2008,10 @@ public class RestContextBuilder extends ContextBuilder
implements ServletConfig
return v.get();
}
+
//-----------------------------------------------------------------------------------------------------------------
+ // defaultRequestHeaders
+
//-----------------------------------------------------------------------------------------------------------------
+
/**
* Returns the builder for the default request headers in the REST
context.
*
@@ -2003,6 +2024,97 @@ public class RestContextBuilder extends ContextBuilder
implements ServletConfig
}
/**
+ * Default request headers.
+ *
+ * <p>
+ * Specifies default values for request headers if they're not passed
in through the request.
+ *
+ * <ul class='notes'>
+ * <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 <c>Accept</c> header when one is not
+ * specified so that a particular default {@link
Serializer} is picked.
+ * </ul>
+ *
+ * <h5 class='section'>Example:</h5>
+ * <p class='bcode w800'>
+ * <jc>// Option #1 - Defined via annotation resolving to a config
file setting with default value.</jc>
+ * <ja>@Rest</ja>(defaultRequestHeaders={<js>"Accept:
application/json"</js>, <js>"My-Header=$C{REST/myHeaderValue}"</js>})
+ * <jk>public class</jk> MyResource {
+ *
+ * <jc>// Option #2 - Defined 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>
+ * .defaultRequestHeaders(
+ *
Accept.<jsm>of</jsm>(<js>"application/json"</js>),
+ *
BasicHeader.<jsm>of</jsm>(<js>"My-Header"</js>, <js>"foo"</js>)
+ * );
+ * }
+ *
+ * <jc>// Option #3 - Defined 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>.defaultRequestHeaders(Accept.<jsm>of</jsm>(<js>"application/json"</js>));
+ * }
+ *
+ * <jc>// Override at the method level.</jc>
+ * <ja>@RestGet</ja>(defaultRequestHeaders={<js>"Accept:
text/xml"</js>})
+ * <jk>public</jk> Object myMethod() {...}
+ * }
+ * </p>
+ *
+ * <ul class='seealso'>
+ * <li class='ja'>{@link Rest#defaultRequestHeaders}
+ * <li class='ja'>{@link RestOp#defaultRequestHeaders}
+ * <li class='ja'>{@link RestGet#defaultRequestHeaders}
+ * <li class='ja'>{@link RestPut#defaultRequestHeaders}
+ * <li class='ja'>{@link RestPost#defaultRequestHeaders}
+ * <li class='ja'>{@link RestDelete#defaultRequestHeaders}
+ * </ul>
+ *
+ * @param values The headers to add.
+ * @return This object (for method chaining).
+ */
+ @FluentSetter
+ public RestContextBuilder defaultRequestHeaders(Header...values) {
+ defaultRequestHeaders().setDefault(values);
+ return this;
+ }
+
+ /**
+ * Specifies a default <c>Accept</c> header value if not specified on a
request.
+ *
+ * @param value
+ * The default value of the <c>Accept</c> header.
+ * <br>Ignored if <jk>null</jk> or empty.
+ * @return This object (for method chaining).
+ */
+ @FluentSetter
+ public RestContextBuilder defaultAccept(String value) {
+ if (isNotEmpty(value))
+ defaultRequestHeaders(accept(value));
+ return this;
+ }
+
+ /**
+ * Specifies a default <c>Content-Type</c> header value if not
specified on a request.
+ *
+ * @param value
+ * The default value of the <c>Content-Type</c> header.
+ * <br>Ignored if <jk>null</jk> or empty.
+ * @return This object (for method chaining).
+ */
+ @FluentSetter
+ public RestContextBuilder defaultContentType(String value) {
+ if (isNotEmpty(value))
+ defaultRequestHeaders(contentType(value));
+ return this;
+ }
+
+ /**
* Instantiates the default request headers for this REST object.
*
* @param beanStore
@@ -2042,6 +2154,10 @@ public class RestContextBuilder extends ContextBuilder
implements ServletConfig
return v.get();
}
+
//-----------------------------------------------------------------------------------------------------------------
+ // defaultResponseHeaders
+
//-----------------------------------------------------------------------------------------------------------------
+
/**
* Returns the builder for the default response headers in the REST
context.
*
@@ -2054,6 +2170,63 @@ public class RestContextBuilder extends ContextBuilder
implements ServletConfig
}
/**
+ * Default response headers.
+ *
+ * <p>
+ * Specifies default values for response headers if they're not set
after the Java REST method is called.
+ *
+ * <ul class='notes'>
+ * <li>
+ * This is equivalent to calling {@link
RestResponse#setHeader(String, String)} programmatically in each of
+ * the Java methods.
+ * <li>
+ * The header value will not be set if the header value
has already been specified (hence the 'default' in the name).
+ * </ul>
+ *
+ * <h5 class='section'>Example:</h5>
+ * <p class='bcode w800'>
+ * <jc>// Option #1 - Defined via annotation resolving to a config
file setting with default value.</jc>
+ * <ja>@Rest</ja>(defaultResponseHeaders={<js>"Content-Type:
$C{REST/defaultContentType,text/plain}"</js>,<js>"My-Header:
$C{REST/myHeaderValue}"</js>})
+ * <jk>public class</jk> MyResource {
+ *
+ * <jc>// Option #2 - Defined 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>
+ * .defaultResponseHeaders(
+ *
ContentType.<jsm>of</jsm>(<js>"text/plain"</js>),
+ *
BasicHeader.<jsm>ofPair</jsm>(<js>"My-Header: foo"</js>)
+ * );
+ * }
+ *
+ * <jc>// Option #3 - Defined 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>.defaultResponseHeaders(ContentType.<jsm>of</jsm>(<js>"text/plain"</js>));
+ * }
+ * }
+ * </p>
+ *
+ * <ul class='seealso'>
+ * <li class='ja'>{@link Rest#defaultResponseHeaders}
+ * <li class='ja'>{@link RestOp#defaultResponseHeaders}
+ * <li class='ja'>{@link RestGet#defaultResponseHeaders}
+ * <li class='ja'>{@link RestPut#defaultResponseHeaders}
+ * <li class='ja'>{@link RestPost#defaultResponseHeaders}
+ * <li class='ja'>{@link RestDelete#defaultResponseHeaders}
+ * </ul>
+ *
+ * @param values The headers to add.
+ * @return This object (for method chaining).
+ */
+ @FluentSetter
+ public RestContextBuilder defaultResponseHeaders(Header...values) {
+ defaultResponseHeaders().setDefault(values);
+ return this;
+ }
+
+ /**
* Instantiates the default response headers for this REST object.
*
* @param beanStore
@@ -2093,6 +2266,10 @@ public class RestContextBuilder extends ContextBuilder
implements ServletConfig
return v.get();
}
+
//-----------------------------------------------------------------------------------------------------------------
+ // defaultRequestAttributes
+
//-----------------------------------------------------------------------------------------------------------------
+
/**
* Returns the builder for the default requests attributes in the REST
context.
*
@@ -2105,56 +2282,300 @@ public class RestContextBuilder extends ContextBuilder
implements ServletConfig
}
/**
- * Instantiates the default response headers for this REST object.
- *
- * @param beanStore
- * The factory used for creating beans and retrieving injected
beans.
- * @param resource
- * The REST servlet or bean that this context defines.
- * @return The default response headers for this REST object.
- */
- protected NamedAttributeList createDefaultRequestAttributes(BeanStore
beanStore, Supplier<?> resource) {
-
- Value<NamedAttributeList> v = Value.empty();
- Object r = resource.get();
-
- beanStore.getBean("RestContext.defaultRequestAttributes",
NamedAttributeList.class).map(x -> x.copy()).ifPresent(x -> v.set(x));
-
- if (v.isEmpty())
- v.set(NamedAttributeList.create());
-
- BeanStore
- .of(beanStore, r)
- .addBean(NamedAttributeList.class, v.get())
- .beanCreateMethodFinder(NamedAttributeList.class, r)
- .find("createDefaultRequestAttributes")
- .execute()
- .ifPresent(x -> v.set(x));
-
- return v.get();
- }
-
-
//----------------------------------------------------------------------------------------------------
- // Methods that give access to the config file, var resolver, and
properties.
-
//----------------------------------------------------------------------------------------------------
-
- /**
- * Returns the serializer group builder containing the serializers for
marshalling POJOs into response bodies.
+ * Default request attributes.
*
* <p>
- * Serializer are used to convert POJOs to HTTP response bodies.
- * <br>Any of the Juneau framework serializers can be used in this
setting.
- * <br>The serializer selected is based on the request <c>Accept</c>
header matched against the values returned by the following method
- * using a best-match algorithm:
- * <ul class='javatree'>
- * <li class='jm'>{@link Serializer#getMediaTypeRanges()}
- * </ul>
+ * Specifies default values for request attributes if they're not
already set on the request.
*
- * <p>
- * The builder is initialized with serializers defined via the {@link
Rest#serializers()} annotation. That annotation is applied
- * from parent-to-child order with child entries given priority over
parent entries.
+ * Affects values returned by the following methods:
+ * <ul>
+ * <li class='jm'>{@link RestRequest#getAttribute(String)}.
+ * <li class='jm'>{@link RestRequest#getAttributes()}.
+ * </ul>
*
- * <ul class='seealso'>
+ * <h5 class='section'>Example:</h5>
+ * <p class='bcode w800'>
+ * <jc>// Option #1 - Defined via annotation resolving to a config
file setting with default value.</jc>
+ * <ja>@Rest</ja>(defaultRequestAttributes={<js>"Foo=bar"</js>,
<js>"Baz: $C{REST/myAttributeValue}"</js>})
+ * <jk>public class</jk> MyResource {
+ *
+ * <jc>// Option #2 - Defined 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>
+ * .defaultRequestAttributes(
+ *
BasicNamedAttribute.<jsm>of</jsm>(<js>"Foo"</js>, <js>"bar"</js>),
+ *
BasicNamedAttribute.<jsm>of</jsm>(<js>"Baz"</js>, <jk>true</jk>)
+ * );
+ * }
+ *
+ * <jc>// Option #3 - Defined 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>.defaultRequestAttribute(<js>"Foo"</js>, <js>"bar"</js>);
+ * }
+ *
+ * <jc>// Override at the method level.</jc>
+ * <ja>@RestGet</ja>(defaultRequestAttributes={<js>"Foo:
bar"</js>})
+ * <jk>public</jk> Object myMethod() {...}
+ * }
+ * </p>
+ *
+ * <ul class='notes'>
+ * <li>Use {@link BasicNamedAttribute#of(String, Supplier)} to
provide a dynamically changeable attribute value.
+ * </ul>
+ *
+ * @param values The attributes.
+ * @return This object (for method chaining).
+ */
+ @FluentSetter
+ public RestContextBuilder
defaultRequestAttributes(NamedAttribute...values) {
+ defaultRequestAttributes().appendUnique(values);
+ return this;
+ }
+
+ /**
+ * Instantiates the default response headers for this REST object.
+ *
+ * @param beanStore
+ * The factory used for creating beans and retrieving injected
beans.
+ * @param resource
+ * The REST servlet or bean that this context defines.
+ * @return The default response headers for this REST object.
+ */
+ protected NamedAttributeList createDefaultRequestAttributes(BeanStore
beanStore, Supplier<?> resource) {
+
+ Value<NamedAttributeList> v = Value.empty();
+ Object r = resource.get();
+
+ beanStore.getBean("RestContext.defaultRequestAttributes",
NamedAttributeList.class).map(x -> x.copy()).ifPresent(x -> v.set(x));
+
+ if (v.isEmpty())
+ v.set(NamedAttributeList.create());
+
+ BeanStore
+ .of(beanStore, r)
+ .addBean(NamedAttributeList.class, v.get())
+ .beanCreateMethodFinder(NamedAttributeList.class, r)
+ .find("createDefaultRequestAttributes")
+ .execute()
+ .ifPresent(x -> v.set(x));
+
+ return v.get();
+ }
+
+
//-----------------------------------------------------------------------------------------------------------------
+ // restOpArgs
+
//-----------------------------------------------------------------------------------------------------------------
+
+ /**
+ * Returns the builder for the default requests attributes in the REST
context.
+ *
+ * @return The builder for the default request attributer object in the
REST context.
+ */
+ public final RestOpArgList.Builder restOpArgs() {
+ if (restOpArgs == null)
+ restOpArgs = createRestOpArgs(beanStore(), resource());
+ return restOpArgs;
+ }
+
+ /**
+ * 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.
+ *
+ * <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> MyRestOpArg <jk>implements</jk> RestOpArg
{
+ *
+ * <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> MyRestOpArg
<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> MyRestOpArg(ParamInfo
<jv>paramInfo</jv>) {}
+ *
+ * <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>(restOpArgs=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>.restOpArgs(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>.restOpArgs(MyRestParam.<jk>class</jk>);
+ * }
+ *
+ * <jc>// Now pass it into your method.</jc>
+ * <ja>@RestPost</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 RestOpArg} for the list of predefined
parameter resolvers.
+ * </ul>
+ *
+ * @param values The values to add to this setting.
+ * @return This object (for method chaining).
+ * @throws IllegalArgumentException if any class does not extend from
{@link RestOpArg}.
+ */
+ @FluentSetter
+ public RestContextBuilder restOpArgs(Class<?>...values) {
+ restOpArgs().add(assertClassArrayArgIsType("values",
RestOpArg.class, values));
+ return this;
+ }
+
+ /**
+ * Instantiates the REST method parameter resolvers for this REST
resource.
+ *
+ * <p>
+ * Instantiates based on the following logic:
+ * <ul>
+ * <li>Looks for REST op args set via any of the following:
+ * <ul>
+ * <li>{@link
RestContextBuilder#restOpArgs(Class...)}/{@link
RestContextBuilder#restOpArgs(Class...)}
+ * <li>{@link Rest#restOpArgs()}.
+ * </ul>
+ * <li>Looks for a static or non-static <c>createRestParams()</>
method that returns <c>{@link Class}[]</c>.
+ * <li>Resolves it via the bean store registered in this context.
+ * <li>Instantiates a default set of parameters.
+ * </ul>
+ *
+ * @param beanStore
+ * The factory used for creating beans and retrieving injected
beans.
+ * @param resource
+ * The REST servlet or bean that this context defines.
+ * @return The REST method parameter resolvers for this REST resource.
+ */
+ protected RestOpArgList.Builder createRestOpArgs(BeanStore beanStore,
Supplier<?> resource) {
+
+ Value<RestOpArgList.Builder> v = Value.empty();
+ Object r = resource.get();
+
+ beanStore.getBean(RestOpArgList.Builder.class).map(x ->
x.copy()).ifPresent(x -> v.set(x));
+
+ if (v.isEmpty()) {
+ v.set(
+ RestOpArgList
+ .of(
+ AttributeArg.class,
+ BodyArg.class,
+ ConfigArg.class,
+ FormDataArg.class,
+ HasFormDataArg.class,
+ HasQueryArg.class,
+ HeaderArg.class,
+ HttpServletRequestArg.class,
+ HttpServletResponseArg.class,
+ InputStreamArg.class,
+ InputStreamParserArg.class,
+ LocaleArg.class,
+ MessagesArg.class,
+ MethodArg.class,
+ OutputStreamArg.class,
+ ParserArg.class,
+ PathArg.class,
+ QueryArg.class,
+ ReaderArg.class,
+ ReaderParserArg.class,
+ RequestAttributesArg.class,
+ RequestBeanArg.class,
+ RequestBodyArg.class,
+ RequestFormDataArg.class,
+ RequestHeadersArg.class,
+ RequestPathArg.class,
+ RequestQueryArg.class,
+ ResourceBundleArg.class,
+ ResponseBeanArg.class,
+ ResponseHeaderArg.class,
+ ResponseStatusArg.class,
+ RestContextArg.class,
+ RestRequestArg.class,
+ ServetInputStreamArg.class,
+ ServletOutputStreamArg.class,
+ SwaggerArg.class,
+ TimeZoneArg.class,
+ UriContextArg.class,
+ UriResolverArg.class,
+ WriterArg.class,
+ DefaultArg.class
+ )
+ );
+ }
+
+ beanStore.getBean(RestOpArgList.class).ifPresent(x ->
v.get().impl(x));
+
+ BeanStore
+ .of(beanStore, r)
+ .addBean(RestOpArgList.Builder.class, v.get())
+ .beanCreateMethodFinder(RestOpArgList.Builder.class, r)
+ .find("createRestOpArgs")
+ .execute()
+ .ifPresent(x -> v.set(x));
+
+ BeanStore
+ .of(beanStore, r)
+ .addBean(RestOpArgList.Builder.class, v.get())
+ .beanCreateMethodFinder(RestOpArgList.class, r)
+ .find("createRestOpArgs")
+ .execute()
+ .ifPresent(x -> v.get().impl(x));
+
+ return v.get();
+ }
+
+
+
//----------------------------------------------------------------------------------------------------
+ // Methods that give access to the config file, var resolver, and
properties.
+
//----------------------------------------------------------------------------------------------------
+
+ /**
+ * Returns the serializer group builder containing the serializers for
marshalling POJOs into response bodies.
+ *
+ * <p>
+ * Serializer are used to convert POJOs to HTTP response bodies.
+ * <br>Any of the Juneau framework serializers can be used in this
setting.
+ * <br>The serializer selected is based on the request <c>Accept</c>
header matched against the values returned by the following method
+ * using a best-match algorithm:
+ * <ul class='javatree'>
+ * <li class='jm'>{@link Serializer#getMediaTypeRanges()}
+ * </ul>
+ *
+ * <p>
+ * The builder is initialized with serializers defined via the {@link
Rest#serializers()} annotation. That annotation is applied
+ * from parent-to-child order with child entries given priority over
parent entries.
+ *
+ * <ul class='seealso'>
* <li class='link'>{@doc RestSerializers}
* </ul>
*
@@ -2743,208 +3164,6 @@ public class RestContextBuilder extends ContextBuilder
implements ServletConfig
}
/**
- * Specifies a default <c>Accept</c> header value if not specified on a
request.
- *
- * @param value
- * The default value of the <c>Accept</c> header.
- * <br>Ignored if <jk>null</jk> or empty.
- * @return This object (for method chaining).
- */
- @FluentSetter
- public RestContextBuilder defaultAccept(String value) {
- if (isNotEmpty(value))
- defaultRequestHeaders(accept(value));
- return this;
- }
-
- /**
- * Specifies a default <c>Content-Type</c> header value if not
specified on a request.
- *
- * @param value
- * The default value of the <c>Content-Type</c> header.
- * <br>Ignored if <jk>null</jk> or empty.
- * @return This object (for method chaining).
- */
- @FluentSetter
- public RestContextBuilder defaultContentType(String value) {
- if (isNotEmpty(value))
- defaultRequestHeaders(contentType(value));
- return this;
- }
-
- /**
- * Default request attributes.
- *
- * <p>
- * Specifies default values for request attributes if they're not
already set on the request.
- *
- * Affects values returned by the following methods:
- * <ul>
- * <li class='jm'>{@link RestRequest#getAttribute(String)}.
- * <li class='jm'>{@link RestRequest#getAttributes()}.
- * </ul>
- *
- * <h5 class='section'>Example:</h5>
- * <p class='bcode w800'>
- * <jc>// Option #1 - Defined via annotation resolving to a config
file setting with default value.</jc>
- * <ja>@Rest</ja>(defaultRequestAttributes={<js>"Foo=bar"</js>,
<js>"Baz: $C{REST/myAttributeValue}"</js>})
- * <jk>public class</jk> MyResource {
- *
- * <jc>// Option #2 - Defined 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>
- * .defaultRequestAttributes(
- *
BasicNamedAttribute.<jsm>of</jsm>(<js>"Foo"</js>, <js>"bar"</js>),
- *
BasicNamedAttribute.<jsm>of</jsm>(<js>"Baz"</js>, <jk>true</jk>)
- * );
- * }
- *
- * <jc>// Option #3 - Defined 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>.defaultRequestAttribute(<js>"Foo"</js>, <js>"bar"</js>);
- * }
- *
- * <jc>// Override at the method level.</jc>
- * <ja>@RestGet</ja>(defaultRequestAttributes={<js>"Foo:
bar"</js>})
- * <jk>public</jk> Object myMethod() {...}
- * }
- * </p>
- *
- * <ul class='notes'>
- * <li>Use {@link BasicNamedAttribute#of(String, Supplier)} to
provide a dynamically changeable attribute value.
- * </ul>
- *
- * @param values The attributes.
- * @return This object (for method chaining).
- */
- @FluentSetter
- public RestContextBuilder
defaultRequestAttributes(NamedAttribute...values) {
- defaultRequestAttributes().appendUnique(values);
- return this;
- }
-
- /**
- * Default request headers.
- *
- * <p>
- * Specifies default values for request headers if they're not passed
in through the request.
- *
- * <ul class='notes'>
- * <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 <c>Accept</c> header when one is not
- * specified so that a particular default {@link
Serializer} is picked.
- * </ul>
- *
- * <h5 class='section'>Example:</h5>
- * <p class='bcode w800'>
- * <jc>// Option #1 - Defined via annotation resolving to a config
file setting with default value.</jc>
- * <ja>@Rest</ja>(defaultRequestHeaders={<js>"Accept:
application/json"</js>, <js>"My-Header=$C{REST/myHeaderValue}"</js>})
- * <jk>public class</jk> MyResource {
- *
- * <jc>// Option #2 - Defined 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>
- * .defaultRequestHeaders(
- *
Accept.<jsm>of</jsm>(<js>"application/json"</js>),
- *
BasicHeader.<jsm>of</jsm>(<js>"My-Header"</js>, <js>"foo"</js>)
- * );
- * }
- *
- * <jc>// Option #3 - Defined 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>.defaultRequestHeaders(Accept.<jsm>of</jsm>(<js>"application/json"</js>));
- * }
- *
- * <jc>// Override at the method level.</jc>
- * <ja>@RestGet</ja>(defaultRequestHeaders={<js>"Accept:
text/xml"</js>})
- * <jk>public</jk> Object myMethod() {...}
- * }
- * </p>
- *
- * <ul class='seealso'>
- * <li class='ja'>{@link Rest#defaultRequestHeaders}
- * <li class='ja'>{@link RestOp#defaultRequestHeaders}
- * <li class='ja'>{@link RestGet#defaultRequestHeaders}
- * <li class='ja'>{@link RestPut#defaultRequestHeaders}
- * <li class='ja'>{@link RestPost#defaultRequestHeaders}
- * <li class='ja'>{@link RestDelete#defaultRequestHeaders}
- * </ul>
- *
- * @param values The headers to add.
- * @return This object (for method chaining).
- */
- @FluentSetter
- public RestContextBuilder defaultRequestHeaders(Header...values) {
- defaultRequestHeaders().setDefault(values);
- return this;
- }
-
- /**
- * Default response headers.
- *
- * <p>
- * Specifies default values for response headers if they're not set
after the Java REST method is called.
- *
- * <ul class='notes'>
- * <li>
- * This is equivalent to calling {@link
RestResponse#setHeader(String, String)} programmatically in each of
- * the Java methods.
- * <li>
- * The header value will not be set if the header value
has already been specified (hence the 'default' in the name).
- * </ul>
- *
- * <h5 class='section'>Example:</h5>
- * <p class='bcode w800'>
- * <jc>// Option #1 - Defined via annotation resolving to a config
file setting with default value.</jc>
- * <ja>@Rest</ja>(defaultResponseHeaders={<js>"Content-Type:
$C{REST/defaultContentType,text/plain}"</js>,<js>"My-Header:
$C{REST/myHeaderValue}"</js>})
- * <jk>public class</jk> MyResource {
- *
- * <jc>// Option #2 - Defined 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>
- * .defaultResponseHeaders(
- *
ContentType.<jsm>of</jsm>(<js>"text/plain"</js>),
- *
BasicHeader.<jsm>ofPair</jsm>(<js>"My-Header: foo"</js>)
- * );
- * }
- *
- * <jc>// Option #3 - Defined 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>.defaultResponseHeaders(ContentType.<jsm>of</jsm>(<js>"text/plain"</js>));
- * }
- * }
- * </p>
- *
- * <ul class='seealso'>
- * <li class='ja'>{@link Rest#defaultResponseHeaders}
- * <li class='ja'>{@link RestOp#defaultResponseHeaders}
- * <li class='ja'>{@link RestGet#defaultResponseHeaders}
- * <li class='ja'>{@link RestPut#defaultResponseHeaders}
- * <li class='ja'>{@link RestPost#defaultResponseHeaders}
- * <li class='ja'>{@link RestDelete#defaultResponseHeaders}
- * </ul>
- *
- * @param values The headers to add.
- * @return This object (for method chaining).
- */
- @FluentSetter
- public RestContextBuilder defaultResponseHeaders(Header...values) {
- defaultResponseHeaders().setDefault(values);
- return this;
- }
-
- /**
* Disable body URL parameter.
*
* <p>
@@ -3309,81 +3528,6 @@ public class RestContextBuilder extends ContextBuilder
implements ServletConfig
}
/**
- * 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.
- *
- * <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> MyRestOpArg <jk>implements</jk> RestOpArg
{
- *
- * <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> MyRestOpArg
<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> MyRestOpArg(ParamInfo
<jv>paramInfo</jv>) {}
- *
- * <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>(restOpArgs=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>.restOpArgs(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>.restOpArgs(MyRestParam.<jk>class</jk>);
- * }
- *
- * <jc>// Now pass it into your method.</jc>
- * <ja>@RestPost</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 RestOpArg} for the list of predefined
parameter resolvers.
- * </ul>
- *
- * @param values The values to add to this setting.
- * @return This object (for method chaining).
- * @throws IllegalArgumentException if any class does not extend from
{@link RestOpArg}.
- */
- @FluentSetter
- public RestContextBuilder restOpArgs(Class<?>...values) {
- restOpArgs.add(assertClassArrayArgIsType("values",
RestOpArg.class, values));
- return this;
- }
-
- /**
* REST operations class.
*
* <p>
diff --git
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestOpArgList.java
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestOpArgList.java
index 8e04a15..de4127f 100644
---
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestOpArgList.java
+++
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestOpArgList.java
@@ -37,6 +37,17 @@ public class RestOpArgList {
return new Builder();
}
+ /**
+ * Static creator.
+ *
+ * @param values The initial contents of the list.
+ * @return A list initialized with the specified values.
+ */
+ @SafeVarargs
+ public static Builder of(Class<? extends RestOpArg>...values) {
+ return new Builder().add(values);
+ }
+
//-----------------------------------------------------------------------------------------------------------------
// Builder
//-----------------------------------------------------------------------------------------------------------------
@@ -48,20 +59,32 @@ public class RestOpArgList {
AList<Class<? extends RestOpArg>> entries;
BeanStore beanStore;
+ RestOpArgList impl;
/**
- * Create an empty builder.
+ * Constructor.
*/
protected Builder() {
this.entries = AList.create();
}
/**
+ * Copy constructor.
+ *
+ * @param copyFrom The builder being copied.
+ */
+ protected Builder(Builder copyFrom) {
+ this.entries = AList.of(copyFrom.entries);
+ }
+
+ /**
* Creates a new {@link RestOpArgList} object using a snapshot
of the settings defined in this builder.
*
* @return A new {@link RestOpArgList} object.
*/
public RestOpArgList build() {
+ if (impl != null)
+ return impl;
return new RestOpArgList(this);
}
@@ -76,6 +99,26 @@ public class RestOpArgList {
entries.addAll(0,
Arrays.asList(assertClassArrayArgIsType("values", RestOpArg.class, values)));
return this;
}
+
+ /**
+ * Creates a copy of this builder.
+ *
+ * @return A copy of this builder.
+ */
+ public Builder copy() {
+ return new Builder(this);
+ }
+
+ /**
+ * Specifies an already instantiated bean for the {@link
#build()} method to return.
+ *
+ * @param value The value for this setting.
+ * @return This object.
+ */
+ public Builder impl(RestOpArgList value) {
+ impl = value;
+ return this;
+ }
}
//-----------------------------------------------------------------------------------------------------------------