001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.juneau.rest;
018
019import static org.apache.juneau.commons.reflect.AnnotationTraversal.*;
020import static org.apache.juneau.commons.utils.AssertionUtils.*;
021import static org.apache.juneau.commons.utils.CollectionUtils.*;
022import static org.apache.juneau.commons.utils.StringUtils.*;
023import static org.apache.juneau.commons.utils.ThrowableUtils.*;
024import static org.apache.juneau.commons.utils.Utils.*;
025import static org.apache.juneau.http.HttpHeaders.*;
026import static org.apache.juneau.http.HttpParts.*;
027import static org.apache.juneau.httppart.HttpPartType.*;
028import static org.apache.juneau.rest.util.RestUtils.*;
029
030import java.lang.annotation.*;
031import java.lang.reflect.Method;
032import java.nio.charset.*;
033import java.util.*;
034import java.util.concurrent.*;
035import java.util.function.*;
036import org.apache.http.*;
037import org.apache.juneau.*;
038import org.apache.juneau.annotation.*;
039import org.apache.juneau.commons.collections.*;
040import org.apache.juneau.commons.collections.FluentMap;
041import org.apache.juneau.commons.lang.*;
042import org.apache.juneau.commons.reflect.*;
043import org.apache.juneau.commons.utils.*;
044import org.apache.juneau.cp.*;
045import org.apache.juneau.encoders.*;
046import org.apache.juneau.http.annotation.*;
047import org.apache.juneau.http.annotation.Header;
048import org.apache.juneau.http.header.*;
049import org.apache.juneau.http.part.*;
050import org.apache.juneau.http.remote.*;
051import org.apache.juneau.http.response.*;
052import org.apache.juneau.httppart.*;
053import org.apache.juneau.httppart.HttpPartSerializer.*;
054import org.apache.juneau.httppart.bean.*;
055import org.apache.juneau.jsonschema.*;
056import org.apache.juneau.parser.*;
057import org.apache.juneau.parser.ParseException;
058import org.apache.juneau.rest.annotation.*;
059import org.apache.juneau.rest.common.utils.*;
060import org.apache.juneau.rest.converter.*;
061import org.apache.juneau.rest.debug.*;
062import org.apache.juneau.rest.guard.*;
063import org.apache.juneau.rest.httppart.*;
064import org.apache.juneau.rest.logger.*;
065import org.apache.juneau.rest.matcher.*;
066import org.apache.juneau.rest.swagger.*;
067import org.apache.juneau.rest.util.*;
068import org.apache.juneau.serializer.*;
069import jakarta.servlet.*;
070import jakarta.servlet.http.*;
071
072/**
073 * Represents a single Java servlet/resource method annotated with {@link RestOp @RestOp}.
074 *
075 * <h5 class='section'>Notes:</h5><ul>
076 *    <li class='note'>This class is thread safe and reusable.
077 * </ul>
078 *
079 * <h5 class='section'>See Also:</h5><ul>
080 *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/RestOpContext">RestOpContext</a>
081 * </ul>
082 */
083public class RestOpContext extends Context implements Comparable<RestOpContext> {
084
085   private static final AnnotationProvider AP = AnnotationProvider.INSTANCE;
086
087   /**
088    * Builder class.
089    */
090   public static class Builder extends Context.Builder {
091
092      private BeanContext.Builder beanContext;
093      private BeanStore beanStore;
094      private boolean dotAll;
095      private Charset defaultCharset;
096      private EncoderSet.Builder encoders;
097      private Enablement debug;
098      private HeaderList defaultRequestHeaders;
099      private HeaderList defaultResponseHeaders;
100      private HttpPartParser.Creator partParser;
101      private HttpPartSerializer.Creator partSerializer;
102      private JsonSchemaGenerator.Builder jsonSchemaGenerator;
103      private List<MediaType> consumes;
104      private List<MediaType> produces;
105      private List<String> path;
106      private Long maxInput;
107      private Method restMethod;
108      private NamedAttributeMap defaultRequestAttributes;
109      private ParserSet.Builder parsers;
110      private PartList defaultRequestFormData;
111      private PartList defaultRequestQueryData;
112      private RestContext restContext;
113      private RestContext.Builder parent;
114      private RestConverterList.Builder converters;
115      private RestGuardList.Builder guards;
116      private RestMatcherList.Builder matchers;
117      private SerializerSet.Builder serializers;
118      private Set<String> roleGuard;
119      private Set<String> rolesDeclared;
120      private String clientVersion;
121      private String httpMethod;
122
123      Builder(java.lang.reflect.Method method, RestContext context) {
124
125         this.restContext = context;
126         this.parent = context.builder;
127         this.restMethod = method;
128
129         this.beanStore = BeanStore.of(context.getBeanStore(), context.builder.resource().get()).addBean(java.lang.reflect.Method.class, method);
130         var ap = context.getBeanContext().getAnnotationProvider();
131
132         var mi = MethodInfo.of(context.getResourceClass(), method);
133
134         try {
135            var vr = context.getVarResolver();
136            var vrs = vr.createSession();
137
138            var work = AnnotationWorkList.of(vrs, rstream(ap.find(mi, SELF, MATCHING_METHODS, DECLARING_CLASS, RETURN_TYPE, PACKAGE)).filter(CONTEXT_APPLY_FILTER));
139
140            apply(work);
141
142            if (context.builder.beanContext().canApply(work))
143               beanContext().apply(work);
144            if (context.builder.serializers().canApply(work))
145               serializers().apply(work);
146            if (context.builder.parsers().canApply(work))
147               parsers().apply(work);
148            if (context.builder.partSerializer().canApply(work))
149               partSerializer().apply(work);
150            if (context.builder.partParser().canApply(work))
151               partParser().apply(work);
152            if (context.builder.jsonSchemaGenerator().canApply(work))
153               jsonSchemaGenerator().apply(work);
154
155            processParameterAnnotations();
156
157         } catch (Exception e) {
158            throw new InternalServerError(e);
159         }
160      }
161
162      @Override /* Overridden from Builder */
163      public Builder annotations(Annotation...values) {
164         super.annotations(values);
165         return this;
166      }
167
168      @Override /* Overridden from Builder */
169      public Builder apply(AnnotationWorkList work) {
170         super.apply(work);
171         return this;
172      }
173
174      @Override /* Overridden from Builder */
175      public Builder applyAnnotations(Class<?>...from) {
176         super.applyAnnotations(from);
177         return this;
178      }
179
180      @Override /* Overridden from Builder */
181      public Builder applyAnnotations(Object...from) {
182         super.applyAnnotations(from);
183         return this;
184      }
185
186      /**
187       * Returns the bean context sub-builder.
188       *
189       * @return The bean context sub-builder.
190       */
191      public BeanContext.Builder beanContext() {
192         if (beanContext == null)
193            beanContext = createBeanContext(beanStore(), parent, resource());
194         return beanContext;
195      }
196
197      /**
198       * Returns access to the bean store being used by this builder.
199       *
200       * <p>
201       * Can be used to add more beans to the bean store.
202       *
203       * @return The bean store being used by this builder.
204       */
205      public BeanStore beanStore() {
206         return beanStore;
207      }
208
209      /**
210       * Adds a bean to the bean store of this operation.
211       *
212       * <p>
213       * Equivalent to calling:
214       * <p class='bjava'>
215       *    <jv>builder</jv>.beanStore().add(<jv>beanType</jv>, <jv>bean</jv>);
216       * </p>
217       *
218       * @param <T> The class to associate this bean with.
219       * @param beanType The class to associate this bean with.
220       *    <br>Cannot be <jk>null</jk>.
221       * @param bean The bean.
222       *    <br>Can be <jk>null</jk> (a null bean will be stored in the bean store).
223       * @return This object.
224       */
225      public <T> Builder beanStore(Class<T> beanType, T bean) {
226         beanStore().addBean(assertArgNotNull("beanType", beanType), bean);
227         return this;
228      }
229
230      /**
231       * Adds a bean to the bean store of this operation.
232       *
233       * <p>
234       * Equivalent to calling:
235       * <p class='bjava'>
236       *    <jv>builder</jv>.beanStore().add(<jv>beanType</jv>, <jv>bean</jv>, <jv>name</jv>);
237       * </p>
238       *
239       * @param <T> The class to associate this bean with.
240       * @param beanType The class to associate this bean with.
241       *    <br>Cannot be <jk>null</jk>.
242       * @param bean The bean.
243       *    <br>Can be <jk>null</jk> (a null bean will be stored in the bean store).
244       * @param name The bean name if this is a named bean.
245       *    <br>Can be <jk>null</jk> (bean will be stored as an unnamed bean).
246       * @return This object.
247       */
248      public <T> Builder beanStore(Class<T> beanType, T bean, String name) {
249         beanStore().addBean(assertArgNotNull("beanType", beanType), bean, name);
250         return this;
251      }
252
253      @Override /* Overridden from BeanContext.Builder */
254      public RestOpContext build() {
255         try {
256            return beanStore.createBean(RestOpContext.class).type(getType().orElse(getDefaultImplClass())).builder(RestOpContext.Builder.class, this).run();
257         } catch (Exception e) {
258            throw new InternalServerError(e);
259         }
260      }
261
262      @Override /* Overridden from Builder */
263      public Builder cache(Cache<HashKey,? extends org.apache.juneau.Context> value) {
264         super.cache(value);
265         return this;
266      }
267
268      /**
269       * Client version pattern matcher.
270       *
271       * <p>
272       * Specifies whether this method can be called based on the client version.
273       *
274       * <p>
275       * The client version is identified via the HTTP request header identified by
276       * {@link Rest#clientVersionHeader() @Rest(clientVersionHeader)} which by default is <js>"Client-Version"</js>.
277       *
278       * <p>
279       * This is a specialized kind of {@link RestMatcher} that allows you to invoke different Java methods for the same
280       * method/path based on the client version.
281       *
282       * <p>
283       * The format of the client version range is similar to that of OSGi versions.
284       *
285       * <p>
286       * In the following example, the Java methods are mapped to the same HTTP method and URL <js>"/foobar"</js>.
287       * <p class='bjava'>
288       *    <jc>// Call this method if Client-Version is at least 2.0.
289       *    // Note that this also matches 2.0.1.</jc>
290       *    <ja>@RestGet</ja>(path=<js>"/foobar"</js>, clientVersion=<js>"2.0"</js>)
291       *    <jk>public</jk> Object method1()  {...}
292       *
293       *    <jc>// Call this method if Client-Version is at least 1.1, but less than 2.0.</jc>
294       *    <ja>@RestGet</ja>(path=<js>"/foobar"</js>, clientVersion=<js>"[1.1,2.0)"</js>)
295       *    <jk>public</jk> Object method2()  {...}
296       *
297       *    <jc>// Call this method if Client-Version is less than 1.1.</jc>
298       *    <ja>@RestGet</ja>(path=<js>"/foobar"</js>, clientVersion=<js>"[0,1.1)"</js>)
299       *    <jk>public</jk> Object method3()  {...}
300       * </p>
301       *
302       * <p>
303       * It's common to combine the client version with transforms that will convert new POJOs into older POJOs for
304       * backwards compatibility.
305       * <p class='bjava'>
306       *    <jc>// Call this method if Client-Version is at least 2.0.</jc>
307       *    <ja>@RestGet</ja>(path=<js>"/foobar"</js>, clientVersion=<js>"2.0"</js>)
308       *    <jk>public</jk> NewPojo newMethod()  {...}
309       *
310       *    <jc>// Call this method if Client-Version is at least 1.1, but less than 2.0.</jc>
311       *    <ja>@RestGet</ja>(path=<js>"/foobar"</js>, clientVersion=<js>"[1.1,2.0)"</js>)
312       *    <ja>@BeanConfig(swaps=NewToOldSwap.<jk>class</jk>)
313       *    <jk>public</jk> NewPojo oldMethod() {
314       *       <jk>return</jk> newMethod();
315       *    }
316       *
317       * <p>
318       * Note that in the previous example, we're returning the exact same POJO, but using a transform to convert it into
319       * an older form.
320       * The old method could also just return back a completely different object.
321       * The range can be any of the following:
322       * <ul>
323       *    <li><js>"[0,1.0)"</js> = Less than 1.0.  1.0 and 1.0.0 does not match.
324       *    <li><js>"[0,1.0]"</js> = Less than or equal to 1.0.  Note that 1.0.1 will match.
325       *    <li><js>"1.0"</js> = At least 1.0.  1.0 and 2.0 will match.
326       * </ul>
327       *
328       * <h5 class='section'>See Also:</h5><ul>
329       *    <li class='ja'>{@link RestOp#clientVersion}
330       *    <li class='ja'>{@link RestGet#clientVersion}
331       *    <li class='ja'>{@link RestPut#clientVersion}
332       *    <li class='ja'>{@link RestPost#clientVersion}
333       *    <li class='ja'>{@link RestDelete#clientVersion}
334       *    <li class='jm'>{@link RestContext.Builder#clientVersionHeader(String)}
335       * </ul>
336       *
337       * @param value The new value for this setting.
338       *    <br>Cannot be <jk>null</jk>.
339       * @return This object.
340       */
341      public Builder clientVersion(String value) {
342         clientVersion = assertArgNotNull("value", value);
343         return this;
344      }
345
346      /**
347       * Supported content media types.
348       *
349       * <p>
350       * Overrides the media types inferred from the parsers that identify what media types can be consumed by the resource.
351       * <br>An example where this might be useful if you have parsers registered that handle media types that you
352       * don't want exposed in the Swagger documentation.
353       *
354       * <p>
355       * This affects the returned values from the following:
356       * <ul class='javatree'>
357       *    <li class='jm'>{@link RestContext#getConsumes() RestContext.getConsumes()}
358       * </ul>
359       *
360       * <h5 class='section'>See Also:</h5><ul>
361       *    <li class='ja'>{@link Rest#consumes}
362       *    <li class='ja'>{@link RestOp#consumes}
363       *    <li class='ja'>{@link RestPut#consumes}
364       *    <li class='ja'>{@link RestPost#consumes}
365       * </ul>
366       *
367       * @param values The values to add to this setting.
368       *    <br>Cannot contain <jk>null</jk> values.
369       * @return This object.
370       */
371      public Builder consumes(MediaType...values) {
372         assertArgNoNulls("values", values);
373         consumes = addAll(consumes, values);
374         return this;
375      }
376
377      /**
378       * Returns the response converter list sub-builder.
379       *
380       * @return The response converter list sub-builder.
381       */
382      public RestConverterList.Builder converters() {
383         if (converters == null)
384            converters = createConverters(beanStore(), resource());
385         return converters;
386      }
387
388      /**
389       * Adds one or more converters to use to convert response objects for this operation.
390       *
391       * <p>
392       * Equivalent to calling:
393       * <p class='bjava'>
394       *    <jv>builder</jv>.converters().append(<jv>value</jv>);
395       * </p>
396       *
397       * @param value The new value.
398       *    <br>Cannot contain <jk>null</jk> values.
399       * @return This object.
400       */
401      @SafeVarargs
402      public final Builder converters(Class<? extends RestConverter>...value) {
403         assertArgNoNulls("value", value);
404         converters().append(value);
405         return this;
406      }
407
408      /**
409       * Adds one or more converters to this operation.
410       *
411       * <p>
412       * Equivalent to calling:
413       * <p class='bjava'>
414       *    <jv>builder</jv>.converters().append(<jv>value</jv>);
415       * </p>
416       *
417       * @param value The new value.
418       *    <br>Cannot contain <jk>null</jk> values.
419       * @return This object.
420       */
421      public Builder converters(RestConverter...value) {
422         assertArgNoNulls("value", value);
423         converters().append(value);
424         return this;
425      }
426
427      @Override /* Overridden from Context.Builder */
428      public Builder copy() {
429         throw new NoSuchMethodError("Not implemented.");
430      }
431
432      @Override /* Overridden from Builder */
433      public Builder debug() {
434         super.debug();
435         return this;
436      }
437
438      @Override /* Overridden from Builder */
439      public Builder debug(boolean value) {
440         super.debug(value);
441         return this;
442      }
443
444      /**
445       * Debug mode.
446       *
447       * <p>
448       * Enables the following:
449       * <ul class='spaced-list'>
450       *    <li>
451       *       HTTP request/response bodies are cached in memory for logging purposes.
452       * </ul>
453       *
454       * <p>
455       * If not sppecified, the debug enablement is inherited from the class context.
456       *
457       * @param value The new value for this setting.
458       *    <br>Cannot be <jk>null</jk>.
459       * @return This object.
460       */
461      public Builder debug(Enablement value) {
462         debug = assertArgNotNull("value", value);
463         return this;
464      }
465
466      /**
467       * Default character encoding.
468       *
469       * <p>
470       * The default character encoding for the request and response if not specified on the request.
471       *
472       * <p>
473       * This overrides the value defined on the {@link RestContext}.
474       *
475       * <h5 class='section'>See Also:</h5><ul>
476       *    <li class='jm'>{@link RestContext.Builder#defaultCharset(Charset)}
477       *    <li class='ja'>{@link Rest#defaultCharset}
478       *    <li class='ja'>{@link RestOp#defaultCharset}
479       * </ul>
480       *
481       * @param value
482       *    The new value for this setting.
483       *    <br>The default is the first value found:
484       *    <ul>
485       *       <li>System property <js>"RestContext.defaultCharset"
486       *       <li>Environment variable <js>"RESTCONTEXT_defaultCharset"
487       *       <li><js>"utf-8"</js>
488       *    </ul>
489       *    <br>Cannot be <jk>null</jk>.
490       * @return This object.
491       */
492      public Builder defaultCharset(Charset value) {
493         defaultCharset = assertArgNotNull("value", value);
494         return this;
495      }
496
497      /**
498       * Returns the default classes list.
499       *
500       * <p>
501       * This defines the implementation classes for a variety of bean types.
502       *
503       * <p>
504       * Default classes are inherited from the parent REST object.
505       * Typically used on the top-level {@link RestContext.Builder} to affect class types for that REST object and all children.
506       *
507       * <p>
508       * Modifying the default class list on this builder does not affect the default class list on the parent builder, but changes made
509       * here are inherited by child builders.
510       *
511       * @return The default classes list for this builder.
512       */
513      public DefaultClassList defaultClasses() {
514         return restContext.builder.defaultClasses();
515      }
516
517      /**
518       * Returns the default request attributes sub-builder.
519       *
520       * @return The default request attributes sub-builder.
521       */
522      public NamedAttributeMap defaultRequestAttributes() {
523         if (defaultRequestAttributes == null)
524            defaultRequestAttributes = createDefaultRequestAttributes(beanStore(), parent, resource());
525         return defaultRequestAttributes;
526      }
527
528      /**
529       * Adds one or more default request attributes to this operation.
530       *
531       * <p>
532       * Equivalent to calling:
533       * <p class='bjava'>
534       *    <jv>builder</jv>.defaultRequestAttributes().append(<jv>value</jv>);
535       * </p>
536       *
537       * @param value The values to add.
538       *    <br>Cannot contain <jk>null</jk> values.
539       * @return This object.
540       */
541      public Builder defaultRequestAttributes(NamedAttribute...value) {
542         assertArgNoNulls("value", value);
543         defaultRequestAttributes().add(value);
544         return this;
545      }
546
547      /**
548       * Returns the default request form data.
549       *
550       * @return The default request form data.
551       */
552      public PartList defaultRequestFormData() {
553         if (defaultRequestFormData == null)
554            defaultRequestFormData = createDefaultRequestFormData(beanStore(), parent, resource());
555         return defaultRequestFormData;
556      }
557
558      /**
559       * Adds one or more default request form data to this operation.
560       *
561       * <p>
562       * Equivalent to calling:
563       * <p class='bjava'>
564       *    <jv>builder</jv>.defaultRequestFormData().append(<jv>value</jv>);
565       * </p>
566       *
567       * @param value The values to add.
568       *    <br>Cannot contain <jk>null</jk> values.
569       * @return This object.
570       */
571      public Builder defaultRequestFormData(NameValuePair...value) {
572         assertArgNoNulls("value", value);
573         defaultRequestFormData().append(value);
574         return this;
575      }
576
577      /**
578       * Returns the default request headers.
579       *
580       * @return The default request headers.
581       */
582      public HeaderList defaultRequestHeaders() {
583         if (defaultRequestHeaders == null)
584            defaultRequestHeaders = createDefaultRequestHeaders(beanStore(), parent, resource());
585         return defaultRequestHeaders;
586      }
587
588      /**
589       * Adds one or more default request headers to this operation.
590       *
591       * <p>
592       * Equivalent to calling:
593       * <p class='bjava'>
594       *    <jv>builder</jv>.defaultRequestHeaders().append(<jv>value</jv>);
595       * </p>
596       *
597       * @param value The values to add.
598       *    <br>Cannot contain <jk>null</jk> values.
599       * @return This object.
600       */
601      public Builder defaultRequestHeaders(org.apache.http.Header...value) {
602         assertArgNoNulls("value", value);
603         defaultRequestHeaders().append(value);
604         return this;
605      }
606
607      /**
608       * Returns the default request query data.
609       *
610       * @return The default request query data.
611       */
612      public PartList defaultRequestQueryData() {
613         if (defaultRequestQueryData == null)
614            defaultRequestQueryData = createDefaultRequestQueryData(beanStore(), parent, resource());
615         return defaultRequestQueryData;
616      }
617
618      /**
619       * Adds one or more default request query data to this operation.
620       *
621       * <p>
622       * Equivalent to calling:
623       * <p class='bjava'>
624       *    <jv>builder</jv>.defaultRequestQueryData().append(<jv>value</jv>);
625       * </p>
626       *
627       * @param value The values to add.
628       *    <br>Cannot contain <jk>null</jk> values.
629       * @return This object.
630       */
631      public Builder defaultRequestQueryData(NameValuePair...value) {
632         assertArgNoNulls("value", value);
633         defaultRequestQueryData().append(value);
634         return this;
635      }
636
637      /**
638       * Returns the default response headers.
639       *
640       * @return The default response headers.
641       */
642      public HeaderList defaultResponseHeaders() {
643         if (defaultResponseHeaders == null)
644            defaultResponseHeaders = createDefaultResponseHeaders(beanStore(), parent, resource());
645         return defaultResponseHeaders;
646      }
647
648      /**
649       * Adds one or more default response headers to this operation.
650       *
651       * <p>
652       * Equivalent to calling:
653       * <p class='bjava'>
654       *    <jv>builder</jv>.defaultResponseHeaders().append(<jv>value</jv>);
655       * </p>
656       *
657       * @param value The values to add.
658       *    <br>Cannot contain <jk>null</jk> values.
659       * @return This object.
660       */
661      public Builder defaultResponseHeaders(org.apache.http.Header...value) {
662         assertArgNoNulls("value", value);
663         defaultResponseHeaders().append(value);
664         return this;
665      }
666
667      /**
668       * When enabled, append <js>"/*"</js> to path patterns if not already present.
669       *
670       * @return This object.
671       */
672      public Builder dotAll() {
673         dotAll = true;
674         return this;
675      }
676
677      /**
678       * Returns the encoder group sub-builder.
679       *
680       * @return The encoder group sub-builder.
681       */
682      public EncoderSet.Builder encoders() {
683         if (encoders == null)
684            encoders = createEncoders(beanStore(), parent, resource());
685         return encoders;
686      }
687
688      /**
689       * Adds one or more encoders to this operation.
690       *
691       * <p>
692       * Equivalent to calling:
693       * <p class='bjava'>
694       *    <jv>builder</jv>.encoders().add(<jv>value</jv>);
695       * </p>
696       *
697       * @param value The values to add.
698       *    <br>Cannot contain <jk>null</jk> values.
699       * @return This object.
700       */
701      @SafeVarargs
702      public final Builder encoders(Class<? extends Encoder>...value) {
703         assertArgNoNulls("value", value);
704         encoders().add(value);
705         return this;
706      }
707
708      /**
709       * Adds one or more encoders to this operation.
710       *
711       * <p>
712       * Equivalent to calling:
713       * <p class='bjava'>
714       *    <jv>builder</jv>.encoders().add(<jv>value</jv>);
715       * </p>
716       *
717       * @param value The values to add.
718       *    <br>Cannot contain <jk>null</jk> values.
719       * @return This object.
720       */
721      public Builder encoders(Encoder...value) {
722         assertArgNoNulls("value", value);
723         encoders().add(value);
724         return this;
725      }
726
727      /**
728       * Returns the guard list sub-builder.
729       *
730       * @return The guard list sub-builder.
731       */
732      public RestGuardList.Builder guards() {
733         if (guards == null)
734            guards = createGuards(beanStore(), resource());
735         return guards;
736      }
737
738      /**
739       * Adds one or more guards to this operation.
740       *
741       * <p>
742       * Equivalent to calling:
743       * <p class='bjava'>
744       *    <jv>builder</jv>.guards().append(<jv>value</jv>);
745       * </p>
746       *
747       * @param value The values to add.
748       *    <br>Cannot contain <jk>null</jk> values.
749       * @return This object.
750       */
751      @SafeVarargs
752      public final Builder guards(Class<? extends RestGuard>...value) {
753         assertArgNoNulls("value", value);
754         guards().append(value);
755         return this;
756      }
757
758      /**
759       * Adds one or more guards to this operation.
760       *
761       * <p>
762       * Equivalent to calling:
763       * <p class='bjava'>
764       *    <jv>builder</jv>.guards().append(<jv>value</jv>);
765       * </p>
766       *
767       * @param value The values to add.
768       *    <br>Cannot contain <jk>null</jk> values.
769       * @return This object.
770       */
771      public Builder guards(RestGuard...value) {
772         assertArgNoNulls("value", value);
773         guards().append(value);
774         return this;
775      }
776
777      /**
778       * HTTP method name.
779       *
780       * <p>
781       * Typically <js>"GET"</js>, <js>"PUT"</js>, <js>"POST"</js>, <js>"DELETE"</js>, or <js>"OPTIONS"</js>.
782       *
783       * <p>
784       * Method names are case-insensitive (always folded to upper-case).
785       *
786       * <p>
787       * Note that you can use {@link org.apache.juneau.http.HttpMethod} for constant values.
788       *
789       * <p>
790       * Besides the standard HTTP method names, the following can also be specified:
791       * <ul class='spaced-list'>
792       *    <li>
793       *       <js>"*"</js>
794       *       - Denotes any method.
795       *       <br>Use this if you want to capture any HTTP methods in a single Java method.
796       *       <br>The {@link org.apache.juneau.rest.annotation.Method @Method} annotation and/or {@link RestRequest#getMethod()} method can be used to
797       *       distinguish the actual HTTP method name.
798       *    <li>
799       *       <js>""</js>
800       *       - Auto-detect.
801       *       <br>The method name is determined based on the Java method name.
802       *       <br>For example, if the method is <c>doPost(...)</c>, then the method name is automatically detected
803       *       as <js>"POST"</js>.
804       *       <br>Otherwise, defaults to <js>"GET"</js>.
805       *    <li>
806       *       <js>"RRPC"</js>
807       *       - Remote-proxy interface.
808       *       <br>This denotes a Java method that returns an object (usually an interface, often annotated with the
809       *       {@link Remote @Remote} annotation) to be used as a remote proxy using
810       *       <c>RestClient.getRemoteInterface(Class&lt;T&gt; interfaceClass, String url)</c>.
811       *       <br>This allows you to construct client-side interface proxies using REST as a transport medium.
812       *       <br>Conceptually, this is simply a fancy <c>POST</c> against the url <js>"/{path}/{javaMethodName}"</js>
813       *       where the arguments are marshalled from the client to the server as an HTTP content containing an array of
814       *       objects, passed to the method as arguments, and then the resulting object is marshalled back to the client.
815       *    <li>
816       *       Anything else
817       *       - Overloaded non-HTTP-standard names that are passed in through a <c>&amp;method=methodName</c> URL
818       *       parameter.
819       * </ul>
820       *
821       * <h5 class='section'>See Also:</h5><ul>
822       *    <li class='ja'>{@link RestOp#method()}
823       *    <li class='ja'>{@link RestGet}
824       *    <li class='ja'>{@link RestPut}
825       *    <li class='ja'>{@link RestPost}
826       *    <li class='ja'>{@link RestDelete}
827       * </ul>
828       *
829       * @param value The new value for this setting.
830       *    <br>Cannot be <jk>null</jk>.
831       * @return This object.
832       */
833      public Builder httpMethod(String value) {
834         httpMethod = assertArgNotNull("value", value);
835         return this;
836      }
837
838      @Override /* Overridden from Builder */
839      public Builder impl(Context value) {
840         super.impl(value);
841         return this;
842      }
843
844      /**
845       * Returns the JSON schema generator sub-builder.
846       *
847       * @return The JSON schema generator sub-builder.
848       */
849      public JsonSchemaGenerator.Builder jsonSchemaGenerator() {
850         if (jsonSchemaGenerator == null)
851            jsonSchemaGenerator = createJsonSchemaGenerator(beanStore(), parent, resource());
852         return jsonSchemaGenerator;
853      }
854
855      /**
856       * Specifies the JSON schema generator for this operation.
857       *
858       * <p>
859       * Equivalent to calling:
860       * <p class='bjava'>
861       *    <jv>builder</jv>.jsonSchemaGenerator().type(<jv>value</jv>);
862       * </p>
863       *
864       * @param value The new value.
865       *    <br>Cannot be <jk>null</jk>.
866       * @return This object.
867       */
868      public Builder jsonSchemaGenerator(Class<? extends JsonSchemaGenerator> value) {
869         jsonSchemaGenerator().type(assertArgNotNull("value", value));
870         return this;
871      }
872
873      /**
874       * Specifies the JSON schema generator for this operation.
875       *
876       * <p>
877       * Equivalent to calling:
878       * <p class='bjava'>
879       *    <jv>builder</jv>.jsonSchemaGenerator().impl(<jv>value</jv>);
880       * </p>
881       *
882       * @param value The new value.
883       *    <br>Cannot be <jk>null</jk>.
884       * @return This object.
885       */
886      public Builder jsonSchemaGenerator(JsonSchemaGenerator value) {
887         jsonSchemaGenerator().impl(assertArgNotNull("value", value));
888         return this;
889      }
890
891      /**
892       * Returns the matcher list sub-builder.
893       *
894       * @return The matcher list sub-builder.
895       */
896      public RestMatcherList.Builder matchers() {
897         if (matchers == null)
898            matchers = createMatchers(beanStore(), resource());
899         return matchers;
900      }
901
902      /**
903       * Adds one or more matchers to this operation.
904       *
905       * <p>
906       * Equivalent to calling:
907       * <p class='bjava'>
908       *    <jv>builder</jv>.matchers().append(<jv>value</jv>);
909       * </p>
910       *
911       * @param value The values to add.
912       *    <br>Cannot contain <jk>null</jk> values.
913       * @return This object.
914       */
915      @SafeVarargs
916      public final Builder matchers(Class<? extends RestMatcher>...value) {
917         assertArgNoNulls("value", value);
918         matchers().append(value);
919         return this;
920      }
921
922      /**
923       * Adds one or more matchers to this operation.
924       *
925       * <p>
926       * Equivalent to calling:
927       * <p class='bjava'>
928       *    <jv>builder</jv>.matchers().append(<jv>value</jv>);
929       * </p>
930       *
931       * @param value The values to add.
932       *    <br>Cannot contain <jk>null</jk> values.
933       * @return This object.
934       */
935      public Builder matchers(RestMatcher...value) {
936         assertArgNoNulls("value", value);
937         matchers().append(value);
938         return this;
939      }
940
941      /**
942       * The maximum allowed input size (in bytes) on HTTP requests.
943       *
944       * <p>
945       * Useful for alleviating DoS attacks by throwing an exception when too much input is received instead of resulting
946       * in out-of-memory errors which could affect system stability.
947       *
948       * <h5 class='section'>Example:</h5>
949       * <p class='bjava'>
950       *    <jc>// Option #1 - Defined via annotation resolving to a config file setting with default value.</jc>
951       *    <ja>@Rest</ja>(maxInput=<js>"$C{REST/maxInput,10M}"</js>)
952       *    <jk>public class</jk> MyResource {
953       *
954       *       <jc>// Option #2 - Defined via builder passed in through resource constructor.</jc>
955       *       <jk>public</jk> MyResource(RestContext.Builder <jv>builder</jv>) <jk>throws</jk> Exception {
956       *
957       *          <jc>// Using method on builder.</jc>
958       *          <jv>builder</jv>.maxInput(<js>"10M"</js>);
959       *       }
960       *
961       *       <jc>// Option #3 - Defined via builder passed in through init method.</jc>
962       *       <ja>@RestInit</ja>
963       *       <jk>public void</jk> init(RestContext.Builder <jv>builder</jv>) <jk>throws</jk> Exception {
964       *          <jv>builder</jv>.maxInput(<js>"10M"</js>);
965       *       }
966       *
967       *       <jc>// Override at the method level.</jc>
968       *       <ja>@RestPost</ja>(maxInput=<js>"10M"</js>)
969       *       <jk>public</jk> Object myMethod() {...}
970       *    }
971       * </p>
972       *
973       * <h5 class='section'>Notes:</h5><ul>
974       *    <li class='note'>
975       *       String value that gets resolved to a <jk>long</jk>.
976       *    <li class='note'>
977       *       Can be suffixed with any of the following representing kilobytes, megabytes, and gigabytes:
978       *       <js>'K'</js>, <js>'M'</js>, <js>'G'</js>.
979       *    <li class='note'>
980       *       A value of <js>"-1"</js> can be used to represent no limit.
981       * </ul>
982       *
983       * <h5 class='section'>See Also:</h5><ul>
984       *    <li class='ja'>{@link Rest#maxInput}
985       *    <li class='ja'>{@link RestOp#maxInput}
986       *    <li class='jm'>{@link RestOpContext.Builder#maxInput(String)}
987       * </ul>
988       *
989       * @param value
990       *    The new value for this setting.
991       *    <br>The default is the first value found:
992       *    <ul>
993       *       <li>System property <js>"RestContext.maxInput"
994       *       <li>Environment variable <js>"RESTCONTEXT_MAXINPUT"
995       *       <li><js>"100M"</js>
996       *    </ul>
997       *    <br>The default is <js>"100M"</js>.
998       *    <br>Cannot be <jk>null</jk>.
999       * @return This object.
1000       */
1001      public Builder maxInput(String value) {
1002         maxInput = parseLongWithSuffix(assertArgNotNull("value", value));
1003         return this;
1004      }
1005
1006      /**
1007       * Returns the parser group sub-builder.
1008       *
1009       * @return The parser group sub-builder.
1010       */
1011      public ParserSet.Builder parsers() {
1012         if (parsers == null)
1013            parsers = createParsers(beanStore(), parent, resource());
1014         return parsers;
1015      }
1016
1017      /**
1018       * Adds one or more parsers to this operation.
1019       *
1020       * <p>
1021       * Equivalent to calling:
1022       * <p class='bjava'>
1023       *    <jv>builder</jv>.parsers().add(<jv>value</jv>);
1024       * </p>
1025       *
1026       * @param value The values to add.
1027       *    <br>Cannot contain <jk>null</jk> values.
1028       * @return This object.
1029       */
1030      @SafeVarargs
1031      public final Builder parsers(Class<? extends Parser>...value) {
1032         assertArgNoNulls("value", value);
1033         parsers().add(value);
1034         return this;
1035      }
1036
1037      /**
1038       * Adds one or more parsers to this operation.
1039       *
1040       * <p>
1041       * Equivalent to calling:
1042       * <p class='bjava'>
1043       *    <jv>builder</jv>.parsers().add(<jv>value</jv>);
1044       * </p>
1045       *
1046       * @param value The values to add.
1047       *    <br>Cannot contain <jk>null</jk> values.
1048       * @return This object.
1049       */
1050      public Builder parsers(Parser...value) {
1051         assertArgNoNulls("value", value);
1052         parsers().add(value);
1053         return this;
1054      }
1055
1056      /**
1057       * Returns the part parser sub-builder.
1058       *
1059       * @return The part parser sub-builder.
1060       */
1061      public HttpPartParser.Creator partParser() {
1062         if (partParser == null)
1063            partParser = createPartParser(beanStore(), parent, resource());
1064         return partParser;
1065      }
1066
1067      /**
1068       * Specifies the part parser to use for parsing HTTP parts for this operation.
1069       *
1070       * <p>
1071       * Equivalent to calling:
1072       * <p class='bjava'>
1073       *    <jv>builder</jv>.partParser().type(<jv>value</jv>);
1074       * </p>
1075       *
1076       * @param value The new value.
1077       *    <br>Cannot be <jk>null</jk>.
1078       * @return This object.
1079       */
1080      public Builder partParser(Class<? extends HttpPartParser> value) {
1081         partParser().type(assertArgNotNull("value", value));
1082         return this;
1083      }
1084
1085      /**
1086       * Specifies the part parser to use for parsing HTTP parts for this operation.
1087       *
1088       * <p>
1089       * Equivalent to calling:
1090       * <p class='bjava'>
1091       *    <jv>builder</jv>.partParser().impl(<jv>value</jv>);
1092       * </p>
1093       *
1094       * @param value The new value.
1095       *    <br>Cannot be <jk>null</jk>.
1096       * @return This object.
1097       */
1098      public Builder partParser(HttpPartParser value) {
1099         partParser().impl(assertArgNotNull("value", value));
1100         return this;
1101      }
1102
1103      /**
1104       * Returns the part serializer sub-builder.
1105       *
1106       * @return The part serializer sub-builder.
1107       */
1108      public HttpPartSerializer.Creator partSerializer() {
1109         if (partSerializer == null)
1110            partSerializer = createPartSerializer(beanStore(), parent, resource());
1111         return partSerializer;
1112      }
1113
1114      /**
1115       * Specifies the part serializer to use for serializing HTTP parts for this operation.
1116       *
1117       * <p>
1118       * Equivalent to calling:
1119       * <p class='bjava'>
1120       *    <jv>builder</jv>.partSerializer().type(<jv>value</jv>);
1121       * </p>
1122       *
1123       * @param value The new value.
1124       *    <br>Cannot be <jk>null</jk>.
1125       * @return This object.
1126       */
1127      public Builder partSerializer(Class<? extends HttpPartSerializer> value) {
1128         partSerializer().type(assertArgNotNull("value", value));
1129         return this;
1130      }
1131
1132      /**
1133       * Specifies the part serializer to use for serializing HTTP parts for this operation.
1134       *
1135       * <p>
1136       * Equivalent to calling:
1137       * <p class='bjava'>
1138       *    <jv>builder</jv>.partSerializer().impl(<jv>value</jv>);
1139       * </p>
1140       *
1141       * @param value The new value.
1142       *    <br>Cannot be <jk>null</jk>.
1143       * @return This object.
1144       */
1145      public Builder partSerializer(HttpPartSerializer value) {
1146         partSerializer().impl(assertArgNotNull("value", value));
1147         return this;
1148      }
1149
1150      /**
1151       * Resource method paths.
1152       *
1153       * <p>
1154       * Identifies the URL subpath relative to the servlet class.
1155       *
1156       * <p>
1157       * <h5 class='section'>Notes:</h5><ul>
1158       *    <li class='note'>
1159       *       This method is only applicable for Java methods.
1160       *    <li class='note'>
1161       *       Slashes are trimmed from the path ends.
1162       *       <br>As a convention, you may want to start your path with <js>'/'</js> simple because it make it easier to read.
1163       * </ul>
1164       *
1165       * @param values The new values for this setting.
1166       *    <br>Cannot contain <jk>null</jk> values.
1167       * @return This object.
1168       */
1169      public Builder path(String...values) {
1170         assertArgNoNulls("values", values);
1171         path = prependAll(path, values);
1172         return this;
1173      }
1174
1175      /**
1176       * Supported accept media types.
1177       *
1178       * <p>
1179       * Overrides the media types inferred from the serializers that identify what media types can be produced by the resource.
1180       * <br>An example where this might be useful if you have serializers registered that handle media types that you
1181       * don't want exposed in the Swagger documentation.
1182       *
1183       * <p>
1184       * This affects the returned values from the following:
1185       * <ul class='javatree'>
1186       *    <li class='jm'>{@link RestContext#getProduces() RestContext.getProduces()}
1187       *    <li class='jm'>{@link SwaggerProvider#getSwagger(RestContext,Locale)} - Affects produces field.
1188       * </ul>
1189       *
1190       * <h5 class='section'>See Also:</h5><ul>
1191       *    <li class='ja'>{@link Rest#produces}
1192       *    <li class='ja'>{@link RestOp#produces}
1193       *    <li class='ja'>{@link RestGet#produces}
1194       *    <li class='ja'>{@link RestPut#produces}
1195       *    <li class='ja'>{@link RestPost#produces}
1196       * </ul>
1197       *
1198       * @param values The values to add to this setting.
1199       *    <br>Cannot contain <jk>null</jk> values.
1200       * @return This object.
1201       */
1202      public Builder produces(MediaType...values) {
1203         assertArgNoNulls("values", values);
1204         produces = addAll(produces, values);
1205         return this;
1206      }
1207
1208      /**
1209       * Returns the REST servlet/bean instance that this context is defined against.
1210       *
1211       * @return The REST servlet/bean instance that this context is defined against.
1212       */
1213      public Supplier<?> resource() {
1214         return restContext.builder.resource();
1215      }
1216
1217      /**
1218       * Role guard.
1219       *
1220       * <p>
1221       * An expression defining if a user with the specified roles are allowed to access methods on this class.
1222       *
1223       * <h5 class='section'>Example:</h5>
1224       * <p class='bjava'>
1225       *    <ja>@Rest</ja>(
1226       *       path=<js>"/foo"</js>,
1227       *       roleGuard=<js>"ROLE_ADMIN || (ROLE_READ_WRITE &amp;&amp; ROLE_SPECIAL)"</js>
1228       *    )
1229       *    <jk>public class</jk> MyResource <jk>extends</jk> BasicRestServlet {
1230       *       ...
1231       *    }
1232       * </p>
1233       *
1234       * <h5 class='section'>Notes:</h5><ul>
1235       *    <li class='note'>
1236       *       Supports any of the following expression constructs:
1237       *       <ul>
1238       *          <li><js>"foo"</js> - Single arguments.
1239       *          <li><js>"foo,bar,baz"</js> - Multiple OR'ed arguments.
1240       *          <li><js>"foo | bar | bqz"</js> - Multiple OR'ed arguments, pipe syntax.
1241       *          <li><js>"foo || bar || bqz"</js> - Multiple OR'ed arguments, Java-OR syntax.
1242       *          <li><js>"fo*"</js> - Patterns including <js>'*'</js> and <js>'?'</js>.
1243       *          <li><js>"fo* &amp; *oo"</js> - Multiple AND'ed arguments, ampersand syntax.
1244       *          <li><js>"fo* &amp;&amp; *oo"</js> - Multiple AND'ed arguments, Java-AND syntax.
1245       *          <li><js>"fo* || (*oo || bar)"</js> - Parenthesis.
1246       *       </ul>
1247       *    <li class='note'>
1248       *       AND operations take precedence over OR operations (as expected).
1249       *    <li class='note'>
1250       *       Whitespace is ignored.
1251       *    <li class='note'>
1252       *       <jk>null</jk> or empty expressions always match as <jk>false</jk>.
1253       *    <li class='note'>
1254       *       If patterns are used, you must specify the list of declared roles using {@link Rest#rolesDeclared()} or {@link RestOpContext.Builder#rolesDeclared(String...)}.
1255       *    <li class='note'>
1256       *       Supports <a class="doclink" href="https://juneau.apache.org/docs/topics/RestServerSvlVariables">SVL Variables</a>
1257       *       (e.g. <js>"$L{my.localized.variable}"</js>).
1258       * </ul>
1259       *
1260       * @param value The values to add to this setting.
1261       *    <br>Cannot be <jk>null</jk>.
1262       * @return This object.
1263       */
1264      public Builder roleGuard(String value) {
1265         if (roleGuard == null)
1266            roleGuard = set(assertArgNotNull("value", value));
1267         else
1268            roleGuard.add(assertArgNotNull("value", value));
1269         return this;
1270      }
1271
1272      /**
1273       * Declared roles.
1274       *
1275       * <p>
1276       * A comma-delimited list of all possible user roles.
1277       *
1278       * <p>
1279       * Used in conjunction with {@link RestOpContext.Builder#roleGuard(String)} is used with patterns.
1280       *
1281       * <h5 class='section'>Example:</h5>
1282       * <p class='bjava'>
1283       *    <ja>@Rest</ja>(
1284       *       rolesDeclared=<js>"ROLE_ADMIN,ROLE_READ_WRITE,ROLE_READ_ONLY,ROLE_SPECIAL"</js>,
1285       *       roleGuard=<js>"ROLE_ADMIN || (ROLE_READ_WRITE &amp;&amp; ROLE_SPECIAL)"</js>
1286       *    )
1287       *    <jk>public class</jk> MyResource <jk>extends</jk> BasicRestServlet {
1288       *       ...
1289       *    }
1290       * </p>
1291       *
1292       * <h5 class='section'>See Also:</h5><ul>
1293       *    <li class='ja'>{@link Rest#rolesDeclared}
1294       * </ul>
1295       *
1296       * @param values The values to add to this setting.
1297       *    <br>Cannot contain <jk>null</jk> values.
1298       * @return This object.
1299       */
1300      public Builder rolesDeclared(String...values) {
1301         assertArgNoNulls("values", values);
1302         rolesDeclared = addAll(rolesDeclared, values);
1303         return this;
1304      }
1305
1306      /**
1307       * Returns the serializer group sub-builder.
1308       *
1309       * @return The serializer group sub-builder.
1310       */
1311      public SerializerSet.Builder serializers() {
1312         if (serializers == null)
1313            serializers = createSerializers(beanStore(), parent, resource());
1314         return serializers;
1315      }
1316
1317      /**
1318       * Adds one or more serializers to this operation.
1319       *
1320       * <p>
1321       * Equivalent to calling:
1322       * <p class='bjava'>
1323       *    <jv>builder</jv>.serializers().add(<jv>value</jv>);
1324       * </p>
1325       *
1326       * @param value The values to add.
1327       *    <br>Cannot contain <jk>null</jk> values.
1328       * @return This object.
1329       */
1330      @SafeVarargs
1331      public final Builder serializers(Class<? extends Serializer>...value) {
1332         assertArgNoNulls("value", value);
1333         serializers().add(value);
1334         return this;
1335      }
1336
1337      /**
1338       * Adds one or more serializers to this operation.
1339       *
1340       * <p>
1341       * Equivalent to calling:
1342       * <p class='bjava'>
1343       *    <jv>builder</jv>.serializers().add(<jv>value</jv>);
1344       * </p>
1345       *
1346       * @param value The values to add.
1347       *    <br>Cannot contain <jk>null</jk> values.
1348       * @return This object.
1349       */
1350      public Builder serializers(Serializer...value) {
1351         assertArgNoNulls("value", value);
1352         serializers().add(value);
1353         return this;
1354      }
1355
1356      @Override /* Overridden from Builder */
1357      public Builder type(Class<? extends org.apache.juneau.Context> value) {
1358         super.type(value);
1359         return this;
1360      }
1361
1362      private static String joinnlFirstNonEmptyArray(String[]...s) {
1363         for (var ss : s)
1364            if (ss.length > 0)
1365               return joinnl(ss);
1366         return null;
1367      }
1368
1369      private boolean matches(MethodInfo annotated) {
1370         var a = annotated.getAnnotations(RestInject.class).findFirst().map(AnnotationInfo::inner).orElse(null);
1371         if (nn(a)) {
1372            for (var n : a.methodScope()) {
1373               if ("*".equals(n) || restMethod.getName().equals(n))
1374                  return true;
1375            }
1376         }
1377         return false;
1378      }
1379
1380      private boolean matches(MethodInfo annotated, String beanName) {
1381         var a = annotated.getAnnotations(RestInject.class).findFirst().map(AnnotationInfo::inner).orElse(null);
1382         if (nn(a)) {
1383            if (! a.name().equals(beanName))
1384               return false;
1385            for (var n : a.methodScope()) {
1386               if ("*".equals(n) || restMethod.getName().equals(n))
1387                  return true;
1388            }
1389         }
1390         return false;
1391      }
1392
1393      /**
1394       * Specifies a {@link BeanStore} to use when resolving constructor arguments.
1395       *
1396       * @param beanStore The bean store to use for resolving constructor arguments.
1397       * @return This object.
1398       */
1399      protected Builder beanStore(BeanStore beanStore) {
1400         this.beanStore = beanStore;
1401         return this;
1402      }
1403
1404      /**
1405       * Instantiates the bean context sub-builder.
1406       *
1407       * @param beanStore
1408       *    The factory used for creating beans and retrieving injected beans.
1409       * @param parent
1410       *    The builder for the REST resource class.
1411       * @param resource
1412       *    The REST servlet/bean instance that this context is defined against.
1413       * @return A new bean context sub-builder.
1414       */
1415      protected BeanContext.Builder createBeanContext(BeanStore beanStore, RestContext.Builder parent, Supplier<?> resource) {
1416
1417         // Default value.
1418         Value<BeanContext.Builder> v = Value.of(parent.beanContext().copy());
1419
1420         // Replace with bean from:  @RestInject(methodScope="foo") public [static] BeanContext xxx(<args>)
1421         // @formatter:off
1422         BeanStore
1423            .of(beanStore, resource)
1424            .addBean(BeanContext.Builder.class, v.get())
1425            .createMethodFinder(BeanContext.class, resource)
1426            .find(this::matches)
1427            .run(x -> v.get().impl(x));
1428         // @formatter:on
1429
1430         return v.get();
1431      }
1432
1433      /**
1434       * Instantiates the response converter list sub-builder.
1435       *
1436       * <p>
1437       * Associates one or more {@link RestConverter converters} with a resource class.
1438       * <br>These converters get called immediately after execution of the REST method in the same order specified in the
1439       * annotation.
1440       * <br>The object passed into this converter is the object returned from the Java method or passed into
1441       * the {@link RestResponse#setContent(Object)} method.
1442       *
1443       * <p>
1444       * Can be used for performing post-processing on the response object before serialization.
1445       *
1446       * <p>
1447       *    When multiple converters are specified, they're executed in the order they're specified in the annotation
1448       *    (e.g. first the results will be traversed, then the resulting node will be searched/sorted).
1449       *
1450       * <h5 class='section'>Example:</h5>
1451       * <p class='bjava'>
1452       *    <jc>// Our converter.</jc>
1453       *    <jk>public class</jk> MyConverter <jk>implements</jk> RestConverter {
1454       *       <ja>@Override</ja>
1455       *       <jk>public</jk> Object convert(RestRequest <jv>req</jv>, Object <jv>object</jv>) {
1456       *          <jc>// Do something with object and return another object.</jc>
1457       *          <jc>// Or just return the same object for a no-op.</jc>
1458       *       }
1459       *    }
1460       *
1461       *    <jc>// Option #1 - Registered via annotation resolving to a config file setting with default value.</jc>
1462       *    <ja>@Rest</ja>(converters={MyConverter.<jk>class</jk>})
1463       *    <jk>public class</jk> MyResource {
1464       *
1465       *       <jc>// Option #2 - Registered via builder passed in through resource constructor.</jc>
1466       *       <jk>public</jk> MyResource(RestContext.Builder <jv>builder</jv>) <jk>throws</jk> Exception {
1467       *
1468       *          <jc>// Using method on builder.</jc>
1469       *          <jv>builder</jv>.converters(MyConverter.<jk>class</jk>);
1470       *
1471       *          <jc>// Pass in an instance instead.</jc>
1472       *          <jv>builder</jv>.converters(<jk>new</jk> MyConverter());
1473       *       }
1474       *
1475       *       <jc>// Option #3 - Registered via builder passed in through init method.</jc>
1476       *       <ja>@RestInit</ja>
1477       *       <jk>public void</jk> init(RestContext.Builder <jv>builder</jv>) <jk>throws</jk> Exception {
1478       *          <jv>builder</jv>.converters(MyConverter.<jk>class</jk>);
1479       *       }
1480       *    }
1481       * </p>
1482       *
1483       * <h5 class='section'>Notes:</h5><ul>
1484       *    <li class='note'>
1485       *       When defined as a class, the implementation must have one of the following constructors:
1486       *       <ul>
1487       *          <li><code><jk>public</jk> T(BeanContext)</code>
1488       *          <li><code><jk>public</jk> T()</code>
1489       *          <li><code><jk>public static</jk> T <jsm>create</jsm>(RestContext)</code>
1490       *          <li><code><jk>public static</jk> T <jsm>create</jsm>()</code>
1491       *       </ul>
1492       *    <li class='note'>
1493       *       Inner classes of the REST resource class are allowed.
1494       * </ul>
1495       *
1496       * <h5 class='section'>See Also:</h5><ul>
1497       *    <li class='jc'>{@link Traversable} - Allows URL additional path info to address individual elements in a POJO tree.
1498       *    <li class='jc'>{@link Queryable} - Allows query/view/sort functions to be performed on POJOs.
1499       *    <li class='jc'>{@link Introspectable} - Allows Java public methods to be invoked on the returned POJOs.
1500       *    <li class='ja'>{@link Rest#converters()}
1501       *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/Converters">Converters</a>
1502       * </ul>
1503       *
1504       * @param beanStore
1505       *    The factory used for creating beans and retrieving injected beans.
1506       * @param resource
1507       *    The REST servlet/bean instance that this context is defined against.
1508       * @return A new response converter list sub-builder.
1509       */
1510      protected RestConverterList.Builder createConverters(BeanStore beanStore, Supplier<?> resource) {
1511
1512         // Default value.
1513         Value<RestConverterList.Builder> v = Value.of(RestConverterList.create(beanStore));
1514
1515         // Specify the implementation class if its set as a default.
1516         defaultClasses().get(RestConverterList.class).ifPresent(x -> v.get().type(x));
1517
1518         // Replace with bean from bean store.
1519         beanStore.getBean(RestConverterList.class).ifPresent(x -> v.get().impl(x));
1520
1521         // Replace with bean from:  @RestInject(methodScope="foo") public [static] RestConverterList xxx(<args>)
1522         beanStore.createMethodFinder(RestConverterList.class).addBean(RestConverterList.Builder.class, v.get()).find(this::matches).run(x -> v.get().impl(x));
1523
1524         return v.get();
1525      }
1526
1527      /**
1528       * Instantiates the default request attributes sub-builder.
1529       *
1530       * @param beanStore
1531       *    The factory used for creating beans and retrieving injected beans.
1532       * @param parent
1533       *    The builder for the REST resource class.
1534       * @param resource
1535       *    The REST servlet/bean instance that this context is defined against.
1536       * @return A new default request attributes sub-builder.
1537       */
1538      protected NamedAttributeMap createDefaultRequestAttributes(BeanStore beanStore, RestContext.Builder parent, Supplier<?> resource) {
1539
1540         var v = Value.of(parent.defaultRequestAttributes().copy());
1541
1542         // Replace with bean from:  @RestInject(name="defaultRequestAttributes",methodScope="foo") public [static] NamedAttributeMap xxx(<args>)
1543         // @formatter:off
1544         BeanStore
1545            .of(beanStore, resource)
1546            .addBean(NamedAttributeMap.class, v.get())
1547            .createMethodFinder(NamedAttributeMap.class, resource)
1548            .find(x -> matches(x, "defaultRequestAttributes"))
1549            .run(x -> v.set(x));
1550         // @formatter:on
1551
1552         return v.get();
1553      }
1554
1555      /**
1556       * Instantiates the default request form data.
1557       *
1558       * @param beanStore
1559       *    The factory used for creating beans and retrieving injected beans.
1560       * @param parent
1561       *    The builder for the REST resource class.
1562       * @param resource
1563       *    The REST servlet/bean instance that this context is defined against.
1564       * @return A new default request form data sub-builder.
1565       */
1566      protected PartList createDefaultRequestFormData(BeanStore beanStore, RestContext.Builder parent, Supplier<?> resource) {
1567
1568         var v = Value.of(PartList.create());
1569
1570         // Replace with bean from:  @RestInject(name="defaultRequestFormData",methodScope="foo") public [static] PartList xxx(<args>)
1571         // @formatter:off
1572         BeanStore
1573            .of(beanStore, resource)
1574            .addBean(PartList.class, v.get())
1575            .createMethodFinder(PartList.class, resource)
1576            .find(x -> matches(x, "defaultRequestFormData"))
1577            .run(x -> v.set(x));
1578         // @formatter:on
1579
1580         return v.get();
1581      }
1582
1583      /**
1584       * Instantiates the default request headers.
1585       *
1586       * @param beanStore
1587       *    The factory used for creating beans and retrieving injected beans.
1588       * @param parent
1589       *    The builder for the REST resource class.
1590       * @param resource
1591       *    The REST servlet/bean instance that this context is defined against.
1592       * @return A new default request headers sub-builder.
1593       */
1594      protected HeaderList createDefaultRequestHeaders(BeanStore beanStore, RestContext.Builder parent, Supplier<?> resource) {
1595
1596         var v = Value.of(parent.defaultRequestHeaders().copy());
1597
1598         // Replace with bean from:  @RestInject(name="defaultRequestHeaders",methodScope="foo") public [static] HeaderList xxx(<args>)
1599         // @formatter:off
1600         BeanStore
1601            .of(beanStore, resource)
1602            .addBean(HeaderList.class, v.get())
1603            .createMethodFinder(HeaderList.class, resource)
1604            .find(x -> matches(x, "defaultRequestHeaders"))
1605            .run(x -> v.set(x));
1606         // @formatter:on
1607
1608         return v.get();
1609      }
1610
1611      /**
1612       * Instantiates the default request query data.
1613       *
1614       * @param beanStore
1615       *    The factory used for creating beans and retrieving injected beans.
1616       * @param parent
1617       *    The builder for the REST resource class.
1618       * @param resource
1619       *    The REST servlet/bean instance that this context is defined against.
1620       * @return A new default request query data sub-builder.
1621       */
1622      protected PartList createDefaultRequestQueryData(BeanStore beanStore, RestContext.Builder parent, Supplier<?> resource) {
1623
1624         var v = Value.of(PartList.create());
1625
1626         // Replace with bean from:  @RestInject(name="defaultRequestQueryData",methodScope="foo") public [static] PartList xxx(<args>)
1627         // @formatter:off
1628         BeanStore
1629            .of(beanStore, resource)
1630            .addBean(PartList.class, v.get())
1631            .createMethodFinder(PartList.class, resource)
1632            .find(x -> matches(x, "defaultRequestQueryData"))
1633            .run(x -> v.set(x));
1634         // @formatter:on
1635
1636         return v.get();
1637      }
1638
1639      /**
1640       * Instantiates the default response headers.
1641       *
1642       * @param beanStore
1643       *    The factory used for creating beans and retrieving injected beans.
1644       * @param parent
1645       *    The builder for the REST resource class.
1646       * @param resource
1647       *    The REST servlet/bean instance that this context is defined against.
1648       * @return A new default response headers sub-builder.
1649       */
1650      protected HeaderList createDefaultResponseHeaders(BeanStore beanStore, RestContext.Builder parent, Supplier<?> resource) {
1651
1652         var v = Value.of(parent.defaultResponseHeaders().copy());
1653
1654         // Replace with bean from:  @RestInject(name="defaultResponseHeaders",methodScope="foo") public [static] HeaderList xxx(<args>)
1655         // @formatter:off
1656         BeanStore
1657            .of(beanStore, resource)
1658            .addBean(HeaderList.class, v.get())
1659            .createMethodFinder(HeaderList.class, resource)
1660            .find(x -> matches(x, "defaultResponseHeaders"))
1661            .run(x -> v.set(x));
1662         // @formatter:on
1663
1664         return v.get();
1665      }
1666
1667      /**
1668       * Instantiates the encoder group sub-builder.
1669       *
1670       * @param beanStore
1671       *    The factory used for creating beans and retrieving injected beans.
1672       * @param parent
1673       *    The builder for the REST resource class.
1674       * @param resource
1675       *    The REST servlet/bean instance that this context is defined against.
1676       * @return A new encoder group sub-builder.
1677       */
1678      protected EncoderSet.Builder createEncoders(BeanStore beanStore, RestContext.Builder parent, Supplier<?> resource) {
1679
1680         // Default value.
1681         Value<EncoderSet.Builder> v = Value.of(parent.encoders().copy());
1682
1683         // Replace with bean from:  @RestInject(methodScope="foo") public [static] EncoderSet xxx(<args>)
1684         // @formatter:off
1685         BeanStore
1686            .of(beanStore, resource)
1687            .addBean(EncoderSet.Builder.class, v.get())
1688            .createMethodFinder(EncoderSet.class, resource)
1689            .find(this::matches)
1690            .run(x -> v.get().impl(x));
1691         // @formatter:on
1692
1693         return v.get();
1694      }
1695
1696      /**
1697       * Instantiates the guard list sub-builder.
1698       *
1699       * <p>
1700       * Instantiates based on the following logic:
1701       * <ul>
1702       *    <li>Looks for guards set via any of the following:
1703       *       <ul>
1704       *          <li>{@link RestOpContext.Builder#guards()}}
1705       *          <li>{@link RestOp#guards()}.
1706       *          <li>{@link Rest#guards()}.
1707       *       </ul>
1708       *    <li>Looks for a static or non-static <c>createGuards()</c> method that returns <c>{@link RestGuard}[]</c> on the
1709       *       resource class with any of the following arguments:
1710       *       <ul>
1711       *          <li>{@link Method} - The Java method this context belongs to.
1712       *          <li>{@link RestContext}
1713       *          <li>{@link BeanStore}
1714       *          <li>Any <a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauRestServerSpringbootBasics">juneau-rest-server-springboot Basics</a>.
1715       *       </ul>
1716       *    <li>Resolves it via the bean store registered in this context.
1717       *    <li>Instantiates a <c>RestGuard[0]</c>.
1718       * </ul>
1719       *
1720       * @param beanStore
1721       *    The factory used for creating beans and retrieving injected beans.
1722       * @param resource
1723       *    The REST servlet/bean instance that this context is defined against.
1724       * @return A new guard list sub-builder.
1725       */
1726      protected RestGuardList.Builder createGuards(BeanStore beanStore, Supplier<?> resource) {
1727
1728         // Default value.
1729         Value<RestGuardList.Builder> v = Value.of(RestGuardList.create(beanStore));
1730
1731         // Specify the implementation class if its set as a default.
1732         defaultClasses().get(RestGuardList.class).ifPresent(x -> v.get().type(x));
1733
1734         // Replace with bean from bean store.
1735         beanStore.getBean(RestGuardList.class).ifPresent(x -> v.get().impl(x));
1736
1737         // Replace with bean from:  @RestInject(methodScope="foo") public [static] RestGuardList xxx(<args>)
1738         // @formatter:off
1739         beanStore
1740            .createMethodFinder(RestGuardList.class)
1741            .addBean(RestGuardList.Builder.class, v.get())
1742            .find(m -> this.matches(m))
1743            .run(x -> v.get().impl(x));
1744         // @formatter:on
1745
1746         return v.get();
1747      }
1748
1749      /**
1750       * Instantiates the JSON schema generator sub-builder.
1751       *
1752       * @param beanStore
1753       *    The factory used for creating beans and retrieving injected beans.
1754       * @param parent
1755       *    The builder for the REST resource class.
1756       * @param resource
1757       *    The REST servlet/bean instance that this context is defined against.
1758       * @return A new JSON schema generator sub-builder.
1759       */
1760      protected JsonSchemaGenerator.Builder createJsonSchemaGenerator(BeanStore beanStore, RestContext.Builder parent, Supplier<?> resource) {
1761
1762         // Default value.
1763         Value<JsonSchemaGenerator.Builder> v = Value.of(parent.jsonSchemaGenerator().copy());
1764
1765         // Replace with bean from:  @RestInject(methodScope="foo") public [static] JsonSchemaGenerator xxx(<args>)
1766         // @formatter:off
1767         BeanStore
1768            .of(beanStore, resource)
1769            .addBean(JsonSchemaGenerator.Builder.class, v.get())
1770            .createMethodFinder(JsonSchemaGenerator.class, resource)
1771            .find(this::matches)
1772            .run(x -> v.get().impl(x));
1773         // @formatter:on
1774
1775         return v.get();
1776      }
1777
1778      /**
1779       * Instantiates the matcher list sub-builder.
1780       *
1781       * <p>
1782       * Associates one or more {@link RestMatcher RestMatchers} with the specified method.
1783       *
1784       * <p>
1785       * If multiple matchers are specified, <b>ONE</b> matcher must pass.
1786       * <br>Note that this is different than guards where <b>ALL</b> guards needs to pass.
1787       *
1788       * <h5 class='section'>Notes:</h5><ul>
1789       *    <li class='note'>
1790       *       When defined as a class, the implementation must have one of the following constructors:
1791       *       <ul>
1792       *          <li><code><jk>public</jk> T(RestContext)</code>
1793       *          <li><code><jk>public</jk> T()</code>
1794       *          <li><code><jk>public static</jk> T <jsm>create</jsm>(RestContext)</code>
1795       *          <li><code><jk>public static</jk> T <jsm>create</jsm>()</code>
1796       *       </ul>
1797       *    <li class='note'>
1798       *       Inner classes of the REST resource class are allowed.
1799       * </ul>
1800       *
1801       * <h5 class='section'>See Also:</h5><ul>
1802       *    <li class='ja'>{@link RestOp#matchers()}
1803       *    <li class='ja'>{@link RestGet#matchers()}
1804       *    <li class='ja'>{@link RestPut#matchers()}
1805       *    <li class='ja'>{@link RestPost#matchers()}
1806       *    <li class='ja'>{@link RestDelete#matchers()}
1807       * </ul>
1808       *
1809       * <p>
1810       * Instantiates based on the following logic:
1811       * <ul>
1812       *    <li>Looks for matchers set via any of the following:
1813       *       <ul>
1814       *          <li>{@link RestOp#matchers()}.
1815       *       </ul>
1816       *    <li>Looks for a static or non-static <c>createMatchers()</c> method that returns <c>{@link RestMatcher}[]</c> on the
1817       *       resource class with any of the following arguments:
1818       *       <ul>
1819       *          <li>{@link java.lang.reflect.Method} - The Java method this context belongs to.
1820       *          <li>{@link RestContext}
1821       *          <li>{@link BeanStore}
1822       *          <li>Any <a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauRestServerSpringbootBasics">juneau-rest-server-springboot Basics</a>.
1823       *       </ul>
1824       *    <li>Resolves it via the bean store registered in this context.
1825       *    <li>Instantiates a <c>RestMatcher[0]</c>.
1826       * </ul>
1827       *
1828       * @param beanStore
1829       *    The factory used for creating beans and retrieving injected beans.
1830       * @param resource
1831       *    The REST servlet/bean instance that this context is defined against.
1832       * @return A new matcher list sub-builder.
1833       */
1834      protected RestMatcherList.Builder createMatchers(BeanStore beanStore, Supplier<?> resource) {
1835
1836         // Default value.
1837         Value<RestMatcherList.Builder> v = Value.of(RestMatcherList.create(beanStore));
1838
1839         // Specify the implementation class if its set as a default.
1840         defaultClasses().get(RestMatcherList.class).ifPresent(x -> v.get().type(x));
1841
1842         // Replace with bean from bean store.
1843         beanStore.getBean(RestMatcherList.class).ifPresent(x -> v.get().impl(x));
1844
1845         // Replace with bean from:  @RestInject(methodScope="foo") public [static] RestMatcherList xxx(<args>)
1846         // @formatter:off
1847         beanStore
1848            .createMethodFinder(RestMatcherList.class)
1849            .addBean(RestMatcherList.Builder.class, v.get())
1850            .find(this::matches)
1851            .run(x -> v.get().impl(x));
1852         // @formatter:on
1853
1854         return v.get();
1855      }
1856
1857      /**
1858       * Instantiates the parser group sub-builder.
1859       *
1860       * @param beanStore
1861       *    The factory used for creating beans and retrieving injected beans.
1862       * @param parent
1863       *    The builder for the REST resource class.
1864       * @param resource
1865       *    The REST servlet/bean instance that this context is defined against.
1866       * @return A new parser group sub-builder.
1867       */
1868      protected ParserSet.Builder createParsers(BeanStore beanStore, RestContext.Builder parent, Supplier<?> resource) {
1869
1870         // Default value.
1871         Value<ParserSet.Builder> v = Value.of(parent.parsers().copy());
1872
1873         // Replace with bean from:  @RestInject(methodScope="foo") public [static] ParserSet xxx(<args>)
1874         // @formatter:off
1875         BeanStore
1876            .of(beanStore, resource)
1877            .addBean(ParserSet.Builder.class, v.get())
1878            .createMethodFinder(ParserSet.class, resource)
1879            .find(this::matches)
1880            .run(x -> v.get().impl(x));
1881         // @formatter:on
1882
1883         return v.get();
1884      }
1885
1886      /**
1887       * Instantiates the part parser sub-builder.
1888       *
1889       * @param beanStore
1890       *    The factory used for creating beans and retrieving injected beans.
1891       * @param parent
1892       *    The builder for the REST resource class.
1893       * @param resource
1894       *    The REST servlet/bean instance that this context is defined against.
1895       * @return A new part parser sub-builder.
1896       */
1897      protected HttpPartParser.Creator createPartParser(BeanStore beanStore, RestContext.Builder parent, Supplier<?> resource) {
1898
1899         // Default value.
1900         Value<HttpPartParser.Creator> v = Value.of(parent.partParser().copy());
1901
1902         // Replace with bean from:  @RestInject(methodScope="foo") public [static] HttpPartParser xxx(<args>)
1903         // @formatter:off
1904         BeanStore
1905            .of(beanStore, resource)
1906            .addBean(HttpPartParser.Creator.class, v.get())
1907            .createMethodFinder(HttpPartParser.class, resource)
1908            .find(this::matches)
1909            .run(x -> v.get().impl(x));
1910         // @formatter:on
1911
1912         return v.get();
1913      }
1914
1915      /**
1916       * Instantiates the part serializer sub-builder.
1917       *
1918       * @param beanStore
1919       *    The factory used for creating beans and retrieving injected beans.
1920       * @param parent
1921       *    The builder for the REST resource class.
1922       * @param resource
1923       *    The REST servlet/bean instance that this context is defined against.
1924       * @return A new part serializer sub-builder.
1925       */
1926      protected HttpPartSerializer.Creator createPartSerializer(BeanStore beanStore, RestContext.Builder parent, Supplier<?> resource) {
1927
1928         // Default value.
1929         Value<HttpPartSerializer.Creator> v = Value.of(parent.partSerializer().copy());
1930
1931         // Replace with bean from:  @RestInject(methodScope="foo") public [static] HttpPartSerializer xxx(<args>)
1932         // @formatter:off
1933         BeanStore
1934            .of(beanStore, resource)
1935            .addBean(HttpPartSerializer.Creator.class, v.get())
1936            .createMethodFinder(HttpPartSerializer.class, resource)
1937            .find(this::matches)
1938            .run(x -> v.get().impl(x));
1939         // @formatter:on
1940
1941         return v.get();
1942      }
1943
1944      /**
1945       * Instantiates the serializer group sub-builder.
1946       *
1947       * @param beanStore
1948       *    The factory used for creating beans and retrieving injected beans.
1949       * @param parent
1950       *    The builder for the REST resource class.
1951       * @param resource
1952       *    The REST servlet/bean instance that this context is defined against.
1953       * @return A new serializer group sub-builder.
1954       */
1955      protected SerializerSet.Builder createSerializers(BeanStore beanStore, RestContext.Builder parent, Supplier<?> resource) {
1956
1957         // Default value.
1958         Value<SerializerSet.Builder> v = Value.of(parent.serializers().copy());
1959
1960         // Replace with bean from:  @RestInject(methodScope="foo") public [static] SerializerSet xxx(<args>)
1961         // @formatter:off
1962         BeanStore
1963            .of(beanStore, resource)
1964            .addBean(SerializerSet.Builder.class, v.get())
1965            .createMethodFinder(SerializerSet.class, resource)
1966            .find(this::matches)
1967            .run(x -> v.get().impl(x));
1968         // @formatter:on
1969
1970         return v.get();
1971      }
1972
1973      /**
1974       * Specifies the default implementation class if not specified via {@link #type(Class)}.
1975       *
1976       * @return The default implementation class if not specified via {@link #type(Class)}.
1977       */
1978      protected Class<? extends RestOpContext> getDefaultImplClass() { return RestOpContext.class; }
1979
1980      /**
1981       * Instantiates the path matchers for this method.
1982       *
1983       * @return The path matchers for this method.
1984       */
1985      protected UrlPathMatcherList getPathMatchers() {
1986
1987         var v = Value.of(UrlPathMatcherList.create());
1988
1989         if (nn(path)) {
1990            for (var p : path) {
1991               if (dotAll && ! p.endsWith("/*"))
1992                  p += "/*";
1993               v.get().add(UrlPathMatcher.of(p));
1994            }
1995         }
1996
1997         if (v.get().isEmpty()) {
1998            var mi = MethodInfo.of(restMethod);
1999            var p = (String)null;
2000            var httpMethod = (String)null;
2001            if (mi.hasAnnotation(RestGet.class))
2002               httpMethod = "get";
2003            else if (mi.hasAnnotation(RestPut.class))
2004               httpMethod = "put";
2005            else if (mi.hasAnnotation(RestPost.class))
2006               httpMethod = "post";
2007            else if (mi.hasAnnotation(RestDelete.class))
2008               httpMethod = "delete";
2009            else if (mi.hasAnnotation(RestOp.class)) {
2010               // @formatter:off
2011               httpMethod = AP.find(RestOp.class, mi)
2012                  .stream()
2013                  .map(x -> x.inner().method())
2014                  .filter(Utils::ne)
2015                  .findFirst()
2016                  .orElse(null);
2017               // @formatter:on
2018            }
2019
2020            p = HttpUtils.detectHttpPath(restMethod, httpMethod);
2021
2022            if (dotAll && ! p.endsWith("/*"))
2023               p += "/*";
2024
2025            v.get().add(UrlPathMatcher.of(p));
2026         }
2027
2028         // Replace with bean from:  @RestInject(methodScope="foo") public [static] UrlPathMatcherList xxx(<args>)
2029         // @formatter:off
2030         beanStore
2031            .createMethodFinder(UrlPathMatcherList.class, resource().get())
2032            .addBean(UrlPathMatcherList.class, v.get())
2033            .find(this::matches)
2034            .run(x -> v.set(x));
2035         // @formatter:on
2036
2037         return v.get();
2038      }
2039
2040      /**
2041       * Handles processing of any annotations on parameters.
2042       *
2043       * <p>
2044       * This includes: {@link Header}, {@link Query}, {@link FormData}.
2045       */
2046      protected void processParameterAnnotations() {
2047         for (var aa : restMethod.getParameterAnnotations()) {
2048
2049            var def = (String)null;
2050            for (var a : aa) {
2051               if (a instanceof Schema a2) {
2052                  def = joinnlFirstNonEmptyArray(a2.default_(), a2.df());
2053               }
2054            }
2055
2056            for (var a : aa) {
2057               if (a instanceof Header a2) {
2058                  if (nn(def)) {
2059                     try {
2060                        defaultRequestHeaders().set(basicHeader(firstNonEmpty(a2.name(), a2.value()), parseIfJson(def)));
2061                     } catch (ParseException e) {
2062                        throw new ConfigException(e, "Malformed @Header annotation");
2063                     }
2064                  }
2065               }
2066               if (a instanceof Query a2) {
2067                  if (nn(def)) {
2068                     try {
2069                        defaultRequestQueryData().setDefault(basicPart(firstNonEmpty(a2.name(), a2.value()), parseIfJson(def)));
2070                     } catch (ParseException e) {
2071                        throw new ConfigException(e, "Malformed @Query annotation");
2072                     }
2073                  }
2074               }
2075               if (a instanceof FormData a2) {
2076                  if (nn(def)) {
2077                     try {
2078                        defaultRequestFormData().setDefault(basicPart(firstNonEmpty(a2.name(), a2.value()), parseIfJson(def)));
2079                     } catch (ParseException e) {
2080                        throw new ConfigException(e, "Malformed @FormData annotation");
2081                     }
2082                  }
2083               }
2084            }
2085         }
2086      }
2087
2088      Optional<BeanContext> getBeanContext() { return opt(beanContext).map(BeanContext.Builder::build); }
2089
2090      Optional<EncoderSet> getEncoders() { return opt(encoders).map(EncoderSet.Builder::build); }
2091
2092      RestGuardList getGuards() {
2093         var b = guards();
2094         var roleGuard = opt(this.roleGuard).orElseGet(CollectionUtils::set);
2095
2096         for (var rg : roleGuard) {
2097            try {
2098               b.append(new RoleBasedRestGuard(rolesDeclared, rg));
2099            } catch (java.text.ParseException e1) {
2100               throw toRex(e1);
2101            }
2102         }
2103
2104         return guards.build();
2105      }
2106
2107      Optional<JsonSchemaGenerator> getJsonSchemaGenerator() { return opt(jsonSchemaGenerator).map(JsonSchemaGenerator.Builder::build); }
2108
2109      RestMatcherList getMatchers(RestContext restContext) {
2110         RestMatcherList.Builder b = matchers();
2111         if (nn(clientVersion))
2112            b.append(new ClientVersionMatcher(restContext.getClientVersionHeader(), MethodInfo.of(restMethod)));
2113
2114         return b.build();
2115      }
2116
2117      Optional<ParserSet> getParsers() { return opt(parsers).map(ParserSet.Builder::build); }
2118
2119      Optional<HttpPartParser> getPartParser() { return opt(partParser).map(org.apache.juneau.httppart.HttpPartParser.Creator::create); }
2120
2121      Optional<HttpPartSerializer> getPartSerializer() { return opt(partSerializer).map(Creator::create); }
2122
2123      Optional<SerializerSet> getSerializers() { return opt(serializers).map(SerializerSet.Builder::build); }
2124
2125   }
2126
2127   /**
2128    * Creates a new builder for this object.
2129    *
2130    * @param method The Java method this context belongs to.
2131    * @param context The Java class context.
2132    * @return A new builder.
2133    */
2134   public static Builder create(java.lang.reflect.Method method, RestContext context) {
2135      return new Builder(method, context);
2136   }
2137
2138   private static HttpPartSerializer createPartSerializer(Class<? extends HttpPartSerializer> c, HttpPartSerializer _default) {
2139      return BeanCreator.of(HttpPartSerializer.class).type(c).orElse(_default);
2140   }
2141
2142   protected final boolean dotAll;
2143   protected final int hierarchyDepth;
2144   protected final long maxInput;
2145   protected final BeanContext beanContext;
2146   protected final CallLogger callLogger;
2147   protected final Charset defaultCharset;
2148   protected final DebugEnablement debug;
2149   protected final EncoderSet encoders;
2150   protected final HeaderList defaultRequestHeaders;
2151   protected final HeaderList defaultResponseHeaders;
2152   protected final HttpPartParser partParser;
2153   protected final HttpPartSerializer partSerializer;
2154   protected final JsonSchemaGenerator jsonSchemaGenerator;
2155   protected final List<MediaType> supportedAcceptTypes;
2156   protected final List<MediaType> supportedContentTypes;
2157   protected final Map<Class<?>,ResponseBeanMeta> responseBeanMetas = new ConcurrentHashMap<>();
2158   protected final Map<Class<?>,ResponsePartMeta> headerPartMetas = new ConcurrentHashMap<>();
2159   protected final Method method;
2160   protected final MethodInfo mi;
2161   protected final NamedAttributeMap defaultRequestAttributes;
2162   protected final PartList defaultRequestFormData;
2163   protected final PartList defaultRequestQueryData;
2164   protected final ParserSet parsers;
2165   protected final RestContext context;
2166   protected final RestConverter[] converters;
2167   protected final RestGuard[] guards;
2168   protected final RestMatcher[] optionalMatchers;
2169   protected final RestMatcher[] requiredMatchers;
2170   protected final RestOpInvoker methodInvoker;
2171   protected final RestOpInvoker[] postCallMethods;
2172   protected final RestOpInvoker[] preCallMethods;
2173   protected final ResponseBeanMeta responseMeta;
2174   protected final SerializerSet serializers;
2175   protected final String httpMethod;
2176   protected final UrlPathMatcher[] pathMatchers;
2177
2178   /**
2179    * Context constructor.
2180    *
2181    * @param builder The builder for this object.
2182    * @throws ServletException If context could not be created.
2183    */
2184   protected RestOpContext(Builder builder) throws ServletException {
2185      super(builder);
2186
2187      try {
2188         context = builder.restContext;
2189         method = builder.restMethod;
2190
2191         if (builder.debug == null)
2192            debug = context.getDebugEnablement();
2193         else
2194            debug = DebugEnablement.create(context.getBeanStore()).enable(builder.debug, "*").build();
2195
2196         mi = MethodInfo.of(method).accessible();
2197         var r = context.getResource();
2198
2199      // @formatter:off
2200      var bs = BeanStore.of(context.getRootBeanStore(), r)
2201            .addBean(RestOpContext.class, this)
2202            .addBean(Method.class, method)
2203            .addBean(AnnotationWorkList.class, builder.getApplied());
2204         // @formatter:on
2205         bs.addBean(BeanStore.class, bs);
2206
2207         beanContext = bs.add(BeanContext.class, builder.getBeanContext().orElse(context.getBeanContext()));
2208         converters = bs.add(RestConverter[].class, builder.converters().build().asArray());
2209         encoders = bs.add(EncoderSet.class, builder.getEncoders().orElse(context.getEncoders()));
2210         guards = bs.add(RestGuard[].class, builder.getGuards().asArray());
2211         jsonSchemaGenerator = bs.add(JsonSchemaGenerator.class, builder.getJsonSchemaGenerator().orElse(context.getJsonSchemaGenerator()));
2212         parsers = bs.add(ParserSet.class, builder.getParsers().orElse(context.getParsers()));
2213         partParser = bs.add(HttpPartParser.class, builder.getPartParser().orElse(context.getPartParser()));
2214         partSerializer = bs.add(HttpPartSerializer.class, builder.getPartSerializer().orElse(context.getPartSerializer()));
2215         serializers = bs.add(SerializerSet.class, builder.getSerializers().orElse(context.getSerializers()));
2216
2217         var matchers = builder.getMatchers(context);
2218         optionalMatchers = matchers.getOptionalEntries();
2219         requiredMatchers = matchers.getRequiredEntries();
2220
2221         pathMatchers = bs.add(UrlPathMatcher[].class, builder.getPathMatchers().asArray());
2222         bs.addBean(UrlPathMatcher.class, pathMatchers.length > 0 ? pathMatchers[0] : null);
2223
2224         supportedAcceptTypes = u(nn(builder.produces) ? builder.produces : serializers.getSupportedMediaTypes());
2225         supportedContentTypes = u(nn(builder.consumes) ? builder.consumes : parsers.getSupportedMediaTypes());
2226
2227         defaultRequestAttributes = builder.defaultRequestAttributes();
2228         defaultRequestFormData = builder.defaultRequestFormData();
2229         defaultRequestHeaders = builder.defaultRequestHeaders();
2230         defaultRequestQueryData = builder.defaultRequestQueryData();
2231         defaultResponseHeaders = builder.defaultResponseHeaders();
2232
2233         int _hierarchyDepth = 0;
2234         var sc = method.getDeclaringClass().getSuperclass();
2235         while (nn(sc)) {
2236            _hierarchyDepth++;
2237            sc = sc.getSuperclass();
2238         }
2239         hierarchyDepth = _hierarchyDepth;
2240
2241         var _httpMethod = builder.httpMethod;
2242         if (_httpMethod == null)
2243            _httpMethod = HttpUtils.detectHttpMethod(method, true, "GET");
2244         if ("METHOD".equals(_httpMethod))
2245            _httpMethod = "*";
2246         httpMethod = _httpMethod.toUpperCase(Locale.ENGLISH);
2247
2248         defaultCharset = nn(builder.defaultCharset) ? builder.defaultCharset : context.defaultCharset;
2249         dotAll = builder.dotAll;
2250         maxInput = nn(builder.maxInput) ? builder.maxInput : context.maxInput;
2251
2252         responseMeta = ResponseBeanMeta.create(mi, builder.getApplied());
2253
2254         preCallMethods = context.getPreCallMethods().stream().map(x -> new RestOpInvoker(x, context.findRestOperationArgs(x, bs), context.getMethodExecStats(x))).toArray(RestOpInvoker[]::new);
2255         postCallMethods = context.getPostCallMethods().stream().map(x -> new RestOpInvoker(x, context.findRestOperationArgs(x, bs), context.getMethodExecStats(x))).toArray(RestOpInvoker[]::new);
2256         methodInvoker = new RestOpInvoker(method, context.findRestOperationArgs(method, bs), context.getMethodExecStats(method));
2257
2258         this.callLogger = context.getCallLogger();
2259      } catch (Exception e) {
2260         throw new ServletException(e);
2261      }
2262   }
2263
2264   /*
2265    * compareTo() method is used to keep SimpleMethods ordered in the RestCallRouter list.
2266    * It maintains the order in which matches are made during requests.
2267    */
2268   @Override /* Overridden from Comparable */
2269   public int compareTo(RestOpContext o) {
2270      int c;
2271
2272      for (int i = 0; i < Math.min(pathMatchers.length, o.pathMatchers.length); i++) {
2273         c = pathMatchers[i].compareTo(o.pathMatchers[i]);
2274         if (c != 0)
2275            return c;
2276      }
2277
2278      c = cmp(o.hierarchyDepth, hierarchyDepth);
2279      if (c != 0)
2280         return c;
2281
2282      c = cmp(o.requiredMatchers.length, requiredMatchers.length);
2283      if (c != 0)
2284         return c;
2285
2286      c = cmp(o.optionalMatchers.length, optionalMatchers.length);
2287      if (c != 0)
2288         return c;
2289
2290      c = cmp(o.guards.length, guards.length);
2291
2292      if (c != 0)
2293         return c;
2294
2295      c = cmp(method.getName(), o.method.getName());
2296      if (c != 0)
2297         return c;
2298
2299      c = cmp(method.getParameterCount(), o.method.getParameterCount());
2300      if (c != 0)
2301         return c;
2302
2303      for (var i = 0; i < method.getParameterCount(); i++) {
2304         c = cmp(method.getParameterTypes()[i].getName(), o.method.getParameterTypes()[i].getName());
2305         if (c != 0)
2306            return c;
2307      }
2308
2309      c = cmp(method.getReturnType().getName(), o.method.getReturnType().getName());
2310      if (c != 0)
2311         return c;
2312
2313      return 0;
2314   }
2315
2316   @Override /* Overridden from Context */
2317   public Context.Builder copy() {
2318      throw unsupportedOp();
2319   }
2320
2321   /**
2322    * Creates a {@link RestRequest} object based on the specified incoming {@link HttpServletRequest} object.
2323    *
2324    * @param session The current REST call.
2325    * @return The wrapped request object.
2326    * @throws Exception If any errors occur trying to interpret the request.
2327    */
2328   public RestRequest createRequest(RestSession session) throws Exception {
2329      return new RestRequest(this, session);
2330   }
2331
2332   /**
2333    * Creates a {@link RestResponse} object based on the specified incoming {@link HttpServletResponse} object
2334    * and the request returned by {@link #createRequest(RestSession)}.
2335    *
2336    * @param session The current REST call.
2337    * @param req The REST request.
2338    * @return The wrapped response object.
2339    * @throws Exception If any errors occur trying to interpret the request or response.
2340    */
2341   public RestResponse createResponse(RestSession session, RestRequest req) throws Exception {
2342      return new RestResponse(this, session, req);
2343   }
2344
2345   /**
2346    * Creates a new REST operation session.
2347    *
2348    * @param session The REST session.
2349    * @return A new REST operation session.
2350    * @throws Exception If op session could not be created.
2351    */
2352   public RestOpSession.Builder createSession(RestSession session) throws Exception {
2353      return RestOpSession.create(this, session).logger(callLogger).debug(debug.isDebug(this, session.getRequest()));
2354   }
2355
2356   @Override /* Overridden from Object */
2357   public boolean equals(Object o) {
2358      return (o instanceof RestOpContext o2) && eq(this, o2, (x, y) -> eq(x.method, y.method));
2359   }
2360
2361   /**
2362    * Returns the bean context associated with this context.
2363    *
2364    * @return The bean context associated with this context.
2365    */
2366   public BeanContext getBeanContext() { return beanContext; }
2367
2368   /**
2369    * Returns the default charset.
2370    *
2371    * @return The default charset.  Never <jk>null</jk>.
2372    */
2373   public Charset getDefaultCharset() { return defaultCharset; }
2374
2375   /**
2376    * Returns the default request attributes.
2377    *
2378    * @return The default request attributes.  Never <jk>null</jk>.
2379    */
2380   public NamedAttributeMap getDefaultRequestAttributes() { return defaultRequestAttributes; }
2381
2382   /**
2383    * Returns the default form data parameters.
2384    *
2385    * @return The default form data parameters.  Never <jk>null</jk>.
2386    */
2387   public PartList getDefaultRequestFormData() { return defaultRequestFormData; }
2388
2389   /**
2390    * Returns the default request headers.
2391    *
2392    * @return The default request headers.  Never <jk>null</jk>.
2393    */
2394   public HeaderList getDefaultRequestHeaders() { return defaultRequestHeaders; }
2395
2396   /**
2397    * Returns the default request query parameters.
2398    *
2399    * @return The default request query parameters.  Never <jk>null</jk>.
2400    */
2401   public PartList getDefaultRequestQueryData() { return defaultRequestQueryData; }
2402
2403   /**
2404    * Returns the default response headers.
2405    *
2406    * @return The default response headers.  Never <jk>null</jk>.
2407    */
2408   public HeaderList getDefaultResponseHeaders() { return defaultResponseHeaders; }
2409
2410   /**
2411    * Returns the compression encoders to use for this method.
2412    *
2413    * @return The compression encoders to use for this method.
2414    */
2415   public EncoderSet getEncoders() { return encoders; }
2416
2417   /**
2418    * Returns the HTTP method name (e.g. <js>"GET"</js>).
2419    *
2420    * @return The HTTP method name.
2421    */
2422   public String getHttpMethod() { return httpMethod; }
2423
2424   /**
2425    * Returns the underlying Java method that this context belongs to.
2426    *
2427    * @return The underlying Java method that this context belongs to.
2428    */
2429   public Method getJavaMethod() { return method; }
2430
2431   /**
2432    * Returns the JSON-Schema generator applicable to this Java method.
2433    *
2434    * @return The JSON-Schema generator applicable to this Java method.
2435    */
2436   public JsonSchemaGenerator getJsonSchemaGenerator() { return jsonSchemaGenerator; }
2437
2438   /**
2439    * Returns the max number of bytes to process in the input content.
2440    *
2441    * @return The max number of bytes to process in the input content.
2442    */
2443   public long getMaxInput() { return maxInput; }
2444
2445   /**
2446    * Returns the parsers to use for this method.
2447    *
2448    * @return The parsers to use for this method.
2449    */
2450   public ParserSet getParsers() { return parsers; }
2451
2452   /**
2453    * Bean property getter:  <property>partParser</property>.
2454    *
2455    * @return The value of the <property>partParser</property> property on this bean, or <jk>null</jk> if it is not set.
2456    */
2457   public HttpPartParser getPartParser() { return partParser; }
2458
2459   /**
2460    * Bean property getter:  <property>partSerializer</property>.
2461    *
2462    * @return The value of the <property>partSerializer</property> property on this bean, or <jk>null</jk> if it is not set.
2463    */
2464   public HttpPartSerializer getPartSerializer() { return partSerializer; }
2465
2466   /**
2467    * Returns the path pattern for this method.
2468    *
2469    * @return The path pattern.
2470    */
2471   public String getPathPattern() { return pathMatchers[0].toString(); }
2472
2473   /**
2474    * Returns metadata about the specified response object if it's annotated with {@link Response @Response}.
2475    *
2476    * @param o The response POJO.
2477    * @return Metadata about the specified response object, or <jk>null</jk> if it's not annotated with {@link Response @Response}.
2478    */
2479   public ResponseBeanMeta getResponseBeanMeta(Object o) {
2480      if (o == null)
2481         return null;
2482      var c = o.getClass();
2483      var rbm = responseBeanMetas.get(c);
2484      if (rbm == null) {
2485         rbm = ResponseBeanMeta.create(c, AnnotationWorkList.create());
2486         if (rbm == null)
2487            rbm = ResponseBeanMeta.NULL;
2488         responseBeanMetas.put(c, rbm);
2489      }
2490      if (rbm == ResponseBeanMeta.NULL)
2491         return null;
2492      return rbm;
2493   }
2494
2495   /**
2496    * Returns metadata about the specified response object if it's annotated with {@link Header @Header}.
2497    *
2498    * @param o The response POJO.
2499    * @return Metadata about the specified response object, or <jk>null</jk> if it's not annotated with {@link Header @Header}.
2500    */
2501   public ResponsePartMeta getResponseHeaderMeta(Object o) {
2502      if (o == null)
2503         return null;
2504      var c = o.getClass();
2505      var pm = headerPartMetas.get(c);
2506      if (pm == null) {
2507         var a = ClassInfo.of(c).getAnnotations(Header.class).findFirst().map(AnnotationInfo::inner).orElse(null);
2508         if (nn(a)) {
2509            var schema = HttpPartSchema.create(a);
2510            var serializer = createPartSerializer(schema.getSerializer(), partSerializer);
2511            pm = new ResponsePartMeta(HEADER, schema, serializer);
2512         }
2513         if (pm == null)
2514            pm = ResponsePartMeta.NULL;
2515         headerPartMetas.put(c, pm);
2516      }
2517      if (pm == ResponsePartMeta.NULL)
2518         return null;
2519      return pm;
2520   }
2521
2522   /**
2523    * Returns the response bean meta if this method returns a {@link Response}-annotated bean.
2524    *
2525    * @return The response bean meta or <jk>null</jk> if it's not a {@link Response}-annotated bean.
2526    */
2527   public ResponseBeanMeta getResponseMeta() { return responseMeta; }
2528
2529   /**
2530    * Returns the serializers to use for this method.
2531    *
2532    * @return The serializers to use for this method.
2533    */
2534   public SerializerSet getSerializers() { return serializers; }
2535
2536   /**
2537    * Returns a list of supported accept types.
2538    *
2539    * @return An unmodifiable list.
2540    */
2541   public List<MediaType> getSupportedAcceptTypes() { return supportedAcceptTypes; }
2542
2543   /**
2544    * Returns the list of supported content types.
2545    *
2546    * @return An unmodifiable list.
2547    */
2548   public List<MediaType> getSupportedContentTypes() { return supportedContentTypes; }
2549
2550   @Override /* Overridden from Object */
2551   public int hashCode() {
2552      return method.hashCode();
2553   }
2554
2555   private UrlPathMatch matchPattern(RestSession call) {
2556      var pm = (UrlPathMatch)null;
2557      for (var pp : pathMatchers)
2558         if (pm == null)
2559            pm = pp.match(call.getUrlPath());
2560      return pm;
2561   }
2562
2563   /**
2564    * Identifies if this method can process the specified call.
2565    *
2566    * <p>
2567    * To process the call, the following must be true:
2568    * <ul>
2569    *    <li>Path pattern must match.
2570    *    <li>Matchers (if any) must match.
2571    * </ul>
2572    *
2573    * @param session The call to check.
2574    * @return
2575    *    One of the following values:
2576    *    <ul>
2577    *       <li><c>0</c> - Path doesn't match.
2578    *       <li><c>1</c> - Path matched but matchers did not.
2579    *       <li><c>2</c> - Matches.
2580    *    </ul>
2581    */
2582   protected int match(RestSession session) {
2583
2584      var pm = matchPattern(session);
2585
2586      if (pm == null)
2587         return 0;
2588
2589      if (requiredMatchers.length == 0 && optionalMatchers.length == 0) {
2590         session.urlPathMatch(pm);  // Cache so we don't have to recalculate.
2591         return 2;
2592      }
2593
2594      try {
2595         var req = session.getRequest();
2596
2597         // If the method implements matchers, test them.
2598         for (var m : requiredMatchers)
2599            if (! m.matches(req))
2600               return 1;
2601         if (optionalMatchers.length > 0) {
2602            var matches = false;
2603            for (var m : optionalMatchers)
2604               matches |= m.matches(req);
2605            if (! matches)
2606               return 1;
2607         }
2608
2609         session.urlPathMatch(pm);  // Cache so we don't have to recalculate.
2610         return 2;
2611      } catch (Exception e) {
2612         throw new InternalServerError(e);
2613      }
2614   }
2615
2616   @Override /* Overridden from Context */
2617   protected FluentMap<String,Object> properties() {
2618      return super.properties()
2619         .a("defaultRequestFormData", defaultRequestFormData)
2620         .a("defaultRequestHeaders", defaultRequestHeaders)
2621         .a("defaultRequestQueryData", defaultRequestQueryData)
2622         .a("httpMethod", httpMethod);
2623   }
2624
2625   RestConverter[] getConverters() { return converters; }
2626
2627   RestGuard[] getGuards() { return guards; }
2628
2629   RestOpInvoker getMethodInvoker() { return methodInvoker; }
2630
2631   RestOpInvoker[] getPostCallMethods() { return postCallMethods; }
2632
2633   RestOpInvoker[] getPreCallMethods() { return preCallMethods; }
2634}