This is an automated email from the ASF dual-hosted git repository.

jamesbognar pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/juneau.git


The following commit(s) were added to refs/heads/master by this push:
     new 8921dc8a1e refactor: inline all remaining Builder.create* methods as 
memoized fields on RestContext
8921dc8a1e is described below

commit 8921dc8a1e95672b1c0c3b1b6a5be8a6b39f33c7
Author: James Bognar <[email protected]>
AuthorDate: Thu May 7 08:48:59 2026 -0400

    refactor: inline all remaining Builder.create* methods as memoized fields 
on RestContext
---
 .../java/org/apache/juneau/rest/RestContext.java   | 1054 +++++---------------
 1 file changed, 265 insertions(+), 789 deletions(-)

diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java
index 58d0f7f9c4..574f9e341d 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
@@ -277,7 +277,7 @@ public class RestContext extends Context {
                // Read-only snapshots of these will be made in 
RestServletContext.
                
//-----------------------------------------------------------------------------------------------------------------
 
-               private static <T extends Annotation> Stream<Method> 
getAnnotatedMethods(Supplier<?> resource, Class<T> annotation) {
+               static <T extends Annotation> Stream<Method> 
getAnnotatedMethods(Supplier<?> resource, Class<T> annotation) {
                        return 
ClassInfo.ofProxy(resource.get()).getAllMethodsTopDown().stream()
                                .filter(y -> y.hasAnnotation(annotation))
                                .filter(distinctByKey(MethodInfo::getSignature))
@@ -328,7 +328,7 @@ public class RestContext extends Context {
                }
 
                @Override /* Overridden from ServletConfig */
-               public Enumeration<String> getInitParameterNames() { return 
inner == null ? new Vector<String>().elements() : 
inner.getInitParameterNames(); }
+               public Enumeration<String> getInitParameterNames() { return 
opt(inner).map(ServletConfig::getInitParameterNames).orElseGet(() -> new 
Vector<String>().elements()); }
 
                @Override /* Overridden from ServletConfig */
                public ServletContext getServletContext() {
@@ -342,165 +342,7 @@ public class RestContext extends Context {
                }
 
                @Override /* Overridden from ServletConfig */
-               public String getServletName() { return inner == null ? null : 
inner.getServletName(); }
-
-               /**
-                * Returns the response processor list sub-builder.
-                *
-                * <p>
-                * Specifies a list of {@link ResponseProcessor} classes that 
know how to convert POJOs returned by REST methods or
-                * set via {@link RestResponse#setContent(Object)} into 
appropriate HTTP responses.
-                *
-                * <p>
-                * By default, the following response handlers are provided in 
the specified order:
-                * <ul class='javatreec'>
-                *      <li class='jc'>{@link ReaderProcessor}
-                *      <li class='jc'>{@link InputStreamProcessor}
-                *      <li class='jc'>{@link ThrowableProcessor}
-                *      <li class='jc'>{@link HttpResponseProcessor}
-                *      <li class='jc'>{@link HttpResourceProcessor}
-                *      <li class='jc'>{@link HttpEntityProcessor}
-                *      <li class='jc'>{@link ResponseBeanProcessor}
-                *      <li class='jc'>{@link PlainTextPojoProcessor}
-                *      <li class='jc'>{@link SerializedPojoProcessor}
-                * </ul>
-                *
-                * <h5 class='section'>Example:</h5>
-                * <p class='bjava'>
-                *      <jc>// Our custom response processor for Foo objects. 
</jc>
-                *      <jk>public class</jk> MyResponseProcessor 
<jk>implements</jk> ResponseProcessor {
-                *
-                *              <ja>@Override</ja>
-                *              <jk>public int</jk> process(RestOpSession 
<jv>opSession</jv>) <jk>throws</jk> IOException {
-                *
-                *                              RestResponse <jv>res</jv> = 
<jv>opSession</jv>.getResponse();
-                *                              Foo <jv>foo</jv> = 
<jv>res</jv>.getOutput(Foo.<jk>class</jk>);
-                *
-                *                              <jk>if</jk> (<jv>foo</jv> == 
<jk>null</jk>)
-                *                                      <jk>return</jk> 
<jsf>NEXT</jsf>;  <jc>// Let the next processor handle it.</jc>
-                *
-                *                              <jk>try</jk> (Writer 
<jv>writer</jv> = <jv>res</jv>.getNegotiatedWriter()) {
-                *                                      <jc>//Pipe it to the 
writer ourselves.</jc>
-                *                              }
-                *
-                *                              <jk>return</jk> 
<jsf>FINISHED</jsf>;  <jc>// We handled it.</jc>
-                *                      }
-                *              }
-                *      }
-                *
-                *      <jc>// Defined via annotation.</jc>
-                *      
<ja>@Rest</ja>(responseProcessors=MyResponseProcessor.<jk>class</jk>)
-                *      <jk>public class</jk> MyResource {
-                *
-                *              <ja>@RestGet</ja>(...)
-                *              <jk>public</jk> Object myMethod() {
-                *                      <jc>// Return a special object for our 
handler.</jc>
-                *                      <jk>return new</jk> MySpecialObject();
-                *              }
-                *      }
-                * </p>
-                *
-                * <p>
-                * The default response processors can overridden via any of 
the following:
-                * <ul class='spaced-list'>
-                *      <li>Injected via bean store.
-                *      <li>Class annotation:  {@link Rest#responseProcessors() 
@Rest(responseProcessors)}
-                *      <li>{@link RestInject @RestInject}-annotated method:
-                *              <p class='bjava'>
-                *      <ja>@RestInject</ja> <jk>public</jk> [<jk>static</jk>] 
ResponseProcessorList myMethod(<i>&lt;args&gt;</i>) {...}
-                *              </p>
-                *              Args can be any injected bean including 
ResponseProcessorList.Builder, the default builder.
-                * </ul>
-                *
-                * <h5 class='section'>Notes:</h5><ul>
-                *      <li class='note'>
-                *              Response processors are always inherited from 
ascendant resources.
-                *      <li class='note'>
-                *              When defined as a class, the implementation 
must have one of the following constructors:
-                *              <ul>
-                *                      <li><code><jk>public</jk> 
T(RestContext)</code>
-                *                      <li><code><jk>public</jk> T()</code>
-                *                      <li><code><jk>public static</jk> T 
<jsm>create</jsm>(RestContext)</code>
-                *                      <li><code><jk>public static</jk> T 
<jsm>create</jsm>()</code>
-                *              </ul>
-                *      <li class='note'>
-                *              Inner classes of the REST resource class are 
allowed.
-                * </ul>
-                *
-                * <h5 class='section'>See Also:</h5><ul>
-                *      <li class='link'><a class="doclink" 
href="https://juneau.apache.org/docs/topics/ResponseProcessors";>Response 
Processors</a>
-                * </ul>
-                *
-                * @return The response processor list sub-builder.
-                */
-               public ResponseProcessorList.Builder 
responseProcessors(BasicBeanStore beanStore, Supplier<?> resource) {
-                       return createResponseProcessors(beanStore, resource);
-               }
-
-               /**
-                * Returns the REST operation args sub-builder.
-                *
-                * @param beanStore The bean store.
-                * @param resource The resource supplier.
-                * @return The REST operation args sub-builder.
-                */
-               public RestOpArgList.Builder restOpArgs(BasicBeanStore 
beanStore, Supplier<?> resource) {
-                       return createRestOpArgs(beanStore, resource);
-               }
-
-               private static void runInitHooks(BasicBeanStore beanStore, 
Supplier<?> resource) throws ServletException {
-
-                       var r = resource.get();
-
-                       var map = CollectionUtils.<String,MethodInfo>map();
-                       // @formatter:off
-                       // Note: pre-9.5 this filter also excluded 
`y.hasParameter(RestOpContext.Builder.class)` because the
-                       // per-op `@RestInit(RestOpContext.Builder)` flow 
handled those separately. That flow was deleted in
-                       // April 2026 refactor Route B (zero real-world 
callers), so the exclusion is gone too. Likewise, the
-                       // class-level `@RestInit(RestContext.Builder)` 
injection protocol was deleted in the same refactor
-                       // (zero non-test callers anywhere) — 
`RestContext.Builder` is no longer added to the bean store, so
-                       // any straggling `@RestInit` method that still 
declares either Builder type as a parameter will now
-                       // surface a "missing prerequisites" error here, which 
is the desired loud-failure signal.
-                       ClassInfo.ofProxy(r).getAllMethodsTopDown().stream()
-                               .filter(y -> y.hasAnnotation(RestInit.class))
-                               .forEach(y -> {
-                                       var sig = y.getSignature();
-                                       if (! map.containsKey(sig))
-                                               map.put(sig, y.accessible());
-                               }
-                       );
-                       // @formatter:on
-
-                       for (var m : map.values()) {
-                               if (! beanStore.hasAllParams(m, r))
-                                       throw servletException("Could not call 
@RestInit method {0}.{1}.  Could not find prerequisites: {2}.", 
cns(m.getDeclaringClass()), m.getSignature(), beanStore.getMissingParams(m, r));
-                               try {
-                                       m.invoke(r, beanStore.getParams(m, r));
-                               } catch (Exception e) {
-                                       throw servletException(e, "Exception 
thrown from @RestInit method {0}.{1}.", cns(m.getDeclaringClass()), 
m.getSignature());
-                               }
-                       }
-               }
-
-               /**
-                * Instantiates the bean context sub-builder.
-                *
-                * @param beanStore
-                *      The factory used for creating beans and retrieving 
injected beans.
-                * @param resource
-                *      The REST servlet/bean instance that this context is 
defined against.
-                * @return A new bean context sub-builder.
-                */
-               protected BeanContext.Builder createBeanContext(BasicBeanStore 
beanStore, Supplier<?> resource) {
-
-                       // Default value.
-                       Value<BeanContext.Builder> v = 
Value.of(BeanContext.create());
-
-                       // Replace with bean from bean store.
-                       beanStore.getBean(BeanContext.class).ifPresent(x -> 
v.get().impl(x));
-
-                       return v.get();
-               }
+               public String getServletName() { return 
opt(inner).map(ServletConfig::getServletName).orElse(null); }
 
                /**
                 * Creates the bean store in this builder.
@@ -535,535 +377,6 @@ public class RestContext extends Context {
 
                        return v.get();
                }
-
-               /**
-                * Creates the config for this builder.
-                *
-                * <h5 class='section'>See Also:</h5><ul>
-                *      <li class='link'><a class="doclink" 
href="https://juneau.apache.org/docs/topics/ConfigurationFiles";>Configuration 
Files</a>
-                * </ul>
-                *
-                * @param beanStore
-                *      The factory used for creating beans and retrieving 
injected beans.
-                * @param resource
-                *      The REST servlet/bean instance that this context is 
defined against.
-                * @param resourceClass
-                *      The REST servlet/bean type that this context is defined 
against.
-                * @return A new config.
-                */
-               protected Config createConfig(BasicBeanStore beanStore, 
Supplier<?> resource, Class<?> resourceClass) {
-
-                       var v = Value.<Config>empty();
-
-                       // Find our config file.  It's the last non-empty 
@RestResource(config).
-                       var vr = 
beanStore.getBean(VarResolver.class).orElseThrow(() -> new 
IllegalArgumentException("VarResolver not found."));
-                       var cfv = Value.<String>empty();
-                       rstream(AP.find(Rest.class, info(resourceClass))).map(x 
-> x.inner().config()).filter(Utils::ne).forEach(x -> cfv.set(vr.resolve(x)));
-                       var cf = cfv.orElse("");
-
-                       // If not specified or value is set to SYSTEM_DEFAULT, 
use system default config.
-                       if (v.isEmpty() && "SYSTEM_DEFAULT".equals(cf))
-                               v.set(Config.getSystemDefault());
-
-                       // Otherwise build one.
-                       if (v.isEmpty()) {
-                               Config.Builder cb = 
Config.create().varResolver(vr);
-                               if (! cf.isEmpty())
-                                       cb.name(cf);
-                               v.set(cb.build());
-                       }
-
-                       // Replace with bean from bean store.
-                       beanStore.getBean(Config.class).ifPresent(v::set);
-
-                       // Replace with bean from:  @RestInject public [static] 
Config xxx(<args>)
-                       new BeanCreateMethodFinder<>(Config.class, 
resource.get(), beanStore).addBean(Config.class, 
v.get()).find(Builder::isRestInjectMethod).run(v::set);
-
-                       return v.get();
-               }
-
-               /**
-                * Instantiates the destroy method list.
-                *
-                * @param beanStore
-                *      The factory used for creating beans and retrieving 
injected beans.
-                * @param resource
-                *      The REST servlet/bean instance that this context is 
defined against.
-                * @return A new destroy method list.
-                */
-               protected MethodList createDestroyMethods(BasicBeanStore 
beanStore, Supplier<?> resource) {
-
-                       // Default value.
-                       var v = 
Value.of(MethodList.of(getAnnotatedMethods(resource, 
RestDestroy.class).toList()));
-
-                       // Replace with bean from:  
@RestInject(name="destroyMethods") public [static] MethodList xxx(<args>)
-                       new BeanCreateMethodFinder<>(MethodList.class, 
resource.get(), beanStore).addBean(MethodList.class, v.get()).find(x -> 
isRestInjectMethod(x, "destroyMethods")).run(v::set);
-
-                       return v.get();
-               }
-
-               /**
-                * Instantiates the end call method list.
-                *
-                * @param beanStore
-                *      The factory used for creating beans and retrieving 
injected beans.
-                * @param resource
-                *      The REST servlet/bean instance that this context is 
defined against.
-                * @return A new end call method list.
-                */
-               protected MethodList createEndCallMethods(BasicBeanStore 
beanStore, Supplier<?> resource) {
-
-                       // Default value.
-                       Value<MethodList> v = 
Value.of(MethodList.of(getAnnotatedMethods(resource, 
RestEndCall.class).toList()));
-
-                       // Replace with bean from:  
@RestInject(name="endCallMethods") public [static] MethodList xxx(<args>)
-                       new BeanCreateMethodFinder<>(MethodList.class, 
resource.get(), beanStore).addBean(MethodList.class, v.get()).find(x -> 
isRestInjectMethod(x, "endCallMethods")).run(v::set);
-
-                       return v.get();
-               }
-
-               /**
-                * Instantiates the JSON schema generator sub-builder.
-                *
-                * <h5 class='section'>See Also:</h5><ul>
-                *      <li class='link'><a class="doclink" 
href="https://juneau.apache.org/docs/topics/JuneauBeanSwagger2";>juneau-bean-swagger-v2</a>
-                * </ul>
-                *
-                * @param beanStore
-                *      The factory used for creating beans and retrieving 
injected beans.
-                * @param resource
-                *      The REST servlet/bean instance that this context is 
defined against.
-                * @return A new JSON schema generator sub-builder.
-                */
-               protected JsonSchemaGenerator.Builder 
createJsonSchemaGenerator(BasicBeanStore beanStore, Supplier<?> resource) {
-
-                       // Default value.
-                       var v = Value.of(JsonSchemaGenerator.create());
-
-                       // Replace with bean from bean store.
-                       
beanStore.getBean(JsonSchemaGenerator.class).ifPresent(x -> v.get().impl(x));
-
-                       // Replace with bean from:  @RestInject public [static] 
JsonSchemaGenerator xxx(<args>)
-                       new BeanCreateMethodFinder<>(JsonSchemaGenerator.class, 
resource.get(), beanStore).find(Builder::isRestInjectMethod).run(x -> 
v.get().impl(x));
-
-                       return v.get();
-               }
-
-
-               /**
-                * Instantiates the part parser sub-builder.
-                *
-                * <h5 class='section'>See Also:</h5><ul>
-                *      <li class='link'><a class="doclink" 
href="https://juneau.apache.org/docs/topics/HttpParts";>HTTP Parts</a>
-                * </ul>
-                *
-                * @param beanStore
-                *      The factory used for creating beans and retrieving 
injected beans.
-                * @param resource
-                *      The REST servlet/bean instance that this context is 
defined against.
-                * @return A new part parser sub-builder.
-                */
-               protected HttpPartParser.Creator 
createPartParser(BasicBeanStore beanStore, Supplier<?> resource) {
-
-                       // Default value.
-                       Value<HttpPartParser.Creator> v = 
Value.of(HttpPartParser.creator().type(OpenApiParser.class));
-
-                       // Replace with bean from bean store.
-                       beanStore.getBean(HttpPartParser.class).ifPresent(x -> 
v.get().impl(x));
-
-                       // Replace with this bean.
-                       var r = resource.get();
-                       opt(r instanceof HttpPartParser x ? x : 
null).ifPresent(x -> v.get().impl(x));
-
-                       // Specify the bean type if its set as a default.
-                       beanStore.getBeanType(HttpPartParser.class).ifPresent(x 
-> v.get().type(x));
-
-                       // Replace with bean from:  @RestInject public [static] 
HttpPartParser xxx(<args>)
-                       new BeanCreateMethodFinder<>(HttpPartParser.class, 
resource.get(), beanStore).find(Builder::isRestInjectMethod).run(x -> 
v.get().impl(x));
-
-                       return v.get();
-               }
-
-               /**
-                * Instantiates the part serializer sub-builder.
-                *
-                * <h5 class='section'>See Also:</h5><ul>
-                *      <li class='link'><a class="doclink" 
href="https://juneau.apache.org/docs/topics/HttpParts";>HTTP Parts</a>
-                * </ul>
-                *
-                * @param beanStore
-                *      The factory used for creating beans and retrieving 
injected beans.
-                * @param resource
-                *      The REST servlet/bean instance that this context is 
defined against.
-                * @return A new part serializer sub-builder.
-                */
-               protected HttpPartSerializer.Creator 
createPartSerializer(BasicBeanStore beanStore, Supplier<?> resource) {
-
-                       // Default value.
-                       Value<HttpPartSerializer.Creator> v = 
Value.of(HttpPartSerializer.creator().type(OpenApiSerializer.class));
-
-                       // Replace with bean from bean store.
-                       beanStore.getBean(HttpPartSerializer.class).ifPresent(x 
-> v.get().impl(x));
-
-                       // Replace with this bean.
-                       var r = resource.get();
-                       opt(r instanceof HttpPartSerializer x ? x : 
null).ifPresent(x -> v.get().impl(x));
-
-                       // Specify the bean type if its set as a default.
-                       
beanStore.getBeanType(HttpPartSerializer.class).ifPresent(x -> v.get().type(x));
-
-                       // Replace with bean from:  @RestInject public [static] 
HttpPartSerializer xxx(<args>)
-                       new BeanCreateMethodFinder<>(HttpPartSerializer.class, 
resource.get(), beanStore).find(Builder::isRestInjectMethod).run(x -> 
v.get().impl(x));
-
-                       return v.get();
-               }
-
-               /**
-                * Instantiates the post-call method list.
-                *
-                * @param beanStore
-                *      The factory used for creating beans and retrieving 
injected beans.
-                * @param resource
-                *      The REST servlet/bean instance that this context is 
defined against.
-                * @return A new post-call method list.
-                */
-               protected MethodList createPostCallMethods(BasicBeanStore 
beanStore, Supplier<?> resource) {
-
-                       // Default value.
-                       Value<MethodList> v = 
Value.of(MethodList.of(getAnnotatedMethods(resource, 
RestPostCall.class).toList()));
-
-                       // Replace with bean from:  
@RestInject(name="postCallMethods") public [static] MethodList xxx(<args>)
-                       new BeanCreateMethodFinder<>(MethodList.class, 
resource.get(), beanStore).addBean(MethodList.class, v.get()).find(x -> 
isRestInjectMethod(x, "postCallMethods")).run(v::set);
-
-                       return v.get();
-               }
-
-               /**
-                * Instantiates the post-init-child-first method list.
-                *
-                * @param beanStore
-                *      The factory used for creating beans and retrieving 
injected beans.
-                * @param resource
-                *      The REST servlet/bean instance that this context is 
defined against.
-                * @return A new post-init-child-first method list.
-                */
-               protected MethodList 
createPostInitChildFirstMethods(BasicBeanStore beanStore, Supplier<?> resource) 
{
-
-                       // Default value.
-                       var ap = AP;
-                       Value<MethodList> v = 
Value.of(MethodList.of(getAnnotatedMethods(resource, RestPostInit.class)
-                               .filter(m -> {
-                                       var mi = MethodInfo.of(m);
-                                       return 
rstream(ap.find(RestPostInit.class, mi))
-                                               .map(AnnotationInfo::inner)
-                                               
.anyMatch(RestPostInit::childFirst);
-                               })
-                               .toList()));
-
-                       // Replace with bean from:  
@RestInject(name="postInitChildFirstMethods") public [static] MethodList 
xxx(<args>)
-                       new BeanCreateMethodFinder<>(MethodList.class, 
resource.get(), beanStore).addBean(MethodList.class, v.get()).find(x -> 
isRestInjectMethod(x, "postInitChildFirstMethods")).run(v::set);
-
-                       return v.get();
-               }
-
-               /**
-                * Instantiates the post-init method list.
-                *
-                * @param beanStore
-                *      The factory used for creating beans and retrieving 
injected beans.
-                * @param resource
-                *      The REST servlet/bean instance that this context is 
defined against.
-                * @return A new post-init method list.
-                */
-               protected MethodList createPostInitMethods(BasicBeanStore 
beanStore, Supplier<?> resource) {
-
-                       // Default value.
-                       var ap = AP;
-                       Value<MethodList> v = 
Value.of(MethodList.of(getAnnotatedMethods(resource, RestPostInit.class)
-                               .filter(m -> {
-                                       var mi = MethodInfo.of(m);
-                                       return 
rstream(ap.find(RestPostInit.class, mi))
-                                               .map(AnnotationInfo::inner)
-                                               .anyMatch(x -> ! 
x.childFirst());
-                               })
-                               .toList()));
-
-                       // Replace with bean from:  
@RestInject(name="postInitMethods") public [static] MethodList xxx(<args>)
-                       new BeanCreateMethodFinder<>(MethodList.class, 
resource.get(), beanStore).addBean(MethodList.class, v.get()).find(x -> 
isRestInjectMethod(x, "postInitMethods")).run(v::set);
-
-                       return v.get();
-               }
-
-               /**
-                * Instantiates the pre-call method list.
-                *
-                * @param beanStore
-                *      The factory used for creating beans and retrieving 
injected beans.
-                * @param resource
-                *      The REST servlet/bean instance that this context is 
defined against.
-                * @return A new pre-call method list.
-                */
-               protected MethodList createPreCallMethods(BasicBeanStore 
beanStore, Supplier<?> resource) {
-
-                       // Default value.
-                       Value<MethodList> v = 
Value.of(MethodList.of(getAnnotatedMethods(resource, 
RestPreCall.class).toList()));
-
-                       // Replace with bean from:  
@RestInject(name="preCallMethods") public [static] MethodList xxx(<args>)
-                       new BeanCreateMethodFinder<>(MethodList.class, 
resource.get(), beanStore).addBean(MethodList.class, v.get()).find(x -> 
isRestInjectMethod(x, "preCallMethods")).run(v::set);
-
-                       return v.get();
-               }
-
-               /**
-                * Instantiates the response processor list sub-builder.
-                *
-                * <h5 class='section'>See Also:</h5><ul>
-                *      <li class='link'><a class="doclink" 
href="https://juneau.apache.org/docs/topics/ResponseProcessors";>Response 
Processors</a>
-                * </ul>
-                *
-                * @param beanStore
-                *      The factory used for creating beans and retrieving 
injected beans.
-                * @param resource
-                *      The REST servlet/bean instance that this context is 
defined against.
-                * @return A new response processor list sub-builder.
-                */
-               protected ResponseProcessorList.Builder 
createResponseProcessors(BasicBeanStore beanStore, Supplier<?> resource) {
-
-                       // Default value.
-                       // @formatter:off
-                       Value<ResponseProcessorList.Builder> v = Value.of(
-                                ResponseProcessorList
-                                       .create(beanStore)
-                                       .add(
-                                               ReaderProcessor.class,
-                                               InputStreamProcessor.class,
-                                               ThrowableProcessor.class,
-                                               HttpResponseProcessor.class,
-                                               HttpResourceProcessor.class,
-                                               HttpEntityProcessor.class,
-                                               ResponseBeanProcessor.class,
-                                               PlainTextPojoProcessor.class,
-                                               SerializedPojoProcessor.class
-                                       )
-                       );
-                       // @formatter:on
-
-                       // Replace with bean from bean store.
-                       
beanStore.getBean(ResponseProcessorList.class).ifPresent(x -> v.get().impl(x));
-
-                       // Replace with bean from:  @RestInject public [static] 
ResponseProcessorList xxx(<args>)
-                       new 
BeanCreateMethodFinder<>(ResponseProcessorList.class, resource.get(), 
beanStore).addBean(ResponseProcessorList.Builder.class, 
v.get()).find(Builder::isRestInjectMethod).run(x -> v.get().impl(x));
-
-                       return v.get();
-               }
-
-               /**
-                * Instantiates the REST operation args sub-builder.
-                *
-                * <p>
-                * Instantiates based on the following logic:
-                * <ul>
-                *      <li>Looks for REST op args set via any of the following:
-                *              <ul>
-                *                      <li>{@link Rest#restOpArgs()}
-                *                      <li>{@link Rest#restOpArgs()}.
-                *              </ul>
-                *      <li>Looks for a static or non-static 
<c>createRestParams()</c> method that returns <c>{@link Class}[]</c>.
-                *      <li>Resolves it via the bean store registered in this 
context.
-                *      <li>Instantiates a default set of parameters.
-                * </ul>
-                *
-                * @param beanStore
-                *      The factory used for creating beans and retrieving 
injected beans.
-                * @param resource
-                *      The REST servlet/bean instance that this context is 
defined against.
-                * @return A new REST operation args sub-builder.
-                */
-               protected RestOpArgList.Builder createRestOpArgs(BasicBeanStore 
beanStore, Supplier<?> resource) {
-
-                       // Default value.
-                       Value<RestOpArgList.Builder> v = 
Value.of(RestOpArgList.create(beanStore).add(AttributeArg.class, 
ContentArg.class, FormDataArg.class, HasFormDataArg.class, HasQueryArg.class,
-                               HeaderArg.class, HttpServletRequestArgs.class, 
HttpServletResponseArgs.class, HttpSessionArgs.class, 
InputStreamParserArg.class, MethodArg.class, ParserArg.class, PathArg.class,
-                               PathRemainderArg.class, QueryArg.class, 
ReaderParserArg.class, RequestBeanArg.class, ResponseBeanArg.class, 
ResponseHeaderArg.class, ResponseCodeArg.class, RestContextArgs.class,
-                               RestSessionArgs.class, RestOpContextArgs.class, 
RestOpSessionArgs.class, RestRequestArgs.class, RestResponseArgs.class, 
DefaultArg.class));
-
-                       // Replace with bean from bean store.
-                       beanStore.getBean(RestOpArgList.class).ifPresent(x -> 
v.get().impl(x));
-
-                       // Replace with bean from:  @RestInject public [static] 
RestOpArgList xxx(<args>)
-                       new BeanCreateMethodFinder<>(RestOpArgList.class, 
resource.get(), beanStore).addBean(RestOpArgList.Builder.class, 
v.get()).find(Builder::isRestInjectMethod).run(x -> v.get().impl(x));
-
-                       return v.get();
-               }
-
-               /**
-                * Instantiates the REST operations list.
-                *
-                * <p>
-                * The set of {@link RestOpContext} objects that represent the 
methods on this resource.
-                *
-                * @param restContext The rest context.
-                * @param beanStore
-                *      The factory used for creating beans and retrieving 
injected beans.
-                * @param resource
-                *      The REST servlet/bean instance that this context is 
defined against.
-                * @return A new REST operations list.
-                * @throws ServletException If a problem occurred instantiating 
one of the child rest contexts.
-                */
-               @SuppressWarnings({
-                       "java:S3776" // Cognitive complexity acceptable for 
REST operations creation
-               })
-               protected RestOperations.Builder 
createRestOperations(BasicBeanStore beanStore, Supplier<?> resource, 
RestContext restContext) throws ServletException {
-
-                       // Default value.
-                       Value<RestOperations.Builder> v = 
Value.of(RestOperations.create(beanStore));
-                       var ap = 
restContext.getBeanContext().getAnnotationProvider();
-
-                       var rci = ClassInfo.of(resource.get());
-
-                       // April 2026 refactor (Route B, 2026-04-19): The 
per-op `@RestInit(RestOpContext.Builder)` protocol
-                       // was deleted. Audit confirmed zero real-world callers 
(only stale javadoc/docs examples). Users who
-                       // previously injected `RestOpContext.Builder` per op 
now configure operations declaratively via
-                       // `@RestOp(...)` attributes, `@RestInject`-named 
beans, or the class-level `@RestInit(RestContext.Builder)`
-                       // hook (still supported until the parent Builder is 
deleted). The corresponding `initMap` scan
-                       // (filtering for 
`y.hasParameter(RestOpContext.Builder.class)`) and the per-op invocation loop 
are gone.
-
-                       for (var mi : rci.getPublicMethods()) {
-                               var al = 
rstream(ap.find(mi)).filter(REST_OP_GROUP).collect(Collectors.toList());
-
-                               // Also include methods on @Rest-annotated 
interfaces.
-                               if (al.isEmpty()) {
-                                       Predicate<MethodInfo> 
isRestAnnotatedInterface = x -> x.getDeclaringClass().isInterface()
-                                               && 
nn(x.getDeclaringClass().getAnnotations(Rest.class).findFirst().map(AnnotationInfo::inner).orElse(null));
-                                       
mi.getMatchingMethods().stream().filter(isRestAnnotatedInterface).forEach(x -> 
al.add(AnnotationInfo.of(x, RestOpAnnotation.DEFAULT)));
-                               }
-
-                               if (!al.isEmpty()) {
-                                       try {
-                                               if (mi.isNotPublic())
-                                                       throw 
servletException("@RestOp method {0}.{1} must be defined as public.", 
rci.inner().getName(), mi.getNameSimple());
-
-                                               // 
`RestOpContext.create(method, 
context).beanStore(beanStore).type(RestOpContext.class).build()` →
-                                               // `new RestOpContext(method, 
context)`. The `.beanStore(beanStore)` override is equivalent to
-                                               // the ctor default 
`BasicBeanStore.of(context.getBeanStore())` since `beanStore` here IS the
-                                               // resource-context's bean 
store; `.type(RestOpContext.class)` was the default. 
-                                               var roc = new 
RestOpContext(mi.inner(), restContext);
-
-                                               String httpMethod = 
roc.getHttpMethod();
-
-                                               // RRPC is a special case where 
a method returns an interface that we
-                                               // can perform REST calls 
against.
-                                               // We override the 
CallMethod.invoke() method to insert our logic.
-                                               if ("RRPC".equals(httpMethod)) {
-
-                                                       // 
`RestOpContext.create(method, 
context).beanStore(restContext.getBootstrapBeanStore()).type(RrpcRestOpContext.class).build()`
 →
-                                                       // `new 
RrpcRestOpContext(method, context)`. The bean-store override (root, not the
-                                                       // resource-layered 
store) is preserved verbatim inside the new 2-arg ctor on
-                                                       // `RrpcRestOpContext`.
-                                                       // RRPC operations 
auto-append `/*` inside `Builder.getPathMatchers()`.
-                                                       RestOpContext roc2 = 
new RrpcRestOpContext(mi.inner(), restContext);
-                                                       v.get()
-                                                               .add("GET", 
roc2)
-                                                               .add("POST", 
roc2);
-
-                                               } else {
-                                                       v.get().add(roc);
-                                               }
-                                       } catch (Exception e) {
-                                               throw servletException(e, 
"Problem occurred trying to initialize methods on class {0}", 
rci.inner().getName());
-                                       }
-                               }
-                       }
-
-                       // Replace with bean from:  @RestInject public [static] 
RestOperations xxx(<args>)
-                       new BeanCreateMethodFinder<>(RestOperations.class, 
resource.get(), beanStore).addBean(RestOperations.Builder.class, 
v.get()).find(Builder::isRestInjectMethod).run(x -> v.get().impl(x));
-
-                       return v.get();
-               }
-
-               /**
-                * Instantiates the start call method list.
-                *
-                * @param beanStore
-                *      The factory used for creating beans and retrieving 
injected beans.
-                * @param resource
-                *      The REST servlet/bean instance that this context is 
defined against.
-                * @return A new start call method list.
-                */
-               protected MethodList createStartCallMethods(BasicBeanStore 
beanStore, Supplier<?> resource) {
-
-                       // Default value.
-                       Value<MethodList> v = 
Value.of(MethodList.of(getAnnotatedMethods(resource, 
RestStartCall.class).toList()));
-
-                       // Replace with bean from:  
@RestInject(name="startCallMethods") public [static] MethodList xxx(<args>)
-                       new BeanCreateMethodFinder<>(MethodList.class, 
resource.get(), beanStore).addBean(MethodList.class, v.get()).find(x -> 
isRestInjectMethod(x, "startCallMethods")).run(v::set);
-
-                       return v.get();
-               }
-
-               /**
-                * Creates the bootstrap (pre-runtime) variable resolver.
-                *
-                * <p>
-                * Builds the same {@link Var} catalog as the runtime resolver 
but without {@link Messages} or {@link Config}
-                * beans wired in — those depend on settings that are 
themselves resolved against this resolver, so they're
-                * added later by {@link RestContext#findVarResolver()}. 
Override via
-                * {@link RestInject @RestInject(name="bootstrapVarResolver")} 
on a static method.
-                *
-                * <h5 class='section'>See Also:</h5><ul>
-                *      <li class='link'><a class="doclink" 
href="https://juneau.apache.org/docs/topics/RestServerSvlVariables";>SVL 
Variables</a>
-                * </ul>
-                *
-                * @param beanStore
-                *      The factory used for creating beans and retrieving 
injected beans.
-                * @param resource
-                *      The REST servlet/bean instance that this context is 
defined against.
-                * @param resourceClass
-                *      The REST servlet/bean type that this context is defined 
against.
-                * @return The built bootstrap variable resolver.
-                */
-               protected VarResolver createBootstrapVarResolver(BasicBeanStore 
beanStore, Supplier<?> resource, Class<?> resourceClass) {
-
-                       // Default value.
-                       // @formatter:off
-                       Value<VarResolver> v = Value.of(
-                               VarResolver
-                                       .create()
-                                       .defaultVars()
-                                       .vars(
-                                               VarList.of(
-                                                       ConfigVar.class,
-                                                       FileVar.class,
-                                                       LocalizationVar.class,
-                                                       
RequestAttributeVar.class,
-                                                       
RequestFormDataVar.class,
-                                                       RequestHeaderVar.class,
-                                                       RequestPathVar.class,
-                                                       RequestQueryVar.class,
-                                                       RequestVar.class,
-                                                       RequestSwaggerVar.class,
-                                                       
SerializedRequestAttrVar.class,
-                                                       
ServletInitParamVar.class,
-                                                       SwaggerVar.class,
-                                                       UrlVar.class,
-                                                       UrlEncodeVar.class,
-                                                       HtmlWidgetVar.class
-                                               )
-                                               .addDefault()
-                                       )
-                                       .bean(FileFinder.class, 
FileFinder.create(beanStore).cp(resourceClass,null,true).build())
-                                       .build()
-                       );
-                       // @formatter:on
-
-                       // Replace with named bean from bean store 
(PROP_bootstrapVarResolver).
-                       beanStore.getBean(VarResolver.class, 
PROP_bootstrapVarResolver).ifPresent(v::set);
-
-                       // Replace with bean from:  
@RestInject(name="bootstrapVarResolver") public [static] VarResolver xxx(<args>)
-                       new BeanCreateMethodFinder<>(VarResolver.class, 
resource.get(), beanStore).find(x -> isRestInjectMethod(x, 
PROP_bootstrapVarResolver)).run(v::set);
-
-                       return v.get();
-               }
        }
 
        private static final Map<Class<?>,RestContext> REGISTRY = new 
ConcurrentHashMap<>();
@@ -1097,17 +410,10 @@ public class RestContext extends Context {
        protected final ThreadLocal<RestSession> localSession = new 
ThreadLocal<>();
        protected final UrlPathMatcher pathMatcher;
        private final Supplier<?> resource;
-       private BeanContext.Builder beanContextBuilder;
-       private HttpPartParser.Creator partParserCreator;
-       private HttpPartSerializer.Creator partSerializerCreator;
-       private JsonSchemaGenerator.Builder jsonSchemaGeneratorBuilder;
-       private VarResolver rawBootstrapVarResolver;
-       private Config rawConfig;
        private AnnotationWorkList annotationWork;
 
        // Private accessors used by memoizer lambdas to satisfy Java's 
definite-assignment rules for blank final fields.
        private BasicBeanStore beanStore() { return beanStore; }
-       private Builder builder() { return builder; }
        private Supplier<?> resource() { return resource; }
        private Class<?> resourceClass() { return resourceClass; }
        private RestContext parentContext() { return parentContext; }
@@ -1127,20 +433,79 @@ public class RestContext extends Context {
         * The {@link BeanContext} for this resource.
         *
         * <p>
-        * Built from the builder's sub-builder, which is lazy-created and then 
mutated by the annotation
-        * apply pass during {@code init()} before this memoizer fires — so the 
builder is in its final
-        * configured state by the time {@code build()} is called.
+        * Triggered eagerly in the constructor after {@code annotationWork} is 
set, so that annotation
+        * work is applied before the builder is used by any other memoizer.
         */
-       private final Memoizer<BeanContext> beanContext = memoizer(() -> 
beanContextBuilder.build());
+       private final Memoizer<BeanContext.Builder> beanContextBuilder = 
memoizer(() -> {
+               var v = Value.of(BeanContext.create());
+               beanStore().getBean(BeanContext.class).ifPresent(x -> 
v.get().impl(x));
+               v.get().apply(annotationWork);
+               return v.get();
+       });
+
+       /**
+        * The {@link BeanContext} for this resource.
+        */
+       private final Memoizer<BeanContext> beanContext = memoizer(() -> 
beanContextBuilder.get().build());
+
+       /**
+        * The unresolved (bootstrap-time) {@link Config} for this resource.
+        *
+        * <p>
+        * Resolved by reading {@code @Rest(config)} from the annotation chain 
against the bootstrap
+        * {@link VarResolver} (which must already be in the bean store). 
Triggered eagerly in the constructor
+        * so the raw config is registered before {@code @RestInit} hooks run.
+        */
+       private final Memoizer<Config> rawConfig = memoizer(() -> {
+               var bs = beanStore();
+               var v = Value.<Config>empty();
+               var vr = bs.getBean(VarResolver.class).orElseThrow(() -> new 
IllegalArgumentException("VarResolver not found."));
+               var cfv = Value.<String>empty();
+               rstream(AnnotationProvider.INSTANCE.find(Rest.class, 
info(resourceClass()))).map(x -> 
x.inner().config()).filter(Utils::ne).forEach(x -> cfv.set(vr.resolve(x)));
+               var cf = cfv.orElse("");
+               if (v.isEmpty() && "SYSTEM_DEFAULT".equals(cf))
+                       v.set(Config.getSystemDefault());
+               if (v.isEmpty()) {
+                       Config.Builder cb = Config.create().varResolver(vr);
+                       if (!cf.isEmpty())
+                               cb.name(cf);
+                       v.set(cb.build());
+               }
+               bs.getBean(Config.class).ifPresent(v::set);
+               new BeanCreateMethodFinder<>(Config.class, resource().get(), 
bs).addBean(Config.class, 
v.get()).find(Builder::isRestInjectMethod).run(v::set);
+               return v.get();
+       });
 
        /**
         * The bootstrap-time {@link VarResolver} — no {@link Messages} or 
{@link Config} bean available yet.
         *
         * <p>
-        * Cached on the builder so that {@code init()} and the {@link 
#messages} / {@link #config}
-        * memoizers all see the same instance during construction.
+        * Builds the same {@link Var} catalog as the runtime resolver but 
without {@link Messages} or {@link Config}
+        * beans wired in — those depend on settings that are themselves 
resolved against this resolver.
+        * Triggered eagerly in the constructor so the result is available in 
the bean store before
+        * {@link Config} and annotation work are initialized.
         */
-       private final Memoizer<VarResolver> bootstrapVarResolver = memoizer(() 
-> rawBootstrapVarResolver);
+       // @formatter:off
+       private final Memoizer<VarResolver> bootstrapVarResolver = memoizer(() 
-> {
+               var bs = beanStore();
+               Value<VarResolver> v = Value.of(
+                       VarResolver.create()
+                               .defaultVars()
+                               .vars(VarList.of(
+                                       ConfigVar.class, FileVar.class, 
LocalizationVar.class,
+                                       RequestAttributeVar.class, 
RequestFormDataVar.class, RequestHeaderVar.class,
+                                       RequestPathVar.class, 
RequestQueryVar.class, RequestVar.class,
+                                       RequestSwaggerVar.class, 
SerializedRequestAttrVar.class, ServletInitParamVar.class,
+                                       SwaggerVar.class, UrlVar.class, 
UrlEncodeVar.class, HtmlWidgetVar.class
+                               ).addDefault())
+                               .bean(FileFinder.class, 
FileFinder.create(bs).cp(resourceClass(), null, true).build())
+                               .build()
+               );
+               bs.getBean(VarResolver.class, 
PROP_bootstrapVarResolver).ifPresent(v::set);
+               new BeanCreateMethodFinder<>(VarResolver.class, 
resource().get(), bs).find(x -> Builder.isRestInjectMethod(x, 
PROP_bootstrapVarResolver)).run(v::set);
+               return v.get();
+       });
+       // @formatter:on
 
        /**
         * The {@link CallLogger} for this resource.
@@ -1174,7 +539,7 @@ public class RestContext extends Context {
         * Wraps the builder's unresolved config with a {@link VarResolver} 
session so that SVL variables
         * in config values are expanded on access.
         */
-       private final Memoizer<Config> config = memoizer(() -> 
rawConfig.resolving(getVarResolver().createSession()));
+       private final Memoizer<Config> config = memoizer(() -> 
rawConfig.get().resolving(getVarResolver().createSession()));
 
        /**
         * The supported request content types ({@code Content-Type} media 
types) for this resource.
@@ -1300,7 +665,12 @@ public class RestContext extends Context {
        /**
         * Methods annotated with {@link 
org.apache.juneau.rest.annotation.RestDestroy @RestDestroy} and their invokers.
         */
-       private final Memoizer<LifecycleInvokerPair> destroyInvokerPair = 
memoizer(() -> buildLifecycleInvokerPair(() -> 
builder().createDestroyMethods(beanStore(), resource())));
+       private final Memoizer<LifecycleInvokerPair> destroyInvokerPair = 
memoizer(() -> buildLifecycleInvokerPair(() -> {
+               var bs = beanStore();
+               var v = 
Value.of(MethodList.of(Builder.getAnnotatedMethods(resource(), 
RestDestroy.class).toList()));
+               new BeanCreateMethodFinder<>(MethodList.class, 
resource().get(), bs).addBean(MethodList.class, v.get()).find(x -> 
Builder.isRestInjectMethod(x, "destroyMethods")).run(v::set);
+               return v.get();
+       }));
 
        /**
         * Fully-configured {@link EncoderSet.Builder} for this resource, 
populated from the
@@ -1330,12 +700,29 @@ public class RestContext extends Context {
        /**
         * Methods annotated with {@link 
org.apache.juneau.rest.annotation.RestEndCall @RestEndCall} and their invokers.
         */
-       private final Memoizer<LifecycleInvokerPair> endCallInvokerPair = 
memoizer(() -> buildLifecycleInvokerPair(() -> 
builder().createEndCallMethods(beanStore(), resource())));
+       private final Memoizer<LifecycleInvokerPair> endCallInvokerPair = 
memoizer(() -> buildLifecycleInvokerPair(() -> {
+               var bs = beanStore();
+               var v = 
Value.of(MethodList.of(Builder.getAnnotatedMethods(resource(), 
RestEndCall.class).toList()));
+               new BeanCreateMethodFinder<>(MethodList.class, 
resource().get(), bs).addBean(MethodList.class, v.get()).find(x -> 
Builder.isRestInjectMethod(x, "endCallMethods")).run(v::set);
+               return v.get();
+       }));
 
        /**
-        * The {@link JsonSchemaGenerator} for this resource, built from the 
builder's JSON-schema sub-builder.
+        * The {@link JsonSchemaGenerator.Builder} for this resource, with 
annotation work applied.
         */
-       private final Memoizer<JsonSchemaGenerator> jsonSchemaGenerator = 
memoizer(() -> jsonSchemaGeneratorBuilder.build());
+       private final Memoizer<JsonSchemaGenerator.Builder> 
jsonSchemaGeneratorBuilder = memoizer(() -> {
+               var bs = beanStore();
+               var v = Value.of(JsonSchemaGenerator.create());
+               bs.getBean(JsonSchemaGenerator.class).ifPresent(x -> 
v.get().impl(x));
+               new BeanCreateMethodFinder<>(JsonSchemaGenerator.class, 
resource().get(), bs).find(Builder::isRestInjectMethod).run(x -> 
v.get().impl(x));
+               v.get().apply(annotationWork);
+               return v.get();
+       });
+
+       /**
+        * The {@link JsonSchemaGenerator} for this resource.
+        */
+       private final Memoizer<JsonSchemaGenerator> jsonSchemaGenerator = 
memoizer(() -> jsonSchemaGeneratorBuilder.get().build());
 
        /**
         * The {@link Logger} for this resource.
@@ -1409,16 +796,29 @@ public class RestContext extends Context {
         */
        private final Memoizer<ParserSet> parsers = memoizer(() -> 
parsersBuilder.get().build());
 
+       /**
+        * The {@link HttpPartParser.Creator} for this resource, with 
annotation work applied.
+        */
+       private final Memoizer<HttpPartParser.Creator> partParserCreator = 
memoizer(() -> {
+               var bs = beanStore();
+               Value<HttpPartParser.Creator> v = 
Value.of(HttpPartParser.creator().type(OpenApiParser.class));
+               bs.getBean(HttpPartParser.class).ifPresent(x -> 
v.get().impl(x));
+               opt(resource().get() instanceof HttpPartParser x ? x : 
null).ifPresent(x -> v.get().impl(x));
+               bs.getBeanType(HttpPartParser.class).ifPresent(x -> 
v.get().type(x));
+               new BeanCreateMethodFinder<>(HttpPartParser.class, 
resource().get(), bs).find(Builder::isRestInjectMethod).run(x -> 
v.get().impl(x));
+               v.get().apply(annotationWork);
+               return v.get();
+       });
+
        /**
         * The {@link HttpPartParser} for this resource.
         *
         * <p>
-        * Uses the builder's part-parser creator (which has general config 
annotations applied by {@code init()}).
-        * Adds the {@code @Rest(partParser)} type override from the most 
specific (child-most)
-        * annotation in the hierarchy, replacing the factory default.
+        * Starts from the creator (general config annotations already applied) 
and adds the
+        * {@code @Rest(partParser)} type override from the most specific 
annotation in the hierarchy.
         */
        private final Memoizer<HttpPartParser> partParser = memoizer(() -> {
-               var creator = partParserCreator;
+               var creator = partParserCreator.get();
                getRestAnnotationsForProperty(PROPERTY_partParser)
                        .map(ai -> ai.inner().partParser())
                        .filter(ClassUtils::isNotVoid)
@@ -1427,16 +827,29 @@ public class RestContext extends Context {
                return creator.create();
        });
 
+       /**
+        * The {@link HttpPartSerializer.Creator} for this resource, with 
annotation work applied.
+        */
+       private final Memoizer<HttpPartSerializer.Creator> 
partSerializerCreator = memoizer(() -> {
+               var bs = beanStore();
+               Value<HttpPartSerializer.Creator> v = 
Value.of(HttpPartSerializer.creator().type(OpenApiSerializer.class));
+               bs.getBean(HttpPartSerializer.class).ifPresent(x -> 
v.get().impl(x));
+               opt(resource().get() instanceof HttpPartSerializer x ? x : 
null).ifPresent(x -> v.get().impl(x));
+               bs.getBeanType(HttpPartSerializer.class).ifPresent(x -> 
v.get().type(x));
+               new BeanCreateMethodFinder<>(HttpPartSerializer.class, 
resource().get(), bs).find(Builder::isRestInjectMethod).run(x -> 
v.get().impl(x));
+               v.get().apply(annotationWork);
+               return v.get();
+       });
+
        /**
         * The {@link HttpPartSerializer} for this resource.
         *
         * <p>
-        * Uses the builder's part-serializer creator (which has general config 
annotations applied by {@code init()}).
-        * Adds the {@code @Rest(partSerializer)} type override from the most 
specific (child-most)
-        * annotation in the hierarchy, replacing the factory default.
+        * Starts from the creator (general config annotations already applied) 
and adds the
+        * {@code @Rest(partSerializer)} type override from the most specific 
annotation in the hierarchy.
         */
        private final Memoizer<HttpPartSerializer> partSerializer = memoizer(() 
-> {
-               var creator = partSerializerCreator;
+               var creator = partSerializerCreator.get();
                getRestAnnotationsForProperty(PROPERTY_partSerializer)
                        .map(ai -> ai.inner().partSerializer())
                        .filter(ClassUtils::isNotVoid)
@@ -1448,22 +861,46 @@ public class RestContext extends Context {
        /**
         * Methods annotated with {@link 
org.apache.juneau.rest.annotation.RestPostCall @RestPostCall}.
         */
-       private final Memoizer<MethodList> postCallMethods = memoizer(() -> 
builder().createPostCallMethods(beanStore(), resource()));
+       private final Memoizer<MethodList> postCallMethods = memoizer(() -> {
+               var bs = beanStore();
+               var v = 
Value.of(MethodList.of(Builder.getAnnotatedMethods(resource(), 
RestPostCall.class).toList()));
+               new BeanCreateMethodFinder<>(MethodList.class, 
resource().get(), bs).addBean(MethodList.class, v.get()).find(x -> 
Builder.isRestInjectMethod(x, "postCallMethods")).run(v::set);
+               return v.get();
+       });
 
        /**
         * Methods annotated with {@link 
org.apache.juneau.rest.annotation.RestPostInit @RestPostInit}{@code 
(childFirst=true)} and their invokers.
         */
-       private final Memoizer<LifecycleInvokerPair> 
postInitChildFirstInvokerPair = memoizer(() -> buildLifecycleInvokerPair(() -> 
builder().createPostInitChildFirstMethods(beanStore(), resource())));
+       private final Memoizer<LifecycleInvokerPair> 
postInitChildFirstInvokerPair = memoizer(() -> buildLifecycleInvokerPair(() -> {
+               var bs = beanStore();
+               var v = 
Value.of(MethodList.of(Builder.getAnnotatedMethods(resource(), 
RestPostInit.class)
+                       .filter(m -> 
rstream(AnnotationProvider.INSTANCE.find(RestPostInit.class, 
MethodInfo.of(m))).map(AnnotationInfo::inner).anyMatch(RestPostInit::childFirst))
+                       .toList()));
+               new BeanCreateMethodFinder<>(MethodList.class, 
resource().get(), bs).addBean(MethodList.class, v.get()).find(x -> 
Builder.isRestInjectMethod(x, "postInitChildFirstMethods")).run(v::set);
+               return v.get();
+       }));
 
        /**
         * Methods annotated with {@link 
org.apache.juneau.rest.annotation.RestPostInit @RestPostInit} and their 
invokers.
         */
-       private final Memoizer<LifecycleInvokerPair> postInitInvokerPair = 
memoizer(() -> buildLifecycleInvokerPair(() -> 
builder().createPostInitMethods(beanStore(), resource())));
+       private final Memoizer<LifecycleInvokerPair> postInitInvokerPair = 
memoizer(() -> buildLifecycleInvokerPair(() -> {
+               var bs = beanStore();
+               var v = 
Value.of(MethodList.of(Builder.getAnnotatedMethods(resource(), 
RestPostInit.class)
+                       .filter(m -> 
rstream(AnnotationProvider.INSTANCE.find(RestPostInit.class, 
MethodInfo.of(m))).map(AnnotationInfo::inner).anyMatch(x -> !x.childFirst()))
+                       .toList()));
+               new BeanCreateMethodFinder<>(MethodList.class, 
resource().get(), bs).addBean(MethodList.class, v.get()).find(x -> 
Builder.isRestInjectMethod(x, "postInitMethods")).run(v::set);
+               return v.get();
+       }));
 
        /**
         * Methods annotated with {@link 
org.apache.juneau.rest.annotation.RestPreCall @RestPreCall}.
         */
-       private final Memoizer<MethodList> preCallMethods = memoizer(() -> 
builder().createPreCallMethods(beanStore(), resource()));
+       private final Memoizer<MethodList> preCallMethods = memoizer(() -> {
+               var bs = beanStore();
+               var v = 
Value.of(MethodList.of(Builder.getAnnotatedMethods(resource(), 
RestPreCall.class).toList()));
+               new BeanCreateMethodFinder<>(MethodList.class, 
resource().get(), bs).addBean(MethodList.class, v.get()).find(x -> 
Builder.isRestInjectMethod(x, "preCallMethods")).run(v::set);
+               return v.get();
+       });
 
        /**
         * The supported response content types ({@code Accept} media types) 
for this resource.
@@ -1563,7 +1000,12 @@ public class RestContext extends Context {
        /**
         * Methods annotated with {@link 
org.apache.juneau.rest.annotation.RestStartCall @RestStartCall} and their 
invokers.
         */
-       private final Memoizer<LifecycleInvokerPair> startCallInvokerPair = 
memoizer(() -> buildLifecycleInvokerPair(() -> 
builder().createStartCallMethods(beanStore(), resource())));
+       private final Memoizer<LifecycleInvokerPair> startCallInvokerPair = 
memoizer(() -> buildLifecycleInvokerPair(() -> {
+               var bs = beanStore();
+               var v = 
Value.of(MethodList.of(Builder.getAnnotatedMethods(resource(), 
RestStartCall.class).toList()));
+               new BeanCreateMethodFinder<>(MethodList.class, 
resource().get(), bs).addBean(MethodList.class, v.get()).find(x -> 
Builder.isRestInjectMethod(x, "startCallMethods")).run(v::set);
+               return v.get();
+       }));
 
        /**
         * The {@link StaticFiles} provider for this resource.
@@ -1631,15 +1073,15 @@ public class RestContext extends Context {
         * The runtime {@link VarResolver} — wraps the bootstrap resolver and 
adds {@link Messages} and {@link Config} beans.
         *
         * <p>
-        * The bootstrap {@link Config} is pulled from the builder to avoid a 
circular dependency: the runtime
-        * {@link Config} wraps the bootstrap config in a session backed by 
this resolver.
+        * 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.
         */
        private final Memoizer<VarResolver> varResolver = memoizer(() -> {
                var bs = beanStore();
                var b = getBootstrapVarResolver().copy()
                        .bean(Messages.class, getMessages())
-                       .bean(Config.class, rawConfig);
+                       .bean(Config.class, rawConfig.get());
                bs.getBean(VarResolver.class).ifPresent(b::impl);
                new BeanCreateMethodFinder<>(VarResolver.class, 
resource().get(), bs).addBean(VarResolver.Builder.class, 
b).find(Builder::isRestInjectMethod).run(b::impl);
                return b.build();
@@ -1651,16 +1093,41 @@ public class RestContext extends Context {
         *
         * <p>
         * Eagerly initialized in the constructor (via an explicit {@code 
.get()} call inside the try-catch block)
-        * so that any {@link ServletException} thrown by {@link 
Builder#createRestOperations} surfaces at
-        * construction time rather than lazily on first request. Subsequent 
calls return the cached instance.
+        * so that any {@link ServletException} surfaces at construction time 
rather than lazily on first request.
+        * Subsequent calls return the cached instance.
         */
-       private final Memoizer<RestOperations> restOperations = memoizer(() -> {
-               try {
-                       return builder().createRestOperations(beanStore(), 
resource(), this).build();
-               } catch (ServletException e) {
-                       throw new RuntimeException(e);
+       @SuppressWarnings({"java:S3776", "java:S1141"})
+       private final Memoizer<RestOperations> restOperations = memoizer(() -> 
safe(() -> {
+               var bs = beanStore();
+               var v = Value.of(RestOperations.create(bs));
+               var ap = getBeanContext().getAnnotationProvider();
+               var rci = ClassInfo.of(resource().get());
+               for (var mi : rci.getPublicMethods()) {
+                       var al = 
rstream(ap.find(mi)).filter(REST_OP_GROUP).collect(Collectors.toList());
+                       if (al.isEmpty()) {
+                               Predicate<MethodInfo> isRestAnnotatedInterface 
= x -> x.getDeclaringClass().isInterface()
+                                       && 
nn(x.getDeclaringClass().getAnnotations(Rest.class).findFirst().map(AnnotationInfo::inner).orElse(null));
+                               
mi.getMatchingMethods().stream().filter(isRestAnnotatedInterface).forEach(x -> 
al.add(AnnotationInfo.of(x, RestOpAnnotation.DEFAULT)));
+                       }
+                       if (!al.isEmpty()) {
+                               try {
+                                       if (mi.isNotPublic())
+                                               throw servletException("@RestOp 
method {0}.{1} must be defined as public.", rci.inner().getName(), 
mi.getNameSimple());
+                                       var roc = new RestOpContext(mi.inner(), 
this);
+                                       if ("RRPC".equals(roc.getHttpMethod())) 
{
+                                               RestOpContext roc2 = new 
RrpcRestOpContext(mi.inner(), this);
+                                               v.get().add("GET", 
roc2).add("POST", roc2);
+                                       } else {
+                                               v.get().add(roc);
+                                       }
+                               } catch (Exception e) {
+                                       throw servletException(e, "Problem 
occurred trying to initialize methods on class {0}", rci.inner().getName());
+                               }
+                       }
                }
-       });
+               new BeanCreateMethodFinder<>(RestOperations.class, 
resource().get(), bs).addBean(RestOperations.Builder.class, 
v.get()).find(Builder::isRestInjectMethod).run(x -> v.get().impl(x));
+               return v.get().build();
+       }));
 
        /**
         * The {@link RestChildren} for this resource — child {@link 
RestContext} instances registered via
@@ -1675,46 +1142,42 @@ public class RestContext extends Context {
        @SuppressWarnings({
                "java:S3776" // cognitive complexity acceptable for 
child-context construction
        })
-       private final Memoizer<RestChildren> restChildren = memoizer(() -> {
-               try {
-                       var bs = beanStore();
-                       var servletConfig = 
bs.getBean(ServletConfig.class).orElse(null);
-                       var v = 
Value.of(RestChildren.create(bs).type(RestChildren.class));
-
-                       // Collect child classes from @Rest(children) on the 
annotation chain (parent-to-child order).
-                       // Deduplicate so the same child class registered on 
both a parent and child annotation
-                       // doesn't create two contexts.
-                       var seen = new LinkedHashSet<Class<?>>();
-                       getRestAnnotations().forEach(ai -> 
seen.addAll(Arrays.asList(ai.inner().children())));
-
-                       for (var rc2 : seen) {
-                               if (rc2 == resourceClass())
-                                       continue;  // Guard against 
self-reference infinite loop.
-                               Supplier<?> so;
-                               if (bs.getBean(rc2).isPresent()) {
-                                       so = () -> bs.getBean(rc2).get();
-                               } else {
-                                       Object o2 = BeanCreator.of(rc2, 
bs).run();
-                                       so = () -> o2;
-                               }
-                               var cc = new RestContext(new Args(rc2, this, 
servletConfig, so, "", null));
-                               var mi = ClassInfo.of(so.get()).getMethod(x -> 
x.hasName("setContext") && x.hasParameterTypes(RestContext.class)).orElse(null);
-                               if (nn(mi))
-                                       mi.accessible().invoke(so.get(), cc);
-                               v.get().add(cc);
+       private final Memoizer<RestChildren> restChildren = memoizer(() -> 
safe(() -> {
+               var bs = beanStore();
+               var servletConfig = 
bs.getBean(ServletConfig.class).orElse(null);
+               var v = 
Value.of(RestChildren.create(bs).type(RestChildren.class));
+
+               // Collect child classes from @Rest(children) on the annotation 
chain (parent-to-child order).
+               // Deduplicate so the same child class registered on both a 
parent and child annotation
+               // doesn't create two contexts.
+               var seen = new LinkedHashSet<Class<?>>();
+               getRestAnnotations().forEach(ai -> 
seen.addAll(Arrays.asList(ai.inner().children())));
+
+               for (var rc2 : seen) {
+                       if (rc2 == resourceClass())
+                               continue;  // Guard against self-reference 
infinite loop.
+                       Supplier<?> so;
+                       if (bs.getBean(rc2).isPresent()) {
+                               so = () -> bs.getBean(rc2).get();
+                       } else {
+                               Object o2 = BeanCreator.of(rc2, bs).run();
+                               so = () -> o2;
                        }
+                       var cc = new RestContext(new Args(rc2, this, 
servletConfig, so, "", null));
+                       var mi = ClassInfo.of(so.get()).getMethod(x -> 
x.hasName("setContext") && x.hasParameterTypes(RestContext.class)).orElse(null);
+                       if (nn(mi))
+                               mi.accessible().invoke(so.get(), cc);
+                       v.get().add(cc);
+               }
 
-                       // @RestInject override — allows replacing the entire 
RestChildren instance.
-                       new BeanCreateMethodFinder<>(RestChildren.class, 
resource().get(), bs)
-                               .addBean(RestChildren.Builder.class, v.get())
-                               .find(Builder::isRestInjectMethod)
-                               .run(x -> v.get().impl(x));
+               // @RestInject override — allows replacing the entire 
RestChildren instance.
+               new BeanCreateMethodFinder<>(RestChildren.class, 
resource().get(), bs)
+                       .addBean(RestChildren.Builder.class, v.get())
+                       .find(Builder::isRestInjectMethod)
+                       .run(x -> v.get().impl(x));
 
-                       return v.get().build();
-               } catch (Exception e) {
-                       throw new RuntimeException(e);
-               }
-       });
+               return v.get().build();
+       }));
 
        /**
         * Constructor.
@@ -1737,6 +1200,7 @@ public class RestContext extends Context {
         * @param builder The builder containing the settings for this bean.
         * @throws Exception If any initialization problems were encountered.
         */
+       @SuppressWarnings({"java:S3776", "java:S1141"})
        private RestContext(Builder builder) throws Exception {
                super(builder);
 
@@ -1778,10 +1242,8 @@ public class RestContext extends Context {
                        beanStore = bs;
 
                        beanStore.add(BasicBeanStore.class, beanStore);
-                       rawBootstrapVarResolver = 
builder.createBootstrapVarResolver(beanStore, resource, resourceClass);
-                       beanStore.add(VarResolver.class, 
rawBootstrapVarResolver);
-                       rawConfig = builder.createConfig(beanStore, resource, 
resourceClass);
-                       beanStore.add(Config.class, rawConfig);
+                       beanStore.add(VarResolver.class, 
getBootstrapVarResolver());
+                       beanStore.add(Config.class, rawConfig.get());
 
                        var rci2 = ClassInfo.of(resourceClass);
 
@@ -1811,7 +1273,28 @@ public class RestContext extends Context {
                                }
                        });
 
-                       Builder.runInitHooks(beanStore, resource);
+                       // Run @RestInit-annotated methods on the resource 
object (deduplicated by signature, top-down order).
+                       // Note: pre-9.5 this filter also excluded 
`y.hasParameter(RestOpContext.Builder.class)` because the
+                       // per-op `@RestInit(RestOpContext.Builder)` flow 
handled those separately. That flow was deleted in
+                       // April 2026 refactor Route B (zero real-world 
callers), so the exclusion is gone too. Likewise, the
+                       // class-level `@RestInit(RestContext.Builder)` 
injection protocol was deleted in the same refactor
+                       // (zero non-test callers anywhere) — 
`RestContext.Builder` is no longer added to the bean store, so
+                       // any straggling `@RestInit` method that still 
declares either Builder type as a parameter will now
+                       // surface a "missing prerequisites" error here, which 
is the desired loud-failure signal.
+                       var r = resource.get();
+                       var initMap = CollectionUtils.<String,MethodInfo>map();
+                       ClassInfo.ofProxy(r).getAllMethodsTopDown().stream()
+                               .filter(y -> y.hasAnnotation(RestInit.class))
+                               .forEach(y -> { var sig = y.getSignature(); if 
(!initMap.containsKey(sig)) initMap.put(sig, y.accessible()); });
+                       for (var m : initMap.values()) {
+                               if (!beanStore.hasAllParams(m, r))
+                                       throw servletException("Could not call 
@RestInit method {0}.{1}.  Could not find prerequisites: {2}.", 
cns(m.getDeclaringClass()), m.getSignature(), beanStore.getMissingParams(m, r));
+                               try {
+                                       m.invoke(r, beanStore.getParams(m, r));
+                               } catch (Exception e) {
+                                       throw servletException(e, "Exception 
thrown from @RestInit method {0}.{1}.", cns(m.getDeclaringClass()), 
m.getSignature());
+                               }
+                       }
 
                        // Back-fill @RestInject fields that were null before 
init hooks ran.
                        // @formatter:off
@@ -1844,17 +1327,10 @@ public class RestContext extends Context {
                                p += "/*";
                        pathMatcher = UrlPathMatcher.of(p);
 
-                       // Initialize sub-builders and apply @Rest annotation 
work.
-                       beanContextBuilder = 
builder.createBeanContext(beanStore, resource);
-                       partParserCreator = builder.createPartParser(beanStore, 
resource);
-                       partSerializerCreator = 
builder.createPartSerializer(beanStore, resource);
-                       jsonSchemaGeneratorBuilder = 
builder.createJsonSchemaGenerator(beanStore, resource);
-                       var vrs = rawBootstrapVarResolver.createSession();
+                       // Build annotation work list, then trigger 
beanContextBuilder (which applies it).
+                       var vrs = getBootstrapVarResolver().createSession();
                        annotationWork = AnnotationWorkList.of(vrs, 
rstream(AnnotationProvider.INSTANCE.find(rci2)).filter(CONTEXT_APPLY_FILTER));
-                       beanContextBuilder.apply(annotationWork);
-                       partSerializerCreator.apply(annotationWork);
-                       partParserCreator.apply(annotationWork);
-                       jsonSchemaGeneratorBuilder.apply(annotationWork);
+                       beanContextBuilder.get(); // force init with 
annotationWork now set
 
                        // @formatter:off
                        beanStore
@@ -2457,12 +1933,12 @@ public class RestContext extends Context {
         */
        public BeanContext getBeanContext() { return beanContext.get(); }
 
-       BeanContext.Builder         getBeanContextBuilder()          { return 
beanContextBuilder; }
+       BeanContext.Builder         getBeanContextBuilder()          { return 
beanContextBuilder.get(); }
        EncoderSet.Builder          getEncodersBuilder()             { return 
encodersBuilder.get(); }
-       JsonSchemaGenerator.Builder getJsonSchemaGeneratorBuilder()  { return 
jsonSchemaGeneratorBuilder; }
+       JsonSchemaGenerator.Builder getJsonSchemaGeneratorBuilder()  { return 
jsonSchemaGeneratorBuilder.get(); }
        ParserSet.Builder           getParsersBuilder()              { return 
parsersBuilder.get(); }
-       HttpPartParser.Creator      getPartParserCreator()           { return 
partParserCreator; }
-       HttpPartSerializer.Creator  getPartSerializerCreator()       { return 
partSerializerCreator; }
+       HttpPartParser.Creator      getPartParserCreator()           { return 
partParserCreator.get(); }
+       HttpPartSerializer.Creator  getPartSerializerCreator()       { return 
partSerializerCreator.get(); }
        SerializerSet.Builder       getSerializersBuilder()          { return 
serializersBuilder.get(); }
 
        /**

Reply via email to