001// ***************************************************************************************************************************
002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
003// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
005// * with the License.  You may obtain a copy of the License at                                                              *
006// *                                                                                                                         *
007// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
008// *                                                                                                                         *
009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
011// * specific language governing permissions and limitations under the License.                                              *
012// ***************************************************************************************************************************
013package org.apache.juneau;
014
015import static org.apache.juneau.internal.ClassUtils.*;
016import static org.apache.juneau.internal.CollectionUtils.*;
017import static org.apache.juneau.internal.ConsumerUtils.*;
018import static org.apache.juneau.collections.JsonMap.*;
019import static org.apache.juneau.common.internal.ThrowableUtils.*;
020
021import java.lang.annotation.Annotation;
022import java.lang.reflect.*;
023import java.util.*;
024import java.util.concurrent.*;
025import java.util.function.*;
026
027import org.apache.juneau.annotation.*;
028import org.apache.juneau.collections.*;
029import org.apache.juneau.csv.annotation.*;
030import org.apache.juneau.html.annotation.*;
031import org.apache.juneau.internal.*;
032import org.apache.juneau.json.annotation.*;
033import org.apache.juneau.jsonschema.annotation.*;
034import org.apache.juneau.msgpack.annotation.*;
035import org.apache.juneau.oapi.annotation.*;
036import org.apache.juneau.parser.annotation.*;
037import org.apache.juneau.plaintext.annotation.*;
038import org.apache.juneau.reflect.*;
039import org.apache.juneau.serializer.annotation.*;
040import org.apache.juneau.soap.annotation.*;
041import org.apache.juneau.svl.*;
042import org.apache.juneau.uon.annotation.*;
043import org.apache.juneau.urlencoding.annotation.*;
044import org.apache.juneau.utils.*;
045import org.apache.juneau.xml.annotation.*;
046
047/**
048 * Base class for all Context beans.
049 *
050 * <p>
051 * Context beans follow the convention of havinTg the following parts:
052 * <ul>
053 *    <li>A {@link Builder} class for configuring the context bean.
054 *    <ul>
055 *       <li>This bean is non-thread-safe and meant for one-time use.
056 *    </ul>
057 *    <li>A {@link Context#Context(Builder)} constructor that takes in a builder object.
058 *    <ul>
059 *       <li>This bean is thread-safe and cacheable/reusable.
060 *    </ul>
061 *    <li>A {@link ContextSession} class for doing work.
062 *    <ul>
063 *       <li>This bean is non-thread-safe and meant for one-time use.
064 *    </ul>
065 *
066 * <h5 class='section'>Notes:</h5><ul>
067 *    <li class='note'>This class is thread safe and reusable.
068 * </ul>
069 *
070 * <h5 class='section'>See Also:</h5><ul>
071 * </ul>
072 */
073public abstract class Context implements AnnotationProvider {
074
075   //-----------------------------------------------------------------------------------------------------------------
076   // Static
077   //-----------------------------------------------------------------------------------------------------------------
078
079   private static final Map<Class<?>,MethodInfo> BUILDER_CREATE_METHODS = new ConcurrentHashMap<>();
080
081   /**
082    * Predicate for annotations that themselves are annotated with {@link ContextApply}.
083    */
084   public static final Predicate<AnnotationInfo<?>> CONTEXT_APPLY_FILTER = x -> x.hasAnnotation(ContextApply.class);
085
086   /**
087    * Instantiates a builder of the specified context class.
088    *
089    * <p>
090    * Looks for a public static method called <c>create</c> that returns an object that can be passed into a public
091    * or protected constructor of the class.
092    *
093    * @param type The builder to create.
094    * @return A new builder.
095    */
096   public static Builder createBuilder(Class<? extends Context> type) {
097      try {
098         MethodInfo mi = BUILDER_CREATE_METHODS.get(type);
099         if (mi == null) {
100            ClassInfo c = ClassInfo.of(type);
101            for (ConstructorInfo ci : c.getPublicConstructors()) {
102               if (ci.matches(x -> x.hasNumParams(1) && ! x.getParam(0).getParameterType().is(type))) {
103                  mi = c.getPublicMethod(
104                     x -> x.isStatic()
105                     && x.isNotDeprecated()
106                     && x.hasName("create")
107                     && x.hasReturnType(ci.getParam(0).getParameterType())
108                  );
109                  if (mi != null)
110                     break;
111               }
112            }
113            if (mi == null)
114               throw new BasicRuntimeException("Could not find builder create method on class {0}", type);
115            BUILDER_CREATE_METHODS.put(type, mi);
116         }
117         Builder b = (Builder)mi.invoke(null);
118         b.type(type);
119         return b;
120      } catch (ExecutableException e) {
121         throw asRuntimeException(e);
122      }
123   }
124
125   //-----------------------------------------------------------------------------------------------------------------
126   // Builder
127   //-----------------------------------------------------------------------------------------------------------------
128
129   /**
130    * Builder class.
131    */
132   @FluentSetters
133   public static abstract class Builder {
134
135      private static final Map<Class<?>,ConstructorInfo> CONTEXT_CONSTRUCTORS = new ConcurrentHashMap<>();
136
137      boolean debug;
138      Class<? extends Context> type;
139      Context impl;
140      List<Annotation> annotations;
141      Cache<HashKey,? extends Context> cache;
142
143      private final List<Object> builders = list();
144      private final AnnotationWorkList applied = AnnotationWorkList.create();
145
146      /**
147       * Constructor.
148       * Default settings.
149       */
150      @SuppressWarnings("unchecked")
151      protected Builder() {
152         debug = env("Context.debug", false);
153         annotations = null;
154         registerBuilders(this);
155
156         // By default, the type being created should be the class declaring the builder.
157         Class<?> dc = getClass().getDeclaringClass();
158         if (Context.class.isAssignableFrom(dc))
159            type((Class<? extends Context>)dc);
160      }
161
162      /**
163       * Copy constructor.
164       *
165       * @param copyFrom The bean to copy from.
166       */
167      protected Builder(Context copyFrom) {
168         debug = copyFrom.debug;
169         type = copyFrom.getClass();
170         annotations = listFrom(copyFrom.annotations, true);
171         registerBuilders(this);
172      }
173
174      /**
175       * Copy constructor.
176       *
177       * @param copyFrom The builder to copy from.
178       */
179      protected Builder(Builder copyFrom) {
180         debug = copyFrom.debug;
181         type = copyFrom.type;
182         annotations = listFrom(copyFrom.annotations, true);
183         registerBuilders(this);
184      }
185
186      private Context innerBuild() {
187         if (type == null)
188            throw new BasicRuntimeException("Type not specified for context builder {0}", getClass().getName());
189         if (impl != null && type.isInstance(impl))
190            return type.cast(impl);
191         if (cache != null)
192            return cache.get(hashKey(), ()->getContextConstructor().invoke(this));
193         return getContextConstructor().invoke(this);
194      }
195
196      private ConstructorInfo getContextConstructor() {
197         ConstructorInfo cci = CONTEXT_CONSTRUCTORS.get(type);
198         if (cci == null) {
199            cci = ClassInfo.of(type).getPublicConstructor(
200               x -> x.hasNumParams(1)
201               && x.getParam(0).canAccept(this)
202            );
203            if (cci == null)
204               throw new BasicRuntimeException("Public constructor not found: {0}({1})", className(type), className(this));
205            CONTEXT_CONSTRUCTORS.put(type, cci);
206         }
207         return cci;
208      }
209
210      /**
211       * Copy creator.
212       *
213       * @return A new mutable copy of this builder.
214       */
215      public abstract Builder copy();
216
217      /**
218       * Build the object.
219       *
220       * @return The built object.
221       */
222      public Context build() {
223         return innerBuild();
224      }
225
226      /**
227       * Returns the hashkey of this builder.
228       *
229       * <p>
230       * Used to return previously instantiated context beans that have matching hashkeys.
231       * The {@link HashKey} object is suitable for use as a hashmap key of a map of context beans.
232       * A context bean is considered equivalent if the {@link HashKey#equals(Object)} method is the same.
233       *
234       * @return The hashkey of this builder.
235       */
236      public HashKey hashKey() {
237         return HashKey.of(debug, type, annotations);
238      }
239
240      /**
241       * Specifies a cache to use for hashkey-based caching.
242       *
243       * @param value The cache.
244       * @return This object.
245       */
246      @FluentSetter
247      public Builder cache(Cache<HashKey,? extends Context> value) {
248         this.cache = value;
249         return this;
250      }
251
252      /**
253       * Convenience method for calling {@link #build()} while avoiding a cast.
254       *
255       * @param <T> The type to cast the built object to.
256       * @param c The type to cast the built object to.
257       * @return The built context bean.
258       */
259      @SuppressWarnings("unchecked")
260      public final <T extends Context> T build(Class<T> c) {
261         if (type == null || ! c.isAssignableFrom(type))
262            type = c;
263         return (T)innerBuild();
264      }
265
266      /**
267       * Apply a consumer to this builder.
268       *
269       * @param <T> The builder subtype that this consumer can be applied to.
270       * @param subtype The builder subtype that this consumer can be applied to.
271       * @param consumer The consumer.
272       * @return This object.
273       */
274      public <T extends Builder> Builder apply(Class<T> subtype, Consumer<T> consumer) {
275         if (subtype.isInstance(this))
276            consumer.accept(subtype.cast(this));
277         return this;
278      }
279
280      /**
281       * Associates a context class with this builder.
282       *
283       * <p>
284       * This is the type of object that this builder creates when the {@link #build()} method is called.
285       *
286       * <p>
287       * By default, it's the outer class of where the builder class is defined.
288       *
289       * @param value The context class that this builder should create.
290       * @return This object.
291       */
292      @FluentSetter
293      public Builder type(Class<? extends Context> value) {
294         this.type = value;
295         return this;
296      }
297
298      /**
299       * Returns the context class that this builder should create.
300       *
301       * @return The context class if it was specified.
302       */
303      public Optional<Class<?>> getType() {
304         return optional(type);
305      }
306
307      /**
308       * Specifies a pre-instantiated bean for the {@link #build()} method to return.
309       *
310       * @param value The value for this setting.
311       * @return This object.
312       */
313      @FluentSetter
314      public Builder impl(Context value) {
315         impl = value;
316         return this;
317      }
318
319      /**
320       * Returns <jk>true</jk> if any of the annotations/appliers can be applied to this builder.
321       *
322       * @param work The work to check.
323       * @return <jk>true</jk> if any of the annotations/appliers can be applied to this builder.
324       */
325      public boolean canApply(AnnotationWorkList work) {
326         Flag f = Flag.create();
327         work.forEach(x -> builders.forEach(b -> f.setIf(x.canApply(b))));
328         return f.isSet();
329      }
330
331      /**
332       * Applies a set of applied to this builder.
333       *
334       * <p>
335       * An {@link AnnotationWork} consists of a single pair of {@link AnnotationInfo} that represents an annotation instance,
336       * and {@link AnnotationApplier} which represents the code used to apply the values in that annotation to a specific builder.
337       *
338       * <h5 class='section'>Example:</h5>
339       * <p class='bjava'>
340       *    <jc>// A class annotated with a config annotation.</jc>
341       *    <ja>@BeanConfig</ja>(sortProperties=<js>"$S{sortProperties,false}"</js>)
342       *    <jk>public class</jk> MyClass {...}
343       *
344       *    <jc>// Find all annotations that themselves are annotated with @ContextPropertiesApply.</jc>
345       *    AnnotationList <jv>annotations</jv> = ClassInfo.<jsm>of</jsm>(MyClass.<jk>class</jk>).getAnnotationList(<jsf>CONTEXT_APPLY_FILTER</jsf>);
346       *    VarResolverSession <jv>vrs</jv> = VarResolver.<jsf>DEFAULT</jsf>.createSession();
347       *    AnnotationWorkList <jv>work</jv> = AnnotationWorkList.of(<jv>vrs</jv>, <jv>annotations</jv>);
348       *
349       *    <jc>// Apply any settings found on the annotations.</jc>
350       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
351       *       .<jsm>create</jsm>()
352       *       .apply(<jv>work</jv>)
353       *       .build();
354       * </p>
355       *
356       * @param work The list of annotations and appliers to apply to this builder.
357       * @return This object.
358       */
359      @FluentSetter
360      public Builder apply(AnnotationWorkList work) {
361         applied.addAll(work);
362         work.forEach(x -> builders.forEach(y -> x.apply(y)));
363         return this;
364      }
365
366      /**
367       * Returns all the annotations that have been applied to this builder.
368       *
369       * @return All the annotations that have been applied to this builder.
370       */
371      public AnnotationWorkList getApplied() {
372         return applied;
373      }
374
375      /**
376       * Registers the specified secondary builders with this context builder.
377       *
378       * <p>
379       * When {@link #apply(AnnotationWorkList)} is called, it gets called on all registered builders.
380       *
381       * @param builders The builders to add to the list of builders.
382       */
383      protected void registerBuilders(Object...builders) {
384         for (Object b : builders) {
385            if (b == this)
386               this.builders.add(b);
387            else if (b instanceof Builder)
388               this.builders.addAll(((Builder)b).builders);
389            else
390               this.builders.add(b);
391         }
392      }
393
394      /**
395       * Applies any of the various <ja>@XConfig</ja> annotations on the specified class to this context.
396       *
397       * <p>
398       * Any annotations found that themselves are annotated with {@link ContextApply} will be resolved and
399       * applied as properties to this builder.  These annotations include:
400       * <ul class='javatreec'>
401       *    <li class ='ja'>{@link BeanConfig}
402       *    <li class ='ja'>{@link CsvConfig}
403       *    <li class ='ja'>{@link HtmlConfig}
404       *    <li class ='ja'>{@link HtmlDocConfig}
405       *    <li class ='ja'>{@link JsonConfig}
406       *    <li class ='ja'>{@link JsonSchemaConfig}
407       *    <li class ='ja'>{@link MsgPackConfig}
408       *    <li class ='ja'>{@link OpenApiConfig}
409       *    <li class ='ja'>{@link ParserConfig}
410       *    <li class ='ja'>{@link PlainTextConfig}
411       *    <li class ='ja'>{@link SerializerConfig}
412       *    <li class ='ja'>{@link SoapXmlConfig}
413       *    <li class ='ja'>{@link UonConfig}
414       *    <li class ='ja'>{@link UrlEncodingConfig}
415       *    <li class ='ja'>{@link XmlConfig}
416       *    <li class ='ja'><c>RdfConfig</c>
417       * </ul>
418       *
419       * <p>
420       * Annotations on classes are appended in the following order:
421       * <ol>
422       *    <li>On the package of this class.
423       *    <li>On interfaces ordered parent-to-child.
424       *    <li>On parent classes ordered parent-to-child.
425       *    <li>On this class.
426       * </ol>
427       *
428       * <p>
429       * The default var resolver {@link VarResolver#DEFAULT} is used to resolve any variables in annotation field values.
430       *
431       * <h5 class='section'>Example:</h5>
432       * <p class='bjava'>
433       *    <jc>// A class annotated with a config annotation.</jc>
434       *    <ja>@BeanConfig</ja>(sortProperties=<js>"$S{sortProperties,false}"</js>)
435       *    <jk>public class</jk> MyClass {...}
436       *
437       *    <jc>// Apply any settings found on the annotations.</jc>
438       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
439       *       .<jsm>create</jsm>()
440       *       .applyAnnotations(MyClass.<jk>class</jk>)
441       *       .build();
442       * </p>
443       *
444       * @param fromClasses The classes on which the annotations are defined.
445       * @return This object.
446       */
447      @FluentSetter
448      public Builder applyAnnotations(Class<?>...fromClasses) {
449         AnnotationWorkList work = AnnotationWorkList.create();
450         for (Class<?> c : fromClasses)
451            work.add(ClassInfo.of(c).getAnnotationList(CONTEXT_APPLY_FILTER));
452         return apply(work);
453      }
454
455      /**
456       * Applies any of the various <ja>@XConfig</ja> annotations on the specified method to this context.
457       *
458       * <p>
459       * Any annotations found that themselves are annotated with {@link ContextApply} will be resolved and
460       * applied as properties to this builder.  These annotations include:
461       * <ul class='javatreec'>
462       *    <li class ='ja'>{@link BeanConfig}
463       *    <li class ='ja'>{@link CsvConfig}
464       *    <li class ='ja'>{@link HtmlConfig}
465       *    <li class ='ja'>{@link HtmlDocConfig}
466       *    <li class ='ja'>{@link JsonConfig}
467       *    <li class ='ja'>{@link JsonSchemaConfig}
468       *    <li class ='ja'>{@link MsgPackConfig}
469       *    <li class ='ja'>{@link OpenApiConfig}
470       *    <li class ='ja'>{@link ParserConfig}
471       *    <li class ='ja'>{@link PlainTextConfig}
472       *    <li class ='ja'>{@link SerializerConfig}
473       *    <li class ='ja'>{@link SoapXmlConfig}
474       *    <li class ='ja'>{@link UonConfig}
475       *    <li class ='ja'>{@link UrlEncodingConfig}
476       *    <li class ='ja'>{@link XmlConfig}
477       *    <li class ='ja'><c>RdfConfig</c>
478       * </ul>
479       *
480       * <p>
481       * Annotations on methods are appended in the following order:
482       * <ol>
483       *    <li>On the package of the method class.
484       *    <li>On interfaces ordered parent-to-child.
485       *    <li>On parent classes ordered parent-to-child.
486       *    <li>On the method class.
487       *    <li>On this method and matching methods ordered parent-to-child.
488       * </ol>
489       *
490       * <p>
491       * The default var resolver {@link VarResolver#DEFAULT} is used to resolve any variables in annotation field values.
492       *
493       * <h5 class='section'>Example:</h5>
494       * <p class='bjava'>
495       *    <jc>// A method annotated with a config annotation.</jc>
496       *    <jk>public class</jk> MyClass {
497       *       <ja>@BeanConfig</ja>(sortProperties=<js>"$S{sortProperties,false}"</js>)
498       *       <jk>public void</jk> myMethod() {...}
499       *    }
500       *
501       *    <jc>// Apply any settings found on the annotations.</jc>
502       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
503       *       .<jsm>create</jsm>()
504       *       .applyAnnotations(MyClass.<jk>class</jk>.getMethod(<js>"myMethod"</js>))
505       *       .build();
506       * </p>
507       *
508       * @param fromMethods The methods on which the annotations are defined.
509       * @return This object.
510       */
511      @FluentSetter
512      public Builder applyAnnotations(Method...fromMethods) {
513         AnnotationWorkList work = AnnotationWorkList.create();
514         for (Method m : fromMethods)
515            work.add(MethodInfo.of(m).getAnnotationList(CONTEXT_APPLY_FILTER));
516         return apply(work);
517      }
518
519      //-----------------------------------------------------------------------------------------------------------------
520      // Properties
521      //-----------------------------------------------------------------------------------------------------------------
522
523      /**
524       * Defines annotations to apply to specific classes and methods.
525       *
526       * <p>
527       * Allows you to dynamically apply Juneau annotations typically applied directly to classes and methods.
528       * Useful in cases where you want to use the functionality of the annotation on beans and bean properties but
529       * do not have access to the code to do so.
530       *
531       * <p>
532       * As a rule, any Juneau annotation with an <l>on()</l> method can be used with this setting.
533       *
534       * <p>
535       * The following example shows the equivalent methods for applying the {@link Bean @Bean} annotation:
536       * <p class='bjava'>
537       *    <jc>// Class with explicit annotation.</jc>
538       *    <ja>@Bean</ja>(properties=<js>"street,city,state"</js>)
539       *    <jk>public class</jk> A {...}
540       *
541       *    <jc>// Class with annotation applied via @BeanConfig</jc>
542       *    <jk>public class</jk> B {...}
543       *
544       *    <jc>// Java REST method with @BeanConfig annotation.</jc>
545       *    <ja>@RestGet</ja>(...)
546       *    <ja>@Bean</ja>(on=<js>"B"</js>, properties=<js>"street,city,state"</js>)
547       *    <jk>public void</jk> doFoo() {...}
548       * </p>
549       *
550       * <p>
551       * In general, the underlying framework uses this method when it finds dynamically applied annotations on
552       * config annotations.  However, concrete implementations of annotations are also provided that can be passed
553       * directly into builder classes like so:
554       * <p class='bjava'>
555       *    <jc>// Create a concrete @Bean annotation.</jc>
556       *    <ja>Bean</ja> <jv>annotation</jv> = BeanAnnotation.<jsm>create</jsm>(B.<jk>class</jk>).properties(<js>"street,city,state"</js>).build();
557       *
558       *    <jc>// Apply it to a serializer.</jc>
559       *    WriterSerializer <jv>serializer</jv> = JsonSerializer.<jsm>create</jsm>().annotations(<jv>annotation</jv>).build();
560       *
561       *    <jc>// Serialize a bean with the dynamically applied annotation.</jc>
562       *    String <jv>json</jv> = <jv>serializer</jv>.serialize(<jk>new</jk> B());
563       * </p>
564       *
565       * <p>
566       * The following is the list of annotations builders provided that can be constructed
567       * and passed into the builder class:
568       * <ul class='javatreec'>
569       *    <li class='ja'>{@link org.apache.juneau.annotation.BeanAnnotation}
570       *    <li class='ja'>{@link org.apache.juneau.annotation.BeancAnnotation}
571       *    <li class='ja'>{@link org.apache.juneau.annotation.BeanIgnoreAnnotation}
572       *    <li class='ja'>{@link org.apache.juneau.annotation.BeanpAnnotation}
573       *    <li class='ja'>{@link org.apache.juneau.annotation.ExampleAnnotation}
574       *    <li class='ja'>{@link org.apache.juneau.annotation.NamePropertyAnnotation}
575       *    <li class='ja'>{@link org.apache.juneau.annotation.ParentPropertyAnnotation}
576       *    <li class='ja'>{@link org.apache.juneau.annotation.SwapAnnotation}
577       *    <li class='ja'>{@link org.apache.juneau.annotation.UriAnnotation}
578       *    <li class='ja'>{@link org.apache.juneau.csv.annotation.CsvAnnotation}
579       *    <li class='ja'>{@link org.apache.juneau.html.annotation.HtmlAnnotation}
580       *    <li class='ja'>{@link org.apache.juneau.json.annotation.JsonAnnotation}
581       *    <li class='ja'>{@link org.apache.juneau.annotation.SchemaAnnotation}
582       *    <li class='ja'>{@link org.apache.juneau.msgpack.annotation.MsgPackAnnotation}
583       *    <li class='ja'>{@link org.apache.juneau.oapi.annotation.OpenApiAnnotation}
584       *    <li class='ja'>{@link org.apache.juneau.plaintext.annotation.PlainTextAnnotation}
585       *    <li class='ja'>{@link org.apache.juneau.soap.annotation.SoapXmlAnnotation}
586       *    <li class='ja'>{@link org.apache.juneau.uon.annotation.UonAnnotation}
587       *    <li class='ja'>{@link org.apache.juneau.urlencoding.annotation.UrlEncodingAnnotation}
588       *    <li class='ja'>{@link org.apache.juneau.xml.annotation.XmlAnnotation}
589       * </ul>
590       *
591       * <p>
592       * The syntax for the <l>on()</l> pattern match parameter depends on whether it applies to a class, method, field, or constructor.
593       * The valid pattern matches are:
594       * <ul class='spaced-list'>
595       *  <li>Classes:
596       *       <ul>
597       *          <li>Fully qualified:
598       *             <ul>
599       *                <li><js>"com.foo.MyClass"</js>
600       *             </ul>
601       *          <li>Fully qualified inner class:
602       *             <ul>
603       *                <li><js>"com.foo.MyClass$Inner1$Inner2"</js>
604       *             </ul>
605       *          <li>Simple:
606       *             <ul>
607       *                <li><js>"MyClass"</js>
608       *             </ul>
609       *          <li>Simple inner:
610       *             <ul>
611       *                <li><js>"MyClass$Inner1$Inner2"</js>
612       *                <li><js>"Inner1$Inner2"</js>
613       *                <li><js>"Inner2"</js>
614       *             </ul>
615       *       </ul>
616       *    <li>Methods:
617       *       <ul>
618       *          <li>Fully qualified with args:
619       *             <ul>
620       *                <li><js>"com.foo.MyClass.myMethod(String,int)"</js>
621       *                <li><js>"com.foo.MyClass.myMethod(java.lang.String,int)"</js>
622       *                <li><js>"com.foo.MyClass.myMethod()"</js>
623       *             </ul>
624       *          <li>Fully qualified:
625       *             <ul>
626       *                <li><js>"com.foo.MyClass.myMethod"</js>
627       *             </ul>
628       *          <li>Simple with args:
629       *             <ul>
630       *                <li><js>"MyClass.myMethod(String,int)"</js>
631       *                <li><js>"MyClass.myMethod(java.lang.String,int)"</js>
632       *                <li><js>"MyClass.myMethod()"</js>
633       *             </ul>
634       *          <li>Simple:
635       *             <ul>
636       *                <li><js>"MyClass.myMethod"</js>
637       *             </ul>
638       *          <li>Simple inner class:
639       *             <ul>
640       *                <li><js>"MyClass$Inner1$Inner2.myMethod"</js>
641       *                <li><js>"Inner1$Inner2.myMethod"</js>
642       *                <li><js>"Inner2.myMethod"</js>
643       *             </ul>
644       *       </ul>
645       *    <li>Fields:
646       *       <ul>
647       *          <li>Fully qualified:
648       *             <ul>
649       *                <li><js>"com.foo.MyClass.myField"</js>
650       *             </ul>
651       *          <li>Simple:
652       *             <ul>
653       *                <li><js>"MyClass.myField"</js>
654       *             </ul>
655       *          <li>Simple inner class:
656       *             <ul>
657       *                <li><js>"MyClass$Inner1$Inner2.myField"</js>
658       *                <li><js>"Inner1$Inner2.myField"</js>
659       *                <li><js>"Inner2.myField"</js>
660       *             </ul>
661       *       </ul>
662       *    <li>Constructors:
663       *       <ul>
664       *          <li>Fully qualified with args:
665       *             <ul>
666       *                <li><js>"com.foo.MyClass(String,int)"</js>
667       *                <li><js>"com.foo.MyClass(java.lang.String,int)"</js>
668       *                <li><js>"com.foo.MyClass()"</js>
669       *             </ul>
670       *          <li>Simple with args:
671       *             <ul>
672       *                <li><js>"MyClass(String,int)"</js>
673       *                <li><js>"MyClass(java.lang.String,int)"</js>
674       *                <li><js>"MyClass()"</js>
675       *             </ul>
676       *          <li>Simple inner class:
677       *             <ul>
678       *                <li><js>"MyClass$Inner1$Inner2()"</js>
679       *                <li><js>"Inner1$Inner2()"</js>
680       *                <li><js>"Inner2()"</js>
681       *             </ul>
682       *       </ul>
683       *    <li>A comma-delimited list of anything on this list.
684       * </ul>
685       *
686       * <h5 class='section'>See Also:</h5><ul>
687       *    <li class='ja'>{@link BeanConfig}
688       * </ul>
689       *
690       * @param values
691       *    The annotations to register with the context.
692       * @return This object.
693       */
694      @FluentSetter
695      public Builder annotations(Annotation...values) {
696         annotations = addAll(annotations, values);
697         return this;
698      }
699
700      /**
701       * <i><l>Context</l> configuration property:&emsp;</i>  Debug mode.
702       *
703       * <p>
704       * Enables the following additional information during serialization:
705       * <ul class='spaced-list'>
706       *    <li>
707       *       When bean getters throws exceptions, the exception includes the object stack information
708       *       in order to determine how that method was invoked.
709       *    <li>
710       *       Enables {@link BeanTraverseContext.Builder#detectRecursions()}.
711       * </ul>
712       *
713       * <p>
714       * Enables the following additional information during parsing:
715       * <ul class='spaced-list'>
716       *    <li>
717       *       When bean setters throws exceptions, the exception includes the object stack information
718       *       in order to determine how that method was invoked.
719       * </ul>
720       *
721       * <h5 class='section'>Example:</h5>
722       * <p class='bjava'>
723       *    <jc>// Create a serializer with debug enabled.</jc>
724       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
725       *       .<jsm>create</jsm>()
726       *       .debug()
727       *       .build();
728       *
729       *    <jc>// Create a POJO model with a recursive loop.</jc>
730       *    <jk>public class</jk> MyBean {
731       *       <jk>public</jk> Object <jf>f</jf>;
732       *    }
733       *    MyBean <jv>bean</jv> = <jk>new</jk> MyBean();
734       *    <jv>bean</jv>.<jf>f</jf> = <jv>bean</jv>;
735       *
736       *    <jc>// Throws a SerializeException and not a StackOverflowError</jc>
737       *    String <jv>json</jv> = <jv>serializer</jv>.serialize(<jv>bean</jv>);
738       * </p>
739       *
740       * <h5 class='section'>See Also:</h5><ul>
741       *    <li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#debug()}
742       *    <li class='jm'>{@link org.apache.juneau.ContextSession.Builder#debug(Boolean)}
743       * </ul>
744       *
745       * @return This object.
746       */
747      @FluentSetter
748      public Builder debug() {
749         return debug(true);
750      }
751
752      /**
753       * Same as {@link #debug()} but allows you to explicitly specify the value.
754       *
755       * @param value The value for this setting.
756       * @return This object.
757       */
758      @FluentSetter
759      public Builder debug(boolean value) {
760         debug = value;
761         return this;
762      }
763
764      /**
765       * Returns <jk>true</jk> if debug is enabled.
766       *
767       * @return <jk>true</jk> if debug is enabled.
768       */
769      public boolean isDebug() {
770         return debug;
771      }
772
773      /**
774       * Looks up a system property or environment variable.
775       *
776       * <p>
777       * First looks in system properties.  Then converts the name to env-safe and looks in the system environment.
778       * Then returns the default if it can't be found.
779       *
780       * @param <T> The type to convert to.
781       * @param name The property name.
782       * @param def The default value if not found.
783       * @return The default value.
784       */
785      protected <T> T env(String name, T def) {
786         return SystemEnv.env(name, def);
787      }
788
789      /**
790       * Looks up a system property or environment variable.
791       *
792       * <p>
793       * First looks in system properties.  Then converts the name to env-safe and looks in the system environment.
794       * Then returns the default if it can't be found.
795       *
796       * @param name The property name.
797       * @return The value if found.
798       */
799      protected Optional<String> env(String name) {
800         return SystemEnv.env(name);
801      }
802      // <FluentSetters>
803
804      // </FluentSetters>
805   }
806
807   //-----------------------------------------------------------------------------------------------------------------
808   // Instance
809   //-----------------------------------------------------------------------------------------------------------------
810
811   final List<Annotation> annotations;
812   final boolean debug;
813
814   private final ReflectionMap<Annotation> annotationMap;
815   private final TwoKeyConcurrentCache<Class<?>,Class<? extends Annotation>,Annotation[]> classAnnotationCache;
816   private final TwoKeyConcurrentCache<Class<?>,Class<? extends Annotation>,Annotation[]> declaredClassAnnotationCache;
817   private final TwoKeyConcurrentCache<Method,Class<? extends Annotation>,Annotation[]> methodAnnotationCache;
818   private final TwoKeyConcurrentCache<Field,Class<? extends Annotation>,Annotation[]> fieldAnnotationCache;
819   private final TwoKeyConcurrentCache<Constructor<?>,Class<? extends Annotation>,Annotation[]> constructorAnnotationCache;
820
821   /**
822    * Copy constructor.
823    *
824    * @param copyFrom The context to copy from.
825    */
826   protected Context(Context copyFrom) {
827      annotationMap = copyFrom.annotationMap;
828      annotations = copyFrom.annotations;
829      debug = copyFrom.debug;
830      classAnnotationCache = copyFrom.classAnnotationCache;
831      declaredClassAnnotationCache = copyFrom.declaredClassAnnotationCache;
832      methodAnnotationCache = copyFrom.methodAnnotationCache;
833      fieldAnnotationCache = copyFrom.fieldAnnotationCache;
834      constructorAnnotationCache = copyFrom.constructorAnnotationCache;
835   }
836
837   /**
838    * Constructor for this class.
839    *
840    * @param builder The builder for this class.
841    */
842   protected Context(Builder builder) {
843      init(builder);
844      debug = builder.debug;
845      annotations = optional(builder.annotations).orElseGet(()->emptyList());
846
847      ReflectionMap.Builder<Annotation> rmb = ReflectionMap.create(Annotation.class);
848
849      annotations.forEach(a -> {
850         try {
851            ClassInfo ci = ClassInfo.of(a.getClass());
852
853            MethodInfo mi = ci.getPublicMethod(x -> x.hasName("onClass"));
854            if (mi != null) {
855               if (! mi.getReturnType().is(Class[].class))
856                  throw new ConfigException("Invalid annotation @{0} used in BEAN_annotations property.  Annotation must define an onClass() method that returns a Class array.", a.getClass().getSimpleName());
857               for (Class<?> c : (Class<?>[])mi.accessible().invoke(a))
858                  rmb.append(c.getName(), a);
859            }
860
861            mi = ci.getPublicMethod(x -> x.hasName("on"));
862            if (mi != null) {
863               if (! mi.getReturnType().is(String[].class))
864                  throw new ConfigException("Invalid annotation @{0} used in BEAN_annotations property.  Annotation must define an on() method that returns a String array.", a.getClass().getSimpleName());
865               for (String s : (String[])mi.accessible().invoke(a))
866                  rmb.append(s, a);
867            }
868
869         } catch (Exception e) {
870            throw new ConfigException(e, "Invalid annotation @{0} used in BEAN_annotations property.", className(a));
871         }
872      });
873      this.annotationMap = rmb.build();
874      boolean disabled = Boolean.getBoolean("juneau.disableAnnotationCaching");
875      classAnnotationCache = new TwoKeyConcurrentCache<>(disabled, (k1,k2) -> annotationMap.appendAll(k1, k2, k1.getAnnotationsByType(k2)));
876      declaredClassAnnotationCache = new TwoKeyConcurrentCache<>(disabled, (k1,k2) -> annotationMap.appendAll(k1, k2, k1.getDeclaredAnnotationsByType(k2)));
877      methodAnnotationCache = new TwoKeyConcurrentCache<>(disabled, (k1,k2) -> annotationMap.appendAll(k1, k2, k1.getAnnotationsByType(k2)));
878      fieldAnnotationCache = new TwoKeyConcurrentCache<>(disabled, (k1,k2) -> annotationMap.appendAll(k1, k2, k1.getAnnotationsByType(k2)));
879      constructorAnnotationCache = new TwoKeyConcurrentCache<>(disabled, (k1,k2) -> annotationMap.appendAll(k1, k2, k1.getAnnotationsByType(k2)));
880   }
881
882   /**
883    * Perform optional initialization on builder before it is used.
884    *
885    * <p>
886    * Default behavior is a no-op.
887    *
888    * @param builder The builder to initialize.
889    */
890   protected void init(Builder builder) {}
891
892   /**
893    * Creates a builder from this context object.
894    *
895    * <p>
896    * Builders are used to define new contexts (e.g. serializers, parsers) based on existing configurations.
897    *
898    * @return A new Builder object.
899    */
900   public Builder copy() {
901      throw new UnsupportedOperationException("Not implemented.");
902   }
903
904   /**
905    * Create a session builder based on the properties defined on this context.
906    *
907    * <p>
908    * Use this method for creating sessions where you want to override basic settings.
909    * Otherwise, use {@link #getSession()} directly.
910    *
911    * @return A new session builder.
912    */
913   public ContextSession.Builder createSession() {
914      throw new UnsupportedOperationException("Not implemented.");
915   }
916
917   /**
918    * Returns a session to use for this context.
919    *
920    * <p>
921    * Note that subclasses may opt to return a reusable non-modifiable session.
922    *
923    * @return A new session object.
924    */
925   public ContextSession getSession() {
926      return createSession().build();
927   }
928
929   //-----------------------------------------------------------------------------------------------------------------
930   // Properties
931   //-----------------------------------------------------------------------------------------------------------------
932
933   /**
934    * Debug mode.
935    *
936    * @see Context.Builder#debug()
937    * @return
938    *    <jk>true</jk> if debug mode is enabled.
939    */
940   public boolean isDebug() {
941      return debug;
942   }
943
944   //-----------------------------------------------------------------------------------------------------------------
945   // MetaProvider methods
946   //-----------------------------------------------------------------------------------------------------------------
947
948   @Override /* MetaProvider */
949   public <A extends Annotation> void forEachAnnotation(Class<A> type, Class<?> onClass, Predicate<A> filter, Consumer<A> action) {
950      if (type != null && onClass != null)
951         for (A a : annotations(type, onClass))
952            consume(filter, action, a);
953   }
954
955   @Override /* MetaProvider */
956   public <A extends Annotation> A firstAnnotation(Class<A> type, Class<?> onClass, Predicate<A> filter) {
957      if (type != null && onClass != null)
958         for (A a : annotations(type, onClass))
959            if (test(filter, a))
960               return a;
961      return null;
962   }
963
964   @Override /* MetaProvider */
965   public <A extends Annotation> A lastAnnotation(Class<A> type, Class<?> onClass, Predicate<A> filter) {
966      A x = null;
967      if (type != null && onClass != null)
968         for (A a : annotations(type, onClass))
969            if (test(filter, a))
970               x = a;
971      return x;
972   }
973
974   @Override /* MetaProvider */
975   public <A extends Annotation> void forEachDeclaredAnnotation(Class<A> type, Class<?> onClass, Predicate<A> filter, Consumer<A> action) {
976      if (type != null && onClass != null)
977         for (A a : declaredAnnotations(type, onClass))
978            consume(filter, action, a);
979   }
980
981   @Override /* MetaProvider */
982   public <A extends Annotation> A firstDeclaredAnnotation(Class<A> type, Class<?> onClass, Predicate<A> filter) {
983      if (type != null && onClass != null)
984         for (A a : declaredAnnotations(type, onClass))
985            if (test(filter, a))
986               return a;
987      return null;
988   }
989
990   @Override /* MetaProvider */
991   public <A extends Annotation> A lastDeclaredAnnotation(Class<A> type, Class<?> onClass, Predicate<A> filter) {
992      A x = null;
993      if (type != null && onClass != null)
994         for (A a : declaredAnnotations(type, onClass))
995            if (test(filter, a))
996               x = a;
997      return x;
998   }
999
1000   @Override /* MetaProvider */
1001   public <A extends Annotation> void forEachAnnotation(Class<A> type, Method onMethod, Predicate<A> filter, Consumer<A> action) {
1002      if (type != null && onMethod != null)
1003         for (A a : annotations(type, onMethod))
1004            consume(filter, action, a);
1005   }
1006
1007   @Override /* MetaProvider */
1008   public <A extends Annotation> A firstAnnotation(Class<A> type, Method onMethod, Predicate<A> filter) {
1009      if (type != null && onMethod != null)
1010         for (A a : annotations(type, onMethod))
1011            if (test(filter, a))
1012               return a;
1013      return null;
1014   }
1015
1016   @Override /* MetaProvider */
1017   public <A extends Annotation> A lastAnnotation(Class<A> type, Method onMethod, Predicate<A> filter) {
1018      A x = null;
1019      if (type != null && onMethod != null)
1020         for (A a : annotations(type, onMethod))
1021            if (test(filter, a))
1022               x = a;
1023      return x;
1024   }
1025
1026   @Override /* MetaProvider */
1027   public <A extends Annotation> void forEachAnnotation(Class<A> type, Field onField, Predicate<A> filter, Consumer<A> action) {
1028      if (type != null && onField != null)
1029         for (A a : annotations(type, onField))
1030            consume(filter, action, a);
1031   }
1032
1033   @Override /* MetaProvider */
1034   public <A extends Annotation> A firstAnnotation(Class<A> type, Field onField, Predicate<A> filter) {
1035      if (type != null && onField != null)
1036         for (A a : annotations(type, onField))
1037            if (test(filter, a))
1038               return a;
1039      return null;
1040   }
1041
1042   @Override /* MetaProvider */
1043   public <A extends Annotation> A lastAnnotation(Class<A> type, Field onField, Predicate<A> filter) {
1044      A x = null;
1045      if (type != null && onField != null)
1046         for (A a : annotations(type, onField))
1047            if (test(filter, a))
1048               x = a;
1049      return x;
1050   }
1051
1052   @Override /* MetaProvider */
1053   public <A extends Annotation> void forEachAnnotation(Class<A> type, Constructor<?> onConstructor, Predicate<A> filter, Consumer<A> action) {
1054      if (type != null && onConstructor != null)
1055         for (A a : annotations(type, onConstructor))
1056            consume(filter, action, a);
1057   }
1058
1059   @Override /* MetaProvider */
1060   public <A extends Annotation> A firstAnnotation(Class<A> type, Constructor<?> onConstructor, Predicate<A> filter) {
1061      if (type != null && onConstructor != null)
1062         for (A a : annotations(type, onConstructor))
1063            if (test(filter, a))
1064               return a;
1065      return null;
1066   }
1067
1068   @Override /* MetaProvider */
1069   public <A extends Annotation> A lastAnnotation(Class<A> type, Constructor<?> onConstructor, Predicate<A> filter) {
1070      A x = null;
1071      if (type != null && onConstructor != null)
1072         for (A a : annotations(type, onConstructor))
1073            if (test(filter, a))
1074               x = a;
1075      return x;
1076   }
1077
1078   /**
1079    * Returns <jk>true</jk> if <c>getAnnotation(a,c)</c> returns a non-null value.
1080    *
1081    * @param <A> The annotation being checked for.
1082    * @param type The annotation being checked for.
1083    * @param onClass The class being checked on.
1084    * @return <jk>true</jk> if the annotation exists on the specified class.
1085    */
1086   public <A extends Annotation> boolean hasAnnotation(Class<A> type, Class<?> onClass) {
1087      return annotations(type, onClass).length > 0;
1088   }
1089
1090   /**
1091    * Returns <jk>true</jk> if <c>getAnnotation(a,m)</c> returns a non-null value.
1092    *
1093    * @param <A> The annotation being checked for.
1094    * @param type The annotation being checked for.
1095    * @param onMethod The method being checked on.
1096    * @return <jk>true</jk> if the annotation exists on the specified method.
1097    */
1098   public <A extends Annotation> boolean hasAnnotation(Class<A> type, Method onMethod) {
1099      return annotations(type, onMethod).length > 0;
1100   }
1101
1102   /**
1103    * Returns <jk>true</jk> if <c>getAnnotation(a,f)</c> returns a non-null value.
1104    *
1105    * @param <A> The annotation being checked for.
1106    * @param type The annotation being checked for.
1107    * @param onField The field being checked on.
1108    * @return <jk>true</jk> if the annotation exists on the specified field.
1109    */
1110   public <A extends Annotation> boolean hasAnnotation(Class<A> type, Field onField) {
1111      return annotations(type, onField).length > 0;
1112   }
1113
1114   /**
1115    * Returns <jk>true</jk> if <c>getAnnotation(a,c)</c> returns a non-null value.
1116    *
1117    * @param <A> The annotation being checked for.
1118    * @param type The annotation being checked for.
1119    * @param onConstructor The constructor being checked on.
1120    * @return <jk>true</jk> if the annotation exists on the specified field.
1121    */
1122   public <A extends Annotation> boolean hasAnnotation(Class<A> type, Constructor<?> onConstructor) {
1123      return annotations(type, onConstructor).length > 0;
1124   }
1125
1126   @SuppressWarnings("unchecked")
1127   private <A extends Annotation> A[] annotations(Class<A> type, Class<?> onClass) {
1128      return (A[])classAnnotationCache.get(onClass, type);
1129   }
1130
1131   @SuppressWarnings("unchecked")
1132   private <A extends Annotation> A[] declaredAnnotations(Class<A> type, Class<?> onClass) {
1133      return (A[])declaredClassAnnotationCache.get(onClass, type);
1134   }
1135
1136   @SuppressWarnings("unchecked")
1137   private <A extends Annotation> A[] annotations(Class<A> type, Method onMethod) {
1138      return (A[])methodAnnotationCache.get(onMethod, type);
1139   }
1140
1141   @SuppressWarnings("unchecked")
1142   private <A extends Annotation> A[] annotations(Class<A> type, Field onField) {
1143      return (A[])fieldAnnotationCache.get(onField, type);
1144   }
1145
1146   @SuppressWarnings("unchecked")
1147   private <A extends Annotation> A[] annotations(Class<A> type, Constructor<?> onConstructor) {
1148      return (A[])constructorAnnotationCache.get(onConstructor, type);
1149   }
1150
1151   //-----------------------------------------------------------------------------------------------------------------
1152   // Other methods
1153   //-----------------------------------------------------------------------------------------------------------------
1154
1155   /**
1156    * Returns the properties on this bean as a map for debugging.
1157    *
1158    * @return The properties on this bean as a map for debugging.
1159    */
1160   protected JsonMap properties() {
1161      return filteredMap("annotations", annotations, "debug", debug);
1162   }
1163
1164   @Override /* Object */
1165   public String toString() {
1166      return ObjectUtils.toPropertyMap(this).asReadableString();
1167   }
1168}