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
commit 75aa50426d0daf234d760acd38cd5e13fec77995 Author: James Bognar <[email protected]> AuthorDate: Mon May 11 17:50:37 2026 -0400 refactor(inject): introduce commons.inject.@Bean as successor to @RestInject; delete @RestInject - Created org.apache.juneau.commons.inject.Bean annotation (successor to RestInject) - Created org.apache.juneau.commons.inject.BeanAnnotation annotation processor - Migrated all @RestInject callsites across rest-server, rest-springboot, and tests to @Bean - Renamed RestContext.isRestInjectMethod() to isBeanMethod() for consistency - Deleted RestInject.java and RestInjectAnnotation.java (clean break, no deprecated alias) Co-authored-by: Cursor <[email protected]> --- .../org/apache/juneau/commons/inject/Bean.java | 190 ++++++++++++++++ .../juneau/commons/inject/BeanAnnotation.java | 44 ++-- .../apache/juneau/commons/inject/BeanStore.java | 4 +- .../juneau/rest/springboot/SpringRestServlet.java | 3 +- .../java/org/apache/juneau/rest/RestContext.java | 174 +++++++------- .../java/org/apache/juneau/rest/RestOpContext.java | 36 +-- .../org/apache/juneau/rest/annotation/Rest.java | 6 +- .../apache/juneau/rest/annotation/RestDelete.java | 2 +- .../org/apache/juneau/rest/annotation/RestGet.java | 4 +- .../apache/juneau/rest/annotation/RestInit.java | 8 +- .../apache/juneau/rest/annotation/RestInject.java | 249 --------------------- .../org/apache/juneau/rest/annotation/RestOp.java | 6 +- .../apache/juneau/rest/annotation/RestOptions.java | 4 +- .../apache/juneau/rest/annotation/RestPatch.java | 6 +- .../apache/juneau/rest/annotation/RestPost.java | 6 +- .../org/apache/juneau/rest/annotation/RestPut.java | 6 +- .../juneau/rest/RestContext_Builder_Test.java | 16 +- .../juneau/rest/RestContext_Precedence_Test.java | 76 +++---- .../juneau/rest/annotation/RestInit_Test.java | 5 +- .../juneau/rest/annotation/Rest_Messages_Test.java | 3 +- 20 files changed, 396 insertions(+), 452 deletions(-) diff --git a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/inject/Bean.java b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/inject/Bean.java new file mode 100644 index 0000000000..7c369eec9b --- /dev/null +++ b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/inject/Bean.java @@ -0,0 +1,190 @@ +/* + * 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.commons.inject; + +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.*; + +import java.lang.annotation.*; + +/** + * Bean injection annotation. + * + * <p> + * Used on methods and fields of {@link BeanStore}-managed objects to denote methods and fields that override and + * customize beans used by the framework. + * + * <h5 class='figure'>Example</h5> + * <p class='bcode'> + * <jc>// Rest resource that uses a customized call logger.</jc> + * <ja>@Rest</ja> + * <jk>public class</jk> MyRest <jk>extends</jk> BasicRestServlet { + * + * <jc>// Option #1: As a field.</jc> + * <ja>@Bean</ja> + * CallLogger <jf>myCallLogger</jf> = CallLogger.<jsm>create</jsm>().logger(<js>"mylogger"</js>).build(); + * + * <jc>// Option #2: As a method.</jc> + * <ja>@Bean</ja> + * <jk>public</jk> CallLogger myCallLogger() { + * <jk>return</jk> CallLogger.<jsm>create</jsm>().logger(<js>"mylogger"</js>).build(); + * } + * } + * </p> + * + * <p> + * The {@link Bean#name()}/{@link Bean#value()} attributes are used to differentiate between named beans. + * </p> + * <h5 class='figure'>Example</h5> + * <p class='bcode'> + * <jc>// Customized default request headers.</jc> + * <ja>@Bean</ja>(<js>"defaultRequestHeaders"</js>) + * HeaderList <jf>defaultRequestHeaders</jf> = HeaderList.<jsm>create</jsm>().set(ContentType.<jsf>TEXT_PLAIN</jsf>).build(); + * + * <jc>// Customized default response headers.</jc> + * <ja>@Bean</ja>(<js>"defaultResponseHeaders"</js>) + * HeaderList <jf>defaultResponseHeaders</jf> = HeaderList.<jsm>create</jsm>().set(ContentType.<jsf>TEXT_PLAIN</jsf>).build(); + * </p> + * + * <p> + * The {@link Bean#methodScope()} attribute is used to define beans in the scope of specific {@code @RestOp}-annotated methods. + * </p> + * <h5 class='figure'>Example</h5> + * <p class='bcode'> + * <jc>// Set a default header on a specific REST method.</jc> + * <jc>// Input parameter is the default header list builder with all annotations applied.</jc> + * <ja>@Bean</ja>(name=<js>"defaultRequestHeaders"</js>, methodScope=<js>"myRestMethod"</js>) + * <jk>public</jk> HeaderList.Builder myRequestHeaders(HeaderList.Builder <jv>builder</jv>) { + * <jk>return</jk> <jv>builder</jv>.set(ContentType.<jsf>TEXT_PLAIN</jsf>); + * } + * + * <jc>// Method that picks up default header defined above.</jc> + * <ja>@RestGet</ja> + * <jk>public</jk> Object myRestMethod(ContentType <jv>contentType</jv>) { ... } + * </p> + * + * <p> + * This annotation can also be used to inject arbitrary beans into the bean store which allows them to be + * passed as resolved parameters on {@code @RestOp}-annotated methods. + * </p> + * <h5 class='figure'>Example</h5> + * <p class='bcode'> + * <jc>// Custom beans injected into the bean store.</jc> + * <ja>@Bean</ja> MyBean <jv>myBean1</jv> = <jk>new</jk> MyBean(); + * <ja>@Bean</ja>(<js>"myBean2"</js>) MyBean <jv>myBean2</jv> = <jk>new</jk> MyBean(); + * + * <jc>// Method that uses injected beans.</jc> + * <ja>@RestGet</ja> + * <jk>public</jk> Object doGet(MyBean <jv>myBean1</jv>, <ja>@Name</ja>(<js>"myBean2"</js>) MyBean <jv>myBean2</jv>) { ... } + * </p> + * + * <p> + * This annotation can also be used on uninitialized fields. When fields are uninitialized, they will + * be set during initialization based on beans found in the bean store. + * </p> + * <h5 class='figure'>Example</h5> + * <p class='bcode'> + * <jc>// Fields that get set during initialization based on beans found in the bean store.</jc> + * <ja>@Bean</ja> CallLogger <jf>callLogger</jf>; + * <ja>@Bean</ja> BeanStore <jf>beanStore</jf>; <jc>// Note that the BeanStore itself can be accessed this way.</jc> + * </p> + * + * <h5 class='section'>Notes:</h5><ul> + * <li class='note'>Methods and fields can be static or non-static. + * <li class='note'>Any injectable beans (including spring beans) can be passed as arguments into methods. + * <li class='note'>Bean names are required when multiple beans of the same type exist in the bean store. + * <li class='note'>By default, the injected bean scope is class-level (applies to the entire class). The + * {@link Bean#methodScope()} annotation can be used to apply to method-level only (when applicable). + * </ul> + * + * <h5 class='section'>Precedence (since 9.5.0):</h5> + * <p> + * {@code @Bean} acts as a <i>programmable default</i>, analogous to Spring's + * <c>@ConditionalOnMissingBean</c>. When a REST context resolves a framework-managed bean + * (<c>CallLogger</c>, <c>EncoderSet</c>, <c>SerializerSet</c>, <c>ParserSet</c>, <c>ThrownStore</c>, + * <c>Config</c>, <c>VarResolver</c>, <c>HttpPartSerializer</c>, <c>HttpPartParser</c>, etc.), the lookup + * walks the following tiers in order, returning the first hit: + * </p> + * <ol> + * <li><b>Overriding-parent bean store</b> — Spring beans (in <c>juneau-rest-server-springboot</c> deployments, + * via <c>SpringBeanStore</c>), or any bean reachable through the configured overriding-parent + * bean-store chain.</li> + * <li><b>{@code @Bean} method/field on the resource class</b> — registered as a regular bean-store + * entry, beating the framework default.</li> + * <li><b>Memoizer-backed framework default</b> — built into the context as a default supplier.</li> + * </ol> + * <p> + * In other words: a Spring <c>@Bean</c> of type <c>CallLogger</c> wins over a {@code @Bean CallLogger} + * method on the same servlet, which in turn wins over the framework's built-in <c>BasicCallLogger</c>. Non-Spring + * deployments have an empty overriding-parent layer, so the chain naturally collapses to + * {@code @Bean > default}. + * </p> + * <p> + * Prior to 9.5 the order was {@code @Bean > Spring > default}. See the 9.5.0 release notes for migration + * guidance if you need to keep that legacy behavior (typically by removing the Spring <c>@Bean</c> or marking the + * {@code @Bean} method's type with a Spring-native override such as <c>@Primary</c>). + * </p> + * + * <h5 class='section'>See Also:</h5><ul> + * <li class='jc'>{@link BeanStore} + * <li class='jc'>{@link WritableBeanStore} + * </ul> + */ +@Target({ METHOD, FIELD }) +@Retention(RUNTIME) +@Inherited +public @interface Bean { + + /** + * Optional description for the exposed API. + * + * @return The annotation value. + * @since 9.2.0 + */ + String[] description() default {}; + + /** + * The short names of the methods that this annotation applies to. + * + * <p> + * Can use <js>"*"</js> to apply to all methods. + * + * <p> + * Ignored for class-level scope. + * + * @return The short names of the methods that this annotation applies to, or empty if class-scope. + */ + String[] methodScope() default {}; + + /** + * The bean name to use to distinguish beans of the same type for different purposes. + * + * <p> + * For example, there are two {@link org.apache.juneau.http.header.HeaderList} beans: <js>"defaultRequestHeaders"</js> and <js>"defaultResponseHeaders"</js>. This annotation + * would be used to differentiate between them. + * + * @return The bean name to use to distinguish beans of the same type for different purposes, or blank if bean type is unique. + */ + String name() default ""; + + /** + * Same as {@link #name()}. + * + * @return The bean name to use to distinguish beans of the same type for different purposes, or blank if bean type is unique. + */ + String value() default ""; +} diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestInjectAnnotation.java b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/inject/BeanAnnotation.java similarity index 80% rename from juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestInjectAnnotation.java rename to juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/inject/BeanAnnotation.java index 91100cc976..dc3e1b00e3 100644 --- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestInjectAnnotation.java +++ b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/inject/BeanAnnotation.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.juneau.rest.annotation; +package org.apache.juneau.commons.inject; import static java.lang.annotation.ElementType.*; import static java.lang.annotation.RetentionPolicy.*; @@ -25,20 +25,20 @@ import java.lang.annotation.*; import org.apache.juneau.commons.annotation.*; /** - * Utility classes and methods for the {@link RestInject RestInject} annotation. + * Utility classes and methods for the {@link Bean @Bean} annotation. * */ -public class RestInjectAnnotation { +public class BeanAnnotation { /** * Private constructor to prevent instantiation. */ - private RestInjectAnnotation() { + private BeanAnnotation() { // Utility class - prevent instantiation } /** - * A collection of {@link RestInject @RestInject annotations}. + * A collection of {@link Bean @Bean} annotations. */ @Documented @Target({ FIELD, METHOD, TYPE }) @@ -51,7 +51,7 @@ public class RestInjectAnnotation { * * @return The annotation value. */ - RestInject[] value(); + Bean[] value(); } /** @@ -72,15 +72,15 @@ public class RestInjectAnnotation { * Constructor. */ protected Builder() { - super(RestInject.class); + super(Bean.class); } /** - * Instantiates a new {@link RestInject @RestInject} object initialized with this builder. + * Instantiates a new {@link Bean @Bean} object initialized with this builder. * - * @return A new {@link RestInject @RestInject} object. + * @return A new {@link Bean @Bean} object. */ - public RestInject build() { + public Bean build() { return new Object(this); } @@ -96,7 +96,7 @@ public class RestInjectAnnotation { } /** - * Sets the {@link RestInject#methodScope()} property on this annotation. + * Sets the {@link Bean#methodScope()} property on this annotation. * * @param value The new value for this property. * @return This object. @@ -107,7 +107,7 @@ public class RestInjectAnnotation { } /** - * Sets the {@link RestInject#name()} property on this annotation. + * Sets the {@link Bean#name()} property on this annotation. * * @param value The new value for this property. * @return This object. @@ -118,7 +118,7 @@ public class RestInjectAnnotation { } /** - * Sets the {@link RestInject#value()} property on this annotation. + * Sets the {@link Bean#value()} property on this annotation. * * @param value The new value for this property. * @return This object. @@ -151,14 +151,14 @@ public class RestInjectAnnotation { @SuppressWarnings({ "java:S2160" // equals() inherited from AnnotationObject compares all annotation interface methods; subclass fields are accessed via those methods }) - private static class Object extends AppliedAnnotationObject implements RestInject { + private static class Object extends AppliedAnnotationObject implements Bean { private final String[] description; private final String name; private final String value; private final String[] methodScope; - Object(RestInjectAnnotation.Builder b) { + Object(BeanAnnotation.Builder b) { super(b); description = copyOf(b.description); name = b.name; @@ -166,17 +166,17 @@ public class RestInjectAnnotation { methodScope = b.methodScope; } - @Override /* Overridden from RestInject */ + @Override /* Overridden from Bean */ public String[] methodScope() { return methodScope; } - @Override /* Overridden from RestInject */ + @Override /* Overridden from Bean */ public String name() { return name; } - @Override /* Overridden from RestInject */ + @Override /* Overridden from Bean */ public String value() { return value; } @@ -188,7 +188,7 @@ public class RestInjectAnnotation { } /** Default value */ - public static final RestInject DEFAULT = create().build(); + public static final Bean DEFAULT = create().build(); /** * Instantiates a new builder for this class. @@ -200,16 +200,16 @@ public class RestInjectAnnotation { } /** - * Pulls the name/value attribute from a {@link RestInject} annotation. + * Pulls the name/value attribute from a {@link Bean} annotation. * * @param a The annotation to check. Can be <jk>null</jk>. * @return The annotation value, or an empty string if the annotation is <jk>null</jk>. */ - public static String name(RestInject a) { + public static String name(Bean a) { if (a == null) return ""; if (! a.name().isEmpty()) return a.name(); return a.value(); } -} \ No newline at end of file +} diff --git a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/inject/BeanStore.java b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/inject/BeanStore.java index a949331742..3c673c9996 100644 --- a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/inject/BeanStore.java +++ b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/inject/BeanStore.java @@ -198,12 +198,12 @@ public interface BeanStore { * <p class='bjava'> * <jc>// Filter only</jc> * <jv>beanStore</jv>.createBeanFromMethod(CallLogger.<jk>class</jk>, <jv>resource</jv>, - * RestContext::isRestInjectMethod) + * RestContext::isBeanMethod) * .ifPresent(<jv>creator</jv>::impl); * * <jc>// Filter + extra bean not yet in the store</jc> * <jv>beanStore</jv>.createBeanFromMethod(EncoderSet.<jk>class</jk>, <jv>resource</jv>, - * RestContext::isRestInjectMethod, <jv>builder</jv>) + * RestContext::isBeanMethod, <jv>builder</jv>) * .ifPresent(<jv>x</jv> -> <jv>builder</jv>.impl(<jv>x</jv>)); * * <jc>// No filter, no extra beans</jc> diff --git a/juneau-rest/juneau-rest-server-springboot/src/main/java/org/apache/juneau/rest/springboot/SpringRestServlet.java b/juneau-rest/juneau-rest-server-springboot/src/main/java/org/apache/juneau/rest/springboot/SpringRestServlet.java index 76253efd58..dc9a87c06b 100644 --- a/juneau-rest/juneau-rest-server-springboot/src/main/java/org/apache/juneau/rest/springboot/SpringRestServlet.java +++ b/juneau-rest/juneau-rest-server-springboot/src/main/java/org/apache/juneau/rest/springboot/SpringRestServlet.java @@ -19,7 +19,6 @@ package org.apache.juneau.rest.springboot; import java.util.*; import org.apache.juneau.commons.inject.*; -import org.apache.juneau.rest.annotation.*; import org.apache.juneau.rest.servlet.*; import org.springframework.beans.factory.annotation.*; import org.springframework.context.*; @@ -53,7 +52,7 @@ public abstract class SpringRestServlet extends RestServlet { * @param parent Optional parent resource bean store, used as a fallback after Spring's context. * @return A {@link WritableBeanStore} backed by Spring's {@link ApplicationContext}. */ - @RestInject + @Bean public WritableBeanStore createBeanStore(Optional<BeanStore> parent) { return new SpringBeanStore(appContext.orElse(null), parent.orElse(null)); } 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 4dce883763..4e0a36e0d2 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 @@ -18,6 +18,8 @@ package org.apache.juneau.rest; import org.apache.juneau.commons.http.MediaType; import org.apache.juneau.commons.inject.BasicBeanStore; +import org.apache.juneau.commons.inject.Bean; +import org.apache.juneau.commons.inject.BeanAnnotation; import org.apache.juneau.commons.inject.BeanInstantiator; import org.apache.juneau.commons.inject.BeanStore; import org.apache.juneau.commons.inject.WritableBeanStore; @@ -99,7 +101,7 @@ import jakarta.servlet.http.*; * * <p> * Configuration is supplied declaratively through the {@link Rest @Rest} annotation on the resource class - * (and inherited from any parent classes), and programmatically through {@link RestInject @RestInject}-annotated + * (and inherited from any parent classes), and programmatically through {@link org.apache.juneau.commons.inject.Bean @Bean}-annotated * methods/fields that contribute named beans (e.g. <c>encoders</c>, <c>parsers</c>, <c>callLogger</c>) to the REST * resource's bean store. Where direct construction is needed (test rigs, mock clients, embedded usage), * the public constructor takes a {@link RestContext.Args} record carrying the bootstrap state. @@ -110,7 +112,7 @@ import jakarta.servlet.http.*; * <jk>public class</jk> MyResource { * * <jc>// Programmatically contribute a bean to the resource's bean store.</jc> - * <ja>@RestInject</ja> + * <ja>@Bean</ja> * <jk>public</jk> CallLogger callLogger() { * <jk>return new</jk> MyCustomCallLogger(); * } @@ -235,7 +237,7 @@ public class RestContext extends Context { * Package-private constructor. * * <p> - * Minimized in the May 2026 refactor — the beanStore setup, {@code @RestInject} processing, + * Minimized in the May 2026 refactor — the beanStore setup, {@code @Bean} processing, * {@code @RestInit} hooks, and {@code beanStoreConfigurer} call were all moved into * {@link RestContext#RestContext(Builder)}. The Builder now only stores the three fields * that are final and needed by the {@link ServletConfig} overrides and factory methods. @@ -302,12 +304,12 @@ public class RestContext extends Context { .map(y -> y.accessible().inner()); } - private static boolean isRestInjectMethod(MethodInfo mi) { - return isRestInjectMethod(mi, null); + private static boolean isBeanMethod(MethodInfo mi) { + return isBeanMethod(mi, null); } - private static boolean isRestInjectMethod(MethodInfo mi, String name) { - return mi.getAnnotations(RestInject.class) + private static boolean isBeanMethod(MethodInfo mi, String name) { + return mi.getAnnotations(Bean.class) .map(AnnotationInfo::inner) .anyMatch(x -> nn(x) && x.methodScope().length == 0 && (n(name) || eq(x.name(), name))); } @@ -345,7 +347,7 @@ public class RestContext extends Context { * <p> * Resolution: * <ol> - * <li>If the resource declares an {@code @RestInject} factory method returning a + * <li>If the resource declares an {@code @Bean} factory method returning a * {@link WritableBeanStore} (e.g. {@code SpringRestServlet.createBeanStore(Optional<BeanStore>)}), * that store is used directly. Spring integration relies on this hook. * <li>Otherwise a fresh {@link BasicBeanStore} is created with {@code parentBs} as its @@ -360,7 +362,7 @@ public class RestContext extends Context { */ private WritableBeanStore createBeanStore(BeanStore parentBs, Supplier<?> resource) { var defaultBs = new BasicBeanStore(parentBs); - return defaultBs.createBeanFromMethod(WritableBeanStore.class, resource.get(), RestContext::isRestInjectMethod) + return defaultBs.createBeanFromMethod(WritableBeanStore.class, resource.get(), RestContext::isBeanMethod) .orElse(defaultBs); } private RestContext parentContext() { return parentContext; } @@ -372,10 +374,10 @@ public class RestContext extends Context { * * <p> * Default suppliers sit at the bottom of the bean-store resolution order: they fire only when no - * {@link RestInject} method, no programmatic {@code addBean(...)} call, and no Spring/overriding-parent + * {@link org.apache.juneau.commons.inject.Bean @Bean} method, no programmatic {@code addBean(...)} call, and no Spring/overriding-parent * binding has been registered for the type. This is the mechanism that replaces the old * {@code DELAYED_INJECTION} list — by registering the framework's own factories as defaults - * <i>before</i> the {@link RestInject} method walk runs, any {@link RestInject} method whose parameters + * <i>before</i> the {@link org.apache.juneau.commons.inject.Bean @Bean} method walk runs, any {@link org.apache.juneau.commons.inject.Bean @Bean} method whose parameters * include framework types can now resolve those parameters lazily through the bean store without * requiring a hand-maintained skip list. */ @@ -472,7 +474,7 @@ public class RestContext extends Context { cb.name(cf); v.set(cb.build()); } - bs.createBeanFromMethod(Config.class, resource().get(), RestContext::isRestInjectMethod, v.get()).ifPresent(v::set); + bs.createBeanFromMethod(Config.class, resource().get(), RestContext::isBeanMethod, v.get()).ifPresent(v::set); return v.get(); }); @@ -501,7 +503,7 @@ public class RestContext extends Context { .bean(FileFinder.class, FileFinder.create(bs).cp(resourceClass(), null, true).build()) .build() ); - bs.createBeanFromMethod(VarResolver.class, resource().get(), x -> isRestInjectMethod(x, PROP_bootstrapVarResolver)).ifPresent(v::set); + bs.createBeanFromMethod(VarResolver.class, resource().get(), x -> isBeanMethod(x, PROP_bootstrapVarResolver)).ifPresent(v::set); return v.get(); }); // @formatter:on @@ -511,7 +513,7 @@ public class RestContext extends Context { * * <p> * Defaults to {@link BasicCallLogger}. {@code @Rest(callLogger=X)} most-derived non-{@code Void} class wins. - * A bean-store override or {@code @RestInject} factory method REPLACES the result. + * A bean-store override or {@code @Bean} factory method REPLACES the result. */ private final Memoizer<CallLogger> callLogger = memoizer(() -> { var bs = beanStore(); @@ -529,7 +531,7 @@ public class RestContext extends Context { .filter(c -> c != CallLogger.Void.class) .reduce((first, second) -> second) .ifPresent(creator::type); - bs.createBeanFromMethod(CallLogger.class, resource().get(), RestContext::isRestInjectMethod).ifPresent(creator::impl); + bs.createBeanFromMethod(CallLogger.class, resource().get(), RestContext::isBeanMethod).ifPresent(creator::impl); return creator.asOptional().orElse(null); }); @@ -570,7 +572,7 @@ public class RestContext extends Context { * Resolved from {@code @Rest(debugDefault)} (most-derived non-blank wins), falling back to * {@code @Rest(debug=true|false)}. The resolved {@link Enablement} is published into the bean store * so that {@link BasicDebugEnablement} subclasses can pick it up. Defaults to {@link BasicDebugEnablement}. - * A bean-store override or {@code @RestInject} factory method REPLACES the result. + * A bean-store override or {@code @Bean} factory method REPLACES the result. */ private final Memoizer<DebugEnablement> debugEnablement = memoizer(() -> { // @Rest(debugDefault="ALWAYS|NEVER|CONDITIONAL") — most-derived non-blank value wins, with parent inheritance @@ -596,7 +598,7 @@ public class RestContext extends Context { .filter(c -> c != DebugEnablement.Void.class) .reduce((first, second) -> second) .ifPresent(creator::type); - bs.createBeanFromMethod(DebugEnablement.class, resource().get(), RestContext::isRestInjectMethod).ifPresent(creator::impl); + bs.createBeanFromMethod(DebugEnablement.class, resource().get(), RestContext::isBeanMethod).ifPresent(creator::impl); return creator.asOptional().orElse(null); }); @@ -605,7 +607,7 @@ public class RestContext extends Context { * * <p> * Walks {@code @Rest} annotations parent-to-child, resolving each attribute string and parsing it as a - * key=value or key:value pair. A named bean-store override or {@code @RestInject} factory method REPLACES + * key=value or key:value pair. A named bean-store override or {@code @Bean} factory method REPLACES * the accumulated result. */ private final Memoizer<NamedAttributeMap> defaultRequestAttributes = memoizer(() -> { @@ -616,7 +618,7 @@ public class RestContext extends Context { .filter(StringUtils::isNotBlank) .map(BasicNamedAttribute::ofPair) .forEach(v.get()::add)); - beanStore().createBeanFromMethod(NamedAttributeMap.class, resource().get(), x -> isRestInjectMethod(x, PROP_defaultRequestAttributes), v.get()).ifPresent(v::set); + beanStore().createBeanFromMethod(NamedAttributeMap.class, resource().get(), x -> isBeanMethod(x, PROP_defaultRequestAttributes), v.get()).ifPresent(v::set); return v.get(); }); @@ -626,7 +628,7 @@ public class RestContext extends Context { * * <p> * Walks {@code @Rest} annotations parent-to-child, resolving each header string. A named bean-store - * override or {@code @RestInject} factory method REPLACES the accumulated result. + * override or {@code @Bean} factory method REPLACES the accumulated result. */ private final Memoizer<HeaderList> defaultRequestHeaders = memoizer(() -> { var v = Value.of(HeaderList.create()); @@ -640,7 +642,7 @@ public class RestContext extends Context { if (isNotBlank(defaultContentType)) v.get().setDefault(contentType(defaultContentType)); }); - beanStore().createBeanFromMethod(HeaderList.class, resource().get(), x -> isRestInjectMethod(x, PROP_defaultRequestHeaders), v.get()).ifPresent(v::set); + beanStore().createBeanFromMethod(HeaderList.class, resource().get(), x -> isBeanMethod(x, PROP_defaultRequestHeaders), v.get()).ifPresent(v::set); return v.get(); }); @@ -649,12 +651,12 @@ public class RestContext extends Context { * * <p> * Walks {@code @Rest} annotations parent-to-child, resolving each header string. A named bean-store - * override or {@code @RestInject} factory method REPLACES the accumulated result. + * override or {@code @Bean} factory method REPLACES the accumulated result. */ private final Memoizer<HeaderList> defaultResponseHeaders = memoizer(() -> { var v = Value.of(HeaderList.create()); getRestAnnotationsTopDown().forEach(ai -> Arrays.stream(ai.inner().defaultResponseHeaders()).filter(StringUtils::isNotBlank).map(this::resolve).filter(StringUtils::isNotBlank).map(s -> stringHeader(s)).forEach(v.get()::setDefault)); - beanStore().createBeanFromMethod(HeaderList.class, resource().get(), x -> isRestInjectMethod(x, PROP_defaultResponseHeaders), v.get()).ifPresent(v::set); + beanStore().createBeanFromMethod(HeaderList.class, resource().get(), x -> isBeanMethod(x, PROP_defaultResponseHeaders), v.get()).ifPresent(v::set); return v.get(); }); @@ -664,25 +666,25 @@ public class RestContext extends Context { private final Memoizer<LifecycleInvokerPair> destroyInvokerPair = memoizer(() -> buildLifecycleInvokerPair(() -> { var bs = beanStore(); var v = Value.of(MethodList.of(getAnnotatedMethods(resource(), RestDestroy.class).toList())); - bs.createBeanFromMethod(MethodList.class, resource().get(), x -> isRestInjectMethod(x, "destroyMethods"), v.get()).ifPresent(v::set); + bs.createBeanFromMethod(MethodList.class, resource().get(), x -> isBeanMethod(x, "destroyMethods"), v.get()).ifPresent(v::set); return v.get(); })); /** * Fully-configured {@link EncoderSet.Builder} for this resource, populated from the - * {@code @Rest(encoders)} annotation chain and any {@code @RestInject} override. + * {@code @Rest(encoders)} annotation chain and any {@code @Bean} override. * * <p> * Starts with {@link IdentityEncoder} as the implicit default. A bean-store type override * or bean-store instance override REPLACES the builder or its impl. Annotation entries - * (parent-to-child) are appended after the default. A {@code @RestInject} factory method + * (parent-to-child) are appended after the default. A {@code @Bean} factory method * REPLACES the impl with the returned value. */ private final Memoizer<EncoderSet.Builder> encodersBuilder = memoizer(() -> { var bs = beanStore(); var v = Value.of(EncoderSet.create(bs)); getRestAnnotationsForProperty(PROPERTY_encoders).forEach(ai -> v.get().add(ai.inner().encoders())); - bs.createBeanFromMethod(EncoderSet.class, resource().get(), RestContext::isRestInjectMethod, v.get()).ifPresent(x -> v.get().impl(x)); + bs.createBeanFromMethod(EncoderSet.class, resource().get(), RestContext::isBeanMethod, v.get()).ifPresent(x -> v.get().impl(x)); return v.get(); }); @@ -697,7 +699,7 @@ public class RestContext extends Context { private final Memoizer<LifecycleInvokerPair> endCallInvokerPair = memoizer(() -> buildLifecycleInvokerPair(() -> { var bs = beanStore(); var v = Value.of(MethodList.of(getAnnotatedMethods(resource(), RestEndCall.class).toList())); - bs.createBeanFromMethod(MethodList.class, resource().get(), x -> isRestInjectMethod(x, "endCallMethods"), v.get()).ifPresent(v::set); + bs.createBeanFromMethod(MethodList.class, resource().get(), x -> isBeanMethod(x, "endCallMethods"), v.get()).ifPresent(v::set); return v.get(); })); @@ -707,7 +709,7 @@ public class RestContext extends Context { private final Memoizer<JsonSchemaGenerator.Builder> jsonSchemaGeneratorBuilder = memoizer(() -> { var bs = beanStore(); var v = Value.of(JsonSchemaGenerator.create()); - bs.createBeanFromMethod(JsonSchemaGenerator.class, resource().get(), RestContext::isRestInjectMethod).ifPresent(x -> v.get().impl(x)); + bs.createBeanFromMethod(JsonSchemaGenerator.class, resource().get(), RestContext::isBeanMethod).ifPresent(x -> v.get().impl(x)); v.get().apply(annotationWork); return v.get(); }); @@ -722,11 +724,11 @@ public class RestContext extends Context { * * <p> * Defaults to {@code Logger.getLogger(resourceClass.getName())}. A bean-store override or - * {@code @RestInject} factory method REPLACES the default. + * {@code @Bean} factory method REPLACES the default. */ private final Memoizer<Logger> logger = memoizer(() -> { var v = Value.of(Logger.getLogger(cn(resourceClass()))); - beanStore().createBeanFromMethod(Logger.class, resource().get(), RestContext::isRestInjectMethod, v.get()).ifPresent(v::set); + beanStore().createBeanFromMethod(Logger.class, resource().get(), RestContext::isBeanMethod, v.get()).ifPresent(v::set); return v.get(); }); @@ -736,7 +738,7 @@ public class RestContext extends Context { * <p> * Walks {@code @Rest} annotations parent-to-child, resolving each {@code messages} location string * against the bootstrap resolver (full resolver not yet available — it depends on {@code getMessages()}). - * A bean-store override or {@code @RestInject} factory method REPLACES the result. + * A bean-store override or {@code @Bean} factory method REPLACES the result. */ private final Memoizer<Messages> messages = memoizer(() -> { var b = Messages.create(resourceClass()); @@ -745,7 +747,7 @@ public class RestContext extends Context { // (it depends on getMessages()). var vrs = getBootstrapVarResolver().createSession(); getRestAnnotationsTopDown().forEach(ai -> ai.getString(PROPERTY_messages).filter(StringUtils::isNotBlank).ifPresent(s -> b.location(vrs.resolve(s)))); - var override = beanStore().createBeanFromMethod(Messages.class, resource().get(), RestContext::isRestInjectMethod, b).orElse(null); + var override = beanStore().createBeanFromMethod(Messages.class, resource().get(), RestContext::isBeanMethod, b).orElse(null); return nn(override) ? override : b.build(); }); @@ -753,28 +755,28 @@ public class RestContext extends Context { * The {@link MethodExecStore} for this resource, wired to the {@link ThrownStore}. * * <p> - * A bean-store override or {@code @RestInject} factory method REPLACES the result. + * A bean-store override or {@code @Bean} factory method REPLACES the result. */ private final Memoizer<MethodExecStore> methodExecStore = memoizer(() -> { var bs = beanStore(); var b = MethodExecStore.create(bs).thrownStoreOnce(getThrownStore()); - bs.createBeanFromMethod(MethodExecStore.class, resource().get(), RestContext::isRestInjectMethod, b).ifPresent(b::impl); + bs.createBeanFromMethod(MethodExecStore.class, resource().get(), RestContext::isBeanMethod, b).ifPresent(b::impl); return b.build(); }); /** * Fully-configured {@link ParserSet.Builder} for this resource, populated from the - * {@code @Rest(parsers)} annotation chain and any {@code @RestInject} override. + * {@code @Rest(parsers)} annotation chain and any {@code @Bean} override. * * <p> * Starts with an empty set. A bean-store type or instance override REPLACES the builder or its impl. - * Annotation entries (parent-to-child) are appended. A {@code @RestInject} factory method REPLACES the impl. + * Annotation entries (parent-to-child) are appended. A {@code @Bean} factory method REPLACES the impl. */ private final Memoizer<ParserSet.Builder> parsersBuilder = memoizer(() -> { var bs = beanStore(); var v = Value.of(ParserSet.create(bs)); getRestAnnotationsForProperty(PROPERTY_parsers).forEach(ai -> v.get().add(ai.inner().parsers())); - bs.createBeanFromMethod(ParserSet.class, resource().get(), RestContext::isRestInjectMethod, v.get()).ifPresent(x -> v.get().impl(x)); + bs.createBeanFromMethod(ParserSet.class, resource().get(), RestContext::isBeanMethod, v.get()).ifPresent(x -> v.get().impl(x)); return v.get(); }); @@ -790,7 +792,7 @@ public class RestContext extends Context { var bs = beanStore(); Value<HttpPartParser.Creator> v = Value.of(HttpPartParser.creator().type(OpenApiParser.class)); opt(resource().get() instanceof HttpPartParser x ? x : null).ifPresent(x -> v.get().impl(x)); - bs.createBeanFromMethod(HttpPartParser.class, resource().get(), RestContext::isRestInjectMethod).ifPresent(x -> v.get().impl(x)); + bs.createBeanFromMethod(HttpPartParser.class, resource().get(), RestContext::isBeanMethod).ifPresent(x -> v.get().impl(x)); v.get().apply(annotationWork); return v.get(); }); @@ -819,7 +821,7 @@ public class RestContext extends Context { var bs = beanStore(); Value<HttpPartSerializer.Creator> v = Value.of(HttpPartSerializer.creator().type(OpenApiSerializer.class)); opt(resource().get() instanceof HttpPartSerializer x ? x : null).ifPresent(x -> v.get().impl(x)); - bs.createBeanFromMethod(HttpPartSerializer.class, resource().get(), RestContext::isRestInjectMethod).ifPresent(x -> v.get().impl(x)); + bs.createBeanFromMethod(HttpPartSerializer.class, resource().get(), RestContext::isBeanMethod).ifPresent(x -> v.get().impl(x)); v.get().apply(annotationWork); return v.get(); }); @@ -847,7 +849,7 @@ public class RestContext extends Context { private final Memoizer<MethodList> postCallMethods = memoizer(() -> { var bs = beanStore(); var v = Value.of(MethodList.of(getAnnotatedMethods(resource(), RestPostCall.class).toList())); - bs.createBeanFromMethod(MethodList.class, resource().get(), x -> isRestInjectMethod(x, "postCallMethods"), v.get()).ifPresent(v::set); + bs.createBeanFromMethod(MethodList.class, resource().get(), x -> isBeanMethod(x, "postCallMethods"), v.get()).ifPresent(v::set); return v.get(); }); @@ -859,7 +861,7 @@ public class RestContext extends Context { var v = Value.of(MethodList.of(getAnnotatedMethods(resource(), RestPostInit.class) .filter(m -> rstream(AnnotationProvider.INSTANCE.find(RestPostInit.class, MethodInfo.of(m))).map(AnnotationInfo::inner).anyMatch(RestPostInit::childFirst)) .toList())); - bs.createBeanFromMethod(MethodList.class, resource().get(), x -> isRestInjectMethod(x, "postInitChildFirstMethods"), v.get()).ifPresent(v::set); + bs.createBeanFromMethod(MethodList.class, resource().get(), x -> isBeanMethod(x, "postInitChildFirstMethods"), v.get()).ifPresent(v::set); return v.get(); })); @@ -871,7 +873,7 @@ public class RestContext extends Context { var v = Value.of(MethodList.of(getAnnotatedMethods(resource(), RestPostInit.class) .filter(m -> rstream(AnnotationProvider.INSTANCE.find(RestPostInit.class, MethodInfo.of(m))).map(AnnotationInfo::inner).anyMatch(x -> !x.childFirst())) .toList())); - bs.createBeanFromMethod(MethodList.class, resource().get(), x -> isRestInjectMethod(x, "postInitMethods"), v.get()).ifPresent(v::set); + bs.createBeanFromMethod(MethodList.class, resource().get(), x -> isBeanMethod(x, "postInitMethods"), v.get()).ifPresent(v::set); return v.get(); })); @@ -881,7 +883,7 @@ public class RestContext extends Context { private final Memoizer<MethodList> preCallMethods = memoizer(() -> { var bs = beanStore(); var v = Value.of(MethodList.of(getAnnotatedMethods(resource(), RestPreCall.class).toList())); - bs.createBeanFromMethod(MethodList.class, resource().get(), x -> isRestInjectMethod(x, "preCallMethods"), v.get()).ifPresent(v::set); + bs.createBeanFromMethod(MethodList.class, resource().get(), x -> isBeanMethod(x, "preCallMethods"), v.get()).ifPresent(v::set); return v.get(); }); @@ -911,7 +913,7 @@ public class RestContext extends Context { * * <p> * Walks {@code @Rest(responseProcessors)} annotations parent-to-child (append order). A bean-store - * override or {@code @RestInject} factory method REPLACES the entire list. + * override or {@code @Bean} factory method REPLACES the entire list. */ private final Memoizer<ResponseProcessor[]> responseProcessors = memoizer(() -> { // Walk @Rest(responseProcessors=...) chain (parent-to-child via getRestAnnotationsForProperty). @@ -921,8 +923,8 @@ public class RestContext extends Context { var b = ResponseProcessorList.create(bs); getRestAnnotationsForProperty(PROPERTY_responseProcessors) .forEach(ai -> b.add(ai.inner().responseProcessors())); - // @RestInject method override REPLACES the entire annotation-derived list. - var override = bs.createBeanFromMethod(ResponseProcessorList.class, resource().get(), RestContext::isRestInjectMethod, b).orElse(null); + // @Bean method override REPLACES the entire annotation-derived list. + var override = bs.createBeanFromMethod(ResponseProcessorList.class, resource().get(), RestContext::isBeanMethod, b).orElse(null); return (nn(override) ? override : b.build()).toArray(); }); @@ -931,7 +933,7 @@ public class RestContext extends Context { * * <p> * Walks {@code @Rest(restOpArgs)} annotations parent-to-child (prepend order, so child entries - * take priority). A bean-store override or {@code @RestInject} factory method REPLACES the entire list. + * take priority). A bean-store override or {@code @Bean} factory method REPLACES the entire list. */ private final Memoizer<Class<? extends RestOpArg>[]> restOpArgs = memoizer(() -> { // Walk @Rest(restOpArgs=...) chain (parent-to-child via getRestAnnotationsForProperty). @@ -942,24 +944,24 @@ public class RestContext extends Context { var b = RestOpArgList.create(bs); getRestAnnotationsForProperty(PROPERTY_restOpArgs) .forEach(ai -> b.add(ai.inner().restOpArgs())); - // @RestInject method override REPLACES the entire annotation-derived list. - var override = bs.createBeanFromMethod(RestOpArgList.class, resource().get(), RestContext::isRestInjectMethod, b).orElse(null); + // @Bean method override REPLACES the entire annotation-derived list. + var override = bs.createBeanFromMethod(RestOpArgList.class, resource().get(), RestContext::isBeanMethod, b).orElse(null); return (nn(override) ? override : b.build()).asArray(); }); /** * Fully-configured {@link SerializerSet.Builder} for this resource, populated from the - * {@code @Rest(serializers)} annotation chain and any {@code @RestInject} override. + * {@code @Rest(serializers)} annotation chain and any {@code @Bean} override. * * <p> * Starts with an empty set. A bean-store type or instance override REPLACES the builder or its impl. - * Annotation entries (parent-to-child) are appended. A {@code @RestInject} factory method REPLACES the impl. + * Annotation entries (parent-to-child) are appended. A {@code @Bean} factory method REPLACES the impl. */ private final Memoizer<SerializerSet.Builder> serializersBuilder = memoizer(() -> { var bs = beanStore(); var v = Value.of(SerializerSet.create(bs)); getRestAnnotationsForProperty(PROPERTY_serializers).forEach(ai -> v.get().add(ai.inner().serializers())); - bs.createBeanFromMethod(SerializerSet.class, resource().get(), RestContext::isRestInjectMethod, v.get()).ifPresent(x -> v.get().impl(x)); + bs.createBeanFromMethod(SerializerSet.class, resource().get(), RestContext::isBeanMethod, v.get()).ifPresent(x -> v.get().impl(x)); return v.get(); }); @@ -974,7 +976,7 @@ public class RestContext extends Context { private final Memoizer<LifecycleInvokerPair> startCallInvokerPair = memoizer(() -> buildLifecycleInvokerPair(() -> { var bs = beanStore(); var v = Value.of(MethodList.of(getAnnotatedMethods(resource(), RestStartCall.class).toList())); - bs.createBeanFromMethod(MethodList.class, resource().get(), x -> isRestInjectMethod(x, "startCallMethods"), v.get()).ifPresent(v::set); + bs.createBeanFromMethod(MethodList.class, resource().get(), x -> isBeanMethod(x, "startCallMethods"), v.get()).ifPresent(v::set); return v.get(); })); @@ -983,7 +985,7 @@ public class RestContext extends Context { * * <p> * Defaults to {@link BasicStaticFiles}. {@code @Rest(staticFiles=X)} most-derived non-{@code Void} class wins. - * A bean-store override or {@code @RestInject} factory method REPLACES the result. + * A bean-store override or {@code @Bean} factory method REPLACES the result. */ private final Memoizer<StaticFiles> staticFiles = memoizer(() -> { var bs = beanStore(); @@ -995,7 +997,7 @@ public class RestContext extends Context { .filter(c -> c != StaticFiles.Void.class) .reduce((first, second) -> second) .ifPresent(creator::type); - bs.createBeanFromMethod(StaticFiles.class, resource().get(), RestContext::isRestInjectMethod).ifPresent(creator::impl); + bs.createBeanFromMethod(StaticFiles.class, resource().get(), RestContext::isBeanMethod).ifPresent(creator::impl); return creator.asOptional().orElse(null); }); @@ -1004,7 +1006,7 @@ public class RestContext extends Context { * * <p> * Defaults to {@link BasicSwaggerProvider}. {@code @Rest(swaggerProvider=X)} most-derived - * non-{@code Void} class wins. A bean-store override or {@code @RestInject} factory method REPLACES the result. + * non-{@code Void} class wins. A bean-store override or {@code @Bean} factory method REPLACES the result. */ private final Memoizer<SwaggerProvider> swaggerProvider = memoizer(() -> { var bs = beanStore(); @@ -1019,7 +1021,7 @@ public class RestContext extends Context { .filter(c -> c != SwaggerProvider.Void.class) .reduce((first, second) -> second) .ifPresent(creator::type); - bs.createBeanFromMethod(SwaggerProvider.class, resource().get(), RestContext::isRestInjectMethod).ifPresent(creator::impl); + bs.createBeanFromMethod(SwaggerProvider.class, resource().get(), RestContext::isBeanMethod).ifPresent(creator::impl); return creator.asOptional().orElse(null); }); @@ -1028,12 +1030,12 @@ public class RestContext extends Context { * * <p> * Inherits from the parent context's store when one is present. A bean-store override or - * {@code @RestInject} factory method REPLACES the result. + * {@code @Bean} factory method REPLACES the result. */ private final Memoizer<ThrownStore> thrownStore = memoizer(() -> { var bs = beanStore(); var b = ThrownStore.create(bs).impl(parentContext() == null ? null : parentContext().getThrownStore()); - bs.createBeanFromMethod(ThrownStore.class, resource().get(), RestContext::isRestInjectMethod, b).ifPresent(b::impl); + bs.createBeanFromMethod(ThrownStore.class, resource().get(), RestContext::isBeanMethod, b).ifPresent(b::impl); return b.build(); }); @@ -1043,14 +1045,14 @@ public class RestContext extends Context { * <p> * The bootstrap {@link Config} is pulled from the {@code rawConfig} memoizer to avoid a circular * dependency: the runtime {@link Config} wraps the bootstrap config in a session backed by this resolver. - * A bean-store override or {@code @RestInject} factory method REPLACES the result. + * A bean-store override or {@code @Bean} factory method REPLACES the result. */ private final Memoizer<VarResolver> varResolver = memoizer(() -> { var bs = beanStore(); var b = getBootstrapVarResolver().copy() .bean(Messages.class, getMessages()) .bean(Config.class, rawConfig.get()); - var override = bs.createBeanFromMethod(VarResolver.class, resource().get(), RestContext::isRestInjectMethod, b).orElse(null); + var override = bs.createBeanFromMethod(VarResolver.class, resource().get(), RestContext::isBeanMethod, b).orElse(null); return nn(override) ? override : b.build(); }); @@ -1093,7 +1095,7 @@ public class RestContext extends Context { } } } - var override = bs.createBeanFromMethod(RestOperations.class, resource().get(), RestContext::isRestInjectMethod, b).orElse(null); + var override = bs.createBeanFromMethod(RestOperations.class, resource().get(), RestContext::isBeanMethod, b).orElse(null); return nn(override) ? override : b.build(); })); @@ -1138,8 +1140,8 @@ public class RestContext extends Context { b.add(cc); } - // @RestInject override — allows replacing the entire RestChildren instance. - var override = bs.createBeanFromMethod(RestChildren.class, resource().get(), RestContext::isRestInjectMethod, b).orElse(null); + // @Bean override — allows replacing the entire RestChildren instance. + var override = bs.createBeanFromMethod(RestChildren.class, resource().get(), RestContext::isBeanMethod, b).orElse(null); return nn(override) ? override : b.build(); })); @@ -1187,7 +1189,7 @@ public class RestContext extends Context { // Determine the parent (bootstrap) store: inherited from parent resource if present. WritableBeanStore parentBs = parentContext != null ? parentContext.bootstrapBeanStore : null; - // Build the initial beanStore; honor an optional @RestInject WritableBeanStore override. + // Build the initial beanStore; honor an optional @Bean WritableBeanStore override. // In the new 9.5 precedence model, the parent (Spring or parent-resource bootstrap) is // installed as the overriding parent so it wins over local entries. // @formatter:off @@ -1219,47 +1221,47 @@ public class RestContext extends Context { rawConfig.get(); // Register memoizer-backed defaults for every framework-managed type. These sit at the - // bottom of the precedence order and only fire when no @RestInject method, no programmatic + // bottom of the precedence order and only fire when no @Bean method, no programmatic // add, and no Spring/overriding-parent bean has been registered for the type. This is - // what removes the need for the old DELAYED_INJECTION gate-keeping list — the @RestInject + // what removes the need for the old DELAYED_INJECTION gate-keeping list — the @Bean // walk below can now invoke any framework type's factory and still resolve framework // dependencies through the bean store. registerFrameworkDefaults(beanStore); var rci2 = ClassInfo.of(resourceClass); - // Register @RestInject fields that already have a value. + // Register @Bean fields that already have a value. // @formatter:off rci2.getAllFields().stream() - .filter(x -> x.hasAnnotation(RestInject.class)) + .filter(x -> x.hasAnnotation(Bean.class)) .forEach(x -> opt(x.get(resource.get())).ifPresent( y -> beanStore.add( x.getFieldType().inner(), y, - RestInjectAnnotation.name(x.getAnnotations(RestInject.class).findFirst().map(AnnotationInfo::inner).orElse(null)) + BeanAnnotation.name(x.getAnnotations(Bean.class).findFirst().map(AnnotationInfo::inner).orElse(null)) ) )); // @formatter:on - // Run @RestInject methods and register their results as LOCAL entries (level 2 of resolve()). + // Run @Bean methods and register their results as LOCAL entries (level 2 of resolve()). // - // For non-framework types: invoke the @RestInject method directly via createBeanFromMethod + // For non-framework types: invoke the @Bean method directly via createBeanFromMethod // and store the result via addBean. // - // For framework types (those with a default supplier registered above): the @RestInject + // For framework types (those with a default supplier registered above): the @Bean // scan already ran inside the corresponding memoizer body (see e.g. createCallLogger()), // so re-invoking createBeanFromMethod here would create a SECOND instance and produce // inconsistent state between the framework's memoizer-backed bean and the bean store's // local entry. Instead, PROMOTE the existing default supplier (which is memoizer-backed - // and resolves to the @RestInject value when one was supplied) into a local-entry supplier. - // Promoting at level 2 means @RestInject results win over a parent (Spring) at level 3. + // and resolves to the @Bean value when one was supplied) into a local-entry supplier. + // Promoting at level 2 means @Bean results win over a parent (Spring) at level 3. // - // Net effect: @RestInject method results uniformly take precedence over Spring/parent + // Net effect: @Bean method results uniformly take precedence over Spring/parent // bindings for both framework and user-defined types. This auto-derives the legacy // DELAYED_INJECTION list from the default-supplier registrations. - rci2.getAllMethods().stream().filter(x -> x.hasAnnotation(RestInject.class)).forEach(x -> { + rci2.getAllMethods().stream().filter(x -> x.hasAnnotation(Bean.class)).forEach(x -> { var rt = x.getReturnType().<Object>inner(); - var name = RestInjectAnnotation.name(x.getAnnotations(RestInject.class).findFirst().map(AnnotationInfo::inner).orElse(null)); + var name = BeanAnnotation.name(x.getAnnotations(Bean.class).findFirst().map(AnnotationInfo::inner).orElse(null)); // Skip the WritableBeanStore factory (already consumed by createBeanStore()). if (WritableBeanStore.class.equals(rt) || BeanStore.class.equals(rt)) return; @@ -1267,7 +1269,7 @@ public class RestContext extends Context { bbs2.getDefaultSupplier(rt, name).ifPresent(sup -> beanStore.addSupplier(rt, sup, name)); return; } - beanStore.createBeanFromMethod(rt, resource.get(), RestContext::isRestInjectMethod) + beanStore.createBeanFromMethod(rt, resource.get(), RestContext::isBeanMethod) .ifPresent(y -> beanStore.addBean(rt, y, name)); }); @@ -1294,15 +1296,15 @@ public class RestContext extends Context { } } - // Back-fill @RestInject fields that were null before init hooks ran. + // Back-fill @Bean fields that were null before init hooks ran. // @formatter:off rci2.getAllFields().stream() - .filter(x -> x.hasAnnotation(RestInject.class)) + .filter(x -> x.hasAnnotation(Bean.class)) .forEach(x -> x.setIfNull( resource.get(), beanStore.getBean( x.getFieldType().inner(), - RestInjectAnnotation.name(x.getAnnotations(RestInject.class).findFirst().map(AnnotationInfo::inner).orElse(null)) + BeanAnnotation.name(x.getAnnotations(Bean.class).findFirst().map(AnnotationInfo::inner).orElse(null)) ).orElse(null) )); // @formatter:on @@ -1952,9 +1954,9 @@ public class RestContext extends Context { * <p> * The default call logger is {@link BasicCallLogger}. Override via {@link Rest#callLogger() @Rest(callLogger)} * on the resource class, by registering a {@link CallLogger} bean in the bean store, or by declaring a - * {@link RestInject @RestInject}-annotated static method on the resource class: + * {@link org.apache.juneau.commons.inject.Bean @Bean}-annotated static method on the resource class: * <p class='bjava'> - * <ja>@RestInject</ja> <jk>public static</jk> CallLogger myCallLogger(<i><args></i>) {...} + * <ja>@Bean</ja> <jk>public static</jk> CallLogger myCallLogger(<i><args></i>) {...} * </p> * * <h5 class='section'>See Also:</h5><ul> @@ -2463,7 +2465,7 @@ public class RestContext extends Context { * The bootstrap resolver has the same {@link Var} catalog as {@link #getVarResolver()} but does not have * {@link Messages} or {@link Config} beans wired in — it is used to resolve annotation attribute values * (e.g. <c>@Rest(messages=...)</c>) before those beans are built. Override via - * {@link RestInject @RestInject(name="bootstrapVarResolver")} on a static method of the resource class. + * {@link org.apache.juneau.commons.inject.Bean @Bean(name="bootstrapVarResolver")} on a static method of the resource class. * * @return The bootstrap var resolver in use by this resource. */ diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestOpContext.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestOpContext.java index 0688e0b339..7c58be3494 100644 --- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestOpContext.java +++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestOpContext.java @@ -232,8 +232,8 @@ public class RestOpContext extends Context implements Comparable<RestOpContext> * Walks the {@code @Rest(converters)} class chain (parent-to-child) followed by the * {@code @RestOp(converters)} method chain (parent-to-child). Op-level * {@code noInherit={"converters"}} cuts off the class-chain contribution. An - * {@code @RestInject RestConverterList} bean (either as a name-anonymous bean in the bean store - * or as a {@code @RestInject} method whose {@code methodScope} matches this operation's method + * {@code @Bean RestConverterList} bean (either as a name-anonymous bean in the bean store + * or as a {@code @Bean} method whose {@code methodScope} matches this operation's method * name) REPLACES the entire annotation-derived list. */ private final Memoizer<RestConverter[]> converters = memoizer(() -> { @@ -284,7 +284,7 @@ public class RestOpContext extends Context implements Comparable<RestOpContext> * {@code @Rest(defaultRequestAttributes)}), then walks the {@code @RestOp}/verb chain * (parent-to-child) and adds each entry — {@link NamedAttributeMap#add} uses put-semantics so * child entries override parent entries by name. An - * {@code @RestInject(name="defaultRequestAttributes") NamedAttributeMap} bean (matching this + * {@code @Bean(name="defaultRequestAttributes") NamedAttributeMap} bean (matching this * operation's method scope) REPLACES the entire result. */ private final Memoizer<NamedAttributeMap> defaultRequestAttributes = memoizer(() -> { @@ -306,7 +306,7 @@ public class RestOpContext extends Context implements Comparable<RestOpContext> * entry is applied with {@link PartList#setDefault} (first-in-chain wins per name). * Method-parameter {@link FormData @FormData} annotations with a * {@link Schema#default_()}/{@link Schema#df()} default are folded in last (also - * {@code setDefault} = first wins). An {@code @RestInject(name="defaultRequestFormData") PartList} + * {@code setDefault} = first wins). An {@code @Bean(name="defaultRequestFormData") PartList} * bean (matching this operation's method scope) REPLACES the entire result. */ private final Memoizer<PartList> defaultRequestFormData = memoizer(() -> { @@ -344,7 +344,7 @@ public class RestOpContext extends Context implements Comparable<RestOpContext> * Method-parameter {@link Header @Header} annotations with a * {@link Schema#default_()}/{@link Schema#df()} default are folded in last via * {@link HeaderList#set} (overrides any prior entry with the same name). An - * {@code @RestInject(name="defaultRequestHeaders") HeaderList} bean (matching this operation's + * {@code @Bean(name="defaultRequestHeaders") HeaderList} bean (matching this operation's * method scope) REPLACES the entire result. */ private final Memoizer<HeaderList> defaultRequestHeaders = memoizer(() -> { @@ -377,7 +377,7 @@ public class RestOpContext extends Context implements Comparable<RestOpContext> * entry is applied with {@link PartList#setDefault} (first-in-chain wins per name). * Method-parameter {@link Query @Query} annotations with a * {@link Schema#default_()}/{@link Schema#df()} default are folded in last (also - * {@code setDefault} = first wins). An {@code @RestInject(name="defaultRequestQueryData") PartList} + * {@code setDefault} = first wins). An {@code @Bean(name="defaultRequestQueryData") PartList} * bean (matching this operation's method scope) REPLACES the entire result. */ private final Memoizer<PartList> defaultRequestQueryData = memoizer(() -> { @@ -408,7 +408,7 @@ public class RestOpContext extends Context implements Comparable<RestOpContext> * {@code @Rest(defaultResponseHeaders)}), then walks the {@code @RestOp}/verb chain * (parent-to-child); each annotation's {@code defaultResponseHeaders} entries are applied with * {@link HeaderList#setDefault} (first-in-chain wins per name). An - * {@code @RestInject(name="defaultResponseHeaders") HeaderList} bean (matching this operation's + * {@code @Bean(name="defaultResponseHeaders") HeaderList} bean (matching this operation's * method scope) REPLACES the entire result. */ private final Memoizer<HeaderList> defaultResponseHeaders = memoizer(() -> { @@ -430,7 +430,7 @@ public class RestOpContext extends Context implements Comparable<RestOpContext> * array REPLACES the inherited set (with {@link Inherit} as a sentinel that re-injects the prior * set's entries at the specified position — matches the legacy {@code EncoderSet.Builder.set(...)} * semantics). Falls through to the class-level {@link RestContext#getEncoders()} when no op - * annotation declares encoders. An {@code @RestInject EncoderSet} bean (matching this operation's + * annotation declares encoders. An {@code @Bean EncoderSet} bean (matching this operation's * method scope) REPLACES the result entirely. */ private final Memoizer<EncoderSet> encoders = memoizer(() -> { @@ -464,7 +464,7 @@ public class RestOpContext extends Context implements Comparable<RestOpContext> * </ul> * * <p> - * An {@code @RestInject RestGuardList} bean (via the bean store or an {@code @RestInject} method + * An {@code @Bean RestGuardList} bean (via the bean store or an {@code @Bean} method * with matching {@code methodScope}) REPLACES the entire annotation-derived list (Decision #1). */ private final Memoizer<RestGuard[]> guards = memoizer(() -> { @@ -562,7 +562,7 @@ public class RestOpContext extends Context implements Comparable<RestOpContext> * {@code noInherit={"matchers"}}). Each annotation contributes its {@code matchers()} classes * (appended in chain order). The final non-blank {@code clientVersion()} (most-derived wins) * appends a single {@link ClientVersionMatcher} keyed off the resource's client-version header. - * An {@code @RestInject RestMatcherList} bean (via the bean store or an {@code @RestInject} + * An {@code @Bean RestMatcherList} bean (via the bean store or an {@code @Bean} * method with matching {@code methodScope}) REPLACES the entire annotation-derived list. */ private final Memoizer<RestMatcherList> matchersList = memoizer(() -> { @@ -634,7 +634,7 @@ public class RestOpContext extends Context implements Comparable<RestOpContext> * Walks the {@code @RestOp(parsers)} chain (parent-to-child); the most-derived non-empty * {@code parsers()} array REPLACES the entire inherited set. Falls through to the class-level * {@link RestContext#getParsers()} when no op annotation declares parsers. An - * {@code @RestInject ParserSet} bean (matching this operation's method scope) REPLACES the result. + * {@code @Bean ParserSet} bean (matching this operation's method scope) REPLACES the result. */ private final Memoizer<ParserSet> parsers = memoizer(() -> { var aa = appliedAnnotations(); @@ -698,7 +698,7 @@ public class RestOpContext extends Context implements Comparable<RestOpContext> * For RRPC operations with no explicit path, a trailing {@code "/*"} is appended so the matcher * matches anything below the method's URL. * {@code noInherit={"path"}} cuts off any further parent-chain contribution. A - * {@code @RestInject UrlPathMatcherList} bean (matching this operation's method scope) REPLACES + * {@code @Bean UrlPathMatcherList} bean (matching this operation's method scope) REPLACES * the entire result. */ @SuppressWarnings("java:S3776") @@ -788,7 +788,7 @@ public class RestOpContext extends Context implements Comparable<RestOpContext> * Walks the {@code @RestOp(serializers)} chain (parent-to-child); the most-derived non-empty * {@code serializers()} array REPLACES the entire inherited set. Falls through to the class-level * {@link RestContext#getSerializers()} when no op annotation declares serializers. An - * {@code @RestInject SerializerSet} bean (matching this operation's method scope) REPLACES the result. + * {@code @Bean SerializerSet} bean (matching this operation's method scope) REPLACES the result. */ private final Memoizer<SerializerSet> serializers = memoizer(() -> { var aa = appliedAnnotations(); @@ -858,17 +858,17 @@ public class RestOpContext extends Context implements Comparable<RestOpContext> } /** - * Returns {@code true} if the given method has a {@code @RestInject} annotation whose + * Returns {@code true} if the given method has a {@code @Bean} annotation whose * {@code methodScope} includes this operation's method name (or {@code "*"}). * * <p> - * Used by op-level memoizers when scanning the resource class for {@code @RestInject}-supplied + * Used by op-level memoizers when scanning the resource class for {@code @Bean}-supplied * composite-bean overrides ({@code RestConverterList}, {@code RestGuardList}, etc.). This is the * {@link RestOpContext}-scope peer of {@link Builder#matches(MethodInfo)} — kept in sync with that * one. */ private boolean matchesInjectScope(MethodInfo annotated) { - var a = annotated.getAnnotations(RestInject.class).findFirst().map(AnnotationInfo::inner).orElse(null); + var a = annotated.getAnnotations(Bean.class).findFirst().map(AnnotationInfo::inner).orElse(null); if (a != null) { for (var n : a.methodScope()) { if ("*".equals(n) || method.getName().equals(n)) @@ -880,7 +880,7 @@ public class RestOpContext extends Context implements Comparable<RestOpContext> /** * Same as {@link #matchesInjectScope(MethodInfo)} but additionally requires the - * {@link RestInject#name()} attribute to equal {@code beanName}. + * {@link Bean#name()} attribute to equal {@code beanName}. * * <p> * Used for named composite-bean overrides ({@code defaultRequestHeaders}, {@code defaultResponseHeaders}, @@ -888,7 +888,7 @@ public class RestOpContext extends Context implements Comparable<RestOpContext> * response headers). */ private boolean matchesInjectScope(MethodInfo annotated, String beanName) { - var a = annotated.getAnnotations(RestInject.class).findFirst().map(AnnotationInfo::inner).orElse(null); + var a = annotated.getAnnotations(Bean.class).findFirst().map(AnnotationInfo::inner).orElse(null); if (a != null) { if (! a.name().equals(beanName)) return false; 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 863f29cddc..6eaa7608ca 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 @@ -739,7 +739,7 @@ public @interface Rest { * * <p> * For programmatic equivalents, contribute an {@link org.apache.juneau.encoders.EncoderSet} bean via - * {@link RestInject @RestInject(name="encoders")}. + * {@link org.apache.juneau.commons.inject.Bean @Bean(name="encoders")}. * * <h5 class='section'>Inheritance Rules</h5> * <ul> @@ -908,7 +908,7 @@ public @interface Rest { * * <p> * For programmatic equivalents, contribute a {@link org.apache.juneau.parser.ParserSet} bean via - * {@link RestInject @RestInject(name="parsers")}. + * {@link org.apache.juneau.commons.inject.Bean @Bean(name="parsers")}. * * <h5 class='section'>Inheritance Rules</h5> * <ul> @@ -1273,7 +1273,7 @@ public @interface Rest { * * <p> * For programmatic equivalents, contribute a {@link org.apache.juneau.serializer.SerializerSet} bean via - * {@link RestInject @RestInject(name="serializers")}. + * {@link org.apache.juneau.commons.inject.Bean @Bean(name="serializers")}. * * <h5 class='section'>Inheritance Rules</h5> * <ul> diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestDelete.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestDelete.java index cdaa0df507..d76abb5fe2 100644 --- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestDelete.java +++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestDelete.java @@ -348,7 +348,7 @@ public @interface RestDelete { * * <p> * For programmatic equivalents, contribute a {@link org.apache.juneau.encoders.EncoderSet} bean via - * {@link RestInject @RestInject(name="encoders")} (use methodScope to scope to specific operation methods). + * {@link org.apache.juneau.commons.inject.Bean @Bean(name="encoders")} (use methodScope to scope to specific operation methods). * * <h5 class='section'>See Also:</h5><ul> * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/RestServerEncoders">Encoders</a> diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestGet.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestGet.java index 83a7f505a9..63bb93ae4e 100644 --- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestGet.java +++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestGet.java @@ -365,7 +365,7 @@ public @interface RestGet { * * <p> * For programmatic equivalents, contribute a {@link org.apache.juneau.encoders.EncoderSet} bean via - * {@link RestInject @RestInject(name="encoders")} (use methodScope to scope to specific operation methods). + * {@link org.apache.juneau.commons.inject.Bean @Bean(name="encoders")} (use methodScope to scope to specific operation methods). * * <h5 class='section'>See Also:</h5><ul> * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/RestServerEncoders">Encoders</a> @@ -625,7 +625,7 @@ public @interface RestGet { * * <p> * For programmatic equivalents, contribute a {@link org.apache.juneau.serializer.SerializerSet} bean via - * {@link RestInject @RestInject(name="serializers")} (use methodScope to scope to specific operation methods). + * {@link org.apache.juneau.commons.inject.Bean @Bean(name="serializers")} (use methodScope to scope to specific operation methods). * * <h5 class='section'>See Also:</h5><ul> * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/Marshalling">Marshalling</a> diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestInit.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestInit.java index 56dbeea668..51b86aa0fa 100644 --- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestInit.java +++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestInit.java @@ -38,7 +38,7 @@ import jakarta.servlet.*; * Method parameters are resolved from the * {@link org.apache.juneau.commons.inject.BeanStore bean store} the same way as any other Juneau-injected * method. {@link jakarta.servlet.ServletConfig}, {@link jakarta.servlet.ServletContext}, the resource instance - * itself, and any bean registered via {@link org.apache.juneau.rest.annotation.RestInject @RestInject} or the + * itself, and any bean registered via {@link org.apache.juneau.commons.inject.Bean @Bean} or the * configured bean-store hooks are all resolvable. Zero-argument variants are also supported. * * <p> @@ -47,17 +47,17 @@ import jakarta.servlet.*; * <ul> * <li><b>Per-operation:</b> {@code @RestInit public void init(RestOpContext.Builder b)} (invoked once per * <code>@RestOp</code>-annotated method) — replaced by declarative <code>@RestOp(...)</code> attributes, - * <code>@RestInject(name=, methodScope=)</code>-named beans, or class-level <code>@RestInit</code> hooks. + * <code>@Bean(name=, methodScope=)</code>-named beans, or class-level <code>@RestInit</code> hooks. * <li><b>Class-level Builder injection:</b> {@code @RestInit public void init(RestContext.Builder b)} (which * injected the in-flight resource-level builder so the hook could imperatively mutate it) — replaced by the * same declarative surfaces. Migrate by moving each <code>builder.xxx(...)</code> call to the equivalent - * <code>@Rest(xxx=...)</code> annotation attribute or {@code @RestInject}-named bean. + * <code>@Rest(xxx=...)</code> annotation attribute or {@code @Bean}-named bean. * </ul> * * <p> * The remaining supported {@code @RestInit} hook shape is one whose parameters are bean-store-resolvable * (no {@code RestContext.Builder} or {@code RestOpContext.Builder}). The example below uses the resource - * instance itself, but {@code @RestInject}-supplied beans, {@code ServletConfig}, etc. work the same way. + * instance itself, but {@code @Bean}-supplied beans, {@code ServletConfig}, etc. work the same way. * * <h5 class='figure'>Example:</h5> * <p class='bjava'> diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestInject.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestInject.java deleted file mode 100644 index cc5e74605e..0000000000 --- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestInject.java +++ /dev/null @@ -1,249 +0,0 @@ -/* - * 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 java.util.logging.*; - -import org.apache.juneau.*; -import org.apache.juneau.config.*; -import org.apache.juneau.cp.*; -import org.apache.juneau.encoders.*; -import org.apache.juneau.http.header.*; -import org.apache.juneau.http.part.*; -import org.apache.juneau.httppart.*; -import org.apache.juneau.jsonschema.*; -import org.apache.juneau.parser.*; -import org.apache.juneau.rest.*; -import org.apache.juneau.rest.arg.*; -import org.apache.juneau.rest.converter.*; -import org.apache.juneau.rest.debug.*; -import org.apache.juneau.rest.guard.*; -import org.apache.juneau.rest.httppart.*; -import org.apache.juneau.rest.logger.*; -import org.apache.juneau.rest.matcher.*; -import org.apache.juneau.rest.processor.*; -import org.apache.juneau.rest.staticfile.*; -import org.apache.juneau.rest.stats.*; -import org.apache.juneau.rest.swagger.*; -import org.apache.juneau.rest.util.*; -import org.apache.juneau.serializer.*; -import org.apache.juneau.svl.*; - -/** - * Rest bean injection annotation. - * - * <p> - * Used on methods of {@link Rest}-annotated classes to denote methods and fields that override and customize beans - * used by the REST framework. - * - * <h5 class='figure'>Example</h5> - * <p class='bcode'> - * <jc>// Rest resource that uses a customized call logger.</jc> - * <ja>@Rest</ja> - * <jk>public class</jk> MyRest <jk>extends</jk> BasicRestServlet { - * - * <jc>// Option #1: As a field.</jc> - * <ja>@RestInject</ja> - * CallLogger <jf>myCallLogger</jf> = CallLogger.<jsm>create</jsm>().logger(<js>"mylogger"</js>).build(); - * - * <jc>// Option #2: As a method.</jc> - * <ja>@RestInject</ja> - * <jk>public</jk> CallLogger myCallLogger() { - * <jk>return</jk> CallLogger.<jsm>create</jsm>().logger(<js>"mylogger"</js>).build(); - * } - * } - * </p> - * - * <p> - * The {@link RestInject#name()}/{@link RestInject#value()} attributes are used to differentiate between named beans. - * </p> - * <h5 class='figure'>Example</h5> - * <p class='bcode'> - * <jc>// Customized default request headers.</jc> - * <ja>@RestInject</ja>(<js>"defaultRequestHeaders"</js>) - * HeaderList <jf>defaultRequestHeaders</jf> = HeaderList.<jsm>create</jsm>().set(ContentType.<jsf>TEXT_PLAIN</jsf>).build(); - * - * <jc>// Customized default response headers.</jc> - * <ja>@RestInject</ja>(<js>"defaultResponseHeaders"</js>) - * HeaderList <jf>defaultResponseHeaders</jf> = HeaderList.<jsm>create</jsm>().set(ContentType.<jsf>TEXT_PLAIN</jsf>).build(); - * </p> - * - * <p> - * The {@link RestInject#methodScope()} attribute is used to define beans in the scope of specific {@link RestOp}-annotated methods. - * </p> - * <h5 class='figure'>Example</h5> - * <p class='bcode'> - * <jc>// Set a default header on a specific REST method.</jc> - * <jc>// Input parameter is the default header list builder with all annotations applied.</jc> - * <ja>@RestInject</ja>(name=<js>"defaultRequestHeaders"</js>, methodScope=<js>"myRestMethod"</js>) - * <jk>public</jk> HeaderList.Builder myRequestHeaders(HeaderList.Builder <jv>builder</jv>) { - * <jk>return</jk> <jv>builder</jv>.set(ContentType.<jsf>TEXT_PLAIN</jsf>); - * } - * - * <jc>// Method that picks up default header defined above.</jc> - * <ja>@RestGet</ja> - * <jk>public</jk> Object myRestMethod(ContentType <jv>contentType</jv>) { ... } - * </p> - * - * <p> - * This annotation can also be used to inject arbitrary beans into the bean store which allows them to be - * passed as resolved parameters on {@link RestOp}-annotated methods. - * </p> - * <h5 class='figure'>Example</h5> - * <p class='bcode'> - * <jc>// Custom beans injected into the bean store.</jc> - * <ja>@RestInject</ja> MyBean <jv>myBean1</jv> = <jk>new</jk> MyBean(); - * <ja>@RestInject</ja>(<js>"myBean2"</js>) MyBean <jv>myBean2</jv> = <jk>new</jk> MyBean(); - * - * <jc>// Method that uses injected beans.</jc> - * <ja>@RestGet</ja> - * <jk>public</jk> Object doGet(MyBean <jv>myBean1</jv>, <ja>@Name</ja>(<js>"myBean2"</js>) MyBean <jv>myBean2</jv>) { ... } - * </p> - * - * <p> - * This annotation can also be used on uninitialized fields. When fields are uninitialized, they will - * be set during initialization based on beans found in the bean store. - * </p> - * <h5 class='figure'>Example</h5> - * <p class='bcode'> - * <jc>// Fields that get set during initialization based on beans found in the bean store.</jc> - * <ja>@RestInject</ja> CallLogger <jf>callLogger</jf>; - * <ja>@RestInject</ja> BeanStore <jf>beanStore</jf>; <jc>// Note that the BeanStore itself can be accessed this way.</jc> - * </p> - * - * <h5 class='section'>Notes:</h5><ul> - * <li class='note'>Methods and fields can be static or non-static. - * <li class='note'>Any injectable beans (including spring beans) can be passed as arguments into methods. - * <li class='note'>Bean names are required when multiple beans of the same type exist in the bean store. - * <li class='note'>By default, the injected bean scope is class-level (applies to the entire class). The - * {@link RestInject#methodScope()} annotation can be used to apply to method-level only (when applicable). - * </ul> - * - * <h5 class='section'>Precedence (since 9.5.0):</h5> - * <p> - * {@code @RestInject} acts as a <i>programmable default</i>, analogous to Spring's - * <c>@ConditionalOnMissingBean</c>. When a {@link RestContext} resolves a framework-managed bean - * (<c>CallLogger</c>, <c>EncoderSet</c>, <c>SerializerSet</c>, <c>ParserSet</c>, <c>ThrownStore</c>, - * <c>Config</c>, <c>VarResolver</c>, <c>HttpPartSerializer</c>, <c>HttpPartParser</c>, etc.), the lookup - * walks the following tiers in order, returning the first hit: - * </p> - * <ol> - * <li><b>Overriding-parent bean store</b> — Spring beans (in <c>juneau-rest-server-springboot</c> deployments, - * via <c>SpringBeanStore</c>), or any bean reachable through the configured overriding-parent - * bean-store chain.</li> - * <li><b>{@code @RestInject} method/field on the resource class</b> — registered as a regular bean-store - * entry, beating the framework default.</li> - * <li><b>Memoizer-backed framework default</b> — built into {@link RestContext} as a default supplier.</li> - * </ol> - * <p> - * In other words: a Spring <c>@Bean</c> of type <c>CallLogger</c> wins over a {@code @RestInject CallLogger} - * method on the same servlet, which in turn wins over the framework's built-in <c>BasicCallLogger</c>. Non-Spring - * deployments have an empty overriding-parent layer, so the chain naturally collapses to - * {@code @RestInject > default}. - * </p> - * <p> - * Prior to 9.5 the order was {@code @RestInject > Spring > default}. See the 9.5.0 release notes for migration - * guidance if you need to keep that legacy behavior (typically by removing the Spring <c>@Bean</c> or marking the - * {@code @RestInject} method's type with a Spring-native override such as <c>@Primary</c>). - * </p> - * - * <p> - * Any of the following types can be customized via injection: - * <table class='w800 styled'> - * <tr><th>Bean class</td><th>Bean qualifying names</th><th>Scope</th></tr> - * <tr><td>{@link MarshallingContext}<br>{@link org.apache.juneau.MarshallingContext.Builder}</td><td></td><td>class<br>method</td></tr> - * <tr><td>{@link org.apache.juneau.commons.inject.BeanStore BeanStore}<br>{@link org.apache.juneau.commons.inject.WritableBeanStore WritableBeanStore}</td><td></td><td>class</td></tr> - * <tr><td>{@link CallLogger}</td><td></td><td>class</td></tr> - * <tr><td>{@link Config}</td><td></td><td>class</td></tr> - * <tr><td>{@link DebugEnablement}</td><td></td><td>class</td></tr> - * <tr><td>{@link EncoderSet}<br>{@link org.apache.juneau.encoders.EncoderSet.Builder}</td><td></td><td>class<br>method</td></tr> - * <tr><td>{@link FileFinder}<br>{@link org.apache.juneau.cp.FileFinder.Builder}</td><td></td><td>class</td></tr> - * <tr><td>{@link HeaderList}<br>{@link org.apache.juneau.http.header.HeaderList}</td><td><js>"defaultRequestHeaders"</js><br><js>"defaultResponseHeaders"</js></td><td>class<br>method</td></tr> - * <tr><td>{@link HttpPartParser}<br>{@link org.apache.juneau.httppart.HttpPartParser.Creator}</td><td></td><td>class<br>method</td></tr> - * <tr><td>{@link HttpPartSerializer}<br>{@link org.apache.juneau.httppart.HttpPartSerializer.Creator}</td><td></td><td>class<br>method</td></tr> - * <tr><td>{@link JsonSchemaGenerator}<br>{@link org.apache.juneau.jsonschema.JsonSchemaGenerator.Builder}</td><td></td><td>class<br>method</td></tr> - * <tr><td>{@link Logger}</td><td></td><td>class</td></tr> - * <tr><td>{@link Messages}<br>{@link org.apache.juneau.cp.Messages.Builder}</td><td></td><td>class</td></tr> - * <tr><td>{@link MethodExecStore}<br>{@link org.apache.juneau.rest.stats.MethodExecStore.Builder}</td><td></td><td>class</td></tr> - * <tr><td>{@link MethodList}</td><td><js>"destroyMethods"</js><br><js>"endCallMethods"</js><br><js>"postCallMethods"</js><br><js>"postInitChildFirstMethods"</js><br><js>"postInitMethods"</js><br><js>"preCallMethods"</js><br><js>"startCallMethods"</js></td><td>class</td></tr> - * <tr><td>{@link NamedAttributeMap}<br>{@link org.apache.juneau.rest.httppart.NamedAttributeMap}</td><td><js>"defaultRequestAttributes"</js></td><td>class<br>method</td></tr> - * <tr><td>{@link ParserSet}<br>{@link org.apache.juneau.parser.ParserSet.Builder}</td><td></td><td>class<br>method</td></tr> - * <tr><td>{@link PartList}<br>{@link org.apache.juneau.http.part.PartList}</td><td><js>"defaultRequestQueryData"</js><br><js>"defaultRequestFormData"</js></td><td>method</td></tr> - * <tr><td>{@link ResponseProcessorList}<br>{@link org.apache.juneau.rest.processor.ResponseProcessorList.Builder}</td><td></td><td>class</td></tr> - * <tr><td>{@link RestChildren}<br>{@link org.apache.juneau.rest.RestChildren.Builder}</td><td></td><td>class</td></tr> - * <tr><td>{@link RestConverterList}<br>{@link org.apache.juneau.rest.converter.RestConverterList.Builder}</td><td></td><td>method</td></tr> - * <tr><td>{@link RestGuardList}<br>{@link org.apache.juneau.rest.guard.RestGuardList.Builder}</td><td></td><td>method</td></tr> - * <tr><td>{@link RestMatcherList}<br>{@link org.apache.juneau.rest.matcher.RestMatcherList.Builder}</td><td></td><td>method</td></tr> - * <tr><td>{@link RestOpArgList}<br>{@link org.apache.juneau.rest.arg.RestOpArgList.Builder}</td><td></td><td>class</td></tr> - * <tr><td>{@link RestOperations}<br>{@link org.apache.juneau.rest.RestOperations.Builder}</td><td></td><td>class</td></tr> - * <tr><td>{@link SerializerSet}<br>{@link org.apache.juneau.serializer.SerializerSet.Builder}</td><td></td><td>class<br>method</td></tr> - * <tr><td>{@link StaticFiles}</td><td></td><td>class</td></tr> - * <tr><td>{@link SwaggerProvider}</td><td></td><td>class</td></tr> - * <tr><td>{@link ThrownStore}<br>{@link org.apache.juneau.rest.stats.ThrownStore.Builder}</td><td></td><td>class</td></tr> - * <tr><td>{@link UrlPathMatcherList}</td><td></td><td>method</td></tr> - * <tr><td>{@link VarList}</td><td></td><td>class</td></tr> - * <tr><td>{@link VarResolver}<br>{@link org.apache.juneau.svl.VarResolver.Builder}</td><td></td><td>class</td></tr> - * </table> - */ -@Target({ METHOD, FIELD }) -@Retention(RUNTIME) -@Inherited -public @interface RestInject { - - /** - * Optional description for the exposed API. - * - * @return The annotation value. - * @since 9.2.0 - */ - String[] description() default {}; - - /** - * The short names of the methods that this annotation applies to. - * - * <p> - * Can use <js>"*"</js> to apply to all methods. - * - * <p> - * Ignored for class-level scope. - * - * @return The short names of the methods that this annotation applies to, or empty if class-scope. - */ - String[] methodScope() default {}; - - /** - * The bean name to use to distinguish beans of the same type for different purposes. - * - * <p> - * For example, there are two {@link HeaderList} beans: <js>"defaultRequestHeaders"</js> and <js>"defaultResponseHeaders"</js>. This annotation - * would be used to differentiate between them. - * - * @return The bean name to use to distinguish beans of the same type for different purposes, or blank if bean type is unique. - */ - String name() default ""; - - /** - * Same as {@link #name()}. - * - * @return The bean name to use to distinguish beans of the same type for different purposes, or blank if bean type is unique. - */ - String value() default ""; -} \ No newline at end of file diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestOp.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestOp.java index 56d063d3b4..9c8a4945de 100644 --- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestOp.java +++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestOp.java @@ -427,7 +427,7 @@ public @interface RestOp { * * <p> * For programmatic equivalents, contribute a {@link org.apache.juneau.encoders.EncoderSet} bean via - * {@link RestInject @RestInject(name="encoders")} (use methodScope to scope to specific operation methods). + * {@link org.apache.juneau.commons.inject.Bean @Bean(name="encoders")} (use methodScope to scope to specific operation methods). * * <h5 class='section'>See Also:</h5><ul> * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/RestServerEncoders">Encoders</a> @@ -586,7 +586,7 @@ public @interface RestOp { * * <p> * For programmatic equivalents, contribute a {@link org.apache.juneau.parser.ParserSet} bean via - * {@link RestInject @RestInject(name="parsers")} (use methodScope to scope to specific operation methods). + * {@link org.apache.juneau.commons.inject.Bean @Bean(name="parsers")} (use methodScope to scope to specific operation methods). * * <h5 class='section'>See Also:</h5><ul> * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/Marshalling">Marshalling</a> @@ -854,7 +854,7 @@ public @interface RestOp { * * <p> * For programmatic equivalents, contribute a {@link org.apache.juneau.serializer.SerializerSet} bean via - * {@link RestInject @RestInject(name="serializers")} (use methodScope to scope to specific operation methods). + * {@link org.apache.juneau.commons.inject.Bean @Bean(name="serializers")} (use methodScope to scope to specific operation methods). * * <h5 class='section'>See Also:</h5><ul> * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/Marshalling">Marshalling</a> diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestOptions.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestOptions.java index 1f16cbd242..5f822150d8 100644 --- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestOptions.java +++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestOptions.java @@ -365,7 +365,7 @@ public @interface RestOptions { * * <p> * For programmatic equivalents, contribute a {@link org.apache.juneau.encoders.EncoderSet} bean via - * {@link RestInject @RestInject(name="encoders")} (use methodScope to scope to specific operation methods). + * {@link org.apache.juneau.commons.inject.Bean @Bean(name="encoders")} (use methodScope to scope to specific operation methods). * * <h5 class='section'>See Also:</h5><ul> * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/RestServerEncoders">Encoders</a> @@ -625,7 +625,7 @@ public @interface RestOptions { * * <p> * For programmatic equivalents, contribute a {@link org.apache.juneau.serializer.SerializerSet} bean via - * {@link RestInject @RestInject(name="serializers")} (use methodScope to scope to specific operation methods). + * {@link org.apache.juneau.commons.inject.Bean @Bean(name="serializers")} (use methodScope to scope to specific operation methods). * * <h5 class='section'>See Also:</h5><ul> * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/Marshalling">Marshalling</a> diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestPatch.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestPatch.java index 28fa37a4de..3907934931 100644 --- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestPatch.java +++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestPatch.java @@ -427,7 +427,7 @@ public @interface RestPatch { * * <p> * For programmatic equivalents, contribute a {@link org.apache.juneau.encoders.EncoderSet} bean via - * {@link RestInject @RestInject(name="encoders")} (use methodScope to scope to specific operation methods). + * {@link org.apache.juneau.commons.inject.Bean @Bean(name="encoders")} (use methodScope to scope to specific operation methods). * * <h5 class='section'>See Also:</h5><ul> * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/RestServerEncoders">Encoders</a> @@ -535,7 +535,7 @@ public @interface RestPatch { * * <p> * For programmatic equivalents, contribute a {@link org.apache.juneau.parser.ParserSet} bean via - * {@link RestInject @RestInject(name="parsers")} (use methodScope to scope to specific operation methods). + * {@link org.apache.juneau.commons.inject.Bean @Bean(name="parsers")} (use methodScope to scope to specific operation methods). * * <h5 class='section'>See Also:</h5><ul> * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/Marshalling">Marshalling</a> @@ -776,7 +776,7 @@ public @interface RestPatch { * * <p> * For programmatic equivalents, contribute a {@link org.apache.juneau.serializer.SerializerSet} bean via - * {@link RestInject @RestInject(name="serializers")} (use methodScope to scope to specific operation methods). + * {@link org.apache.juneau.commons.inject.Bean @Bean(name="serializers")} (use methodScope to scope to specific operation methods). * * <h5 class='section'>See Also:</h5><ul> * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/Marshalling">Marshalling</a> diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestPost.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestPost.java index 99dd2a3020..fefca60ee5 100644 --- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestPost.java +++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestPost.java @@ -427,7 +427,7 @@ public @interface RestPost { * * <p> * For programmatic equivalents, contribute a {@link org.apache.juneau.encoders.EncoderSet} bean via - * {@link RestInject @RestInject(name="encoders")} (use methodScope to scope to specific operation methods). + * {@link org.apache.juneau.commons.inject.Bean @Bean(name="encoders")} (use methodScope to scope to specific operation methods). * * <h5 class='section'>See Also:</h5><ul> * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/RestServerEncoders">Encoders</a> @@ -535,7 +535,7 @@ public @interface RestPost { * * <p> * For programmatic equivalents, contribute a {@link org.apache.juneau.parser.ParserSet} bean via - * {@link RestInject @RestInject(name="parsers")} (use methodScope to scope to specific operation methods). + * {@link org.apache.juneau.commons.inject.Bean @Bean(name="parsers")} (use methodScope to scope to specific operation methods). * * <h5 class='section'>See Also:</h5><ul> * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/Marshalling">Marshalling</a> @@ -776,7 +776,7 @@ public @interface RestPost { * * <p> * For programmatic equivalents, contribute a {@link org.apache.juneau.serializer.SerializerSet} bean via - * {@link RestInject @RestInject(name="serializers")} (use methodScope to scope to specific operation methods). + * {@link org.apache.juneau.commons.inject.Bean @Bean(name="serializers")} (use methodScope to scope to specific operation methods). * * <h5 class='section'>See Also:</h5><ul> * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/Marshalling">Marshalling</a> diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestPut.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestPut.java index 4bd2f98e42..5caac6d691 100644 --- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestPut.java +++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestPut.java @@ -427,7 +427,7 @@ public @interface RestPut { * * <p> * For programmatic equivalents, contribute a {@link org.apache.juneau.encoders.EncoderSet} bean via - * {@link RestInject @RestInject(name="encoders")} (use methodScope to scope to specific operation methods). + * {@link org.apache.juneau.commons.inject.Bean @Bean(name="encoders")} (use methodScope to scope to specific operation methods). * * <h5 class='section'>See Also:</h5><ul> * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/RestServerEncoders">Encoders</a> @@ -535,7 +535,7 @@ public @interface RestPut { * * <p> * For programmatic equivalents, contribute a {@link org.apache.juneau.parser.ParserSet} bean via - * {@link RestInject @RestInject(name="parsers")} (use methodScope to scope to specific operation methods). + * {@link org.apache.juneau.commons.inject.Bean @Bean(name="parsers")} (use methodScope to scope to specific operation methods). * * <h5 class='section'>See Also:</h5><ul> * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/Marshalling">Marshalling</a> @@ -776,7 +776,7 @@ public @interface RestPut { * * <p> * For programmatic equivalents, contribute a {@link org.apache.juneau.serializer.SerializerSet} bean via - * {@link RestInject @RestInject(name="serializers")} (use methodScope to scope to specific operation methods). + * {@link org.apache.juneau.commons.inject.Bean @Bean(name="serializers")} (use methodScope to scope to specific operation methods). * * <h5 class='section'>See Also:</h5><ul> * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/Marshalling">Marshalling</a> diff --git a/juneau-utest/src/test/java/org/apache/juneau/rest/RestContext_Builder_Test.java b/juneau-utest/src/test/java/org/apache/juneau/rest/RestContext_Builder_Test.java index 051cfb9623..8f5156f46a 100644 --- a/juneau-utest/src/test/java/org/apache/juneau/rest/RestContext_Builder_Test.java +++ b/juneau-utest/src/test/java/org/apache/juneau/rest/RestContext_Builder_Test.java @@ -37,7 +37,7 @@ class RestContext_Builder_Test extends TestBase { @Rest public static class A1 { - @RestInject static WritableBeanStore beanStore; + @Bean static WritableBeanStore beanStore; } @Test void a01_createBeanStore_default() { @@ -47,9 +47,9 @@ class RestContext_Builder_Test extends TestBase { @Rest public static class A4 { - @RestInject static WritableBeanStore beanStore; + @Bean static WritableBeanStore beanStore; - @RestInject WritableBeanStore beanStore() { + @Bean WritableBeanStore beanStore() { return new BasicBeanStore(null).addBean(A.class, new A()); } } @@ -60,7 +60,7 @@ class RestContext_Builder_Test extends TestBase { } //----------------------------------------------------------------------------------------------------------------- - // @RestInject on fields. + // @Bean on fields. //----------------------------------------------------------------------------------------------------------------- public static class B { @@ -73,11 +73,11 @@ class RestContext_Builder_Test extends TestBase { @Rest public static class B1a implements BasicJsonConfig { - @RestInject static B b1 = new B(1); - @RestInject(name="b2") B b2 = new B(2); + @Bean static B b1 = new B(1); + @Bean(name="b2") B b2 = new B(2); - @RestInject static B b3; - @RestInject(name="b2") B b4; + @Bean static B b3; + @Bean(name="b2") B b4; @RestGet("/a1") public B a1(B b) { return b; } @RestGet("/a2") public B a2(@Named("b2") B b) { return b; } diff --git a/juneau-utest/src/test/java/org/apache/juneau/rest/RestContext_Precedence_Test.java b/juneau-utest/src/test/java/org/apache/juneau/rest/RestContext_Precedence_Test.java index 559c46c9a9..0bcc3495e0 100644 --- a/juneau-utest/src/test/java/org/apache/juneau/rest/RestContext_Precedence_Test.java +++ b/juneau-utest/src/test/java/org/apache/juneau/rest/RestContext_Precedence_Test.java @@ -35,25 +35,25 @@ import org.junit.jupiter.api.*; * <p> * Resolution order, top-to-bottom: * <ol> - * <li>{@code @RestInject} factory methods on the resource. For non-framework types these are + * <li>{@code @Bean} factory methods on the resource. For non-framework types these are * registered as local entries directly; for framework types (e.g. {@link CallLogger}, - * {@link ThrownStore}) the per-bean memoizer captures the {@code @RestInject} value, and + * {@link ThrownStore}) the per-bean memoizer captures the {@code @Bean} value, and * {@code RestContext} promotes the memoizer-backed supplier into a local entry so that - * {@code @RestInject} uniformly wins. + * {@code @Bean} uniformly wins. * <li>User-supplied bean store from - * {@code @RestInject WritableBeanStore createBeanStore(...)}, including its + * {@code @Bean WritableBeanStore createBeanStore(...)}, including its * {@link org.apache.juneau.rest.springboot.SpringBeanStore}-style fallback to a backing - * {@code ApplicationContext}. Consulted only when no {@code @RestInject} factory method + * {@code ApplicationContext}. Consulted only when no {@code @Bean} factory method * exists for the type. * <li>Memoizer-backed framework defaults (e.g. {@link BasicCallLogger}). Fire only when neither - * a per-resource {@code @RestInject} method nor a user-supplied bean-store binding exists. + * a per-resource {@code @Bean} method nor a user-supplied bean-store binding exists. * </ol> * * <p> - * Net effect: <b>{@code @RestInject} factory methods on the resource take precedence over + * Net effect: <b>{@code @Bean} factory methods on the resource take precedence over * Spring/user-supplied bindings, which in turn take precedence over framework defaults.</b> * Spring/user-supplied bindings act as drop-in overrides for any type the resource doesn't - * customize via {@code @RestInject}, with the framework filling in defaults for anything else. + * customize via {@code @Bean}, with the framework filling in defaults for anything else. */ class RestContext_Precedence_Test extends TestBase { @@ -62,7 +62,7 @@ class RestContext_Precedence_Test extends TestBase { //----------------------------------------------------------------------------------------------------------------- private static final CallLogger SPRING_LOGGER = BasicCallLogger.create(BasicBeanStore.INSTANCE).build(); - private static final CallLogger RESTINJECT_LOGGER = BasicCallLogger.create(BasicBeanStore.INSTANCE).build(); + private static final CallLogger BEAN_LOGGER = BasicCallLogger.create(BasicBeanStore.INSTANCE).build(); //----------------------------------------------------------------------------------------------------------------- // Spring-substitute bean store @@ -127,42 +127,42 @@ class RestContext_Precedence_Test extends TestBase { } //----------------------------------------------------------------------------------------------------------------- - // 1. @RestInject beats the memoizer-backed framework default. + // 1. @Bean beats the memoizer-backed framework default. //----------------------------------------------------------------------------------------------------------------- @Rest - public static class A_RestInjectBeatsDefault { - @RestInject static CallLogger callLoggerCapture; - @RestInject public CallLogger callLogger() { return RESTINJECT_LOGGER; } + public static class A_BeanBeatsDefault { + @Bean static CallLogger callLoggerCapture; + @Bean public CallLogger callLogger() { return BEAN_LOGGER; } } @Test void a01_restInject_beatsDefault() { - MockRestClient.buildLax(A_RestInjectBeatsDefault.class); - assertSame(RESTINJECT_LOGGER, A_RestInjectBeatsDefault.callLoggerCapture); + MockRestClient.buildLax(A_BeanBeatsDefault.class); + assertSame(BEAN_LOGGER, A_BeanBeatsDefault.callLoggerCapture); } //----------------------------------------------------------------------------------------------------------------- - // 2. @RestInject beats Spring (Spring at fallback layer). + // 2. @Bean beats Spring (Spring at fallback layer). //----------------------------------------------------------------------------------------------------------------- @Rest - public static class B_RestInjectBeatsSpring { - @RestInject static CallLogger callLoggerCapture; - @RestInject public WritableBeanStore createBeanStore() { return springLikeBeanStore(); } - @RestInject public CallLogger callLogger() { return RESTINJECT_LOGGER; } + public static class B_BeanBeatsSpring { + @Bean static CallLogger callLoggerCapture; + @Bean public WritableBeanStore createBeanStore() { return springLikeBeanStore(); } + @Bean public CallLogger callLogger() { return BEAN_LOGGER; } } @Test void b01_restInject_beatsSpring() { - MockRestClient.buildLax(B_RestInjectBeatsSpring.class); - assertSame(RESTINJECT_LOGGER, B_RestInjectBeatsSpring.callLoggerCapture, "@RestInject method should win over Spring fallback"); + MockRestClient.buildLax(B_BeanBeatsSpring.class); + assertSame(BEAN_LOGGER, B_BeanBeatsSpring.callLoggerCapture, "@Bean method should win over Spring fallback"); } //----------------------------------------------------------------------------------------------------------------- - // 3. Spring beats the framework default for framework bean types (when no @RestInject method exists). + // 3. Spring beats the framework default for framework bean types (when no @Bean method exists). // - // Without an @RestInject CallLogger method, the framework's memoizer-backed default supplier sits + // Without an @Bean CallLogger method, the framework's memoizer-backed default supplier sits // at level 4 of resolve(), below the user-supplied bean store (parent at level 3). So Spring // overrides the framework default. This is intentional: if the user wired a CallLogger into Spring, // they meant it to be used in preference to the auto-configured BasicCallLogger. @@ -170,14 +170,14 @@ class RestContext_Precedence_Test extends TestBase { @Rest public static class C_SpringBeatsDefault { - @RestInject static CallLogger callLoggerCapture; - @RestInject public WritableBeanStore createBeanStore() { return springLikeBeanStore(); } + @Bean static CallLogger callLoggerCapture; + @Bean public WritableBeanStore createBeanStore() { return springLikeBeanStore(); } } @Test void c01_spring_beatsDefault_forFrameworkBean() { MockRestClient.buildLax(C_SpringBeatsDefault.class); - assertSame(SPRING_LOGGER, C_SpringBeatsDefault.callLoggerCapture, "User-supplied bean store binding should win over framework default when no @RestInject is declared for the type"); + assertSame(SPRING_LOGGER, C_SpringBeatsDefault.callLoggerCapture, "User-supplied bean store binding should win over framework default when no @Bean is declared for the type"); } //----------------------------------------------------------------------------------------------------------------- @@ -199,32 +199,32 @@ class RestContext_Precedence_Test extends TestBase { @Rest public static class D_SpringFallbackForUserBean { - @RestInject static CustomBean customBeanCapture; - @RestInject public WritableBeanStore createBeanStore() { return springLikeBeanStoreWithCustomBean(); } + @Bean static CustomBean customBeanCapture; + @Bean public WritableBeanStore createBeanStore() { return springLikeBeanStoreWithCustomBean(); } } @Test void d01_spring_fillsInForUserBean() { MockRestClient.buildLax(D_SpringFallbackForUserBean.class); - assertSame(SPRING_CUSTOM, D_SpringFallbackForUserBean.customBeanCapture, "Spring fallback should provide CustomBean since framework has no default for it and there is no @RestInject method"); + assertSame(SPRING_CUSTOM, D_SpringFallbackForUserBean.customBeanCapture, "Spring fallback should provide CustomBean since framework has no default for it and there is no @Bean method"); } //----------------------------------------------------------------------------------------------------------------- - // 5. @RestInject for a non-framework bean type beats Spring fallback. + // 5. @Bean for a non-framework bean type beats Spring fallback. //----------------------------------------------------------------------------------------------------------------- - private static final CustomBean RESTINJECT_CUSTOM = new CustomBean("from-restinject"); + private static final CustomBean BEAN_CUSTOM = new CustomBean("from-restinject"); @Rest - public static class E_RestInjectBeatsSpringForUserBean { - @RestInject static CustomBean customBeanCapture; - @RestInject public WritableBeanStore createBeanStore() { return springLikeBeanStoreWithCustomBean(); } - @RestInject public CustomBean customBean() { return RESTINJECT_CUSTOM; } + public static class E_BeanBeatsSpringForUserBean { + @Bean static CustomBean customBeanCapture; + @Bean public WritableBeanStore createBeanStore() { return springLikeBeanStoreWithCustomBean(); } + @Bean public CustomBean customBean() { return BEAN_CUSTOM; } } @Test void e01_restInject_beatsSpring_forUserBean() { - MockRestClient.buildLax(E_RestInjectBeatsSpringForUserBean.class); - assertSame(RESTINJECT_CUSTOM, E_RestInjectBeatsSpringForUserBean.customBeanCapture, "@RestInject should win over Spring fallback for user-defined bean types too"); + MockRestClient.buildLax(E_BeanBeatsSpringForUserBean.class); + assertSame(BEAN_CUSTOM, E_BeanBeatsSpringForUserBean.customBeanCapture, "@Bean should win over Spring fallback for user-defined bean types too"); } } diff --git a/juneau-utest/src/test/java/org/apache/juneau/rest/annotation/RestInit_Test.java b/juneau-utest/src/test/java/org/apache/juneau/rest/annotation/RestInit_Test.java index 92de48b51a..2420b59671 100644 --- a/juneau-utest/src/test/java/org/apache/juneau/rest/annotation/RestInit_Test.java +++ b/juneau-utest/src/test/java/org/apache/juneau/rest/annotation/RestInit_Test.java @@ -18,6 +18,7 @@ package org.apache.juneau.rest.annotation; import org.apache.juneau.*; import org.apache.juneau.collections.*; +import org.apache.juneau.commons.inject.Bean; import org.apache.juneau.rest.mock.*; import org.junit.jupiter.api.*; @@ -62,8 +63,8 @@ class RestInit_Test extends TestBase { return events; } - // Bean injected via @RestInject so we can also exercise non-built-in @RestInit parameter resolution. - @RestInject + // Bean injected via @Bean so we can also exercise non-built-in @RestInit parameter resolution. + @Bean public MarkerBean marker() { return new MarkerBean(); } diff --git a/juneau-utest/src/test/java/org/apache/juneau/rest/annotation/Rest_Messages_Test.java b/juneau-utest/src/test/java/org/apache/juneau/rest/annotation/Rest_Messages_Test.java index 4bdbdcc756..9a60f5d149 100644 --- a/juneau-utest/src/test/java/org/apache/juneau/rest/annotation/Rest_Messages_Test.java +++ b/juneau-utest/src/test/java/org/apache/juneau/rest/annotation/Rest_Messages_Test.java @@ -20,6 +20,7 @@ import java.util.*; import org.apache.juneau.*; import org.apache.juneau.collections.*; +import org.apache.juneau.commons.inject.Bean; import org.apache.juneau.cp.*; import org.apache.juneau.http.annotation.*; import org.apache.juneau.rest.mock.*; @@ -99,7 +100,7 @@ class Rest_Messages_Test extends TestBase { } public static class B3 extends B1 { - @RestInject + @Bean public static Messages messages(Messages.Builder b) { return b.location(null, "B2x").location(B1.class, "B1x").build(); }
