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 3f8024b Context API refactoring. 3f8024b is described below commit 3f8024b6071094de6e6cca6ba2baf6ad40fb29c0 Author: JamesBognar <james.bog...@salesforce.com> AuthorDate: Mon Aug 30 18:44:47 2021 -0400 Context API refactoring. --- .../java/org/apache/juneau/rest/RestContext.java | 163 ++------------------- .../org/apache/juneau/rest/RestContextBuilder.java | 108 +++++++++++++- .../java/org/apache/juneau/rest/RestOpArg.java | 2 +- .../java/org/apache/juneau/rest/RestOpArgList.java | 64 +++++++- .../org/apache/juneau/rest/annotation/Rest.java | 2 +- .../juneau/rest/annotation/RestAnnotation.java | 2 +- 6 files changed, 178 insertions(+), 163 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 9065918..862fca7 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 @@ -969,94 +969,6 @@ public class RestContext extends BeanContext { public static final String REST_renderResponseStackTraces = PREFIX + ".renderResponseStackTraces.b"; /** - * Configuration property: Java REST method parameter resolvers. - * - * <h5 class='section'>Property:</h5> - * <ul class='spaced-list'> - * <li><b>ID:</b> {@link org.apache.juneau.rest.RestContext#REST_restOperationArgs REST_restParams} - * <li><b>Name:</b> <js>"RestContext.restOperationsParams.lo"</js> - * <li><b>Data type:</b> <c>List<Class<{@link org.apache.juneau.rest.RestOpArg}>></c> - * <li><b>Default:</b> empty list - * <li><b>Session property:</b> <jk>false</jk> - * <li><b>Annotations:</b> - * <ul> - * <li class='ja'>{@link org.apache.juneau.rest.annotation.Rest#restOpArgs()} - * </ul> - * <li><b>Methods:</b> - * <ul> - * <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#restOpArgs(Class...)} - * </ul> - * </ul> - * - * <h5 class='section'>Description:</h5> - * <p> - * By default, the Juneau framework will automatically Java method parameters of various types (e.g. - * <c>RestRequest</c>, <c>Accept</c>, <c>Reader</c>). - * This setting allows you to provide your own resolvers for your own class types that you want resolved. - * - * <p> - * For example, if you want to pass in instances of <c>MySpecialObject</c> to your Java method, define - * the following resolver: - * <p class='bcode w800'> - * <jc>// Define a parameter resolver for resolving MySpecialObject objects.</jc> - * <jk>public class</jk> MyRestParam <jk>implements</jk> 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> MyRestParam <jsm>create</jsm>(ParamInfo <jv>paramInfo</jv>) { - * <jk>if</jk> (<jv>paramInfo</jv>.isType(MySpecialObject.<jk>class</jk>) - * <jk>return new</jk> MyRestParam(); - * <jk>return null</jk>; - * } - * - * <jk>public</jk> MyRestParam() {} - * - * <jc>// The method that creates our object. - * // In this case, we're taking in a query parameter and converting it to our object.</jc> - * <ja>@Override</ja> - * <jk>public</jk> Object resolve(RestCall <jv>call</jv>) <jk>throws</jk> Exception { - * <jk>return new</jk> MySpecialObject(<jv>call</jv>.getRestRequest().getQuery().get(<js>"myparam"</js>)); - * } - * } - * - * <jc>// Option #1 - Registered via annotation.</jc> - * <ja>@Rest</ja>(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>.restOperationParams(MyRestParam.<jk>class</jk>); - * - * <jc>// Same, but using property.</jc> - * <jv>builder</jv>.addTo(<jsf>REST_restOperationArgs</jsf>, MyRestParam.<jk>class</jk>); - * } - * - * <jc>// Option #3 - Registered via builder passed in through init method.</jc> - * <ja>@RestHook</ja>(<jsf>INIT</jsf>) - * <jk>public void</jk> init(RestContextBuilder <jv>builder</jv>) <jk>throws</jk> Exception { - * <jv>builder</jv>.restOperationParams(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> - */ - public static final String REST_restOperationArgs = PREFIX + ".restOperationArgs.lo"; - - /** * Configuration property: Serializers. * * <h5 class='section'>Property:</h5> @@ -1496,7 +1408,7 @@ public class RestContext extends BeanContext { defaultResponseHeaders = createDefaultResponseHeaders(r, cp, bf).build(); defaultRequestAttributes = createDefaultRequestAttributes(r, cp, bf); - opArgs = createOpArgs(r, cp, bf).asArray(); + opArgs = createOpArgs(r, builder, bf).asArray(); hookMethodArgs = createHookMethodArgs(r, cp, bf).asArray(); uriContext = builder.uriContext; @@ -2289,7 +2201,7 @@ public class RestContext extends BeanContext { * <p> * Instantiates based on the following logic: * <ul> - * <li>Looks for {@link #REST_restOperationArgs} value set via any of the following: + * <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()}. @@ -2301,76 +2213,27 @@ public class RestContext extends BeanContext { * * @param resource * The REST servlet or bean that this context defines. - * @param properties - * The properties of this bean. - * <br>Consists of all properties gathered through the builder and annotations on this class and all parent classes. + * @param builder + * The builder for this object. * @param beanStore * The factory used for creating beans and retrieving injected beans. * <br>Created by {@link #createBeanStore(Object,ContextProperties,RestContext)}. * @return The REST method parameter resolvers for this REST resource. * @throws Exception If parameter resolvers could not be instantiated. */ - @SuppressWarnings("unchecked") - protected RestOpArgList createOpArgs(Object resource, ContextProperties properties, BeanStore beanStore) throws Exception { - - RestOpArgList x = RestOpArgList.create(); + protected RestOpArgList createOpArgs(Object resource, RestContextBuilder builder, BeanStore beanStore) throws Exception { - for (Class<?> c : properties.getList(REST_restOperationArgs, Class.class).orElse(emptyList())) - x.append((Class<? extends RestOpArg>)c); - - x.append( - 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 - ); + RestOpArgList.Builder x = builder.restOpArgs; x = BeanStore .of(beanStore, resource) - .addBean(RestOpArgList.class, x) - .beanCreateMethodFinder(RestOpArgList.class, resource) + .addBean(RestOpArgList.Builder.class, x) + .beanCreateMethodFinder(RestOpArgList.Builder.class, resource) .find("createRestOperationArgs") .withDefault(x) .run(); - return x; + return x.build(); } /** @@ -2390,7 +2253,7 @@ public class RestContext extends BeanContext { @SuppressWarnings("unchecked") protected RestOpArgList createHookMethodArgs(Object resource, ContextProperties properties, BeanStore beanStore) throws Exception { - RestOpArgList x = RestOpArgList.create(); + RestOpArgList.Builder x = RestOpArgList.create(); x.append( ConfigArg.class, @@ -2415,13 +2278,13 @@ public class RestContext extends BeanContext { x = BeanStore .of(beanStore, resource) - .addBean(RestOpArgList.class, x) - .beanCreateMethodFinder(RestOpArgList.class, resource) + .addBean(RestOpArgList.Builder.class, x) + .beanCreateMethodFinder(RestOpArgList.Builder.class, resource) .find("createHookMethodArgs") .withDefault(x) .run(); - return x; + return x.build(); } /** 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 40c6dea..7092d52 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 @@ -44,6 +44,7 @@ import org.apache.juneau.oapi.*; import org.apache.juneau.parser.*; import org.apache.juneau.reflect.*; import org.apache.juneau.rest.annotation.*; +import org.apache.juneau.rest.args.*; import org.apache.juneau.rest.logging.*; import org.apache.juneau.rest.processors.*; import org.apache.juneau.rest.vars.*; @@ -154,6 +155,51 @@ public class RestContextBuilder extends BeanContextBuilder implements ServletCon List<Object> children = new ArrayList<>(); + @SuppressWarnings("unchecked") + RestOpArgList.Builder restOpArgs = RestOpArgList.create().append( + 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 + ); + RestContextBuilder(Optional<RestContext> parentContext, Optional<ServletConfig> servletConfig, Class<?> resourceClass, Optional<Object> resource) throws ServletException { try { contextClass(RestContext.class); @@ -2160,15 +2206,68 @@ public class RestContextBuilder extends BeanContextBuilder implements ServletCon } /** - * <i><l>RestContext</l> configuration property: </i> Java method parameter resolvers. + * Java method parameter resolvers. * * <p> * By default, the Juneau framework will automatically Java method parameters of various types (e.g. * <c>RestRequest</c>, <c>Accept</c>, <c>Reader</c>). * This annotation allows you to provide your own resolvers for your own class types that you want resolved. * - * <ul class='seealso'> - * <li class='jf'>{@link RestContext#REST_restOperationArgs} + * <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. @@ -2177,7 +2276,8 @@ public class RestContextBuilder extends BeanContextBuilder implements ServletCon @FluentSetter @SuppressWarnings("unchecked") public RestContextBuilder restOpArgs(Class<? extends RestOpArg>...values) { - return prependTo(REST_restOperationArgs, values); + restOpArgs.append(values); + return this; } /** diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestOpArg.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestOpArg.java index 42eea17..1ba0282 100644 --- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestOpArg.java +++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestOpArg.java @@ -43,7 +43,7 @@ import org.apache.juneau.rest.annotation.*; * </p> * * <ul class='seealso'> - * <li class='jf'>{@link RestContext#REST_restOperationArgs} + * <li class='jm'>{@link RestContextBuilder#restOpArgs(Class...)} * <li class='link'>{@doc RestmParameters} * </ul> */ 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 72dad28..df47e77 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 @@ -12,23 +12,75 @@ // *************************************************************************************************************************** package org.apache.juneau.rest; +import java.util.*; + import org.apache.juneau.collections.*; +import org.apache.juneau.cp.*; /** * A list of {@link RestOpArg} classes. */ -public class RestOpArgList extends AList<Class<? extends RestOpArg>> { +public class RestOpArgList { - private static final long serialVersionUID = 1L; + private final Class<? extends RestOpArg>[] entries; /** * Static creator. * * @return An empty list. */ - @SuppressWarnings("unchecked") - public static RestOpArgList create() { - return new RestOpArgList(); + public static Builder create() { + return new Builder(); + } + + /** + * Constructor. + * + * @param builder The builder containing the contents for this list. + */ + protected RestOpArgList(Builder builder) { + entries = + builder + .entries + .stream() + .toArray(Class[]::new); + } + + /** + * Builder for {@link RestOpArgList} objects. + */ + public static class Builder { + + AList<Class<? extends RestOpArg>> entries; + BeanStore beanStore; + + /** + * Create an empty builder. + */ + protected Builder() { + this.entries = AList.create(); + } + + /** + * 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() { + return new RestOpArgList(this); + } + + /** + * Prepends the specified rest op arg classes to the list. + * + * @param values The values to add. + * @return This object (for method chaining). + */ + @SuppressWarnings("unchecked") + public Builder append(Class<? extends RestOpArg>...values) { + entries.addAll(0, Arrays.asList(values)); + return this; + } } /** @@ -37,6 +89,6 @@ public class RestOpArgList extends AList<Class<? extends RestOpArg>> { * @return The contents of this list as a {@link Class} array. */ public Class<? extends RestOpArg>[] asArray() { - return asArrayOf(Class.class); + return entries; } } diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/Rest.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/Rest.java index ccb508c..bcb8f8a 100644 --- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/Rest.java +++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/Rest.java @@ -977,7 +977,7 @@ public @interface Rest { * <br>This setting allows you to provide your own resolvers for your own class types that you want resolved. * * <ul class='seealso'> - * <li class='jf'>{@link RestContext#REST_restOperationArgs} + * <li class='jm'>{@link RestContextBuilder#restOpArgs(Class...)} * </ul> */ Class<? extends RestOpArg>[] restOpArgs() default {}; diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestAnnotation.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestAnnotation.java index 3e230a4..8c5e27a 100644 --- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestAnnotation.java +++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestAnnotation.java @@ -1052,7 +1052,7 @@ public class RestAnnotation { b.appendToIfNotEmpty(REST_defaultRequestHeaders, contentType(string(a.defaultContentType()))); b.responseProcessors(a.responseProcessors()); b.children((Object[])a.children()); - b.prependTo(REST_restOperationArgs, a.restOpArgs()); + b.restOpArgs(a.restOpArgs()); value(a.contextClass()).ifPresent(x -> b.contextClass(x)); value(a.uriContext()).ifPresent(x -> b.uriContext(x)); value(a.uriAuthority()).ifPresent(x -> b.uriAuthority(x));