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;
018
019import static org.apache.juneau.commons.reflect.ReflectionUtils.*;
020import static org.apache.juneau.commons.reflect.Visibility.*;
021import static org.apache.juneau.commons.utils.AssertionUtils.*;
022import static org.apache.juneau.commons.utils.ClassUtils.*;
023import static org.apache.juneau.commons.utils.CollectionUtils.*;
024import static org.apache.juneau.commons.utils.ThrowableUtils.*;
025import static org.apache.juneau.commons.utils.Utils.*;
026
027import java.beans.*;
028import java.io.*;
029import java.lang.annotation.*;
030import java.lang.reflect.*;
031import java.util.*;
032import java.util.stream.*;
033
034import org.apache.juneau.annotation.*;
035import org.apache.juneau.commons.collections.*;
036import org.apache.juneau.commons.function.*;
037import org.apache.juneau.commons.reflect.*;
038import org.apache.juneau.commons.reflect.Visibility;
039import org.apache.juneau.cp.*;
040import org.apache.juneau.json.*;
041import org.apache.juneau.marshaller.*;
042import org.apache.juneau.serializer.*;
043import org.apache.juneau.swap.*;
044
045/**
046 * Bean context.
047 *
048 * <p>
049 * This class servers multiple purposes:
050 * <ul class='spaced-list'>
051 *    <li>
052 *       Provides the ability to wrap beans inside {@link Map} interfaces.
053 *    <li>
054 *       Serves as a repository for metadata on POJOs, such as associated {@link Bean @Bean} annotations,
055 *       {@link PropertyNamer PropertyNamers}, etc...  which are used to tailor how POJOs are serialized and parsed.
056 * </ul>
057 *
058 * <p>
059 * All serializers and parsers use this context so that they can handle POJOs using a common framework.
060 *
061 * <h5 class='topic'>Bean Contexts</h5>
062 *
063 * <p>
064 * Bean contexts are created through the {@link BeanContext#create() BeanContext.create()} and {@link Builder#build()} methods.
065 * <br>These context objects are read-only, reusable, and thread-safe.
066 *
067 * <p>
068 * Each bean context maintains a cache of {@link ClassMeta} objects that describe information about classes encountered.
069 * These <c>ClassMeta</c> objects are time-consuming to construct.
070 * Therefore, instances of {@link BeanContext} that share the same <js>"BeanContext.*"</js> property values share
071 * the same cache.  This allows for efficient reuse of <c>ClassMeta</c> objects so that the information about
072 * classes only needs to be calculated once.
073 * Because of this, many of the properties defined on the {@link BeanContext} class cannot be overridden on the session.
074 *
075 * <h5 class='topic'>Bean Sessions</h5>
076 *
077 * <p>
078 * Whereas <c>BeanContext</c> objects are permanent, unchangeable, cached, and thread-safe,
079 * {@link BeanSession} objects are ephemeral and not thread-safe.
080 * They are meant to be used as quickly-constructed scratchpads for creating bean maps.
081 * {@link BeanMap} objects can only be created through the session.
082 *
083 * <h5 class='topic'>BeanContext configuration properties</h5>
084 *
085 * <p>
086 * <c>BeanContexts</c> have several configuration properties that can be used to tweak behavior on how beans are
087 * handled.  These are denoted as the static <jsf>BEAN_*</jsf> fields on this class.
088 *
089 * <p>
090 * Some settings (e.g. {@link Builder#beansRequireDefaultConstructor()}) are used to differentiate between bean
091 * and non-bean classes.
092 * Attempting to create a bean map around one of these objects will throw a {@link BeanRuntimeException}.
093 * The purpose for this behavior is so that the serializers can identify these non-bean classes and convert them to
094 * plain strings using the {@link Object#toString()} method.
095 *
096 * <p>
097 * Some settings (e.g. {@link Builder#beanFieldVisibility(Visibility)}) are used to determine what kinds of properties are
098 * detected on beans.
099 *
100 * <p>
101 * Some settings (e.g. {@link Builder#beanMapPutReturnsOldValue()}) change the runtime behavior of bean maps.
102 *
103 * <h5 class='section'>Example:</h5>
104 *
105 * <p class='bjava'>
106 *    <jc>// Construct a context from scratch.</jc>
107 *    BeanContext <jv>beanContext</jv> = BeanContext
108 *       .<jsm>create</jsm>()
109 *       .beansRequireDefaultConstructor()
110 *       .notBeanClasses(Foo.<jk>class</jk>)
111 *       .build();
112 * </p>
113 *
114 * <h5 class='topic'>Bean Maps</h5>
115 *
116 * <p>
117 * {@link BeanMap BeanMaps} are wrappers around Java beans that allow properties to be retrieved and
118 * set using the common {@link Map#put(Object,Object)} and {@link Map#get(Object)} methods.
119 *
120 * <p>
121 * Bean maps are created in two ways...
122 * <ol>
123 *    <li>{@link BeanSession#toBeanMap(Object) BeanSession.toBeanMap()} - Wraps an existing bean inside a {@code Map}
124 *       wrapper.
125 *    <li>{@link BeanSession#newBeanMap(Class) BeanSession.newBeanMap()} - Create a new bean instance wrapped in a
126 *       {@code Map} wrapper.
127 * </ol>
128 *
129 * <h5 class='section'>Example:</h5>
130 *
131 * <p class='bjava'>
132 *    <jc>// A sample bean class</jc>
133 *    <jk>public class</jk> Person {
134 *       <jk>public</jk> String getName();
135 *       <jk>public void</jk> setName(String <jv>name</jv>);
136 *       <jk>public int</jk> getAge();
137 *       <jk>public void</jk> setAge(<jk>int</jk> <jv>age</jv>);
138 *    }
139 *
140 *    <jc>// Create a new bean session</jc>
141 *    BeanSession <jv>session</jv> = BeanContext.<jsf>DEFAULT</jsf>.createSession();
142 *
143 *    <jc>// Wrap an existing bean in a new bean map</jc>
144 *    BeanMap&lt;Person&gt; <jv>map1</jv> = <jv>session</jv>.toBeanMap(<jk>new</jk> Person());
145 *    <jv>map1</jv>.put(<js>"name"</js>, <js>"John Smith"</js>);
146 *    <jv>map1</jv>.put(<js>"age"</js>, 45);
147 *
148 *    <jc>// Create a new bean instance wrapped in a new bean map</jc>
149 *    BeanMap&lt;Person&gt; <jv>map2</jv> = <jv>session</jv>.newBeanMap(Person.<jk>class</jk>);
150 *    <jv>map2</jv>.put(<js>"name"</js>, <js>"John Smith"</js>);
151 *    <jv>map2</jv>.put(<js>"age"</js>, 45);
152 *    Person <jv>person</jv> = <jv>map2</jv>.getBean();  <jc>// Get the bean instance that was created.</jc>
153 * </p>
154 *
155 * <h5 class='section'>Notes:</h5><ul>
156 *    <li class='note'>This class is thread safe and reusable.
157 * </ul>
158 *
159 * <h5 class='section'>See Also:</h5><ul>
160 *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/BeanContextBasics">Bean Context Basics</a>
161 * </ul>
162 */
163@SuppressWarnings({ "unchecked", "rawtypes" })
164public class BeanContext extends Context {
165
166   /**
167    * Builder class.
168    */
169   public static class Builder extends Context.Builder {
170
171      private static final Cache<HashKey,BeanContext> CACHE = Cache.of(HashKey.class, BeanContext.class).build();
172
173      private static int integer(boolean...values) {
174         var n = 0;
175         for (var b : values)
176            n = (n << 1) | (b ? 1 : 0);
177         return n;
178      }
179      private Visibility beanClassVisibility;
180      private Visibility beanConstructorVisibility;
181      private Visibility beanMethodVisibility;
182      private Visibility beanFieldVisibility;
183      private boolean disableBeansRequireSomeProperties;
184      private boolean beanMapPutReturnsOldValue;
185      private boolean beansRequireDefaultConstructor;
186      private boolean beansRequireSerializable;
187      private boolean beansRequireSettersForGetters;
188      private boolean disableIgnoreTransientFields;
189      private boolean disableIgnoreUnknownNullBeanProperties;
190      private boolean disableIgnoreMissingSetters;
191      private boolean disableInterfaceProxies;
192      private boolean findFluentSetters;
193      private boolean ignoreInvocationExceptionsOnGetters;
194      private boolean ignoreInvocationExceptionsOnSetters;
195      private boolean ignoreUnknownBeanProperties;
196      private boolean ignoreUnknownEnumValues;
197      private boolean sortProperties;
198      private boolean useEnumNames;
199      private boolean useJavaBeanIntrospector;
200      private String typePropertyName;
201      private MediaType mediaType;
202      private Locale locale;
203      private TimeZone timeZone;
204      private Class<? extends PropertyNamer> propertyNamer;
205      private List<ClassInfo> beanDictionary;
206      private List<Object> swaps;
207      private Set<ClassInfo> notBeanClasses;
208
209      private Set<String> notBeanPackages;
210
211      /**
212       * Constructor.
213       *
214       * All default settings.
215       */
216      protected Builder() {
217         beanClassVisibility = env("BeanContext.beanClassVisibility", PUBLIC);
218         beanConstructorVisibility = env("BeanContext.beanConstructorVisibility", PUBLIC);
219         beanDictionary = list();
220         beanFieldVisibility = env("BeanContext.beanFieldVisibility", PUBLIC);
221         beanMapPutReturnsOldValue = env("BeanContext.beanMapPutReturnsOldValue", false);
222         beanMethodVisibility = env("BeanContext.beanMethodVisibility", PUBLIC);
223         beansRequireDefaultConstructor = env("BeanContext.beansRequireDefaultConstructor", false);
224         beansRequireSerializable = env("BeanContext.beansRequireSerializable", false);
225         beansRequireSettersForGetters = env("BeanContext.beansRequireSettersForGetters", false);
226         disableBeansRequireSomeProperties = env("BeanContext.disableBeansRequireSomeProperties", false);
227         disableIgnoreMissingSetters = env("BeanContext.disableIgnoreMissingSetters", false);
228         disableIgnoreTransientFields = env("BeanContext.disableIgnoreTransientFields", false);
229         disableIgnoreUnknownNullBeanProperties = env("BeanContext.disableIgnoreUnknownNullBeanProperties", false);
230         disableInterfaceProxies = env("BeanContext.disableInterfaceProxies", false);
231         findFluentSetters = env("BeanContext.findFluentSetters", false);
232         ignoreInvocationExceptionsOnGetters = env("BeanContext.ignoreInvocationExceptionsOnGetters", false);
233         ignoreInvocationExceptionsOnSetters = env("BeanContext.ignoreInvocationExceptionsOnSetters", false);
234         ignoreUnknownBeanProperties = env("BeanContext.ignoreUnknownBeanProperties", false);
235         ignoreUnknownEnumValues = env("BeanContext.ignoreUnknownEnumValues", false);
236         locale = env("BeanContext.locale").map(x -> Locale.forLanguageTag(x)).orElse(Locale.getDefault());
237         mediaType = env("BeanContext.mediaType").map(x -> MediaType.of(x)).orElse(null);
238         notBeanClasses = new TreeSet<>();
239         notBeanPackages = new TreeSet<>();
240         propertyNamer = null;
241         sortProperties = env("BeanContext.sortProperties", false);
242         swaps = list();
243         timeZone = env("BeanContext.timeZone").map(x -> TimeZone.getTimeZone(x)).orElse(null);
244         typePropertyName = env("BeanContext.typePropertyName", "_type");
245         useEnumNames = env("BeanContext.useEnumNames", false);
246         useJavaBeanIntrospector = env("BeanContext.useJavaBeanIntrospector", false);
247      }
248
249      /**
250       * Copy constructor.
251       *
252       * @param copyFrom The bean to copy from.
253       */
254      protected Builder(BeanContext copyFrom) {
255         super(copyFrom);
256         beanClassVisibility = copyFrom.beanClassVisibility;
257         beanConstructorVisibility = copyFrom.beanConstructorVisibility;
258         beanDictionary = copyOf(copyFrom.beanDictionary);
259         beanFieldVisibility = copyFrom.beanFieldVisibility;
260         beanMapPutReturnsOldValue = copyFrom.beanMapPutReturnsOldValue;
261         beanMethodVisibility = copyFrom.beanMethodVisibility;
262         beansRequireDefaultConstructor = copyFrom.beansRequireDefaultConstructor;
263         beansRequireSerializable = copyFrom.beansRequireSerializable;
264         beansRequireSettersForGetters = copyFrom.beansRequireSettersForGetters;
265         disableBeansRequireSomeProperties = ! copyFrom.beansRequireSomeProperties;
266         disableIgnoreMissingSetters = ! copyFrom.ignoreMissingSetters;
267         disableIgnoreTransientFields = ! copyFrom.ignoreTransientFields;
268         disableIgnoreUnknownNullBeanProperties = ! copyFrom.ignoreUnknownNullBeanProperties;
269         disableInterfaceProxies = ! copyFrom.useInterfaceProxies;
270         findFluentSetters = copyFrom.findFluentSetters;
271         ignoreInvocationExceptionsOnGetters = copyFrom.ignoreInvocationExceptionsOnGetters;
272         ignoreInvocationExceptionsOnSetters = copyFrom.ignoreInvocationExceptionsOnSetters;
273         ignoreUnknownBeanProperties = copyFrom.ignoreUnknownBeanProperties;
274         ignoreUnknownEnumValues = copyFrom.ignoreUnknownEnumValues;
275         locale = copyFrom.locale;
276         mediaType = copyFrom.mediaType;
277         notBeanClasses = new TreeSet<>(copyFrom.notBeanClasses);
278         notBeanPackages = toSortedSet(copyFrom.notBeanPackages, false);
279         propertyNamer = copyFrom.propertyNamer;
280         sortProperties = copyFrom.sortProperties;
281         swaps = copyOf(copyFrom.swaps);
282         timeZone = copyFrom.timeZone;
283         typePropertyName = copyFrom.typePropertyName;
284         useEnumNames = copyFrom.useEnumNames;
285         useJavaBeanIntrospector = copyFrom.useJavaBeanIntrospector;
286      }
287
288      /**
289       * Copy constructor.
290       *
291       * @param copyFrom The builder to copy from.
292       */
293      protected Builder(Builder copyFrom) {
294         super(copyFrom);
295         beanClassVisibility = copyFrom.beanClassVisibility;
296         beanConstructorVisibility = copyFrom.beanConstructorVisibility;
297         beanDictionary = copyOf(copyFrom.beanDictionary);
298         beanFieldVisibility = copyFrom.beanFieldVisibility;
299         beanMapPutReturnsOldValue = copyFrom.beanMapPutReturnsOldValue;
300         beanMethodVisibility = copyFrom.beanMethodVisibility;
301         beansRequireDefaultConstructor = copyFrom.beansRequireDefaultConstructor;
302         beansRequireSerializable = copyFrom.beansRequireSerializable;
303         beansRequireSettersForGetters = copyFrom.beansRequireSettersForGetters;
304         disableBeansRequireSomeProperties = copyFrom.disableBeansRequireSomeProperties;
305         disableIgnoreMissingSetters = copyFrom.disableIgnoreMissingSetters;
306         disableIgnoreTransientFields = copyFrom.disableIgnoreTransientFields;
307         disableIgnoreUnknownNullBeanProperties = copyFrom.disableIgnoreUnknownNullBeanProperties;
308         disableInterfaceProxies = copyFrom.disableInterfaceProxies;
309         findFluentSetters = copyFrom.findFluentSetters;
310         ignoreInvocationExceptionsOnGetters = copyFrom.ignoreInvocationExceptionsOnGetters;
311         ignoreInvocationExceptionsOnSetters = copyFrom.ignoreInvocationExceptionsOnSetters;
312         ignoreUnknownBeanProperties = copyFrom.ignoreUnknownBeanProperties;
313         ignoreUnknownEnumValues = copyFrom.ignoreUnknownEnumValues;
314         locale = copyFrom.locale;
315         mediaType = copyFrom.mediaType;
316         notBeanClasses = new TreeSet<>(copyFrom.notBeanClasses);
317         notBeanPackages = toSortedSet(copyFrom.notBeanPackages);
318         propertyNamer = copyFrom.propertyNamer;
319         sortProperties = copyFrom.sortProperties;
320         swaps = copyOf(copyFrom.swaps);
321         timeZone = copyFrom.timeZone;
322         typePropertyName = copyFrom.typePropertyName;
323         useEnumNames = copyFrom.useEnumNames;
324         useJavaBeanIntrospector = copyFrom.useJavaBeanIntrospector;
325      }
326
327      @Override /* Overridden from Builder */
328      public Builder annotations(Annotation...values) {
329         super.annotations(values);
330         return this;
331      }
332
333      @Override /* Overridden from Builder */
334      public Builder apply(AnnotationWorkList work) {
335         super.apply(work);
336         return this;
337      }
338
339      @Override /* Overridden from Builder */
340      public Builder applyAnnotations(Class<?>...from) {
341         super.applyAnnotations(from);
342         return this;
343      }
344
345      @Override /* Overridden from Builder */
346      public Builder applyAnnotations(Object...from) {
347         super.applyAnnotations(from);
348         return this;
349      }
350
351      /**
352       * Minimum bean class visibility.
353       *
354       * <p>
355       * Classes are not considered beans unless they meet the minimum visibility requirements.
356       * For example, if the visibility is <jsf>PUBLIC</jsf> and the bean class is <jk>protected</jk>, then the class
357       * will not be interpreted as a bean class and be serialized as a string.
358       * Use this setting to reduce the visibility requirement.
359       *
360       * <h5 class='section'>Example:</h5>
361       * <p class='bjava'>
362       *    <jc>// A bean with a protected class and one field.</jc>
363       *    <jk>protected class</jk> MyBean {
364       *       <jk>public</jk> String <jf>foo</jf> = <js>"bar"</js>;
365       *    }
366       *
367       *    <jc>// Create a serializer that's capable of serializing the class.</jc>
368       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
369       *       .<jsm>create</jsm>()
370       *       .beanClassVisibility(<jsf>PROTECTED</jsf>)
371       *       .build();
372       *
373       *    <jc>// Produces:  {"foo","bar"}</jc>
374       *    String <jv>json</jv> = <jv>serializer</jv>.serialize(<jk>new</jk> MyBean());
375       * </p>
376       *
377       * <h5 class='section'>Notes:</h5><ul>
378       *    <li class='note'>The {@link Bean @Bean} annotation can be used on a non-public bean class to override this setting.
379       *    <li class='note'>The {@link BeanIgnore @BeanIgnore} annotation can also be used on a public bean class to ignore it as a bean.
380       * </ul>
381       *
382       * <h5 class='section'>See Also:</h5><ul>
383       *    <li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#beanClassVisibility()}
384       * </ul>
385       *
386       * @param value
387       *    The new value for this setting.
388       *    <br>The default is {@link Visibility#PUBLIC}.
389       *    <br>Cannot be <jk>null</jk>.
390       * @return This object.
391       */
392      public Builder beanClassVisibility(Visibility value) {
393         beanClassVisibility = assertArgNotNull("value", value);
394         return this;
395      }
396
397      /**
398       * Minimum bean constructor visibility.
399       *
400       * <p>
401       * Only look for constructors with the specified minimum visibility.
402       *
403       * <p>
404       * This setting affects the logic for finding no-arg constructors for bean.  Normally, only <jk>public</jk> no-arg
405       * constructors are used.  Use this setting if you want to reduce the visibility requirement.
406       *
407       * <h5 class='section'>Example:</h5>
408       * <p class='bjava'>
409       *    <jc>// A bean with a protected constructor and one field.</jc>
410       *    <jk>public class</jk> MyBean {
411       *       <jk>public</jk> String <jf>foo</jf>;
412       *
413       *       <jk>protected</jk> MyBean() {}
414       *    }
415       *
416       *    <jc>// Create a parser capable of calling the protected constructor.</jc>
417       *    ReaderParser <jv>parser</jv> = ReaderParser
418       *       .<jsm>create</jsm>()
419       *       .beanConstructorVisibility(<jsf>PROTECTED</jsf>)
420       *       .build();
421       *
422       *    <jc>// Use it.</jc>
423       *    MyBean <jv>myBean</jv> = <jv>parser</jv>.parse(<js>"{foo:'bar'}"</js>, MyBean.<jk>class</jk>);
424       * </p>
425       *
426       * <h5 class='section'>Notes:</h5><ul>
427       *    <li class='note'>The {@link Beanc @Beanc} annotation can also be used to expose a non-public constructor.
428       *    <li class='note'>The {@link BeanIgnore @BeanIgnore} annotation can also be used on a public bean constructor to ignore it.
429       * </ul>
430       *
431       * <h5 class='section'>See Also:</h5><ul>
432       *    <li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#beanConstructorVisibility()}
433       * </ul>
434       *
435       * @param value
436       *    The new value for this setting.
437       *    <br>The default is {@link Visibility#PUBLIC}.
438       *    <br>Cannot be <jk>null</jk>.
439       * @return This object.
440       */
441      public Builder beanConstructorVisibility(Visibility value) {
442         beanConstructorVisibility = assertArgNotNull("value", value);
443         return this;
444      }
445
446      /**
447       * Returns the bean dictionary list.
448       *
449       * <p>
450       * Gives access to the inner list if you need to make more than simple additions via {@link #beanDictionary(Class...)}.
451       *
452       * @return The bean dictionary list.
453       * @see #beanDictionary(Class...)
454       */
455      public List<ClassInfo> beanDictionary() {
456         return beanDictionary;
457      }
458
459      /**
460       * Convenience method for {@link #beanDictionary(ClassInfo...)} that accepts {@link Class} objects.
461       *
462       * @param values
463       *    The values to add to this setting.
464       *    <br>Cannot contain <jk>null</jk> values.
465       * @return This object.
466       * @see #beanDictionary(ClassInfo...)
467       */
468      public Builder beanDictionary(Class<?>...values) {
469         assertArgNoNulls("values", values);
470         return beanDictionary(Stream.of(values).map(ReflectionUtils::info).toArray(ClassInfo[]::new));
471      }
472
473      /**
474       * Bean dictionary.
475       *
476       * <p>
477       * The list of classes that make up the bean dictionary in this bean context.
478       *
479       * <p>
480       * Values are prepended to the list so that later calls can override classes of earlier calls.
481       *
482       * <p>
483       * A dictionary is a name/class mapping used to find class types during parsing when they cannot be inferred
484       * through reflection.  The names are defined through the {@link Bean#typeName() @Bean(typeName)} annotation defined
485       * on the bean class.  For example, if a class <c>Foo</c> has a type-name of <js>"myfoo"</js>, then it would end up
486       * serialized as <js>"{_type:'myfoo',...}"</js> in JSON
487       * or <js>"&lt;myfoo&gt;...&lt;/myfoo&gt;"</js> in XML.
488       *
489       * <p>
490       * This setting tells the parsers which classes to look for when resolving <js>"_type"</js> attributes.
491       *
492       * <p>
493       * Values can consist of any of the following types:
494       * <ul>
495       *    <li>Any bean class that specifies a value for {@link Bean#typeName() @Bean(typeName)}.
496       *    <li>Any subclass of {@link BeanDictionaryList} containing a collection of bean classes with type name annotations.
497       *    <li>Any subclass of {@link BeanDictionaryMap} containing a mapping of type names to classes without type name annotations.
498       *    <li>Any array or collection of the objects above.
499       * </ul>
500       *
501       * <h5 class='section'>Example:</h5>
502       * <p class='bjava'>
503       *    <jc>// POJOs with @Bean(name) annotations.</jc>
504       *    <ja>@Bean</ja>(typeName=<js>"foo"</js>)
505       *    <jk>public class</jk> Foo {...}
506       *    <ja>@Bean</ja>(typeName=<js>"bar"</js>)
507       *    <jk>public class</jk> Bar {...}
508       *
509       *    <jc>// Create a parser and tell it which classes to try to resolve.</jc>
510       *    ReaderParser <jv>parser</jv> = JsonParser
511       *       .<jsm>create</jsm>()
512       *       .dictionary(Foo.<jk>class</jk>, Bar.<jk>class</jk>)
513       *       .addBeanTypes()
514       *       .build();
515       *
516       *    <jc>// A bean with a field with an indeterminate type.</jc>
517       *    <jk>public class</jk> MyBean {
518       *       <jk>public</jk> Object <jf>mySimpleField</jf>;
519       *    }
520       *
521       *    <jc>// Parse bean.</jc>
522       *    MyBean <jv>myBean</jv> = <jv>parser</jv>.parse(<js>"{mySimpleField:{_type:'foo',...}}"</js>, MyBean.<jk>class</jk>);
523       * </p>
524       *
525       * <p>
526       * Another option is to use the {@link Bean#dictionary()} annotation on the POJO class itself:
527       *
528       * <p class='bjava'>
529       *    <jc>// Instead of by parser, define a bean dictionary on a class through an annotation.</jc>
530       *    <jc>// This applies to all properties on this class and all subclasses.</jc>
531       *    <ja>@Bean</ja>(dictionary={Foo.<jk>class</jk>,Bar.<jk>class</jk>})
532       *    <jk>public class</jk> MyBean {
533       *       <jk>public</jk> Object <jf>mySimpleField</jf>;  <jc>// May contain Foo or Bar object.</jc>
534       *       <jk>public</jk> Map&lt;String,Object&gt; <jf>myMapField</jf>;  <jc>// May contain Foo or Bar objects.</jc>
535       *    }
536       * </p>
537       *
538       * <p>
539       *    A typical usage is to allow for HTML documents to be parsed back into HTML beans:
540       * <p class='bjava'>
541       *    <jc>// Use the predefined HTML5 bean dictionary which is a BeanDictionaryList.</jc>
542       *    ReaderParser <jv>parser</jv> = HtmlParser
543       *       .<jsm>create</jsm>()
544       *       .dictionary(HtmlBeanDictionary.<jk>class</jk>)
545       *       .build();
546       *
547       *    <jc>// Parse an HTML body into HTML beans.</jc>
548       *    Body <jv>body</jv> = <jv>parser</jv>.parse(<js>"&lt;body&gt;&lt;ul&gt;&lt;li&gt;foo&lt;/li&gt;&lt;li&gt;bar&lt;/li&gt;&lt;/ul&gt;"</js>, Body.<jk>class</jk>);
549       * </p>
550       *
551       * <h5 class='section'>See Also:</h5><ul>
552       *    <li class='ja'>{@link org.apache.juneau.annotation.Bean#dictionary()}
553       *    <li class='ja'>{@link org.apache.juneau.annotation.Beanp#dictionary()}
554       *    <li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#dictionary()}
555       *    <li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#dictionary_replace()}
556       *    <li class='jm'>{@link org.apache.juneau.BeanContext.Builder#beanDictionary(ClassInfo...)}
557       * </ul>
558       *
559       * @param values
560       *    The values to add to this setting.
561       *    <br>Cannot contain <jk>null</jk> values.
562       * @return This object.
563       */
564      public Builder beanDictionary(ClassInfo...values) {
565         assertArgNoNulls("values", values);
566         return beanDictionary(l(values));
567      }
568
569      /**
570       * Same as {@link #beanDictionary(ClassInfo...)} but allows you to pass in a collection of class info objects.
571       *
572       * @param values
573       *    The values to add to this setting.
574       *    <br>Cannot be <jk>null</jk> or contain <jk>null</jk> values.
575       * @return This object.
576       * @see #beanDictionary(ClassInfo...)
577       */
578      public Builder beanDictionary(Collection<ClassInfo> values) {
579         assertArgNoNulls("values", values);
580         beanDictionary().addAll(0, values);
581         return this;
582      }
583
584      /**
585       * Minimum bean field visibility.
586       *
587       * <p>
588       * Only look for bean fields with the specified minimum visibility.
589       *
590       * <p>
591       * This affects which fields on a bean class are considered bean properties.  Normally only <jk>public</jk> fields are considered.
592       * Use this setting if you want to reduce the visibility requirement.
593       *
594       * <h5 class='section'>Example:</h5>
595       * <p class='bjava'>
596       *    <jc>// A bean with a protected field.</jc>
597       *    <jk>public class</jk> MyBean {
598       *       <jk>protected</jk> String <jf>foo</jf> = <js>"bar"</js>;
599       *    }
600       *
601       *    <jc>// Create a serializer that recognizes the protected field.</jc>
602       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
603       *       .<jsm>create</jsm>()
604       *       .beanFieldVisibility(<jsf>PROTECTED</jsf>)
605       *       .build();
606       *
607       *    <jc>// Produces:  {"foo":"bar"}</jc>
608       *    String <jv>json</jv> = <jv>serializer</jv>.serialize(<jk>new</jk> MyBean());
609       * </p>
610       *
611       * <p>
612       * Bean fields can be ignored as properties entirely by setting the value to {@link Visibility#NONE}
613       *
614       * <p class='bjava'>
615       *    <jc>// Disable using fields as properties entirely.</jc>
616       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
617       *       .<jsm>create</jsm>()
618       *       .beanFieldVisibility(<jsf>NONE</jsf>)
619       *       .build();
620       * </p>
621       *
622       * <h5 class='section'>Notes:</h5><ul>
623       *    <li class='note'>The {@link Beanp @Beanp} annotation can also be used to expose a non-public field.
624       *    <li class='note'>The {@link BeanIgnore @BeanIgnore} annotation can also be used on a public bean field to ignore it as a bean property.
625       * </ul>
626       *
627       * <h5 class='section'>See Also:</h5><ul>
628       *    <li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#beanFieldVisibility()}
629       * </ul>
630       *
631       * @param value
632       *    The new value for this setting.
633       *    <br>The default is {@link Visibility#PUBLIC}.
634       *    <br>Cannot be <jk>null</jk>.
635       * @return This object.
636       */
637      public Builder beanFieldVisibility(Visibility value) {
638         beanFieldVisibility = assertArgNotNull("value", value);
639         return this;
640      }
641
642      /**
643       * Bean interceptor.
644       *
645       * <p>
646       * Bean interceptors can be used to intercept calls to getters and setters and alter their values in transit.
647       *
648       * <h5 class='section'>Example:</h5>
649       * <p class='bjava'>
650       *    <jc>// Interceptor that strips out sensitive information.</jc>
651       *    <jk>public class</jk> AddressInterceptor <jk>extends</jk> BeanInterceptor&lt;Address&gt; {
652       *
653       *       <jk>public</jk> Object readProperty(Address <jv>bean</jv>, String <jv>name</jv>, Object <jv>value</jv>) {
654       *          <jk>if</jk> (<js>"taxInfo"</js>.equals(<jv>name</jv>))
655       *             <jk>return</jk> <js>"redacted"</js>;
656       *          <jk>return</jk> <jv>value</jv>;
657       *       }
658       *
659       *       <jk>public</jk> Object writeProperty(Address <jv>bean</jv>, String <jv>name</jv>, Object <jv>value</jv>) {
660       *          <jk>if</jk> (<js>"taxInfo"</js>.equals(<jv>name</jv>) &amp;&amp; <js>"redacted"</js>.equals(<jv>value</jv>))
661       *             <jk>return</jk> TaxInfoUtils.<jsm>lookup</jsm>(<jv>bean</jv>.getStreet(), <jv>bean</jv>.getCity(), <jv>bean</jv>.getState());
662       *          <jk>return</jk> <jv>value</jv>;
663       *       }
664       *    }
665       *
666       *    <jc>// Our bean class.</jc>
667       *    <jk>public class</jk> Address {
668       *       <jk>public</jk> String getTaxInfo() {...}
669       *       <jk>public void</jk> setTaxInfo(String <jv>value</jv>) {...}
670       *    }
671       *
672       *    <jc>// Register filter on serializer or parser.</jc>
673       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
674       *       .<jsm>create</jsm>()
675       *       .beanInterceptor(Address.<jk>class</jk>, AddressInterceptor.<jk>class</jk>)
676       *       .build();
677       *
678       *    <jc>// Produces:  {"taxInfo":"redacted"}</jc>
679       *    String <jv>json</jv> = <jv>serializer</jv>.serialize(<jk>new</jk> Address());
680       * </p>
681       *
682       * <h5 class='section'>See Also:</h5><ul>
683       *    <li class='jc'>{@link BeanInterceptor}
684       *    <li class='ja'>{@link Bean#interceptor() Bean(interceptor)}
685       * </ul>
686       *
687       * @param on The bean that the filter applies to.
688       *    <br>Cannot be <jk>null</jk>.
689       * @param value
690       *    The new value for this setting.
691       *    <br>Cannot be <jk>null</jk>.
692       * @return This object.
693       */
694      public Builder beanInterceptor(Class<?> on, Class<? extends BeanInterceptor<?>> value) {
695         assertArgNotNull("on", on);
696         assertArgNotNull("value", value);
697         return annotations(BeanAnnotation.create(on).interceptor(value).build());
698      }
699
700      /**
701       * BeanMap.put() returns old property value.
702       *
703       * <p>
704       * When enabled, then the {@link BeanMap#put(String,Object) BeanMap.put()} method will return old property
705       * values.  Otherwise, it returns <jk>null</jk>.
706       *
707       * <p>
708       * Disabled by default because it introduces a slight performance penalty during serialization.
709       *
710       * <h5 class='section'>Example:</h5>
711       * <p class='bjava'>
712       *    <jc>// Create a context that creates BeanMaps with normal put() behavior.</jc>
713       *    BeanContext <jv>context</jv> = BeanContext
714       *       .<jsm>create</jsm>()
715       *       .beanMapPutReturnsOldValue()
716       *       .build();
717       *
718       *    BeanMap&lt;MyBean&gt; <jv>myBeanMap</jv> = <jv>context</jv>.createSession().toBeanMap(<jk>new</jk> MyBean());
719       *    <jv>myBeanMap</jv>.put(<js>"foo"</js>, <js>"bar"</js>);
720       *    Object <jv>oldValue</jv> = <jv>myBeanMap</jv>.put(<js>"foo"</js>, <js>"baz"</js>);  <jc>// oldValue == "bar"</jc>
721       * </p>
722       *
723       * <h5 class='section'>See Also:</h5><ul>
724       *    <li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#beanMapPutReturnsOldValue()}
725       * </ul>
726       *
727       * @return This object.
728       */
729      public Builder beanMapPutReturnsOldValue() {
730         return beanMapPutReturnsOldValue(true);
731      }
732
733      /**
734       * Same as {@link #beanMapPutReturnsOldValue()} but allows you to explicitly specify the value.
735       *
736       * @param value The value for this setting.
737       * @return This object.
738       */
739      public Builder beanMapPutReturnsOldValue(boolean value) {
740         beanMapPutReturnsOldValue = value;
741         return this;
742      }
743
744      /**
745       * Minimum bean method visibility.
746       *
747       * <p>
748       * Only look for bean methods with the specified minimum visibility.
749       *
750       * <p>
751       * This affects which methods are detected as getters and setters on a bean class. Normally only <jk>public</jk> getters and setters are considered.
752       * Use this setting if you want to reduce the visibility requirement.
753       *
754       * <h5 class='section'>Example:</h5>
755       * <p class='bjava'>
756       *    <jc>// A bean with a protected getter.</jc>
757       *    <jk>public class</jk> MyBean {
758       *       <jk>public</jk> String getFoo() { <jk>return</jk> <js>"foo"</js>; }
759       *       <jk>protected</jk> String getBar() { <jk>return</jk> <js>"bar"</js>; }
760       *    }
761       *
762       *    <jc>// Create a serializer that looks for protected getters and setters.</jc>
763       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
764       *       .<jsm>create</jsm>()
765       *       .beanMethodVisibility(<jsf>PROTECTED</jsf>)
766       *       .build();
767       *
768       *    <jc>// Produces:  {"foo":"foo","bar":"bar"}</jc>
769       *    String <jv>json</jv> = <jv>serializer</jv>.serialize(<jk>new</jk> MyBean());
770       * </p>
771       *
772       * <h5 class='section'>Notes:</h5><ul>
773       *    <li class='note'>The {@link Beanp @Beanp} annotation can also be used to expose a non-public method.
774       *    <li class='note'>The {@link BeanIgnore @BeanIgnore} annotation can also be used on a public bean getter/setter to ignore it as a bean property.
775       * </ul>
776       *
777       * <h5 class='section'>See Also:</h5><ul>
778       *    <li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#beanMethodVisibility()}
779       * </ul>
780       *
781       * @param value
782       *    The new value for this setting.
783       *    <br>The default is {@link Visibility#PUBLIC}
784       * @return This object.
785       */
786      public Builder beanMethodVisibility(Visibility value) {
787         beanMethodVisibility = assertArgNotNull("value", value);
788         return this;
789      }
790
791      /**
792       * Bean property includes.
793       *
794       * <p>
795       * Specifies the set and order of names of properties associated with the bean class.
796       *
797       * <p>
798       * For example, <c>beanProperties(MyBean.<jk>class</jk>, <js>"foo,bar"</js>)</c> means only serialize the <c>foo</c> and
799       * <c>bar</c> properties on the specified bean.  Likewise, parsing will ignore any bean properties not specified
800       * and either throw an exception or silently ignore them depending on whether {@link #ignoreUnknownBeanProperties()}
801       * has been called.
802       *
803       * <p>
804       * This value is entirely optional if you simply want to expose all the getters and public fields on
805       * a class as bean properties.  However, it's useful if you want certain getters to be ignored or you want the properties to be
806       * serialized in a particular order.  Note that on IBM JREs, the property order is the same as the order in the source code,
807       * whereas on Oracle JREs, the order is entirely random.
808       *
809       * <p>
810       * Setting applies to specified class and all subclasses.
811       *
812       * <h5 class='section'>Example:</h5>
813       * <p class='bjava'>
814       *    <jc>// A bean with 3 properties.</jc>
815       *    <jk>public class</jk> MyBean {
816       *       <jk>public</jk> String
817       *          <jf>foo</jf> = <js>"foo"</js>,
818       *          <jf>bar</jf> = <js>"bar"</js>,
819       *          <jf>baz</jf> = <js>"baz"</js>;
820       *    }
821       *
822       *    <jc>// Create a serializer that includes only the 'foo' and 'bar' properties on the MyBean class.</jc>
823       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
824       *       .<jsm>create</jsm>()
825       *       .beanProperties(MyBean.<jk>class</jk>, <js>"foo,bar"</js>)
826       *       .build();
827       *
828       *    <jc>// Produces:  {"foo":"foo","bar":"bar"}</jc>
829       *    String <jv>json</jv> = <jv>serializer</jv>.serialize(<jk>new</jk> MyBean());
830       * </p>
831       *
832       * <p>
833       * This method is functionally equivalent to the following code:
834       * <p class='bjava'>
835       *    <jv>builder</jv>.annotations(BeanAnnotation.<jsm>create</jsm>(<jv>beanClass</jv>).properties(<jv>properties</jv>).build());
836       * </p>
837       *
838       * <h5 class='section'>See Also:</h5><ul>
839       *    <li class='jma'>{@link Bean#properties()}/{@link Bean#p()} - On an annotation on the bean class itself.
840       * </ul>
841       *
842       * @param beanClass The bean class.
843       *    <br>Cannot be <jk>null</jk>.
844       * @param properties Comma-delimited list of property names.
845       *    <br>Cannot be <jk>null</jk>.
846       * @return This object.
847       */
848      public Builder beanProperties(Class<?> beanClass, String properties) {
849         assertArgNotNull("beanClass", beanClass);
850         assertArgNotNull("properties", properties);
851         return annotations(BeanAnnotation.create(beanClass).p(properties).build());
852      }
853
854      /**
855       * Bean property includes.
856       *
857       * <p>
858       * Specifies the set and order of names of properties associated with bean classes.
859       *
860       * <p>
861       * For example, <c>beanProperties(AMap.<jsm>of</jsm>(<js>"MyBean"</js>, <js>"foo,bar"</js>))</c> means only serialize the <c>foo</c> and
862       * <c>bar</c> properties on the specified bean.  Likewise, parsing will ignore any bean properties not specified
863       * and either throw an exception or silently ignore them depending on whether {@link #ignoreUnknownBeanProperties()}
864       * has been called.
865       *
866       * <p>
867       * This value is entirely optional if you simply want to expose all the getters and public fields on
868       * a class as bean properties.  However, it's useful if you want certain getters to be ignored or you want the properties to be
869       * serialized in a particular order.  Note that on IBM JREs, the property order is the same as the order in the source code,
870       * whereas on Oracle JREs, the order is entirely random.
871       *
872       * <p>
873       * Setting applies to specified class and all subclasses.
874       *
875       * <h5 class='section'>Example:</h5>
876       * <p class='bjava'>
877       *    <jc>// A bean with 3 properties.</jc>
878       *    <jk>public class</jk> MyBean {
879       *       <jk>public</jk> String
880       *          <jf>foo</jf> = <js>"foo"</js>,
881       *          <jf>bar</jf> = <js>"bar"</js>,
882       *          <jf>baz</jf> = <js>"baz"</js>;
883       *    }
884       *
885       *    <jc>// Create a serializer that includes only the 'foo' and 'bar' properties on the MyBean class.</jc>
886       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
887       *       .<jsm>create</jsm>()
888       *       .beanProperties(AMap.<jsm>of</jsm>(<js>"MyBean"</js>, <js>"foo,bar"</js>))
889       *       .build();
890       *
891       *    <jc>// Produces:  {"foo":"foo","bar":"bar"}</jc>
892       *    String <jv>json</jv> = <jv>serializer</jv>.serialize(<jk>new</jk> MyBean());
893       * </p>
894       *
895       * <p>
896       * This method is functionally equivalent to the following code for each entry:
897       * <p class='bjava'>
898       *    <jv>builder</jv>.annotations(BeanAnnotation.<jsm>create</jsm>(<jv>key</jv>).properties(<jv>value</jv>.toString()).build());
899       * </p>
900       *
901       * <h5 class='section'>See Also:</h5><ul>
902       *    <li class='jma'>{@link Bean#properties()} / {@link Bean#p()}- On an annotation on the bean class itself.
903       * </ul>
904       *
905       * @param values
906       *    The values to add to this builder.
907       *    <br>Keys are bean class names which can be a simple name, fully-qualified name, or <js>"*"</js> for all beans.
908       *    <br>Values are comma-delimited lists of property names.  Non-String objects are first converted to Strings.
909       *    <br>Cannot be <jk>null</jk>.
910       * @return This object.
911       */
912      public Builder beanProperties(Map<String,Object> values) {
913         assertArgNotNull("values", values);
914         values.forEach((k, v) -> annotations(BeanAnnotation.create(k).p(s(v)).build()));
915         return this;
916      }
917
918      /**
919       * Bean property includes.
920       *
921       * <p>
922       * Specifies the set and order of names of properties associated with the bean class.
923       *
924       * <p>
925       * For example, <c>beanProperties(<js>"MyBean"</js>, <js>"foo,bar"</js>)</c> means only serialize the <c>foo</c> and
926       * <c>bar</c> properties on the specified bean.  Likewise, parsing will ignore any bean properties not specified
927       * and either throw an exception or silently ignore them depending on whether {@link #ignoreUnknownBeanProperties()}
928       * has been called.
929       *
930       * <p>
931       * This value is entirely optional if you simply want to expose all the getters and public fields on
932       * a class as bean properties.  However, it's useful if you want certain getters to be ignored or you want the properties to be
933       * serialized in a particular order.  Note that on IBM JREs, the property order is the same as the order in the source code,
934       * whereas on Oracle JREs, the order is entirely random.
935       *
936       * <p>
937       * Setting applies to specified class and all subclasses.
938       *
939       * <h5 class='section'>Example:</h5>
940       * <p class='bjava'>
941       *    <jc>// A bean with 3 properties.</jc>
942       *    <jk>public class</jk> MyBean {
943       *       <jk>public</jk> String
944       *          <jf>foo</jf> = <js>"foo"</js>,
945       *          <jf>bar</jf> = <js>"bar"</js>,
946       *          <jf>baz</jf> = <js>"baz"</js>;
947       *    }
948       *
949       *    <jc>// Create a serializer that includes only the 'foo' and 'bar' properties on the MyBean class.</jc>
950       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
951       *       .<jsm>create</jsm>()
952       *       .beanProperties(<js>"MyBean"</js>, <js>"foo,bar"</js>)
953       *       .build();
954       *
955       *    <jc>// Produces:  {"foo":"foo","bar":"bar"}</jc>
956       *    String <jv>json</jv> = <jv>serializer</jv>.serialize(<jk>new</jk> MyBean());
957       * </p>
958       *
959       * <p>
960       * This method is functionally equivalent to the following code:
961       * <p class='bjava'>
962       *    <jv>builder</jv>.annotations(BeanAnnotation.<jsm>create</jsm>(<jv>beanClassName</jv>).properties(<jv>properties</jv>).build());
963       * </p>
964       *
965       * <h5 class='section'>See Also:</h5><ul>
966       *    <li class='jma'>{@link Bean#properties()} / {@link Bean#p()} - On an annotation on the bean class itself.
967       * </ul>
968       *
969       * @param beanClassName
970       *    The bean class name.
971       *    <br>Can be a simple name, fully-qualified name, or <js>"*"</js> for all beans.
972       * @param properties Comma-delimited list of property names.
973       *    <br>Cannot be <jk>null</jk>.
974       * @return This object.
975       */
976      public Builder beanProperties(String beanClassName, String properties) {
977         assertArgNotNull("beanClassName", beanClassName);
978         assertArgNotNull("properties", properties);
979         return annotations(BeanAnnotation.create(beanClassName).p(properties).build());
980      }
981
982      /**
983       * Bean property excludes.
984       *
985       * <p>
986       * Specifies to exclude the specified list of properties for the specified bean class.
987       *
988       * <p>
989       * Same as {@link #beanProperties(Class, String)} except you specify a list of bean property names that you want to exclude from
990       * serialization.
991       *
992       * <p>
993       * Setting applies to specified class and all subclasses.
994       *
995       * <h5 class='section'>Example:</h5>
996       * <p class='bjava'>
997       *    <jc>// A bean with 3 properties.</jc>
998       *    <jk>public class</jk> MyBean {
999       *       <jk>public</jk> String
1000       *          <jf>foo</jf> = <js>"foo"</js>,
1001       *          <jf>bar</jf> = <js>"bar"</js>,
1002       *          <jf>baz</jf> = <js>"baz"</js>;
1003       *    }
1004       *
1005       *    <jc>// Create a serializer that excludes the "bar" and "baz" properties on the MyBean class.</jc>
1006       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
1007       *       .<jsm>create</jsm>()
1008       *       .beanPropertiesExcludes(MyBean.<jk>class</jk>, <js>"bar,baz"</js>)
1009       *       .build();
1010       *
1011       *    <jc>// Produces:  {"foo":"foo"}</jc>
1012       *    String <jv>json</jv> = <jv>serializer</jv>.serialize(<jk>new</jk> MyBean());
1013       * </p>
1014       *
1015       * <p>
1016       * This method is functionally equivalent to the following code:
1017       * <p class='bjava'>
1018       *    <jv>builder</jv>.annotations(BeanAnnotation.<jsm>create</jsm>(<jv>beanClass</jv>).excludeProperties(<jv>properties</jv>).build());
1019       * </p>
1020       *
1021       * <h5 class='section'>See Also:</h5><ul>
1022       *    <li class='jma'>{@link Bean#excludeProperties()} / {@link Bean#xp()}
1023       * </ul>
1024       *
1025       * @param beanClass The bean class.
1026       *    <br>Cannot be <jk>null</jk>.
1027       * @param properties Comma-delimited list of property names.
1028       *    <br>Cannot be <jk>null</jk>.
1029       * @return This object.
1030       */
1031      public Builder beanPropertiesExcludes(Class<?> beanClass, String properties) {
1032         assertArgNotNull("beanClass", beanClass);
1033         assertArgNotNull("properties", properties);
1034         return annotations(BeanAnnotation.create(beanClass).xp(properties).build());
1035      }
1036
1037      /**
1038       * Bean property excludes.
1039       *
1040       * <p>
1041       * Specifies to exclude the specified list of properties for the specified bean classes.
1042       *
1043       * <p>
1044       * Same as {@link #beanProperties(Map)} except you specify a list of bean property names that you want to exclude from
1045       * serialization.
1046       *
1047       * <p>
1048       * Setting applies to specified class and all subclasses.
1049       *
1050       * <h5 class='section'>Example:</h5>
1051       * <p class='bjava'>
1052       *    <jc>// A bean with 3 properties.</jc>
1053       *    <jk>public class</jk> MyBean {
1054       *       <jk>public</jk> String
1055       *          <jf>foo</jf> = <js>"foo"</js>,
1056       *          <jf>bar</jf> = <js>"bar"</js>,
1057       *          <jf>baz</jf> = <js>"baz"</js>;
1058       *    }
1059       *
1060       *    <jc>// Create a serializer that excludes the "bar" and "baz" properties on the MyBean class.</jc>
1061       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
1062       *       .<jsm>create</jsm>()
1063       *       .beanPropertiesExcludes(AMap.of(<js>"MyBean"</js>, <js>"bar,baz"</js>))
1064       *       .build();
1065       *
1066       *    <jc>// Produces:  {"foo":"foo"}</jc>
1067       *    String <jv>json</jv> = <jv>serializer</jv>.serialize(<jk>new</jk> MyBean());
1068       * </p>
1069       *
1070       * <p>
1071       * This method is functionally equivalent to the following code for each entry:
1072       * <p class='bjava'>
1073       *    <jv>builder</jv>.annotations(BeanAnnotation.<jsm>create</jsm>(<jv>key</jv>).excludeProperties(<jv>value</jv>.toString()).build());
1074       * </p>
1075       *
1076       * <h5 class='section'>See Also:</h5><ul>
1077       *    <li class='jma'>{@link Bean#excludeProperties()} / {@link Bean#xp()}
1078       * </ul>
1079       *
1080       * @param values
1081       *    The values to add to this builder.
1082       *    <br>Keys are bean class names which can be a simple name, fully-qualified name, or <js>"*"</js> for all beans.
1083       *    <br>Values are comma-delimited lists of property names.  Non-String objects are first converted to Strings.
1084       *    <br>Cannot be <jk>null</jk>.
1085       * @return This object.
1086       */
1087      public Builder beanPropertiesExcludes(Map<String,Object> values) {
1088         assertArgNotNull("values", values);
1089         values.forEach((k, v) -> annotations(BeanAnnotation.create(k).xp(s(v)).build()));
1090         return this;
1091      }
1092
1093      /**
1094       * Bean property excludes.
1095       *
1096       * <p>
1097       * Specifies to exclude the specified list of properties for the specified bean class.
1098       *
1099       * <p>
1100       * Same as {@link #beanPropertiesExcludes(String, String)} except you specify a list of bean property names that you want to exclude from
1101       * serialization.
1102       *
1103       * <p>
1104       * Setting applies to specified class and all subclasses.
1105       *
1106       * <h5 class='section'>Example:</h5>
1107       * <p class='bjava'>
1108       *    <jc>// A bean with 3 properties.</jc>
1109       *    <jk>public class</jk> MyBean {
1110       *       <jk>public</jk> String
1111       *          <jf>foo</jf> = <js>"foo"</js>,
1112       *          <jf>bar</jf> = <js>"bar"</js>,
1113       *          <jf>baz</jf> = <js>"baz"</js>;
1114       *    }
1115       *
1116       *    <jc>// Create a serializer that excludes the "bar" and "baz" properties on the MyBean class.</jc>
1117       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
1118       *       .<jsm>create</jsm>()
1119       *       .beanPropertiesExcludes(<js>"MyBean"</js>, <js>"bar,baz"</js>)
1120       *       .build();
1121       *
1122       *    <jc>// Produces:  {"foo":"foo"}</jc>
1123       *    String <jv>json</jv> = <jv>serializer</jv>.serialize(<jk>new</jk> MyBean());
1124       * </p>
1125       *
1126       * <p>
1127       * This method is functionally equivalent to the following code:
1128       * <p class='bjava'>
1129       *    <jv>builder</jv>.annotations(BeanAnnotation.<jsm>create</jsm>(<jv>beanClassName</jv>).excludeProperties(<jv>properties</jv>).build());
1130       * </p>
1131       *
1132       * <h5 class='section'>See Also:</h5><ul>
1133       *    <li class='jma'>{@link Bean#excludeProperties()} / {@link Bean#xp()}
1134       * </ul>
1135       *
1136       * @param beanClassName
1137       *    The bean class name.
1138       *    <br>Can be a simple name, fully-qualified name, or <js>"*"</js> for all bean classes.
1139       *    <br>Cannot be <jk>null</jk>.
1140       * @param properties Comma-delimited list of property names.
1141       *    <br>Cannot be <jk>null</jk>.
1142       * @return This object.
1143       */
1144      public Builder beanPropertiesExcludes(String beanClassName, String properties) {
1145         assertArgNotNull("beanClassName", beanClassName);
1146         assertArgNotNull("properties", properties);
1147         return annotations(BeanAnnotation.create(beanClassName).xp(properties).build());
1148      }
1149
1150      /**
1151       * Read-only bean properties.
1152       *
1153       * <p>
1154       * Specifies one or more properties on a bean that are read-only despite having valid getters.
1155       * Serializers will serialize such properties as usual, but parsers will silently ignore them.
1156       * Note that this is different from the {@link #beanProperties(Class,String) beanProperties}/{@link #beanPropertiesExcludes(Class,String) beanPropertiesExcludes} settings which include or exclude properties
1157       * for both serializers and parsers.
1158       *
1159       * <h5 class='section'>Example:</h5>
1160       * <p class='bjava'>
1161       *    <jc>// A bean with 3 properties.</jc>
1162       *    <jk>public class</jk> MyBean {
1163       *       <jk>public</jk> String <jf>foo</jf>, <jf>bar</jf>, <jf>baz</jf>;
1164       *    }
1165       *
1166       *    <jc>// Create a serializer with read-only property settings.</jc>
1167       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
1168       *       .<jsm>create</jsm>()
1169       *       .beanPropertiesReadOnly(MyBean.<jk>class</jk>, <js>"bar,baz"</js>)
1170       *       .build();
1171       *
1172       *    <jc>// All 3 properties will be serialized.</jc>
1173       *    String <jv>json</jv> = <jv>serializer</jv>.serialize(<jk>new</jk> MyBean());
1174       *
1175       *    <jc>// Create a parser with read-only property settings.</jc>
1176       *    ReaderParser <jv>parser</jv> = JsonParser
1177       *       .<jsm>create</jsm>()
1178       *       .beanPropertiesReadOnly(MyBean.<jk>class</jk>, <js>"bar,baz"</js>)
1179       *       .ignoreUnknownBeanProperties()
1180       *       .build();
1181       *
1182       *    <jc>// Parser ignores bar and baz properties.</jc>
1183       *    MyBean <jv>myBean</jv> = <jv>parser</jv>.parse(<js>"{foo:'foo',bar:'bar',baz:'baz'}"</js>, MyBean.<jk>class</jk>);
1184       * </p>
1185       *
1186       * <p>
1187       * This method is functionally equivalent to the following code:
1188       * <p class='bjava'>
1189       *    <jv>builder</jv>.annotations(BeanAnnotation.<jsm>create</jsm>(<jv>beanClass</jv>).readOnlyProperties(<jv>properties</jv>).build());
1190       * </p>
1191       *
1192       * <h5 class='section'>See Also:</h5><ul>
1193       *    <li class='jma'>{@link Bean#readOnlyProperties()} / {@link Bean#ro()}
1194       * </ul>
1195       *
1196       * @param beanClass The bean class.
1197       *    <br>Cannot be <jk>null</jk>.
1198       * @param properties Comma-delimited list of property names.
1199       *    <br>Cannot be <jk>null</jk>.
1200       * @return This object.
1201       */
1202      public Builder beanPropertiesReadOnly(Class<?> beanClass, String properties) {
1203         assertArgNotNull("beanClass", beanClass);
1204         assertArgNotNull("properties", properties);
1205         return annotations(BeanAnnotation.create(beanClass).ro(properties).build());
1206      }
1207
1208      /**
1209       * Read-only bean properties.
1210       *
1211       * <p>
1212       * Specifies one or more properties on beans that are read-only despite having valid getters.
1213       * Serializers will serialize such properties as usual, but parsers will silently ignore them.
1214       * Note that this is different from the {@link #beanProperties(Class,String) beanProperties}/{@link #beanPropertiesExcludes(Class,String) beanPropertiesExcludes} settings which include or exclude properties
1215       * for both serializers and parsers.
1216       *
1217       * <h5 class='section'>Example:</h5>
1218       * <p class='bjava'>
1219       *    <jc>// A bean with 3 properties.</jc>
1220       *    <jk>public class</jk> MyBean {
1221       *       <jk>public</jk> String <jf>foo</jf>, <jf>bar</jf>, <jf>baz</jf>;
1222       *    }
1223       *
1224       *    <jc>// Create a serializer with read-only property settings.</jc>
1225       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
1226       *       .<jsm>create</jsm>()
1227       *       .beanPropertiesReadOnly(AMap.<jsm>of</jsm>(<js>"MyBean"</js>, <js>"bar,baz"</js>))
1228       *       .build();
1229       *
1230       *    <jc>// All 3 properties will be serialized.</jc>
1231       *    String <jv>json</jv> = <jv>serializer</jv>.serialize(<jk>new</jk> MyBean());
1232       *
1233       *    <jc>// Create a parser with read-only property settings.</jc>
1234       *    ReaderParser <jv>parser</jv> = JsonParser
1235       *       .<jsm>create</jsm>()
1236       *       .beanPropertiesReadOnly(AMap.<jsm>of</jsm>(<js>"MyBean"</js>, <js>"bar,baz"</js>))
1237       *       .ignoreUnknownBeanProperties()
1238       *       .build();
1239       *
1240       *    <jc>// Parser ignores bar and baz properties.</jc>
1241       *    MyBean <jv>myBean</jv> = <jv>parser</jv>.parse(<js>"{foo:'foo',bar:'bar',baz:'baz'}"</js>, MyBean.<jk>class</jk>);
1242       * </p>
1243       *
1244       * <p>
1245       * This method is functionally equivalent to the following code for each entry:
1246       * <p class='bjava'>
1247       *    <jv>builder</jv>.annotations(BeanAnnotation.<jsm>create</jsm>(<jv>key</jv>).readOnlyProperties(<jv>value</jv>.toString()).build());
1248       * </p>
1249       *
1250       * <h5 class='section'>See Also:</h5><ul>
1251       *    <li class='jma'>{@link Bean#readOnlyProperties()} / {@link Bean#ro()}
1252       * </ul>
1253       *
1254       * @param values
1255       *    The values to add to this builder.
1256       *    <br>Keys are bean class names which can be a simple name, fully-qualified name, or <js>"*"</js> for all beans.
1257       *    <br>Values are comma-delimited lists of property names.  Non-String objects are first converted to Strings.
1258       *    <br>Cannot be <jk>null</jk>.
1259       * @return This object.
1260       */
1261      public Builder beanPropertiesReadOnly(Map<String,Object> values) {
1262         assertArgNotNull("values", values);
1263         values.forEach((k, v) -> annotations(BeanAnnotation.create(k).ro(s(v)).build()));
1264         return this;
1265      }
1266
1267      /**
1268       * Read-only bean properties.
1269       *
1270       * <p>
1271       * Specifies one or more properties on a bean that are read-only despite having valid getters.
1272       * Serializers will serialize such properties as usual, but parsers will silently ignore them.
1273       * Note that this is different from the {@link #beanProperties(Class,String) beanProperties}/{@link #beanPropertiesExcludes(Class,String) beanPropertiesExcludes} settings which include or exclude properties
1274       * for both serializers and parsers.
1275       *
1276       * <h5 class='section'>Example:</h5>
1277       * <p class='bjava'>
1278       *    <jc>// A bean with 3 properties.</jc>
1279       *    <jk>public class</jk> MyBean {
1280       *       <jk>public</jk> String <jf>foo</jf>, <jf>bar</jf>, <jf>baz</jf>;
1281       *    }
1282       *
1283       *    <jc>// Create a serializer with read-only property settings.</jc>
1284       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
1285       *       .<jsm>create</jsm>()
1286       *       .beanPropertiesReadOnly(<js>"MyBean"</js>, <js>"bar,baz"</js>)
1287       *       .build();
1288       *
1289       *    <jc>// All 3 properties will be serialized.</jc>
1290       *    String <jv>json</jv> = <jv>serializer</jv>.serialize(<jk>new</jk> MyBean());
1291       *
1292       *    <jc>// Create a parser with read-only property settings.</jc>
1293       *    ReaderParser <jv>parser</jv> = JsonParser
1294       *       .<jsm>create</jsm>()
1295       *       .beanPropertiesReadOnly(<js>"MyBean"</js>, <js>"bar,baz"</js>)
1296       *       .ignoreUnknownBeanProperties()
1297       *       .build();
1298       *
1299       *    <jc>// Parser ignores bar and baz properties.</jc>
1300       *    MyBean <jv>myBean</jv> = <jv>parser</jv>.parse(<js>"{foo:'foo',bar:'bar',baz:'baz'}"</js>, MyBean.<jk>class</jk>);
1301       * </p>
1302       *
1303       * <p>
1304       * This method is functionally equivalent to the following code:
1305       * <p class='bjava'>
1306       *    <jv>builder</jv>.annotations(BeanAnnotation.<jsm>create</jsm>(<jv>beanClassName</jv>).readOnlyProperties(<jv>properties</jv>).build());
1307       * </p>
1308       *
1309       * <h5 class='section'>See Also:</h5><ul>
1310       *    <li class='jma'>{@link Bean#readOnlyProperties()} / {@link Bean#ro()}
1311       * </ul>
1312       *
1313       * @param beanClassName
1314       *    The bean class name.
1315       *    <br>Can be a simple name, fully-qualified name, or <js>"*"</js> for all bean classes.
1316       * @param properties Comma-delimited list of property names.
1317       * @return This object.
1318       */
1319      public Builder beanPropertiesReadOnly(String beanClassName, String properties) {
1320         assertArgNotNull("beanClassName", beanClassName);
1321         assertArgNotNull("properties", properties);
1322         return annotations(BeanAnnotation.create(beanClassName).ro(properties).build());
1323      }
1324
1325      /**
1326       * Write-only bean properties.
1327       *
1328       * <p>
1329       * Specifies one or more properties on a bean that are write-only despite having valid setters.
1330       * Parsers will parse such properties as usual, but serializers will silently ignore them.
1331       * Note that this is different from the {@link #beanProperties(Class,String) beanProperties}/{@link #beanPropertiesExcludes(Class,String) beanPropertiesExcludes} settings which include or exclude properties
1332       * for both serializers and parsers.
1333       *
1334       * <h5 class='section'>Example:</h5>
1335       * <p class='bjava'>
1336       *    <jc>// A bean with 3 properties.</jc>
1337       *    <jk>public class</jk> MyBean {
1338       *       <jk>public</jk> String <jf>foo</jf>, <jf>bar</jf>, <jf>baz</jf>;
1339       *    }
1340       *
1341       *    <jc>// Create a serializer with write-only property settings.</jc>
1342       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
1343       *       .<jsm>create</jsm>()
1344       *       .beanPropertiesWriteOnly(MyBean.<jk>class</jk>, <js>"bar,baz"</js>)
1345       *       .build();
1346       *
1347       *    <jc>// Only foo will be serialized.</jc>
1348       *    String <jv>json</jv> = <jv>serializer</jv>.serialize(<jk>new</jk> MyBean());
1349       *
1350       *    <jc>// Create a parser with write-only property settings.</jc>
1351       *    ReaderParser <jv>parser</jv> = JsonParser
1352       *       .<jsm>create</jsm>()
1353       *       .beanPropertiesWriteOnly(MyBean.<jk>class</jk>, <js>"bar,baz"</js>)
1354       *       .build();
1355       *
1356       *    <jc>// Parser parses all 3 properties.</jc>
1357       *    MyBean <jv>myBean</jv> = <jv>parser</jv>.parse(<js>"{foo:'foo',bar:'bar',baz:'baz'}"</js>, MyBean.<jk>class</jk>);
1358       * </p>
1359       *
1360       * <p>
1361       * This method is functionally equivalent to the following code:
1362       * <p class='bjava'>
1363       *    <jv>builder</jv>.annotations(BeanAnnotation.<jsm>create</jsm>(<jv>beanClass</jv>).writeOnlyProperties(<jv>properties</jv>).build());
1364       * </p>
1365       *
1366       * <h5 class='section'>See Also:</h5><ul>
1367       *    <li class='jma'>{@link Bean#writeOnlyProperties()} / {@link Bean#wo()}
1368       * </ul>
1369       *
1370       * @param beanClass The bean class.
1371       *    <br>Cannot be <jk>null</jk>.
1372       * @param properties Comma-delimited list of property names.
1373       *    <br>Cannot be <jk>null</jk>.
1374       * @return This object.
1375       */
1376      public Builder beanPropertiesWriteOnly(Class<?> beanClass, String properties) {
1377         assertArgNotNull("beanClass", beanClass);
1378         assertArgNotNull("properties", properties);
1379         return annotations(BeanAnnotation.create(beanClass).wo(properties).build());
1380      }
1381
1382      /**
1383       * Write-only bean properties.
1384       *
1385       * <p>
1386       * Specifies one or more properties on a bean that are write-only despite having valid setters.
1387       * Parsers will parse such properties as usual, but serializers will silently ignore them.
1388       * Note that this is different from the {@link #beanProperties(Class,String) beanProperties}/{@link #beanPropertiesExcludes(Class,String) beanPropertiesExcludes} settings which include or exclude properties
1389       * for both serializers and parsers.
1390       *
1391       * <h5 class='section'>Example:</h5>
1392       * <p class='bjava'>
1393       *    <jc>// A bean with 3 properties.</jc>
1394       *    <jk>public class</jk> MyBean {
1395       *       <jk>public</jk> String <jf>foo</jf>, <jf>bar</jf>, <jf>baz</jf>;
1396       *    }
1397       *
1398       *    <jc>// Create a serializer with write-only property settings.</jc>
1399       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
1400       *       .<jsm>create</jsm>()
1401       *       .beanPropertiesWriteOnly(AMap.<jsm>of</jsm>(<js>"MyBean"</js>, <js>"bar,baz"</js>))
1402       *       .build();
1403       *
1404       *    <jc>// Only foo will be serialized.</jc>
1405       *    String <jv>json</jv> = <jv>serializer</jv>.serialize(<jk>new</jk> MyBean());
1406       *
1407       *    <jc>// Create a parser with write-only property settings.</jc>
1408       *    ReaderParser <jv>parser</jv> = JsonParser
1409       *       .<jsm>create</jsm>()
1410       *       .beanPropertiesWriteOnly(AMap.<jsm>of</jsm>(<js>"MyBean"</js>, <js>"bar,baz"</js>))
1411       *       .build();
1412       *
1413       *    <jc>// Parser parses all 3 properties.</jc>
1414       *    MyBean <jv>myBean</jv> = <jv>parser</jv>.parse(<js>"{foo:'foo',bar:'bar',baz:'baz'}"</js>, MyBean.<jk>class</jk>);
1415       * </p>
1416       *
1417       * <p>
1418       * This method is functionally equivalent to the following code for each entry:
1419       * <p class='bjava'>
1420       *    <jv>builder</jv>.annotations(BeanAnnotation.<jsm>create</jsm>(<jv>key</jv>).writeOnlyProperties(<jv>value</jv>.toString()).build());
1421       * </p>
1422       *
1423       * <h5 class='section'>See Also:</h5><ul>
1424       *    <li class='jma'>{@link Bean#writeOnlyProperties()} / {@link Bean#wo()}
1425       * </ul>
1426       *
1427       * @param values
1428       *    The values to add to this builder.
1429       *    <br>Keys are bean class names which can be a simple name, fully-qualified name, or <js>"*"</js> for all beans.
1430       *    <br>Values are comma-delimited lists of property names.  Non-String objects are first converted to Strings.
1431       *    <br>Cannot be <jk>null</jk>.
1432       * @return This object.
1433       */
1434      public Builder beanPropertiesWriteOnly(Map<String,Object> values) {
1435         assertArgNotNull("values", values);
1436         values.forEach((k, v) -> annotations(BeanAnnotation.create(k).wo(s(v)).build()));
1437         return this;
1438      }
1439
1440      /**
1441       * Write-only bean properties.
1442       *
1443       * <p>
1444       * Specifies one or more properties on a bean that are write-only despite having valid setters.
1445       * Parsers will parse such properties as usual, but serializers will silently ignore them.
1446       * Note that this is different from the {@link #beanProperties(Class,String) beanProperties}/{@link #beanPropertiesExcludes(Class,String) beanPropertiesExcludes} settings which include or exclude properties
1447       * for both serializers and parsers.
1448       *
1449       * <h5 class='section'>Example:</h5>
1450       * <p class='bjava'>
1451       *    <jc>// A bean with 3 properties.</jc>
1452       *    <jk>public class</jk> MyBean {
1453       *       <jk>public</jk> String <jf>foo</jf>, <jf>bar</jf>, <jf>baz</jf>;
1454       *    }
1455       *
1456       *    <jc>// Create a serializer with write-only property settings.</jc>
1457       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
1458       *       .<jsm>create</jsm>()
1459       *       .beanPropertiesWriteOnly(<js>"MyBean"</js>, <js>"bar,baz"</js>)
1460       *       .build();
1461       *
1462       *    <jc>// Only foo will be serialized.</jc>
1463       *    String <jv>json</jv> = <jv>serializer</jv>.serialize(<jk>new</jk> MyBean());
1464       *
1465       *    <jc>// Create a parser with write-only property settings.</jc>
1466       *    ReaderParser <jv>parser</jv> = JsonParser
1467       *       .<jsm>create</jsm>()
1468       *       .beanPropertiesWriteOnly(<js>"MyBean"</js>, <js>"bar,baz"</js>)
1469       *       .build();
1470       *
1471       *    <jc>// Parser parses all 3 properties.</jc>
1472       *    MyBean <jv>myBean</jv> = <jv>parser</jv>.parse(<js>"{foo:'foo',bar:'bar',baz:'baz'}"</js>, MyBean.<jk>class</jk>);
1473       * </p>
1474       *
1475       * <p>
1476       * This method is functionally equivalent to the following code:
1477       * <p class='bjava'>
1478       *    <jv>builder</jv>.annotations(BeanAnnotation.<jsm>create</jsm>(<jv>beanClassName</jv>).writeOnlyProperties(<jv>properties</jv>).build());
1479       * </p>
1480       *
1481       * <h5 class='section'>See Also:</h5><ul>
1482       *    <li class='jma'>{@link Bean#writeOnlyProperties()} / {@link Bean#wo()}
1483       * </ul>
1484       *
1485       * @param beanClassName
1486       *    The bean class name.
1487       *    <br>Can be a simple name, fully-qualified name, or <js>"*"</js> for all bean classes.
1488       * @param properties Comma-delimited list of property names.
1489       * @return This object.
1490       */
1491      public Builder beanPropertiesWriteOnly(String beanClassName, String properties) {
1492         assertArgNotNull("beanClassName", beanClassName);
1493         assertArgNotNull("properties", properties);
1494         return annotations(BeanAnnotation.create(beanClassName).wo(properties).build());
1495      }
1496
1497      /**
1498       * Beans require no-arg constructors.
1499       *
1500       * <p>
1501       * When enabled, a Java class must implement a default no-arg constructor to be considered a bean.
1502       * Otherwise, the bean will be serialized as a string using the {@link Object#toString()} method.
1503       *
1504       * <h5 class='section'>Example:</h5>
1505       * <p class='bjava'>
1506       *    <jc>// A bean without a no-arg constructor.</jc>
1507       *    <jk>public class</jk> MyBean {
1508       *
1509       *       <jc>// A property method.</jc>
1510       *       <jk>public</jk> String <jf>foo</jf> = <js>"bar"</js>;
1511       *
1512       *       <jc>// A no-arg constructor</jc>
1513       *       <jk>public</jk> MyBean(String <jv>foo</jv>) {
1514       *          <jk>this</jk>.<jf>foo</jf> = <jv>foo</jv>;
1515       *       }
1516       *
1517       *       <ja>@Override</ja>
1518       *       <jk>public</jk> String toString() {
1519       *          <jk>return</jk> <js>"bar"</js>;
1520       *       }
1521       *    }
1522       *
1523       *    <jc>// Create a serializer that ignores beans without default constructors.</jc>
1524       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
1525       *       .<jsm>create</jsm>()
1526       *       .beansRequireDefaultConstructor()
1527       *       .build();
1528       *
1529       *    <jc>// Produces:  "bar"</jc>
1530       *    String <jv>json</jv> = <jv>serializer</jv>.serialize(<jk>new</jk> MyBean());
1531       * </p>
1532       *
1533       * <h5 class='section'>Notes:</h5><ul>
1534       *    <li class='note'>The {@link Bean @Bean} annotation can be used on a bean class to override this setting.
1535       *    <li class='note'>The {@link BeanIgnore @BeanIgnore} annotation can also be used on a class to ignore it as a bean.
1536       * </ul>
1537       *
1538       * <h5 class='section'>See Also:</h5><ul>
1539       *    <li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#beansRequireDefaultConstructor()}
1540       * </ul>
1541       *
1542       * @return This object.
1543       */
1544      public Builder beansRequireDefaultConstructor() {
1545         return beansRequireDefaultConstructor(true);
1546      }
1547
1548      /**
1549       * Same as {@link #beansRequireDefaultConstructor()} but allows you to explicitly specify the value.
1550       *
1551       * @param value The value for this setting.
1552       * @return This object.
1553       */
1554      public Builder beansRequireDefaultConstructor(boolean value) {
1555         beansRequireDefaultConstructor = value;
1556         return this;
1557      }
1558
1559      /**
1560       * Beans require Serializable interface.
1561       *
1562       * <p>
1563       * When enabled, a Java class must implement the {@link Serializable} interface to be considered a bean.
1564       * Otherwise, the bean will be serialized as a string using the {@link Object#toString()} method.
1565       *
1566       * <h5 class='section'>Example:</h5>
1567       * <p class='bjava'>
1568       *    <jc>// A bean without a Serializable interface.</jc>
1569       *    <jk>public class</jk> MyBean {
1570       *
1571       *       <jc>// A property method.</jc>
1572       *       <jk>public</jk> String <jf>foo</jf> = <js>"bar"</js>;
1573       *
1574       *       <ja>@Override</ja>
1575       *       <jk>public</jk> String toString() {
1576       *          <jk>return</jk> <js>"bar"</js>;
1577       *       }
1578       *    }
1579       *
1580       *    <jc>// Create a serializer that ignores beans not implementing Serializable.</jc>
1581       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
1582       *       .<jsm>create</jsm>()
1583       *       .beansRequireSerializable()
1584       *       .build();
1585       *
1586       *    <jc>// Produces:  "bar"</jc>
1587       *    String <jv>json</jv> = <jv>serializer</jv>.serialize(<jk>new</jk> MyBean());
1588       * </p>
1589       *
1590       * <h5 class='section'>Notes:</h5><ul>
1591       *    <li class='note'>The {@link Bean @Bean} annotation can be used on a bean class to override this setting.
1592       *    <li class='note'>The {@link BeanIgnore @BeanIgnore} annotation can also be used on a class to ignore it as a bean.
1593       * </ul>
1594       *
1595       * <h5 class='section'>See Also:</h5><ul>
1596       *    <li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#beansRequireSerializable()}
1597       * </ul>
1598       *
1599       * @return This object.
1600       */
1601      public Builder beansRequireSerializable() {
1602         return beansRequireSerializable(true);
1603      }
1604
1605      /**
1606       * Same as {@link #beansRequireSerializable()} but allows you to explicitly specify the value.
1607       *
1608       * @param value The value for this setting.
1609       * @return This object.
1610       */
1611      public Builder beansRequireSerializable(boolean value) {
1612         beansRequireSerializable = value;
1613         return this;
1614      }
1615
1616      /**
1617       * Beans require setters for getters.
1618       *
1619       * <p>
1620       * When enabled, ignore read-only properties (properties with getters but not setters).
1621       *
1622       * <h5 class='section'>Example:</h5>
1623       * <p class='bjava'>
1624       *    <jc>// A bean without a Serializable interface.</jc>
1625       *    <jk>public class</jk> MyBean {
1626       *
1627       *       <jc>// A read/write property.</jc>
1628       *       <jk>public</jk> String getFoo() { <jk>return</jk> <js>"foo"</js>; }
1629       *       <jk>public void</jk> setFoo(String <jv>foo</jv>) { ... }
1630       *
1631       *       <jc>// A read-only property.</jc>
1632       *       <jk>public</jk> String getBar() { <jk>return</jk> <js>"bar"</js>; }
1633       *    }
1634       *
1635       *    <jc>// Create a serializer that ignores bean properties without setters.</jc>
1636       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
1637       *       .<jsm>create</jsm>()
1638       *       .beansRequireSettersForGetters()
1639       *       .build();
1640       *
1641       *    <jc>// Produces:  {"foo":"foo"}</jc>
1642       *    String <jv>json</jv> = <jv>serializer</jv>.serialize(<jk>new</jk> MyBean());
1643       * </p>
1644       *
1645       * <h5 class='section'>Notes:</h5><ul>
1646       *    <li class='note'>The {@link Beanp @Beanp} annotation can be used on the getter to override this setting.
1647       *    <li class='note'>The {@link BeanIgnore @BeanIgnore} annotation can also be used on getters to ignore them as bean properties.
1648       * </ul>
1649       *
1650       * @return This object.
1651       */
1652      public Builder beansRequireSettersForGetters() {
1653         return beansRequireSettersForGetters(true);
1654      }
1655
1656      /**
1657       * Same as {@link #beansRequireSettersForGetters()} but allows you to explicitly specify the value.
1658       *
1659       * @param value The value for this setting.
1660       * @return This object.
1661       */
1662      public Builder beansRequireSettersForGetters(boolean value) {
1663         beansRequireSettersForGetters = value;
1664         return this;
1665      }
1666
1667      @Override /* Overridden from Context.Builder */
1668      public BeanContext build() {
1669         return cache(CACHE).build(BeanContext.class);
1670      }
1671
1672      @Override /* Overridden from Builder */
1673      public Builder cache(Cache<HashKey,? extends org.apache.juneau.Context> value) {
1674         super.cache(value);
1675         return this;
1676      }
1677
1678      @Override /* Overridden from Context.Builder */
1679      public Builder copy() {
1680         return new Builder(this);
1681      }
1682
1683      @Override /* Overridden from Builder */
1684      public Builder debug() {
1685         super.debug();
1686         return this;
1687      }
1688
1689      @Override /* Overridden from Builder */
1690      public Builder debug(boolean value) {
1691         super.debug(value);
1692         return this;
1693      }
1694
1695      /**
1696       * Bean dictionary.
1697       *
1698       * <p>
1699       * This is identical to {@link #beanDictionary(Class...)}, but specifies a dictionary within the context of
1700       * a single class as opposed to globally.
1701       *
1702       * <h5 class='section'>Example:</h5>
1703       * <p class='bjava'>
1704       *    <jc>// POJOs with @Bean(name) annotations.</jc>
1705       *    <ja>@Bean</ja>(typeName=<js>"foo"</js>)
1706       *    <jk>public class</jk> Foo {...}
1707       *    <ja>@Bean</ja>(typeName=<js>"bar"</js>)
1708       *    <jk>public class</jk> Bar {...}
1709       *
1710       *    <jc>// A bean with a field with an indeterminate type.</jc>
1711       *    <jk>public class</jk> MyBean {
1712       *       <jk>public</jk> Object <jf>mySimpleField</jf>;
1713       *    }
1714       *
1715       *    <jc>// Create a parser and tell it which classes to try to resolve.</jc>
1716       *    ReaderParser <jv>parser</jv> = JsonParser
1717       *       .<jsm>create</jsm>()
1718       *       .dictionaryOn(MyBean.<jk>class</jk>, Foo.<jk>class</jk>, Bar.<jk>class</jk>)
1719       *       .build();
1720       *
1721       *    <jc>// Parse bean.</jc>
1722       *    MyBean <jv>myBean</jv> = <jv>parser</jv>.parse(<js>"{mySimpleField:{_type:'foo',...}}"</js>, MyBean.<jk>class</jk>);
1723       * </p>
1724       *
1725       * <p>
1726       * This is functionally equivalent to the {@link Bean#dictionary()} annotation.
1727       *
1728       * <h5 class='section'>See Also:</h5><ul>
1729       *    <li class='jma'>{@link Bean#dictionary()}
1730       *    <li class='jm'>{@link #beanDictionary(Class...)}
1731       * </ul>
1732       *
1733       * @param on The class that the dictionary values apply to.
1734       * @param values
1735       *    The new values for this setting.
1736       * @return This object.
1737       */
1738      public Builder dictionaryOn(Class<?> on, Class<?>...values) {
1739         assertArgNotNull("on", on);
1740         assertArgNoNulls("values", values);
1741         return annotations(BeanAnnotation.create(on).dictionary(values).build());
1742      }
1743
1744      /**
1745       * Beans don't require at least one property.
1746       *
1747       * <p>
1748       * When enabled, then a Java class doesn't need to contain at least 1 property to be considered a bean.
1749       * Otherwise, the bean will be serialized as a string using the {@link Object#toString()} method.
1750       *
1751       * <p>
1752       * The {@link Bean @Bean} annotation can be used on a class to override this setting when <jk>true</jk>.
1753       *
1754       * <h5 class='section'>Example:</h5>
1755       * <p class='bjava'>
1756       *    <jc>// A bean with no properties.</jc>
1757       *    <jk>public class</jk> MyBean {
1758       *    }
1759       *
1760       *    <jc>// Create a serializer that serializes beans even if they have zero properties.</jc>
1761       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
1762       *       .<jsm>create</jsm>()
1763       *       .disableBeansRequireSomeProperties()
1764       *       .build();
1765       *
1766       *    <jc>// Produces:  {}</jc>
1767       *    String <jv>json</jv> = <jv>serializer</jv>.serialize(<jk>new</jk> MyBean());
1768       * </p>
1769       *
1770       * <h5 class='section'>Notes:</h5><ul>
1771       *    <li class='note'>The {@link Bean @Bean} annotation can be used on the class to force it to be recognized as a bean class
1772       *       even if it has no properties.
1773       * </ul>
1774       *
1775       * <h5 class='section'>See Also:</h5><ul>
1776       *    <li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#disableBeansRequireSomeProperties()}
1777       * </ul>
1778       *
1779       * @return This object.
1780       */
1781      public Builder disableBeansRequireSomeProperties() {
1782         return disableBeansRequireSomeProperties(true);
1783      }
1784
1785      /**
1786       * Same as {@link #disableBeansRequireSomeProperties()} but allows you to explicitly specify the value.
1787       *
1788       * @param value The value for this setting.
1789       * @return This object.
1790       */
1791      public Builder disableBeansRequireSomeProperties(boolean value) {
1792         disableBeansRequireSomeProperties = value;
1793         return this;
1794      }
1795
1796      /**
1797       * Don't silently ignore missing setters.
1798       *
1799       * <p>
1800       * When enabled, trying to set a value on a bean property without a setter will throw a {@link BeanRuntimeException}.
1801       * Otherwise, it will be silently ignored.
1802       *
1803       * <h5 class='section'>Example:</h5>
1804       * <p class='bjava'>
1805       *    <jc>// A bean with a property with a getter but not a setter.</jc>
1806       *    <jk>public class</jk> MyBean {
1807       *       <jk>public void</jk> getFoo() {
1808       *          <jk>return</jk> <js>"foo"</js>;
1809       *       }
1810       *    }
1811       *
1812       *    <jc>// Create a parser that throws an exception if a setter is not found but a getter is.</jc>
1813       *    ReaderParser <jv>parser</jv> = JsonParser
1814       *       .<jsm>create</jsm>()
1815       *       .disableIgnoreMissingSetters()
1816       *       .build();
1817       *
1818       *    <jc>// Throws a ParseException.</jc>
1819       *    MyBean <jv>myBean</jv> = <jv>parser</jv>.parse(<js>"{foo:'bar'}"</js>, MyBean.<jk>class</jk>);
1820       * </p>
1821       *
1822       * <h5 class='section'>Notes:</h5><ul>
1823       *    <li class='note'>The {@link BeanIgnore @BeanIgnore} annotation can also be used on getters and fields to ignore them.
1824       * </ul>
1825       *
1826       * <h5 class='section'>See Also:</h5><ul>
1827       *    <li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#disableIgnoreMissingSetters()}
1828       * </ul>
1829       *
1830       * @return This object.
1831       */
1832      public Builder disableIgnoreMissingSetters() {
1833         return disableIgnoreMissingSetters(true);
1834      }
1835
1836      /**
1837       * Same as {@link #disableIgnoreMissingSetters()} but allows you to explicitly specify the value.
1838       *
1839       * @param value The value for this setting.
1840       * @return This object.
1841       */
1842      public Builder disableIgnoreMissingSetters(boolean value) {
1843         disableIgnoreMissingSetters = value;
1844         return this;
1845      }
1846
1847      /**
1848       * Don't ignore transient fields.
1849       *
1850       * <p>
1851       * When enabled, methods and fields marked as <jk>transient</jk> will not be ignored as bean properties.
1852       *
1853       * <h5 class='section'>Example:</h5>
1854       * <p class='bjava'>
1855       *    <jc>// A bean with a transient field.</jc>
1856       *    <jk>public class</jk> MyBean {
1857       *       <jk>public transient</jk> String <jf>foo</jf> = <js>"foo"</js>;
1858       *    }
1859       *
1860       *    <jc>// Create a serializer that doesn't ignore transient fields.</jc>
1861       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
1862       *       .<jsm>create</jsm>()
1863       *       .disableIgnoreTransientFields()
1864       *       .build();
1865       *
1866       *    <jc>// Produces:  {"foo":"foo"}</jc>
1867       *    String <jv>json</jv> = <jv>serializer</jv>.serialize(<jk>new</jk> MyBean());
1868       * </p>
1869       *
1870       * <h5 class='section'>Notes:</h5><ul>
1871       *    <li class='note'>The {@link Beanp @Beanp} annotation can also be used on transient fields to keep them from being ignored.
1872       * </ul>
1873       *
1874       * <h5 class='section'>See Also:</h5><ul>
1875       *    <li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#disableIgnoreTransientFields()}
1876       * </ul>
1877       *
1878       * @return This object.
1879       */
1880      public Builder disableIgnoreTransientFields() {
1881         return disableIgnoreTransientFields(true);
1882      }
1883
1884      /**
1885       * Same as {@link #disableIgnoreTransientFields()} but allows you to explicitly specify the value.
1886       *
1887       * @param value The value for this setting.
1888       * @return This object.
1889       */
1890      public Builder disableIgnoreTransientFields(boolean value) {
1891         disableIgnoreTransientFields = value;
1892         return this;
1893      }
1894
1895      /**
1896       * Don't ignore unknown properties with null values.
1897       *
1898       * <p>
1899       * When enabled, trying to set a <jk>null</jk> value on a non-existent bean property will throw a {@link BeanRuntimeException}.
1900       * Otherwise it will be silently ignored.
1901       *
1902       * <h5 class='section'>Example:</h5>
1903       * <p class='bjava'>
1904       *    <jc>// A bean with a single property.</jc>
1905       *    <jk>public class</jk> MyBean {
1906       *       <jk>public</jk> String <jf>foo</jf>;
1907       *    }
1908       *
1909       *    <jc>// Create a parser that throws an exception on an unknown property even if the value being set is null.</jc>
1910       *    ReaderParser <jv>parser</jv> = JsonParser
1911       *       .<jsm>create</jsm>()
1912       *       .disableIgnoreUnknownNullBeanProperties()
1913       *       .build();
1914       *
1915       *    <jc>// Throws a BeanRuntimeException wrapped in a ParseException on the unknown 'bar' property.</jc>
1916       *    MyBean <jv>myBean</jv> = <jv>parser</jv>.parse(<js>"{foo:'foo',bar:null}"</js>, MyBean.<jk>class</jk>);
1917       * </p>
1918       *
1919       * <h5 class='section'>See Also:</h5><ul>
1920       *    <li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#disableIgnoreUnknownNullBeanProperties()}
1921       * </ul>
1922       *
1923       * @return This object.
1924       */
1925      public Builder disableIgnoreUnknownNullBeanProperties() {
1926         return disableIgnoreUnknownNullBeanProperties(true);
1927      }
1928
1929      /**
1930       * Same as {@link #disableIgnoreUnknownNullBeanProperties()} but allows you to explicitly specify the value.
1931       *
1932       * @param value The value for this setting.
1933       * @return This object.
1934       */
1935      public Builder disableIgnoreUnknownNullBeanProperties(boolean value) {
1936         disableIgnoreUnknownNullBeanProperties = value;
1937         return this;
1938      }
1939
1940      /**
1941       * Don't use interface proxies.
1942       *
1943       * <p>
1944       * When enabled, interfaces will be instantiated as proxy classes through the use of an
1945       * {@link InvocationHandler} if there is no other way of instantiating them.
1946       * Otherwise, throws a {@link BeanRuntimeException}.
1947       *
1948       * <h5 class='section'>See Also:</h5><ul>
1949       *    <li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#disableInterfaceProxies()}
1950       * </ul>
1951       *
1952       * @return This object.
1953       */
1954      public Builder disableInterfaceProxies() {
1955         return disableInterfaceProxies(true);
1956      }
1957
1958      /**
1959       * Same as {@link #disableInterfaceProxies()} but allows you to explicitly specify the value.
1960       *
1961       * @param value The value for this setting.
1962       * @return This object.
1963       */
1964      public Builder disableInterfaceProxies(boolean value) {
1965         disableInterfaceProxies = value;
1966         return this;
1967      }
1968
1969      /**
1970       * POJO example.
1971       *
1972       * <p>
1973       * Specifies an example in JSON of the specified class.
1974       *
1975       * <p>
1976       * Examples are used in cases such as POJO examples in Swagger documents.
1977       *
1978       * <p>
1979       * Setting applies to specified class and all subclasses.
1980       *
1981       * <h5 class='section'>Example:</h5>
1982       * <p class='bjava'>
1983       *    <jc>// Create a serializer that excludes the 'foo' and 'bar' properties on the MyBean class.</jc>
1984       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
1985       *       .<jsm>create</jsm>()
1986       *       .example(MyBean.<jk>class</jk>, <js>"{foo:'bar'}"</js>)
1987       *       .build();
1988       * </p>
1989       *
1990       * <p>
1991       * This is a shorthand method for the following code:
1992       * <p class='bjava'>
1993       *    <jv>builder</jv>.annotations(MarshalledAnnotation.<jsm>create</jsm>(<jv>pojoClass</jv>).example(<jv>json</jv>).build())
1994       * </p>
1995       *
1996       * <p>
1997       * POJO examples can also be defined on classes via the following:
1998       * <ul class='spaced-list'>
1999       *    <li>A static field annotated with {@link Example @Example}.
2000       *    <li>A static method annotated with {@link Example @Example} with zero arguments or one {@link BeanSession} argument.
2001       *    <li>A static method with name <c>example</c> with no arguments or one {@link BeanSession} argument.
2002       * </ul>
2003       *
2004       * <h5 class='section'>See Also:</h5><ul>
2005       *    <li class='ja'>{@link Marshalled#example()}
2006       * </ul>
2007       *
2008       * @param <T> The POJO class type.
2009       * @param pojoClass The POJO class.
2010       *    <br>Cannot be <jk>null</jk>.
2011       * @param json The JSON 5 representation of the example.
2012       *    <br>Can be <jk>null</jk> or empty (treated as no example).
2013       * @return This object.
2014       */
2015      public <T> Builder example(Class<T> pojoClass, String json) {
2016         return annotations(MarshalledAnnotation.create(assertArgNotNull("pojoClass", pojoClass)).example(json).build());
2017      }
2018
2019      /**
2020       * POJO example.
2021       *
2022       * <p>
2023       * Specifies an example of the specified class.
2024       *
2025       * <p>
2026       * Examples are used in cases such as POJO examples in Swagger documents.
2027       *
2028       * <h5 class='section'>Example:</h5>
2029       * <p class='bjava'>
2030       *    <jc>// Create a serializer that excludes the 'foo' and 'bar' properties on the MyBean class.</jc>
2031       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
2032       *       .<jsm>create</jsm>()
2033       *       .example(MyBean.<jk>class</jk>, <jk>new</jk> MyBean().setFoo(<js>"foo"</js>).setBar(123))
2034       *       .build();
2035       * </p>
2036       *
2037       * <p>
2038       * This is a shorthand method for the following code:
2039       * <p class='bjava'>
2040       *       <jv>builder</jv>.annotations(MarshalledAnnotation.<jsm>create</jsm>(<jv>pojoClass</jv>).example(Json5.<jsf>DEFAULT</jsf>.toString(<jv>object</jv>)).build())
2041       * </p>
2042       *
2043       * <h5 class='section'>Notes:</h5><ul>
2044       *    <li class='note'>Using this method assumes the serialized form of the object is the same as that produced
2045       *       by the default serializer.  This may not be true based on settings or swaps on the constructed serializer.
2046       * </ul>
2047       *
2048       * <p>
2049       * POJO examples can also be defined on classes via the following:
2050       * <ul class='spaced-list'>
2051       *    <li>The {@link Marshalled#example()} annotation on the class itself.
2052       *    <li>A static field annotated with {@link Example @Example}.
2053       *    <li>A static method annotated with {@link Example @Example} with zero arguments or one {@link BeanSession} argument.
2054       *    <li>A static method with name <c>example</c> with no arguments or one {@link BeanSession} argument.
2055       * </ul>
2056       *
2057       * @param <T> The POJO class.
2058       * @param pojoClass The POJO class.
2059       *    <br>Cannot be <jk>null</jk>.
2060       * @param o
2061       *    An instance of the POJO class used for examples.
2062       *    <br>Can be <jk>null</jk> (will be serialized as <js>"null"</js>).
2063       * @return This object.
2064       */
2065      public <T> Builder example(Class<T> pojoClass, T o) {
2066         return annotations(MarshalledAnnotation.create(assertArgNotNull("pojoClass", pojoClass)).example(Json5.of(o)).build());
2067      }
2068
2069      /**
2070       * Find fluent setters.
2071       *
2072       * <p>
2073       * When enabled, fluent setters are detected on beans during parsing.
2074       *
2075       * <p>
2076       * Fluent setters must have the following attributes:
2077       * <ul>
2078       *    <li>Public.
2079       *    <li>Not static.
2080       *    <li>Take in one parameter.
2081       *    <li>Return the bean itself.
2082       * </ul>
2083       *
2084       * <h5 class='section'>Example:</h5>
2085       * <p class='bjava'>
2086       *    <jc>// A bean with a fluent setter.</jc>
2087       *    <jk>public class</jk> MyBean {
2088       *       <jk>public</jk> MyBean foo(String <jv>value</jv>) {...}
2089       *    }
2090       *
2091       *    <jc>// Create a parser that finds fluent setters.</jc>
2092       *    ReaderParser <jv>parser</jv> = JsonParser
2093       *       .<jsm>create</jsm>()
2094       *       .findFluentSetters()
2095       *       .build();
2096       *
2097       *    <jc>// Parse into bean using fluent setter.</jc>
2098       *    MyBean <jv>myBean</jv> = <jv>parser</jv>.parse(<js>"{foo:'bar'}"</js>);
2099       * </p>
2100       *
2101       * <h5 class='section'>Notes:</h5><ul>
2102       *    <li class='note'>The {@link Beanp @Beanp} annotation can also be used on methods to individually identify them as fluent setters.
2103       *    <li class='note'>The {@link Bean#findFluentSetters() @Bean.fluentSetters()} annotation can also be used on classes to specify to look for fluent setters.
2104       * </ul>
2105       *
2106       * <h5 class='section'>See Also:</h5><ul>
2107       *    <li class='ja'>{@link org.apache.juneau.annotation.Bean#findFluentSetters()}
2108       *    <li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#findFluentSetters()}
2109       * </ul>
2110       *
2111       * @return This object.
2112       */
2113      public Builder findFluentSetters() {
2114         return findFluentSetters(true);
2115      }
2116
2117      /**
2118       * Same as {@link #findFluentSetters()} but allows you to explicitly specify the value.
2119       *
2120       * @param value The value for this setting.
2121       * @return This object.
2122       */
2123      public Builder findFluentSetters(boolean value) {
2124         findFluentSetters = value;
2125         return this;
2126      }
2127
2128      /**
2129       * Find fluent setters.
2130       *
2131       * <p>
2132       * Identical to {@link #findFluentSetters()} but enables it on a specific class only.
2133       *
2134       * <h5 class='section'>Example:</h5>
2135       * <p class='bjava'>
2136       *    <jc>// A bean with a fluent setter.</jc>
2137       *    <jk>public class</jk> MyBean {
2138       *       <jk>public</jk> MyBean foo(String <jv>value</jv>) {...}
2139       *    }
2140       *
2141       *    <jc>// Create a parser that finds fluent setters.</jc>
2142       *    ReaderParser <jv>parser</jv> = JsonParser
2143       *       .<jsm>create</jsm>()
2144       *       .findFluentSetters(MyBean.<jk>class</jk>)
2145       *       .build();
2146       *
2147       *    <jc>// Parse into bean using fluent setter.</jc>
2148       *    MyBean <jv>myBean</jv> = <jv>parser</jv>.parse(<js>"{foo:'bar'}"</js>);
2149       * </p>
2150       *
2151       * <h5 class='section'>Notes:</h5><ul>
2152       *    <li class='note'>This method is functionally equivalent to using the {@link Bean#findFluentSetters()} annotation.
2153       * </ul>
2154       *
2155       * <h5 class='section'>See Also:</h5><ul>
2156       *    <li class='ja'>{@link Bean#findFluentSetters()}
2157       *    <li class='jm'>{@link #findFluentSetters()}
2158       * </ul>
2159       *
2160       * @param on The class that this applies to.
2161       *    <br>Cannot be <jk>null</jk>.
2162       * @return This object.
2163       */
2164      public Builder findFluentSetters(Class<?> on) {
2165         assertArgNotNull("on", on);
2166         return annotations(BeanAnnotation.create(on).findFluentSetters(true).build());
2167      }
2168
2169      @Override /* Overridden from Context.Builder */
2170      public HashKey hashKey() {
2171         // @formatter:off
2172         return HashKey.of(
2173            super.hashKey(),
2174            beanClassVisibility,
2175            beanConstructorVisibility,
2176            beanMethodVisibility,
2177            beanFieldVisibility,
2178            beanDictionary,
2179            swaps,
2180            notBeanClasses,
2181            notBeanPackages,
2182            integer(
2183               disableBeansRequireSomeProperties,
2184               beanMapPutReturnsOldValue,
2185               beansRequireDefaultConstructor,
2186               beansRequireSerializable,
2187               beansRequireSettersForGetters,
2188               disableIgnoreTransientFields,
2189               disableIgnoreUnknownNullBeanProperties,
2190               disableIgnoreMissingSetters,
2191               disableInterfaceProxies,
2192               findFluentSetters,
2193               ignoreInvocationExceptionsOnGetters,
2194               ignoreInvocationExceptionsOnSetters,
2195               ignoreUnknownBeanProperties,
2196               ignoreUnknownEnumValues,
2197               sortProperties,
2198               useEnumNames,
2199               useJavaBeanIntrospector
2200            ),
2201            typePropertyName,
2202            mediaType,
2203            timeZone,
2204            locale,
2205            propertyNamer
2206         );
2207         // @formatter:on
2208      }
2209
2210      /**
2211       * Ignore invocation errors on getters.
2212       *
2213       * <p>
2214       * When enabled, errors thrown when calling bean getter methods will silently be ignored.
2215       * Otherwise, a {@code BeanRuntimeException} is thrown.
2216       *
2217       * <h5 class='section'>Example:</h5>
2218       * <p class='bjava'>
2219       *    <jc>// A bean with a property that throws an exception.</jc>
2220       *    <jk>public class</jk> MyBean {
2221       *       <jk>public</jk> String getFoo() {
2222       *          <jk>throw new</jk> RuntimeException(<js>"foo"</js>);
2223       *       }
2224       *    }
2225       *
2226       *    <jc>// Create a serializer that ignores bean getter exceptions.</jc>
2227       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
2228       *       .<jsm>create</jsm>()
2229       *       .ingoreInvocationExceptionsOnGetters()
2230       *       .build();
2231       *
2232       *    <jc>// Exception is ignored.</jc>
2233       *    String <jv>json</jv> = <jv>serializer</jv>.serialize(<jk>new</jk> MyBean());
2234       * </p>
2235       *
2236       * <h5 class='section'>See Also:</h5><ul>
2237       *    <li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#ignoreInvocationExceptionsOnGetters()}
2238       * </ul>
2239       *
2240       * @return This object.
2241       */
2242      public Builder ignoreInvocationExceptionsOnGetters() {
2243         return ignoreInvocationExceptionsOnGetters(true);
2244      }
2245
2246      /**
2247       * Same as {@link #ignoreInvocationExceptionsOnGetters()} but allows you to explicitly specify the value.
2248       *
2249       * @param value The value for this setting.
2250       * @return This object.
2251       */
2252      public Builder ignoreInvocationExceptionsOnGetters(boolean value) {
2253         ignoreInvocationExceptionsOnGetters = value;
2254         return this;
2255      }
2256
2257      /**
2258       * Ignore invocation errors on setters.
2259       *
2260       * <p>
2261       * When enabled, errors thrown when calling bean setter methods will silently be ignored.
2262       * Otherwise, a {@code BeanRuntimeException} is thrown.
2263       *
2264       * <h5 class='section'>Example:</h5>
2265       * <p class='bjava'>
2266       *    <jc>// A bean with a property that throws an exception.</jc>
2267       *    <jk>public class</jk> MyBean {
2268       *       <jk>public void</jk> setFoo(String <jv>foo</jv>) {
2269       *          <jk>throw new</jk> RuntimeException(<js>"foo"</js>);
2270       *       }
2271       *    }
2272       *
2273       *    <jc>// Create a parser that ignores bean setter exceptions.</jc>
2274       *    ReaderParser <jv>parser</jv> = JsonParser
2275       *       .<jsm>create</jsm>()
2276       *       .ignoreInvocationExceptionsOnSetters()
2277       *       .build();
2278       *
2279       *    <jc>// Exception is ignored.</jc>
2280       *    MyBean <jv>myBean</jv> = <jv>parser</jv>.parse(<js>"{foo:'bar'}"</js>, MyBean.<jk>class</jk>);
2281       * </p>
2282       *
2283       * <h5 class='section'>See Also:</h5><ul>
2284       *    <li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#ignoreInvocationExceptionsOnSetters()}
2285       * </ul>
2286       *
2287       * @return This object.
2288       */
2289      public Builder ignoreInvocationExceptionsOnSetters() {
2290         return ignoreInvocationExceptionsOnSetters(true);
2291      }
2292
2293      /**
2294       * Same as {@link #ignoreInvocationExceptionsOnSetters()} but allows you to explicitly specify the value.
2295       *
2296       * @param value The value for this setting.
2297       * @return This object.
2298       */
2299      public Builder ignoreInvocationExceptionsOnSetters(boolean value) {
2300         ignoreInvocationExceptionsOnSetters = value;
2301         return this;
2302      }
2303
2304      /**
2305       * Ignore unknown properties.
2306       *
2307       * <p>
2308       * When enabled, trying to set a value on a non-existent bean property will silently be ignored.
2309       * Otherwise, a {@code BeanRuntimeException} is thrown.
2310       *
2311       * <h5 class='section'>Example:</h5>
2312       * <p class='bjava'>
2313       *    <jc>// A bean with a single property.</jc>
2314       *    <jk>public class</jk> MyBean {
2315       *       <jk>public</jk> String <jf>foo</jf>;
2316       *    }
2317       *
2318       *    <jc>// Create a parser that ignores missing bean properties.</jc>
2319       *    ReaderParser <jv>parser</jv> = JsonParser
2320       *       .<jsm>create</jsm>()
2321       *       .ignoreUnknownBeanProperties()
2322       *       .build();
2323       *
2324       *    <jc>// Doesn't throw an exception on unknown 'bar' property.</jc>
2325       *    MyBean <jv>myBean</jv> = <jv>parser</jv>.parse(<js>"{foo:'foo',bar:'bar'}"</js>, MyBean.<jk>class</jk>);
2326       * </p>
2327       *
2328       * <h5 class='section'>See Also:</h5><ul>
2329       *    <li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#ignoreUnknownBeanProperties()}
2330       * </ul>
2331       *
2332       * @return This object.
2333       */
2334      public Builder ignoreUnknownBeanProperties() {
2335         return ignoreUnknownBeanProperties(true);
2336      }
2337
2338      /**
2339       * Same as {@link #ignoreUnknownBeanProperties()} but allows you to explicitly specify the value.
2340       *
2341       * @param value The value for this setting.
2342       * @return This object.
2343       */
2344      public Builder ignoreUnknownBeanProperties(boolean value) {
2345         ignoreUnknownBeanProperties = value;
2346         return this;
2347      }
2348
2349      /**
2350       * Ignore unknown properties.
2351       *
2352       * <p>
2353       * When enabled, unknown enum values will be set to <jk>null</jk> instead of throwing an exception.
2354       *
2355       * <h5 class='section'>See Also:</h5><ul>
2356       *    <li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#ignoreUnknownEnumValues()}
2357       * </ul>
2358       *
2359       * @return This object.
2360       */
2361      public Builder ignoreUnknownEnumValues() {
2362         return ignoreUnknownEnumValues(true);
2363      }
2364
2365      /**
2366       * Same as {@link #ignoreUnknownEnumValues()} but allows you to explicitly specify the value.
2367       *
2368       * @param value The value for this setting.
2369       * @return This object.
2370       */
2371      public Builder ignoreUnknownEnumValues(boolean value) {
2372         ignoreUnknownEnumValues = value;
2373         return this;
2374      }
2375
2376      @Override /* Overridden from Builder */
2377      public Builder impl(Context value) {
2378         super.impl(value);
2379         return this;
2380      }
2381
2382      /**
2383       * Implementation classes.
2384       *
2385       * <p>
2386       * For interfaces and abstract classes this method can be used to specify an implementation class for the
2387       * interface/abstract class so that instances of the implementation class are used when instantiated (e.g. during a
2388       * parse).
2389       *
2390       * <h5 class='section'>Example:</h5>
2391       * <p class='bjava'>
2392       *    <jc>// A bean interface.</jc>
2393       *    <jk>public interface</jk> MyBean {
2394       *       ...
2395       *    }
2396       *
2397       *    <jc>// A bean implementation.</jc>
2398       *    <jk>public class</jk> MyBeanImpl <jk>implements</jk> MyBean {
2399       *       ...
2400       *    }
2401
2402       *    <jc>// Create a parser that instantiates MyBeanImpls when parsing MyBeans.</jc>
2403       *    ReaderParser <jv>parser</jv> = JsonParser
2404       *       .<jsm>create</jsm>()
2405       *       .implClass(MyBean.<jk>class</jk>, MyBeanImpl.<jk>class</jk>)
2406       *       .build();
2407       *
2408       *    <jc>// Instantiates a MyBeanImpl,</jc>
2409       *    MyBean <jv>myBean</jv> = <jv>parser</jv>.parse(<js>"..."</js>, MyBean.<jk>class</jk>);
2410       * </p>
2411       *
2412       * @param interfaceClass The interface class.
2413       *    <br>Cannot be <jk>null</jk>.
2414       * @param implClass The implementation class.
2415       *    <br>Cannot be <jk>null</jk>.
2416       * @return This object.
2417       */
2418      public Builder implClass(Class<?> interfaceClass, Class<?> implClass) {
2419         assertArgNotNull("interfaceClass", interfaceClass);
2420         assertArgNotNull("implClass", implClass);
2421         return annotations(MarshalledAnnotation.create(interfaceClass).implClass(implClass).build());
2422      }
2423
2424      /**
2425       * Implementation classes.
2426       *
2427       * <p>
2428       * For interfaces and abstract classes this method can be used to specify an implementation class for the
2429       * interface/abstract class so that instances of the implementation class are used when instantiated (e.g. during a
2430       * parse).
2431       *
2432       * <h5 class='section'>Example:</h5>
2433       * <p class='bjava'>
2434       *    <jc>// A bean with a single property.</jc>
2435       *    <jk>public interface</jk> MyBean {
2436       *       ...
2437       *    }
2438       *
2439       *    <jc>// A bean with a single property.</jc>
2440       *    <jk>public class</jk> MyBeanImpl <jk>implements</jk> MyBean {
2441       *       ...
2442       *    }
2443
2444       *    <jc>// Create a parser that instantiates MyBeanImpls when parsing MyBeans.</jc>
2445       *    ReaderParser <jv>parser</jv> = JsonParser
2446       *       .<jsm>create</jsm>()
2447       *       .implClasses(AMap.<jsm>of</jsm>(MyBean.<jk>class</jk>, MyBeanImpl.<jk>class</jk>))
2448       *       .build();
2449       *
2450       *    <jc>// Instantiates a MyBeanImpl,</jc>
2451       *    MyBean <jv>myBean</jv> = <jv>parser</jv>.parse(<js>"..."</js>, MyBean.<jk>class</jk>);
2452       * </p>
2453       *
2454       * @param values
2455       *    The new value for this setting.
2456       *    <br>Cannot be <jk>null</jk>.
2457       * @return This object.
2458       */
2459      public Builder implClasses(Map<Class<?>,Class<?>> values) {
2460         assertArgNotNull("values", values);
2461         values.forEach((k, v) -> annotations(MarshalledAnnotation.create(k).implClass(v).build()));
2462         return this;
2463      }
2464
2465      /**
2466       * Identifies a class to be used as the interface class for the specified class and all subclasses.
2467       *
2468       * <p>
2469       * When specified, only the list of properties defined on the interface class will be used during serialization.
2470       * Additional properties on subclasses will be ignored.
2471       *
2472       * <p class='bjava'>
2473       *    <jc>// Parent class or interface</jc>
2474       *    <jk>public abstract class</jk> A {
2475       *       <jk>public</jk> String <jf>foo</jf> = <js>"foo"</js>;
2476       *    }
2477       *
2478       *    <jc>// Sub class</jc>
2479       *    <jk>public class</jk> A1 <jk>extends</jk> A {
2480       *       <jk>public</jk> String <jf>bar</jf> = <js>"bar"</js>;
2481       *    }
2482       *
2483       *    <jc>// Create a serializer and define our interface class mapping.</jc>
2484       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
2485       *       .<jsm>create</jsm>()
2486       *       .interfaceClass(A1.<jk>class</jk>, A.<jk>class</jk>)
2487       *       .build();
2488       *
2489       *    <jc>// Produces "{"foo":"foo"}"</jc>
2490       *    String <jv>json</jv> = <jv>serializer</jv>.serialize(<jk>new</jk> A1());
2491       * </p>
2492       *
2493       * <p>
2494       * This annotation can be used on the parent class so that it filters to all child classes, or can be set
2495       * individually on the child classes.
2496       *
2497       * <h5 class='section'>Notes:</h5><ul>
2498       *    <li class='note'>The {@link Bean#interfaceClass() @Bean(interfaceClass)} annotation is the equivalent annotation-based solution.
2499       * </ul>
2500       *
2501       * @param on The class that the interface class applies to.
2502       *    <br>Cannot be <jk>null</jk>.
2503       * @param value
2504       *    The new value for this setting.
2505       *    <br>Cannot be <jk>null</jk>.
2506       * @return This object.
2507       */
2508      public Builder interfaceClass(Class<?> on, Class<?> value) {
2509         assertArgNotNull("on", on);
2510         assertArgNotNull("value", value);
2511         return annotations(BeanAnnotation.create(on).interfaceClass(value).build());
2512      }
2513
2514      /**
2515       * Identifies a set of interfaces.
2516       *
2517       * <p>
2518       * When specified, only the list of properties defined on the interface class will be used during serialization
2519       * of implementation classes.  Additional properties on subclasses will be ignored.
2520       *
2521       * <p class='bjava'>
2522       *    <jc>// Parent class or interface</jc>
2523       *    <jk>public abstract class</jk> A {
2524       *       <jk>public</jk> String <jf>foo</jf> = <js>"foo"</js>;
2525       *    }
2526       *
2527       *    <jc>// Sub class</jc>
2528       *    <jk>public class</jk> A1 <jk>extends</jk> A {
2529       *       <jk>public</jk> String <jf>bar</jf> = <js>"bar"</js>;
2530       *    }
2531       *
2532       *    <jc>// Create a serializer and define our interface class mapping.</jc>
2533       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
2534       *       .<jsm>create</jsm>()
2535       *       .interfaces(A.<jk>class</jk>)
2536       *       .build();
2537       *
2538       *    <jc>// Produces "{"foo":"foo"}"</jc>
2539       *    String <jv>json</jv> = <jv>serializer</jv>.serialize(<jk>new</jk> A1());
2540       * </p>
2541       *
2542       * <p>
2543       * This annotation can be used on the parent class so that it filters to all child classes, or can be set
2544       * individually on the child classes.
2545       *
2546       * <h5 class='section'>Notes:</h5><ul>
2547       *    <li class='note'>The {@link Bean#interfaceClass() @Bean(interfaceClass)} annotation is the equivalent annotation-based solution.
2548       * </ul>
2549       *
2550       * @param value
2551       *    The new value for this setting.
2552       *    <br>Cannot be <jk>null</jk>.
2553       * @return This object.
2554       */
2555      public Builder interfaces(Class<?>...value) {
2556         assertArgNoNulls("value", value);
2557         for (var v : value)
2558            annotations(BeanAnnotation.create(v).interfaceClass(v).build());
2559         return this;
2560      }
2561
2562      /**
2563       * <i><l>Context</l> configuration property:&emsp;</i>  Locale.
2564       *
2565       * <p>
2566       * Specifies the default locale for serializer and parser sessions when not specified via {@link BeanSession.Builder#locale(Locale)}.
2567       * Typically used for POJO swaps that need to deal with locales such as swaps that convert <l>Date</l> and <l>Calendar</l>
2568       * objects to strings by accessing it via the session passed into the {@link ObjectSwap#swap(BeanSession, Object)} and
2569       * {@link ObjectSwap#unswap(BeanSession, Object, ClassMeta, String)} methods.
2570       *
2571       * <h5 class='section'>Example:</h5>
2572       * <p class='bjava'>
2573       *    <jc>// Define a POJO swap that skips serializing beans if we're in the UK.</jc>
2574       *    <jk>public class</jk> MyBeanSwap <jk>extends</jk> StringSwap&lt;MyBean&gt; {
2575       *       <ja>@Override</ja>
2576       *       <jk>public</jk> String swap(BeanSession <jv>session</jv>, MyBean <jv>bean</jv>) <jk>throws</jk> Exception {
2577       *          <jk>if</jk> (<jv>session</jv>.getLocale().equals(Locale.<jsf>UK</jsf>))
2578       *             <jk>return null</jk>;
2579       *          <jk>return</jk> <jv>bean</jv>.toString();
2580       *       }
2581       *    }
2582       *
2583       *    <jc>// Create a serializer that uses the specified locale if it's not passed in through session args.</jc>
2584       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
2585       *       .<jsm>create</jsm>()
2586       *       .locale(Locale.<jsf>UK</jsf>)
2587       *       .swaps(MyBeanSwap.<jk>class</jk>)
2588       *       .build();
2589       * </p>
2590       *
2591       * <h5 class='section'>See Also:</h5><ul>
2592       *    <li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#locale()}
2593       *    <li class='jm'>{@link org.apache.juneau.BeanSession.Builder#locale(Locale)}
2594       * </ul>
2595       *
2596       * @param value The new value for this property.
2597       *    <br>Cannot be <jk>null</jk>.
2598       * @return This object.
2599       */
2600      public Builder locale(Locale value) {
2601         locale = assertArgNotNull("value", value);
2602         return this;
2603      }
2604
2605      /**
2606       * <i><l>Context</l> configuration property:&emsp;</i>  Media type.
2607       *
2608       * <p>
2609       * Specifies the default media type for serializer and parser sessions when not specified via {@link BeanSession.Builder#mediaType(MediaType)}.
2610       * Typically used for POJO swaps that need to serialize the same POJO classes differently depending on
2611       * the specific requested media type.   For example, a swap could handle a request for media types <js>"application/json"</js>
2612       * and <js>"application/json+foo"</js> slightly differently even though they're both being handled by the same JSON
2613       * serializer or parser.
2614       *
2615       * <h5 class='section'>Example:</h5>
2616       * <p class='bjava'>
2617       *    <jc>// Define a POJO swap that skips serializing beans if the media type is application/json.</jc>
2618       *    <jk>public class</jk> MyBeanSwap <jk>extends</jk> StringSwap&lt;MyBean&gt; {
2619       *       <ja>@Override</ja>
2620       *       <jk>public</jk> String swap(BeanSession <jv>session</jv>, MyBean <jv>bean</jv>) <jk>throws</jk> Exception {
2621       *          <jk>if</jk> (<jv>session</jv>.getMediaType().equals(<js>"application/json"</js>))
2622       *             <jk>return null</jk>;
2623       *          <jk>return</jk> <jv>bean</jv>.toString();
2624       *       }
2625       *    }
2626       *
2627       *    <jc>// Create a serializer that uses the specified media type if it's not passed in through session args.</jc>
2628       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
2629       *       .<jsm>create</jsm>()
2630       *       .mediaType(MediaType.<jsf>JSON</jsf>)
2631       *       .build();
2632       * </p>
2633       *
2634       * <h5 class='section'>See Also:</h5><ul>
2635       *    <li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#mediaType()}
2636       *    <li class='jm'>{@link org.apache.juneau.BeanSession.Builder#mediaType(MediaType)}
2637       * </ul>
2638       *
2639       * @param value The new value for this property.
2640       *    <br>Can be <jk>null</jk> (no default media type will be set).
2641       * @return This object.
2642       */
2643      public Builder mediaType(MediaType value) {
2644         mediaType = value;
2645         return this;
2646      }
2647
2648      /**
2649       * Returns the set of not-bean classes.
2650       *
2651       * <p>
2652       * Gives access to the inner set if you need to make more than simple additions via {@link #notBeanClasses(ClassInfo...)}.
2653       *
2654       * @return The set of not-bean classes.
2655       * @see #notBeanClasses(ClassInfo...)
2656       */
2657      public Set<ClassInfo> notBeanClasses() {
2658         return notBeanClasses;
2659      }
2660
2661      /**
2662       * Convenience method for {@link #notBeanClasses(ClassInfo...)} that accepts {@link Class} objects.
2663       *
2664       * @param values
2665       *    The values to add to this setting.
2666       *    <br>Cannot contain <jk>null</jk> values.
2667       * @return This object.
2668       * @see #notBeanClasses(ClassInfo...)
2669       */
2670      public Builder notBeanClasses(Class<?>...values) {
2671         assertArgNoNulls("values", values);
2672         return notBeanClasses(Stream.of(values).map(ReflectionUtils::info).toArray(ClassInfo[]::new));
2673      }
2674
2675      /**
2676       * Bean class exclusions.
2677       *
2678       * <p>
2679       * List of classes that should not be treated as beans even if they appear to be bean-like.
2680       * Not-bean classes are converted to <c>Strings</c> during serialization.
2681       *
2682       * <p>
2683       * Values can consist of any of the following types:
2684       * <ul>
2685       *    <li>Classes.
2686       *    <li>Arrays and collections of classes.
2687       * </ul>
2688       *
2689       * <h5 class='section'>Example:</h5>
2690       * <p class='bjava'>
2691       *    <jc>// A bean with a single property.</jc>
2692       *    <jk>public class</jk> MyBean {
2693       *       <jk>public</jk> String <jf>foo</jf> = <js>"bar"</js>;
2694       *
2695       *       <jk>public</jk> String toString() {
2696       *          <jk>return</jk> <js>"baz"</js>;
2697       *       }
2698       *    }
2699       *
2700       *    <jc>// Create a serializer that doesn't treat MyBean as a bean class.</jc>
2701       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
2702       *       .<jsm>create</jsm>()
2703       *       .notBeanClasses(MyBean.<jk>class</jk>)
2704       *       .build();
2705       *
2706       *    <jc>// Produces "baz" instead of {"foo":"bar"}</jc>
2707       *    String <jv>json</jv> = <jv>serializer</jv>.serialize(<jk>new</jk> MyBean());
2708       * </p>
2709       *
2710       * <h5 class='section'>Notes:</h5><ul>
2711       *    <li class='note'>The {@link BeanIgnore @BeanIgnore} annotation can also be used on classes to prevent them from being recognized as beans.
2712       * </ul>
2713       *
2714       * <h5 class='section'>See Also:</h5><ul>
2715       *    <li class='ja'>{@link org.apache.juneau.annotation.BeanIgnore}
2716       *    <li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#notBeanClasses()}
2717       * </ul>
2718       *
2719       * @param values
2720       *    The values to add to this setting.
2721       *    <br>Cannot contain <jk>null</jk> values.
2722       * @return This object.
2723       */
2724      public Builder notBeanClasses(ClassInfo...values) {
2725         assertArgNoNulls("values", values);
2726         notBeanClasses().addAll(l(values));
2727         return this;
2728      }
2729
2730      /**
2731       * Same as {@link #notBeanClasses(ClassInfo...)} but allows you to pass in a collection of class info objects.
2732       *
2733       * @param values
2734       *    The values to add to this setting.
2735       *    <br>Cannot be <jk>null</jk> or contain <jk>null</jk> values.
2736       * @return This object.
2737       * @see #notBeanClasses(ClassInfo...)
2738       */
2739      public Builder notBeanClasses(Collection<ClassInfo> values) {
2740         assertArgNoNulls("values", values);
2741         notBeanClasses().addAll(values);
2742         return this;
2743      }
2744
2745      /**
2746       * Returns the list of not-bean Java package names.
2747       *
2748       * <p>
2749       * Gives access to the inner list if you need to make more than simple additions via {@link #notBeanPackages(String...)}.
2750       *
2751       * @return The list of not-bean Java package names.
2752       * @see #notBeanPackages(String...)
2753       */
2754      public Set<String> notBeanPackages() {
2755         return notBeanPackages;
2756      }
2757
2758      /**
2759       * Same as {@link #notBeanPackages(String...)} but allows you to pass in a collection of classes.
2760       *
2761       * @param values
2762       *    The values to add to this setting.
2763       *    <br>Cannot be <jk>null</jk> or contain <jk>null</jk> values.
2764       * @return This object.
2765       * @see #notBeanPackages(String...)
2766       */
2767      public Builder notBeanPackages(Collection<String> values) {
2768         assertArgNoNulls("values", values);
2769         notBeanPackages().addAll(values);
2770         return this;
2771      }
2772
2773      /**
2774       * Bean package exclusions.
2775       *
2776       * <p>
2777       * Used as a convenient way of defining the {@link #notBeanClasses(Class...)} property for entire packages.
2778       * Any classes within these packages will be serialized to strings using {@link Object#toString()}.
2779       *
2780       * <p>
2781       * Note that you can specify suffix patterns to include all subpackages.
2782       *
2783       * <p>
2784       * Values can consist of any of the following types:
2785       * <ul>
2786       *    <li>Strings.
2787       *    <li>Arrays and collections of strings.
2788       * </ul>
2789       *
2790       * <h5 class='section'>Example:</h5>
2791       * <p class='bjava'>
2792       *    <jc>// Create a serializer that ignores beans in the specified packages.</jc>
2793       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
2794       *       .<jsm>create</jsm>()
2795       *       .notBeanPackages(<js>"org.apache.foo"</js>, <js>"org.apache.bar.*"</js>)
2796       *       .build();
2797       * </p>
2798       *
2799       * @param values
2800       *    The values to add to this setting.
2801       *    <br>Values can consist of any of the following types:
2802       *    <ul>
2803       *       <li>{@link Package} objects.
2804       *       <li>Strings.
2805       *       <li>Arrays and collections of anything in this list.
2806       *    </ul>
2807       *    <br>Cannot contain <jk>null</jk> values.
2808       * @return This object.
2809       */
2810      public Builder notBeanPackages(String...values) {
2811         assertArgNoNulls("values", values);
2812         return notBeanPackages(l(values));
2813      }
2814
2815      /**
2816       * Bean property namer
2817       *
2818       * <p>
2819       * Same as {@link #propertyNamer(Class)} but allows you to specify a namer for a specific class.
2820       *
2821       * <h5 class='section'>Example:</h5>
2822       * <p class='bjava'>
2823       *    <jc>// A bean with a single property.</jc>
2824       *    <jk>public class</jk> MyBean {
2825       *       <jk>public</jk> String <jf>fooBarBaz</jf> = <js>"fooBarBaz"</js>;
2826       *    }
2827       *
2828       *    <jc>// Create a serializer that uses Dashed-Lower-Case property names for the MyBean class only.</jc>
2829       *    <jc>// (e.g. "foo-bar-baz" instead of "fooBarBaz")</jc>
2830       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
2831       *       .<jsm>create</jsm>()
2832       *       .propertyNamer(MyBean.<jk>class</jk>, PropertyNamerDLC.<jk>class</jk>)
2833       *       .build();
2834       *
2835       *    <jc>// Produces:  {"foo-bar-baz":"fooBarBaz"}</jc>
2836       *    String <jv>json</jv> = <jv>serializer</jv>.serialize(<jk>new</jk> MyBean());
2837       * </p>
2838       *
2839       * <h5 class='section'>See Also:</h5><ul>
2840       *    <li class='ja'>{@link Bean#propertyNamer() Bean(propertyNamer)}
2841       *    <li class='jm'>{@link #propertyNamer(Class)}
2842       * </ul>
2843       *
2844       * @param on The class that the namer applies to.
2845       *    <br>Cannot be <jk>null</jk>.
2846       * @param value
2847       *    The new value for this setting.
2848       *    <br>The default is {@link BasicPropertyNamer}.
2849       *    <br>Cannot be <jk>null</jk>.
2850       * @return This object.
2851       */
2852      public Builder propertyNamer(Class<?> on, Class<? extends PropertyNamer> value) {
2853         assertArgNotNull("on", on);
2854         assertArgNotNull("value", value);
2855         return annotations(BeanAnnotation.create(on).propertyNamer(value).build());
2856      }
2857
2858      /**
2859       * Bean property namer
2860       *
2861       * <p>
2862       * The class to use for calculating bean property names.
2863       *
2864       * <p>
2865       * Predefined classes:
2866       * <ul>
2867       *    <li>{@link BasicPropertyNamer} - Default.
2868       *    <li>{@link PropertyNamerDLC} - Dashed-lower-case names.
2869       *    <li>{@link PropertyNamerULC} - Dashed-upper-case names.
2870       * </ul>
2871       *
2872       * <h5 class='section'>Example:</h5>
2873       * <p class='bjava'>
2874       *    <jc>// A bean with a single property.</jc>
2875       *    <jk>public class</jk> MyBean {
2876       *       <jk>public</jk> String <jf>fooBarBaz</jf> = <js>"fooBarBaz"</js>;
2877       *    }
2878       *
2879       *    <jc>// Create a serializer that uses Dashed-Lower-Case property names.</jc>
2880       *    <jc>// (e.g. "foo-bar-baz" instead of "fooBarBaz")</jc>
2881       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
2882       *       .<jsm>create</jsm>()
2883       *       .propertyNamer(PropertyNamerDLC.<jk>class</jk>)
2884       *       .build();
2885       *
2886       *    <jc>// Produces:  {"foo-bar-baz":"fooBarBaz"}</jc>
2887       *    String <jv>json</jv> = <jv>serializer</jv>.serialize(<jk>new</jk> MyBean());
2888       * </p>
2889       *
2890       * @param value
2891       *    The new value for this setting.
2892       *    <br>Can be <jk>null</jk> (will use {@link BasicPropertyNamer} as the default).
2893       * @return This object.
2894       */
2895      public Builder propertyNamer(Class<? extends PropertyNamer> value) {
2896         propertyNamer = value;
2897         return this;
2898      }
2899
2900      /**
2901       * Sort bean properties.
2902       *
2903       * <p>
2904       * When enabled, all bean properties will be serialized and access in alphabetical order.
2905       * Otherwise, the natural order of the bean properties is used which is dependent on the JVM vendor.
2906       * On IBM JVMs, the bean properties are ordered based on their ordering in the Java file.
2907       * On Oracle JVMs, the bean properties are not ordered (which follows the official JVM specs).
2908       *
2909       * <p>
2910       * this setting is disabled by default so that IBM JVM users don't have to use {@link Bean @Bean} annotations
2911       * to force bean properties to be in a particular order and can just alter the order of the fields/methods
2912       * in the Java file.
2913       *
2914       * <h5 class='section'>Example:</h5>
2915       * <p class='bjava'>
2916       *    <jc>// A bean with 3 properties.</jc>
2917       *    <jk>public class</jk> MyBean {
2918       *       <jk>public</jk> String <jf>c</jf> = <js>"1"</js>;
2919       *       <jk>public</jk> String <jf>b</jf> = <js>"2"</js>;
2920       *       <jk>public</jk> String <jf>a</jf> = <js>"3"</js>;
2921       *    }
2922       *
2923       *    <jc>// Create a serializer that sorts bean properties.</jc>
2924       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
2925       *       .<jsm>create</jsm>()
2926       *       .sortProperties()
2927       *       .build();
2928       *
2929       *    <jc>// Produces:  {"a":"3","b":"2","c":"1"}</jc>
2930       *    String <jv>json</jv> = <jv>serializer</jv>.serialize(<jk>new</jk> MyBean());
2931       * </p>
2932       *
2933       * <h5 class='section'>Notes:</h5><ul>
2934       *    <li class='note'>The {@link Bean#sort() @Bean.sort()} annotation can also be used to sort properties on just a single class.
2935       * </ul>
2936       *
2937       * @return This object.
2938       */
2939      public Builder sortProperties() {
2940         sortProperties = true;
2941         return sortProperties(true);
2942      }
2943
2944      /**
2945       * Same as {@link #sortProperties()} but allows you to explicitly specify the value.
2946       *
2947       * @param value The value for this setting.
2948       * @return This object.
2949       */
2950      public Builder sortProperties(boolean value) {
2951         sortProperties = value;
2952         return this;
2953      }
2954
2955      /**
2956       * Sort bean properties.
2957       *
2958       * <p>
2959       * Same as {@link #sortProperties()} but allows you to specify individual bean classes instead of globally.
2960       *
2961       * <h5 class='section'>Example:</h5>
2962       * <p class='bjava'>
2963       *    <jc>// A bean with 3 properties.</jc>
2964       *    <jk>public class</jk> MyBean {
2965       *       <jk>public</jk> String <jf>c</jf> = <js>"1"</js>;
2966       *       <jk>public</jk> String <jf>b</jf> = <js>"2"</js>;
2967       *       <jk>public</jk> String <jf>a</jf> = <js>"3"</js>;
2968       *    }
2969       *
2970       *    <jc>// Create a serializer that sorts properties on MyBean.</jc>
2971       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
2972       *       .<jsm>create</jsm>()
2973       *       .sortProperties(MyBean.<jk>class</jk>)
2974       *       .build();
2975       *
2976       *    <jc>// Produces:  {"a":"3","b":"2","c":"1"}</jc>
2977       *    String <jv>json</jv> = <jv>serializer</jv>.serialize(<jk>new</jk> MyBean());
2978       * </p>
2979       *
2980       * <h5 class='section'>See Also:</h5><ul>
2981       *    <li class='ja'>{@link Bean#sort() Bean(sort)}
2982       *    <li class='jm'>{@link #sortProperties()}
2983       * </ul>
2984       *
2985       * @param on The bean classes to sort properties on.
2986       *    <br>Cannot contain <jk>null</jk> values.
2987       * @return This object.
2988       */
2989      public Builder sortProperties(Class<?>...on) {
2990         assertArgNoNulls("on", on);
2991         for (var c : on)
2992            annotations(BeanAnnotation.create(c).sort(true).build());
2993         return this;
2994      }
2995
2996      /**
2997       * Identifies a stop class for the annotated class.
2998       *
2999       * <p>
3000       * Identical in purpose to the stop class specified by {@link Introspector#getBeanInfo(Class, Class)}.
3001       * Any properties in the stop class or in its base classes will be ignored during analysis.
3002       *
3003       * <p>
3004       * For example, in the following class hierarchy, instances of <c>C3</c> will include property <c>p3</c>,
3005       * but not <c>p1</c> or <c>p2</c>.
3006       *
3007       * <h5 class='section'>Example:</h5>
3008       * <p class='bjava'>
3009       *    <jk>public class</jk> C1 {
3010       *       <jk>public int</jk> getP1();
3011       *    }
3012       *
3013       *    <jk>public class</jk> C2 <jk>extends</jk> C1 {
3014       *       <jk>public int</jk> getP2();
3015       *    }
3016       *
3017       *    <jk>public class</jk> C3 <jk>extends</jk> C2 {
3018       *       <jk>public int</jk> getP3();
3019       *    }
3020       *
3021       *    <jc>// Create a serializer specifies a stop class for C3.</jc>
3022       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
3023       *       .<jsm>create</jsm>()
3024       *       .stopClass(C3.<jk>class</jk>, C2.<jk>class</jk>)
3025       *       .build();
3026       *
3027       *    <jc>// Produces:  {"p3":"..."}</jc>
3028       *    String <jv>json</jv> = <jv>serializer</jv>.serialize(<jk>new</jk> C3());
3029       * </p>
3030       *
3031       * @param on The class on which the stop class is being applied.
3032       *    <br>Cannot be <jk>null</jk>.
3033       * @param value
3034       *    The new value for this setting.
3035       *    <br>Cannot be <jk>null</jk>.
3036       * @return This object.
3037       */
3038      public Builder stopClass(Class<?> on, Class<?> value) {
3039         assertArgNotNull("on", on);
3040         assertArgNotNull("value", value);
3041         return annotations(BeanAnnotation.create(on).stopClass(value).build());
3042      }
3043
3044      /**
3045       * A shortcut for defining a {@link FunctionalSwap}.
3046       *
3047       * <h5 class='section'>Example:</h5>
3048       * <p class='bjava'>
3049       *    <jc>// Create a serializer that performs a custom format for DAte objects.</jc>
3050       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
3051       *       .<jsm>create</jsm>()
3052       *       .swap(Date.<jk>class</jk>, String.<jk>class</jk>, <jv>x</jv> -&gt; <jsm>format</jsm>(<jv>x</jv>))
3053       *       .build();
3054       * </p>
3055       *
3056       * @param <T> The object type being swapped out.
3057       * @param <S> The object type being swapped in.
3058       * @param normalClass The object type being swapped out.
3059       *    <br>Cannot be <jk>null</jk>.
3060       * @param swappedClass The object type being swapped in.
3061       *    <br>Cannot be <jk>null</jk>.
3062       * @param swapFunction The function to convert the object.
3063       *    <br>Cannot be <jk>null</jk>.
3064       * @return This object.
3065       */
3066      public <T,S> Builder swap(Class<T> normalClass, Class<S> swappedClass, ThrowingFunction<T,S> swapFunction) {
3067         return swap(normalClass, swappedClass, swapFunction, null);
3068      }
3069
3070      /**
3071       * A shortcut for defining a {@link FunctionalSwap}.
3072       *
3073       * <h5 class='section'>Example:</h5>
3074       * <p class='bjava'>
3075       *    <jc>// Create a serializer that performs a custom format for Date objects.</jc>
3076       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
3077       *       .<jsm>create</jsm>()
3078       *       .swap(Date.<jk>class</jk>, String.<jk>class</jk>, <jv>x</jv> -&gt; <jsm>format</jsm>(<jv>x</jv>), <jv>x</jv> -&gt; <jsm>parse</jsm>(<jv>x</jv>))
3079       *       .build();
3080       * </p>
3081       *
3082       * @param <T> The object type being swapped out.
3083       * @param <S> The object type being swapped in.
3084       * @param normalClass The object type being swapped out.
3085       *    <br>Cannot be <jk>null</jk>.
3086       * @param swappedClass The object type being swapped in.
3087       *    <br>Cannot be <jk>null</jk>.
3088       * @param swapFunction The function to convert the object during serialization.
3089       *    <br>Cannot be <jk>null</jk>.
3090       * @param unswapFunction The function to convert the object during parsing.
3091       *    <br>Cannot be <jk>null</jk>.
3092       * @return This object.
3093       */
3094      public <T,S> Builder swap(Class<T> normalClass, Class<S> swappedClass, ThrowingFunction<T,S> swapFunction, ThrowingFunction<S,T> unswapFunction) {
3095         assertArgNotNull("normalClass", normalClass);
3096         assertArgNotNull("swappedClass", swappedClass);
3097         assertArgNotNull("swapFunction", swapFunction);
3098         assertArgNotNull("unswapFunction", unswapFunction);
3099         swaps().add(0, new FunctionalSwap<>(normalClass, swappedClass, swapFunction, unswapFunction));
3100         return this;
3101      }
3102
3103      /**
3104       * Returns the bean swaps list.
3105       *
3106       * <p>
3107       * Gives access to the inner list if you need to make more than simple additions via {@link #swaps(Class...)}.
3108       *
3109       * @return The bean swaps list.
3110       * @see #swaps(Class...)
3111       */
3112      public List<Object> swaps() {
3113         return swaps;
3114      }
3115
3116      /**
3117       * Same as {@link #swaps(Object...)} but explicitly specifies an array of classes to avoid compilation warnings.
3118       *
3119       * @param values
3120       *    The values to add to this setting.
3121       *    <br>Values can consist of any of the following types:
3122       *    <ul>
3123       *       <li>Any subclass of {@link ObjectSwap}.
3124       *       <li>Any surrogate class.  A shortcut for defining a {@link SurrogateSwap}.
3125       *    </ul>
3126       *    <br>Cannot be <jk>null</jk>.
3127       * @return This object.
3128       */
3129      public Builder swaps(Class<?>...values) {
3130         assertArgNoNulls("values", values);
3131         swaps().addAll(0, accumulate(values));
3132         return this;
3133      }
3134
3135      /**
3136       * Java object swaps.
3137       *
3138       * <p>
3139       * Swaps are used to "swap out" non-serializable classes with serializable equivalents during serialization,
3140       * and "swap in" the non-serializable class during parsing.
3141       *
3142       * <p>
3143       * An example of a swap would be a <c>Calendar</c> object that gets swapped out for an ISO8601 string.
3144       *
3145       * <p>
3146       * Multiple swaps can be associated with a single class.
3147       * When multiple swaps are applicable to the same class, the media type pattern defined by
3148       * {@link ObjectSwap#forMediaTypes()} or {@link Swap#mediaTypes() @Swap(mediaTypes)} are used to come up with the best match.
3149       *
3150       * <p>
3151       * Values can consist of any of the following types:
3152       * <ul>
3153       *    <li>Any subclass of {@link ObjectSwap}.
3154       *    <li>Any instance of {@link ObjectSwap}.
3155       *    <li>Any surrogate class.  A shortcut for defining a {@link SurrogateSwap}.
3156       *    <li>Any array or collection of the objects above.
3157       * </ul>
3158       *
3159       * <h5 class='section'>Example:</h5>
3160       * <p class='bjava'>
3161       *    <jc>// Sample swap for converting Dates to ISO8601 strings.</jc>
3162       *    <jk>public class</jk> MyDateSwap <jk>extends</jk> StringSwap&lt;Date&gt; {
3163       *       <jc>// ISO8601 formatter.</jc>
3164       *       <jk>private</jk> DateFormat <jf>format</jf> = <jk>new</jk> SimpleDateFormat(<js>"yyyy-MM-dd'T'HH:mm:ssZ"</js>);
3165       *
3166       *       <ja>@Override</ja>
3167       *       <jk>public</jk> String swap(BeanSession <jv>session</jv>, Date <jv>date</jv>) {
3168       *          <jk>return</jk> <jf>format</jf>.format(<jv>date</jv>);
3169       *       }
3170       *
3171       *       <ja>@Override</ja>
3172       *       <jk>public</jk> Date unswap(BeanSession <jv>session</jv>, String <jv>string</jv>, ClassMeta <jv>hint</jv>) <jk>throws</jk> Exception {
3173       *          <jk>return</jk> <jf>format</jf>.parse(<jv>string</jv>);
3174       *       }
3175       *    }
3176       *
3177       *    <jc>// Sample bean with a Date field.</jc>
3178       *    <jk>public class</jk> MyBean {
3179       *       <jk>public</jk> Date <jf>date</jf> = <jk>new</jk> Date(112, 2, 3, 4, 5, 6);
3180       *    }
3181       *
3182       *    <jc>// Create a serializer that uses our date swap.</jc>
3183       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
3184       *       .<jsm>create</jsm>()
3185       *       .swaps(MyDateSwap.<jk>class</jk>)
3186       *       .build();
3187       *
3188       *    <jc>// Produces:  {"date":"2012-03-03T04:05:06-0500"}</jc>
3189       *    String <jv>json</jv> = <jv>serializer</jv>.serialize(<jk>new</jk> MyBean());
3190       *
3191       *    <jc>// Create a serializer that uses our date swap.</jc>
3192       *    ReaderParser <jv>parser</jv> = JsonParser
3193       *       .<jsm>create</jsm>()
3194       *       .swaps(MyDateSwap.<jk>class</jk>)
3195       *       .build();
3196       *
3197       *    <jc>// Use our parser to parse a bean.</jc>
3198       *    MyBean <jv>bean</jv> = <jv>parser</jv>.parse(<jv>json</jv>, MyBean.<jk>class</jk>);
3199       * </p>
3200       *
3201       * <h5 class='section'>Notes:</h5><ul>
3202       *    <li class='note'>The {@link Swap @Swap} annotation can also be used on classes to identify swaps for the class.
3203       *    <li class='note'>The {@link Swap @Swap} annotation can also be used on bean methods and fields to identify swaps for values of those bean properties.
3204       * </ul>
3205       *
3206       * @param values
3207       *    The values to add to this setting.
3208       *    <br>Values can consist of any of the following types:
3209       *    <ul>
3210       *       <li>Any subclass of {@link ObjectSwap}.
3211       *       <li>Any surrogate class.  A shortcut for defining a {@link SurrogateSwap}.
3212       *       <li>Any array/collection/stream of the objects above.
3213       *    </ul>
3214       *    <br>Cannot be <jk>null</jk>.
3215       * @return This object.
3216       */
3217      public Builder swaps(Object...values) {
3218         assertArgNoNulls("values", values);
3219         swaps().addAll(0, accumulate(values));
3220         return this;
3221      }
3222
3223      /**
3224       * <i><l>Context</l> configuration property:&emsp;</i>  TimeZone.
3225       *
3226       * <p>
3227       * Specifies the default time zone for serializer and parser sessions when not specified via {@link BeanSession.Builder#timeZone(TimeZone)}.
3228       * Typically used for POJO swaps that need to deal with timezones such as swaps that convert <l>Date</l> and <l>Calendar</l>
3229       * objects to strings by accessing it via the session passed into the {@link ObjectSwap#swap(BeanSession, Object)} and
3230       * {@link ObjectSwap#unswap(BeanSession, Object, ClassMeta, String)} methods.
3231       *
3232       * <h5 class='section'>Example:</h5>
3233       * <p class='bjava'>
3234       *    <jc>// Define a POJO swap that skips serializing beans if the time zone is GMT.</jc>
3235       *    <jk>public class</jk> MyBeanSwap <jk>extends</jk> StringSwap&lt;MyBean&gt; {
3236       *       <ja>@Override</ja>
3237       *       <jk>public</jk> String swap(BeanSession <jv>session</jv>, MyBean <jv>bean</jv>) <jk>throws</jk> Exception {
3238       *          <jk>if</jk> (<jv>session</jv>.getTimeZone().equals(TimeZone.<jsf>GMT</jsf>))
3239       *             <jk>return null</jk>;
3240       *          <jk>return</jk> <jv>bean</jv>.toString();
3241       *       }
3242       *    }
3243       *
3244       *    <jc>// Create a serializer that uses GMT if the timezone is not specified in the session args.</jc>
3245       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
3246       *       .<jsm>create</jsm>()
3247       *       .timeZone(TimeZone.<jsf>GMT</jsf>)
3248       *       .build();
3249       * </p>
3250       *
3251       * <h5 class='section'>See Also:</h5><ul>
3252       *    <li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#timeZone()}
3253       *    <li class='jm'>{@link org.apache.juneau.BeanSession.Builder#timeZone(TimeZone)}
3254       * </ul>
3255       *
3256       * @param value The new value for this property.
3257       *    <br>Can be <jk>null</jk> (timezone will not be set, defaults to system timezone).
3258       * @return This object.
3259       */
3260      public Builder timeZone(TimeZone value) {
3261         timeZone = value;
3262         return this;
3263      }
3264
3265      @Override /* Overridden from Builder */
3266      public Builder type(Class<? extends org.apache.juneau.Context> value) {
3267         assertArgNotNull("value", value);
3268         super.type(value);
3269         return this;
3270      }
3271
3272      /**
3273       * An identifying name for this class.
3274       *
3275       * <p>
3276       * The name is used to identify the class type during parsing when it cannot be inferred through reflection.
3277       * For example, if a bean property is of type <c>Object</c>, then the serializer will add the name to the
3278       * output so that the class can be determined during parsing.
3279       *
3280       * <p>
3281       * It is also used to specify element names in XML.
3282       *
3283       * <h5 class='section'>Example:</h5>
3284       * <p class='bjava'>
3285       *    <jc>// Use _type='mybean' to identify this bean.</jc>
3286       *    <jk>public class</jk> MyBean {...}
3287       *
3288       *    <jc>// Create a serializer and specify the type name..</jc>
3289       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
3290       *       .<jsm>create</jsm>()
3291       *       .typeName(MyBean.<jk>class</jk>, <js>"mybean"</js>)
3292       *       .build();
3293       *
3294       *    <jc>// Produces:  {"_type":"mybean",...}</jc>
3295       *    String <jv>json</jv> = <jv>serializer</jv>.serialize(<jk>new</jk> MyBean());
3296       * </p>
3297       *
3298       * <h5 class='section'>Notes:</h5><ul>
3299       *    <li class='note'>Equivalent to the {@link Bean#typeName() Bean(typeName)} annotation.
3300       * </ul>
3301       *
3302       * <h5 class='section'>See Also:</h5><ul>
3303       *    <li class='jc'>{@link Bean#typeName() Bean(typeName)}
3304       *    <li class='jm'>{@link #beanDictionary(Class...)}
3305       * </ul>
3306       *
3307       * @param on
3308       *    The class the type name is being defined on.
3309       *    <br>Cannot be <jk>null</jk>.
3310       * @param value
3311       *    The new value for this setting.
3312       *    <br>Cannot be <jk>null</jk>.
3313       * @return This object.
3314       */
3315      public Builder typeName(Class<?> on, String value) {
3316         assertArgNotNull("on", on);
3317         assertArgNotNull("value", value);
3318         return annotations(BeanAnnotation.create(on).typeName(value).build());
3319      }
3320
3321      /**
3322       * Bean type property name.
3323       *
3324       * <p>
3325       * Same as {@link #typePropertyName(String)} except targets a specific bean class instead of globally.
3326       *
3327       * <h5 class='section'>Example:</h5>
3328       * <p class='bjava'>
3329       *    <jc>// POJOs with @Bean(name) annotations.</jc>
3330       *    <ja>@Bean</ja>(typeName=<js>"foo"</js>)
3331       *    <jk>public class</jk> Foo {...}
3332       *    <ja>@Bean</ja>(typeName=<js>"bar"</js>)
3333       *    <jk>public class</jk> Bar {...}
3334       *
3335       *    <jc>// A bean with a field with an indeterminate type.</jc>
3336       *    <jk>public class</jk> MyBean {
3337       *       <jk>public</jk> Object <jf>mySimpleField</jf>;
3338       *    }
3339       *
3340       *    <jc>// Create a serializer that uses 't' instead of '_type' for dictionary names.</jc>
3341       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
3342       *       .<jsm>create</jsm>()
3343       *       .typePropertyName(MyBean.<jk>class</jk>, <js>"t"</js>)
3344       *       .dictionary(Foo.<jk>class</jk>, Bar.<jk>class</jk>)
3345       *       .build();
3346       *
3347       *    <jc>// Produces "{mySimpleField:{t:'foo',...}}".</jc>
3348       *    String <jv>json</jv> = <jv>serializer</jv>.serialize(<jk>new</jk> MyBean());
3349       * </p>
3350       *
3351       * <h5 class='section'>See Also:</h5><ul>
3352       *    <li class='ja'>{@link Bean#typePropertyName() Bean(typePropertyName)}
3353       * </ul>
3354       *
3355       * @param on The class the type property name applies to.
3356       *    <br>Cannot be <jk>null</jk>.
3357       * @param value
3358       *    The new value for this setting.
3359       *    <br>The default is <js>"_type"</js>.
3360       *    <br>Cannot be <jk>null</jk>.
3361       * @return This object.
3362       */
3363      public Builder typePropertyName(Class<?> on, String value) {
3364         assertArgNotNull("on", on);
3365         assertArgNotNull("value", value);
3366         return annotations(BeanAnnotation.create(on).typePropertyName(value).build());
3367      }
3368
3369      /**
3370       * Bean type property name.
3371       *
3372       * <p>
3373       * This specifies the name of the bean property used to store the dictionary name of a bean type so that the
3374       * parser knows the data type to reconstruct.
3375       *
3376       * <h5 class='section'>Example:</h5>
3377       * <p class='bjava'>
3378       *    <jc>// POJOs with @Bean(name) annotations.</jc>
3379       *    <ja>@Bean</ja>(typeName=<js>"foo"</js>)
3380       *    <jk>public class</jk> Foo {...}
3381       *    <ja>@Bean</ja>(typeName=<js>"bar"</js>)
3382       *    <jk>public class</jk> Bar {...}
3383       *
3384       *    <jc>// Create a serializer that uses 't' instead of '_type' for dictionary names.</jc>
3385       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
3386       *       .<jsm>create</jsm>()
3387       *       .typePropertyName(<js>"t"</js>)
3388       *       .dictionary(Foo.<jk>class</jk>, Bar.<jk>class</jk>)
3389       *       .build();
3390       *
3391       *    <jc>// Create a serializer that uses 't' instead of '_type' for dictionary names.</jc>
3392       *    ReaderParser <jv>parser</jv> = JsonParser
3393       *       .<jsm>create</jsm>()
3394       *       .typePropertyName(<js>"t"</js>)
3395       *       .dictionary(Foo.<jk>class</jk>, Bar.<jk>class</jk>)
3396       *       .build();
3397       *
3398       *    <jc>// A bean with a field with an indeterminate type.</jc>
3399       *    <jk>public class</jk> MyBean {
3400       *       <jk>public</jk> Object <jf>mySimpleField</jf>;
3401       *    }
3402       *
3403       *    <jc>// Produces "{mySimpleField:{t:'foo',...}}".</jc>
3404       *    String <jv>json</jv> = <jv>serializer</jv>.serialize(<jk>new</jk> MyBean());
3405       *
3406       *    <jc>// Parse bean.</jc>
3407       *    MyBean <jv>bean</jv> = <jv>parser</jv>.parse(<jv>json</jv>, MyBean.<jk>class</jk>);
3408       * </p>
3409       *
3410       * <h5 class='section'>See Also:</h5><ul>
3411       *    <li class='ja'>{@link org.apache.juneau.annotation.Bean#typePropertyName()}
3412       *    <li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#typePropertyName()}
3413       * </ul>
3414       *
3415       * @param value
3416       *    The new value for this setting.
3417       *    <br>The default is <js>"_type"</js>.
3418       *    <br>Cannot be <jk>null</jk>.
3419       * @return This object.
3420       */
3421      public Builder typePropertyName(String value) {
3422         typePropertyName = assertArgNotNull("value", value);
3423         return this;
3424      }
3425
3426      /**
3427       * Use enum names.
3428       *
3429       * <p>
3430       * When enabled, enums are always serialized by name, not using {@link Object#toString()}.
3431       *
3432       * <h5 class='section'>Example:</h5>
3433       * <p class='bjava'>
3434       *    <jc>// Create a serializer with debug enabled.</jc>
3435       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
3436       *       .<jsm>create</jsm>()
3437       *       .useEnumNames()
3438       *       .build();
3439       *
3440       *    <jc>// Enum with overridden toString().</jc>
3441       *    <jc>// Will be serialized as ONE/TWO/THREE even though there's a toString() method.</jc>
3442       *    <jk>public enum</jk> Option {
3443       *       <jsf>ONE</jsf>(1),
3444       *       <jsf>TWO</jsf>(2),
3445       *       <jsf>THREE</jsf>(3);
3446       *
3447       *       <jk>private int</jk> <jf>value</jf>;
3448       *
3449       *       Option(<jk>int</jk> <jv>value</jv>) {
3450       *          <jk>this</jk>.<jf>value</jf> = <jv>value</jv>;
3451       *       }
3452       *
3453       *       <ja>@Override</ja>
3454       *       <jk>public</jk> String toString() {
3455       *          <jk>return</jk> String.<jsm>valueOf</jsm>(<jf>value</jf>);
3456       *       }
3457       *    }
3458       * </p>
3459       *
3460       * @return This object.
3461       */
3462      public Builder useEnumNames() {
3463         return useEnumNames(true);
3464      }
3465
3466      /**
3467       * Same as {@link #useEnumNames()} but allows you to explicitly specify the value.
3468       *
3469       * @param value The value for this setting.
3470       * @return This object.
3471       */
3472      public Builder useEnumNames(boolean value) {
3473         useEnumNames = value;
3474         return this;
3475      }
3476
3477      /**
3478       * Use Java Introspector.
3479       *
3480       * <p>
3481       * Using the built-in Java bean introspector will not pick up fields or non-standard getters/setters.
3482       * <br>Most {@link Bean @Bean} annotations will be ignored.
3483       *
3484       * <h5 class='section'>Example:</h5>
3485       * <p class='bjava'>
3486       *    <jc>// Create a serializer that only uses the built-in java bean introspector for finding properties.</jc>
3487       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
3488       *       .<jsm>create</jsm>()
3489       *       .useJavaBeanIntrospector()
3490       *       .build();
3491       * </p>
3492       *
3493       * @return This object.
3494       */
3495      public Builder useJavaBeanIntrospector() {
3496         return useJavaBeanIntrospector(true);
3497      }
3498
3499      /**
3500       * Same as {@link #useJavaBeanIntrospector()} but allows you to explicitly specify the value.
3501       *
3502       * @param value The value for this setting.
3503       * @return This object.
3504       */
3505      public Builder useJavaBeanIntrospector(boolean value) {
3506         useJavaBeanIntrospector = value;
3507         return this;
3508      }
3509   }
3510
3511   /*
3512    * The default package pattern exclusion list.
3513    * Any beans in packages in this list will not be considered beans.
3514    */
3515   // @formatter:off
3516   private static final List<String> DEFAULT_NOTBEAN_PACKAGES = l(
3517      "java.lang",
3518      "java.lang.annotation",
3519      "java.lang.ref",
3520      "java.lang.reflect",
3521      "java.io",
3522      "java.net",
3523      "java.nio.*",
3524      "java.util.*"
3525   );
3526   // @formatter:on
3527
3528   /*
3529    * The default bean class exclusion list.
3530    * Anything in this list will not be considered beans.
3531    */
3532   // @formatter:off
3533   private static final List<ClassInfo> DEFAULT_NOTBEAN_CLASSES = l(
3534      info(Map.class),
3535      info(Collection.class),
3536      info(Reader.class),
3537      info(Writer.class),
3538      info(InputStream.class),
3539      info(OutputStream.class),
3540      info(Throwable.class)
3541   );
3542   // @formatter:on
3543
3544   /** Default config.  All default settings. */
3545   public static final BeanContext DEFAULT = create().build();
3546
3547   /** Default config.  All default settings except sort bean properties. */
3548   public static final BeanContext DEFAULT_SORTED = create().sortProperties().build();
3549
3550   /** Default reusable unmodifiable session.  Can be used to avoid overhead of creating a session (for creating BeanMaps for example).*/
3551   public static final BeanSession DEFAULT_SESSION = DEFAULT.createSession().unmodifiable().build();
3552
3553   /**
3554    * Creates a new builder for this object.
3555    *
3556    * @return A new builder.
3557    */
3558   public static Builder create() {
3559      return new Builder();
3560   }
3561
3562   /**
3563    * Checks if the specified class should be cached.
3564    *
3565    * <p>
3566    * Generated classes (proxies, lambda expressions, etc.) shouldn't be cacheable to prevent
3567    * needlessly filling up the cache.
3568    *
3569    * @param c The class to check.
3570    * @return <jk>true</jk> if the class should be cached.
3571    */
3572   private static boolean isCacheable(Class<?> c) {
3573      var n = c.getName();
3574      var x = n.charAt(n.length() - 1);  // All generated classes appear to end with digits.
3575      if (x >= '0' && x <= '9') {
3576         if (n.indexOf("$$") != -1 || n.startsWith("sun") || n.startsWith("com.sun") || n.indexOf("$Proxy") != -1)
3577            return false;
3578      }
3579      return true;
3580   }
3581
3582   private final OptionalSupplier<WriterSerializer> beanToStringSerializer;
3583   private final BeanRegistry beanRegistry;
3584   private final BeanSession defaultSession;
3585   private final boolean beanMapPutReturnsOldValue;
3586   private final boolean beansRequireDefaultConstructor;
3587   private final boolean beansRequireSerializable;
3588   private final boolean beansRequireSettersForGetters;
3589   private final boolean beansRequireSomeProperties;
3590   private final boolean findFluentSetters;
3591   private final boolean ignoreInvocationExceptionsOnGetters;
3592   private final boolean ignoreInvocationExceptionsOnSetters;
3593   private final boolean ignoreMissingSetters;
3594   private final boolean ignoreTransientFields;
3595   private final boolean ignoreUnknownBeanProperties;
3596   private final boolean ignoreUnknownEnumValues;
3597   private final boolean ignoreUnknownNullBeanProperties;
3598   private final boolean sortProperties;
3599   private final boolean useEnumNames;
3600   private final boolean useInterfaceProxies;
3601   private final boolean useJavaBeanIntrospector;
3602   private final Class<? extends PropertyNamer> propertyNamer;
3603   private final ClassMeta<Object> cmObject;  // Reusable ClassMeta that represents general Objects.
3604   private final ClassMeta<String> cmString;  // Reusable ClassMeta that represents general Strings.
3605   private final HashKey hashKey;
3606   private final List<ClassInfo> beanDictionary;
3607   private final List<ClassInfo> notBeanClasses;
3608   private final List<Object> swaps;
3609   private final List<String> notBeanPackages;
3610   private final Locale locale;
3611   private final Cache<Class,ClassMeta> cmCache;
3612   private final MediaType mediaType;
3613   private final List<ObjectSwap<?,?>> objectSwaps;
3614   private final PropertyNamer propertyNamerBean;
3615   private final String typePropertyName;
3616   private final Set<String> notBeanPackageNames;
3617   private final List<String> notBeanPackagePrefixes;
3618   private final TimeZone timeZone;
3619   private final Visibility beanClassVisibility;
3620   private final Visibility beanConstructorVisibility;
3621   private final Visibility beanFieldVisibility;
3622   private final Visibility beanMethodVisibility;
3623
3624   /**
3625    * Constructor.
3626    *
3627    * @param builder The builder for this object.
3628    */
3629   public BeanContext(Builder builder) {
3630      super(builder);
3631
3632      beanClassVisibility = builder.beanClassVisibility;
3633      beanConstructorVisibility = builder.beanConstructorVisibility;
3634      beanDictionary = u(copyOf(builder.beanDictionary));
3635      beanFieldVisibility = builder.beanFieldVisibility;
3636      beanMapPutReturnsOldValue = builder.beanMapPutReturnsOldValue;
3637      beanMethodVisibility = builder.beanMethodVisibility;
3638      beansRequireDefaultConstructor = builder.beansRequireDefaultConstructor;
3639      beansRequireSerializable = builder.beansRequireSerializable;
3640      beansRequireSettersForGetters = builder.beansRequireSettersForGetters;
3641      beansRequireSomeProperties = ! builder.disableBeansRequireSomeProperties;
3642      findFluentSetters = builder.findFluentSetters;
3643      hashKey = builder.hashKey();
3644      ignoreInvocationExceptionsOnGetters = builder.ignoreInvocationExceptionsOnGetters;
3645      ignoreInvocationExceptionsOnSetters = builder.ignoreInvocationExceptionsOnSetters;
3646      ignoreMissingSetters = ! builder.disableIgnoreMissingSetters;
3647      ignoreTransientFields = ! builder.disableIgnoreTransientFields;
3648      ignoreUnknownBeanProperties = builder.ignoreUnknownBeanProperties;
3649      ignoreUnknownEnumValues = builder.ignoreUnknownEnumValues;
3650      ignoreUnknownNullBeanProperties = ! builder.disableIgnoreUnknownNullBeanProperties;
3651      locale = opt(builder.locale).orElse(Locale.getDefault());
3652      mediaType = builder.mediaType;
3653      notBeanPackages = u(new ArrayList<>(builder.notBeanPackages));
3654      propertyNamer = nn(builder.propertyNamer) ? builder.propertyNamer : BasicPropertyNamer.class;
3655      sortProperties = builder.sortProperties;
3656      swaps = u(copyOf(builder.swaps));
3657      timeZone = builder.timeZone;
3658      typePropertyName = opt(builder.typePropertyName).orElse("_type");
3659      useEnumNames = builder.useEnumNames;
3660      useInterfaceProxies = ! builder.disableInterfaceProxies;
3661      useJavaBeanIntrospector = builder.useJavaBeanIntrospector;
3662
3663      var builderNotBeanClasses = new ArrayList<>(builder.notBeanClasses);
3664      notBeanClasses = builderNotBeanClasses.isEmpty() ? DEFAULT_NOTBEAN_CLASSES : Stream.concat(builderNotBeanClasses.stream(), DEFAULT_NOTBEAN_CLASSES.stream()).distinct().toList();
3665
3666      List<String> _notBeanPackages = notBeanPackages.isEmpty() ? DEFAULT_NOTBEAN_PACKAGES : Stream.concat(notBeanPackages.stream(), DEFAULT_NOTBEAN_PACKAGES.stream()).toList();
3667      LinkedHashSet<String> _notBeanPackageNames = _notBeanPackages.stream().filter(x -> ! x.endsWith(".*")).collect(Collectors.toCollection(LinkedHashSet::new));
3668      notBeanPackageNames = u(_notBeanPackageNames);
3669      notBeanPackagePrefixes = _notBeanPackages.stream().filter(x -> x.endsWith(".*")).map(x -> x.substring(0, x.length() - 2)).toList();
3670
3671      propertyNamerBean = safe(()->propertyNamer.getDeclaredConstructor().newInstance());
3672
3673      var _objectSwaps = new LinkedList<ObjectSwap<?,?>>();
3674      swaps.forEach(x -> {
3675         if (x instanceof ObjectSwap<?,?> os) {
3676            _objectSwaps.add(os);
3677         } else {
3678            var ci = info((Class<?>)x);
3679            if (ci.isChildOf(ObjectSwap.class))
3680               _objectSwaps.add(BeanCreator.of(ObjectSwap.class).type(ci).run());
3681            else if (ci.isChildOf(Surrogate.class))
3682               _objectSwaps.addAll(SurrogateSwap.findObjectSwaps(ci.inner(), this));
3683            else
3684               throw rex("Invalid class {0} specified in BeanContext.swaps property.  Must be a subclass of ObjectSwap or Surrogate.", cn(ci.inner()));
3685         }
3686      });
3687      objectSwaps = u(_objectSwaps);
3688
3689      cmCache = Cache.<Class,ClassMeta>create().supplier(type -> new ClassMeta<>(type, this)).build();
3690      cmString = cmCache.get(String.class);
3691      cmObject = cmCache.get(Object.class);
3692
3693      beanRegistry = new BeanRegistry(this, null, list());
3694      defaultSession = createSession().unmodifiable().build();
3695      beanToStringSerializer = mem(() -> JsonSerializer.create().beanContext(this).sq().simpleAttrs().build());
3696   }
3697
3698   /**
3699    * Converts the specified value to the specified class type.
3700    *
3701    * <p>
3702    * This is a shortcut for the following code:  <c>createSession().build().convertToType(<jv>value</jv>, <jv>type</jv>);</c>
3703    *
3704    * @param <T> The class type to convert the value to.
3705    * @param value The value to convert.
3706    * @param type The class type to convert the value to.
3707    * @throws InvalidDataConversionException If the specified value cannot be converted to the specified type.
3708    * @return The converted value.
3709    * @see BeanSession#convertToType(Object, Class)
3710    */
3711   public final <T> T convertToType(Object value, Class<T> type) throws InvalidDataConversionException {
3712      return defaultSession.convertToType(value, type);
3713   }
3714
3715   @Override /* Overridden from Context */
3716   public Builder copy() {
3717      return new Builder(this);
3718   }
3719
3720   @Override /* Overridden from Context */
3721   public BeanSession.Builder createSession() {
3722      return BeanSession.create(this);
3723   }
3724
3725   /**
3726    * Minimum bean class visibility.
3727    *
3728    * @see BeanContext.Builder#beanClassVisibility(Visibility)
3729    * @return
3730    *    Classes are not considered beans unless they meet the minimum visibility requirements.
3731    */
3732   public final Visibility getBeanClassVisibility() { return beanClassVisibility; }
3733
3734   /**
3735    * Minimum bean constructor visibility.
3736    *
3737    * @see BeanContext.Builder#beanConstructorVisibility(Visibility)
3738    * @return
3739    *    Only look for constructors with this specified minimum visibility.
3740    */
3741   public final Visibility getBeanConstructorVisibility() { return beanConstructorVisibility; }
3742
3743   /**
3744    * Bean dictionary.
3745    *
3746    * @see BeanContext.Builder#beanDictionary()
3747    * @return
3748    *    The list of classes that make up the bean dictionary in this bean context.
3749    *    <br>Never <jk>null</jk>.
3750    *    <br>List is unmodifiable.
3751    */
3752   public final List<ClassInfo> getBeanDictionary() { return beanDictionary; }
3753
3754   /**
3755    * Minimum bean field visibility.
3756    *
3757    *
3758    * @see BeanContext.Builder#beanFieldVisibility(Visibility)
3759    * @return
3760    *    Only look for bean fields with this specified minimum visibility.
3761    */
3762   public final Visibility getBeanFieldVisibility() { return beanFieldVisibility; }
3763
3764   /**
3765    * Returns the {@link BeanMeta} class for the specified class.
3766    *
3767    * @param <T> The class type to get the meta-data on.
3768    * @param c The class to get the meta-data on.
3769    *    <br>Cannot be <jk>null</jk>.
3770    * @return
3771    *    The {@link BeanMeta} for the specified class, or <jk>null</jk> if the class is not a bean per the settings on
3772    *    this context.
3773    */
3774   public final <T> BeanMeta<T> getBeanMeta(Class<T> c) {
3775      assertArgNotNull("c", c);
3776      return getClassMeta(c).getBeanMeta();
3777   }
3778
3779   /**
3780    * Minimum bean method visibility.
3781    *
3782    * @see BeanContext.Builder#beanMethodVisibility(Visibility)
3783    * @return
3784    *    Only look for bean methods with this specified minimum visibility.
3785    */
3786   public final Visibility getBeanMethodVisibility() { return beanMethodVisibility; }
3787
3788
3789   /**
3790    * Bean type property name.
3791    *
3792    * @see BeanContext.Builder#typePropertyName(String)
3793    * @return
3794    * The name of the bean property used to store the dictionary name of a bean type so that the parser knows the data type to reconstruct.
3795    */
3796   public final String getBeanTypePropertyName() { return typePropertyName; }
3797
3798   /**
3799    * Construct a {@code ClassMeta} wrapper around a {@link Class} object.
3800    *
3801    * @param <T> The class type being wrapped.
3802    * @param type The class to resolve.
3803    * @return
3804    *    If the class is not an array, returns a cached {@link ClassMeta} object.
3805    *    Otherwise, returns a new {@link ClassMeta} object every time.
3806    */
3807   public final <T> ClassMeta<T> getClassMeta(Class<T> type) {
3808      // Non-cacheable classes (proxies, generated classes) should not be cached
3809      if (! isCacheable(type))
3810         return new ClassMeta<>(type, this);
3811      return cmCache.get(type);
3812   }
3813
3814   /**
3815    * Used to resolve <c>ClassMetas</c> of type <c>Collection</c> and <c>Map</c> that have
3816    * <c>ClassMeta</c> values that themselves could be collections or maps.
3817    *
3818    * <p>
3819    * <c>Collection</c> meta objects are assumed to be followed by zero or one meta objects indicating the element type.
3820    *
3821    * <p>
3822    * <c>Map</c> meta objects are assumed to be followed by zero or two meta objects indicating the key and value types.
3823    *
3824    * <p>
3825    * The array can be arbitrarily long to indicate arbitrarily complex data structures.
3826    *
3827    * <h5 class='section'>Examples:</h5>
3828    * <ul>
3829    *    <li><code>getClassMeta(String.<jk>class</jk>);</code> - A normal type.
3830    *    <li><code>getClassMeta(List.<jk>class</jk>);</code> - A list containing objects.
3831    *    <li><code>getClassMeta(List.<jk>class</jk>, String.<jk>class</jk>);</code> - A list containing strings.
3832    *    <li><code>getClassMeta(LinkedList.<jk>class</jk>, String.<jk>class</jk>);</code> - A linked-list containing
3833    *       strings.
3834    *    <li><code>getClassMeta(LinkedList.<jk>class</jk>, LinkedList.<jk>class</jk>, String.<jk>class</jk>);</code> -
3835    *       A linked-list containing linked-lists of strings.
3836    *    <li><code>getClassMeta(Map.<jk>class</jk>);</code> - A map containing object keys/values.
3837    *    <li><code>getClassMeta(Map.<jk>class</jk>, String.<jk>class</jk>, String.<jk>class</jk>);</code> - A map
3838    *       containing string keys/values.
3839    *    <li><code>getClassMeta(Map.<jk>class</jk>, String.<jk>class</jk>, List.<jk>class</jk>, MyBean.<jk>class</jk>);</code> -
3840    *       A map containing string keys and values of lists containing beans.
3841    * </ul>
3842    *
3843    * @param <T>
3844    *    The class to resolve.
3845    * @param type
3846    *    The class to resolve.
3847    *    <br>Can be any of the following: {@link ClassMeta}, {@link ClassInfo}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
3848    * @param args
3849    *    The type arguments of the class if it's a collection or map.
3850    *    <br>Can be any of the following: {@link ClassMeta}, {@link ClassInfo}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
3851    *    <br>Ignored if the main type is not a map or collection.
3852    * @return The resolved class meta.
3853    */
3854   public final <T> ClassMeta<T> getClassMeta(Type type, Type...args) {
3855      if (type == null)
3856         return null;
3857      var cm = (ClassMeta<T>)null;
3858      if (type instanceof Class type2)
3859         cm = getClassMeta(type2);
3860      else
3861         cm = resolveClassMeta(type, null);
3862      if (args.length == 0)
3863         return cm;
3864      var cma = new ClassMeta<?>[args.length + 1];
3865      cma[0] = cm;
3866      for (var i = 0; i < length(args); i++) {
3867         var arg = (Type)Array.get(args, i);
3868         if (arg instanceof Class arg2)
3869            cma[i + 1] = getClassMeta(arg2);
3870         else
3871            cma[i + 1] = resolveClassMeta(arg, null);
3872      }
3873      return (ClassMeta<T>)getTypedClassMeta(cma, 0);
3874   }
3875
3876   /**
3877    * Shortcut for calling {@code getClassMeta(o.getClass())}.
3878    *
3879    * @param <T> The class of the object being passed in.
3880    * @param o The class to find the class type for.
3881    *    <br>Cannot be <jk>null</jk>.
3882    * @return The ClassMeta object.
3883    */
3884   public final <T> ClassMeta<T> getClassMetaForObject(T o) {
3885      assertArgNotNull("o", o);
3886      return (ClassMeta<T>)getClassMeta(o.getClass());
3887   }
3888
3889   /**
3890    * Locale.
3891    *
3892    * @see BeanContext.Builder#locale(Locale)
3893    * @return
3894    *    The default locale for serializer and parser sessions.
3895    */
3896   public final Locale getDefaultLocale() { return locale; }
3897
3898   /**
3899    * Media type.
3900    *
3901    * @see BeanContext.Builder#mediaType(MediaType)
3902    * @return
3903    *    The default media type value for serializer and parser sessions.
3904    */
3905   public final MediaType getDefaultMediaType() { return mediaType; }
3906
3907   /**
3908    * Time zone.
3909    *
3910    * @see BeanContext.Builder#timeZone(TimeZone)
3911    * @return
3912    *    The default timezone for serializer and parser sessions.
3913    */
3914   public final TimeZone getDefaultTimeZone() { return timeZone; }
3915
3916   /**
3917    * Bean package exclusions.
3918    *
3919    * @see BeanContext.Builder#notBeanPackages(String...)
3920    * @return
3921    *    The set of fully-qualified package names to exclude from being classified as beans.
3922    *    <br>Never <jk>null</jk>.
3923    *    <br>Set is unmodifiable.
3924    *    <br>Backed by a {@link LinkedHashSet} to preserve insertion order.
3925    */
3926   public final Set<String> getNotBeanPackagesNames() { return notBeanPackageNames; }
3927
3928   /**
3929    * Bean property namer.
3930    *
3931    * @see BeanContext.Builder#propertyNamer(Class)
3932    * @return
3933    *    The interface used to calculate bean property names.
3934    */
3935   public final PropertyNamer getPropertyNamer() { return propertyNamerBean; }
3936
3937   @Override /* Overridden from Context */
3938   public BeanSession getSession() { return defaultSession; }
3939
3940   /**
3941    * Java object swaps.
3942    *
3943    * @see BeanContext.Builder#swaps(Class...)
3944    * @return
3945    *    The list POJO swaps defined.
3946    *    <br>Never <jk>null</jk>.
3947    *    <br>List is unmodifiable.
3948    */
3949   public final List<ObjectSwap<?,?>> getSwaps() { return objectSwaps; }
3950
3951   /**
3952    * Returns <jk>true</jk> if the specified bean context shares the same cache as this bean context.
3953    *
3954    * <p>
3955    * Useful for testing purposes.
3956    *
3957    * @param bc The bean context to compare to.
3958    *    <br>Cannot be <jk>null</jk>.
3959    * @return <jk>true</jk> if the bean contexts have equivalent settings and thus share caches.
3960    */
3961   public final boolean hasSameCache(BeanContext bc) {
3962      assertArgNotNull("bc", bc);
3963      return bc.getCmCache() == this.getCmCache();
3964   }
3965
3966   /**
3967    * BeanMap.put() returns old property value.
3968    *
3969    * @see BeanContext.Builder#beanMapPutReturnsOldValue()
3970    * @return
3971    *    <jk>true</jk> if the {@link BeanMap#put(String,Object) BeanMap.put()} method will return old property values.
3972    *    <br>Otherwise, it returns <jk>null</jk>.
3973    */
3974   public final boolean isBeanMapPutReturnsOldValue() { return beanMapPutReturnsOldValue; }
3975
3976   /**
3977    * Beans require no-arg constructors.
3978    *
3979    * @see BeanContext.Builder#beansRequireDefaultConstructor()
3980    * @return
3981    *    <jk>true</jk> if a Java class must implement a default no-arg constructor to be considered a bean.
3982    *    <br>Otherwise, the bean will be serialized as a string using the {@link Object#toString()} method.
3983    */
3984   public final boolean isBeansRequireDefaultConstructor() { return beansRequireDefaultConstructor; }
3985
3986   /**
3987    * Beans require Serializable interface.
3988    *
3989    * @see BeanContext.Builder#beansRequireSerializable()
3990    * @return
3991    *    <jk>true</jk> if a Java class must implement the {@link Serializable} interface to be considered a bean.
3992    *    <br>Otherwise, the bean will be serialized as a string using the {@link Object#toString()} method.
3993    */
3994   public final boolean isBeansRequireSerializable() { return beansRequireSerializable; }
3995
3996   /**
3997    * Beans require setters for getters.
3998    *
3999    * @see BeanContext.Builder#beansRequireSettersForGetters()
4000    * @return
4001    *    <jk>true</jk> if only getters that have equivalent setters will be considered as properties on a bean.
4002    *    <br>Otherwise, they are ignored.
4003    */
4004   public final boolean isBeansRequireSettersForGetters() { return beansRequireSettersForGetters; }
4005
4006   /**
4007    * Beans require at least one property.
4008    *
4009    * @see BeanContext.Builder#disableBeansRequireSomeProperties()
4010    * @return
4011    *    <jk>true</jk> if a Java class doesn't need to contain at least 1 property to be considered a bean.
4012    *    <br>Otherwise, the bean is serialized as a string using the {@link Object#toString()} method.
4013    */
4014   public final boolean isBeansRequireSomeProperties() { return beansRequireSomeProperties; }
4015
4016   /**
4017    * Find fluent setters.
4018    *
4019    * <h5 class='section'>Description:</h5>
4020    * <p>
4021    *
4022    * @see BeanContext.Builder#findFluentSetters()
4023    * @return
4024    *    <jk>true</jk> if fluent setters are detected on beans.
4025    */
4026   public final boolean isFindFluentSetters() { return findFluentSetters; }
4027
4028   /**
4029    * Ignore invocation errors on getters.
4030    *
4031    * @see BeanContext.Builder#ignoreInvocationExceptionsOnGetters()
4032    * @return
4033    *    <jk>true</jk> if errors thrown when calling bean getter methods are silently ignored.
4034    */
4035   public final boolean isIgnoreInvocationExceptionsOnGetters() { return ignoreInvocationExceptionsOnGetters; }
4036
4037   /**
4038    * Ignore invocation errors on setters.
4039    *
4040    * @see BeanContext.Builder#ignoreInvocationExceptionsOnSetters()
4041    * @return
4042    *    <jk>true</jk> if errors thrown when calling bean setter methods are silently ignored.
4043    */
4044   public final boolean isIgnoreInvocationExceptionsOnSetters() { return ignoreInvocationExceptionsOnSetters; }
4045
4046   /**
4047    * Silently ignore missing setters.
4048    *
4049    * @see BeanContext.Builder#disableIgnoreMissingSetters()
4050    * @return
4051    *    <jk>true</jk> if trying to set a value on a bean property without a setter should throw a {@link BeanRuntimeException}.
4052    */
4053   public final boolean isIgnoreMissingSetters() { return ignoreMissingSetters; }
4054
4055   /**
4056    * Ignore unknown properties.
4057    *
4058    * @see BeanContext.Builder#ignoreUnknownBeanProperties()
4059    * @return
4060    *    <jk>true</jk> if trying to set a value on a non-existent bean property is silently ignored.
4061    *    <br>Otherwise, a {@code RuntimeException} is thrown.
4062    */
4063   public final boolean isIgnoreUnknownBeanProperties() { return ignoreUnknownBeanProperties; }
4064
4065   /**
4066    * Ignore unknown enum values.
4067    *
4068    * @see BeanContext.Builder#ignoreUnknownEnumValues()
4069    * @return
4070    *    <jk>true</jk> if unknown enum values should be set as <jk>null</jk> instead of throwing an exception.
4071    */
4072   public final boolean isIgnoreUnknownEnumValues() { return ignoreUnknownEnumValues; }
4073
4074   /**
4075    * Ignore unknown properties with null values.
4076    *
4077    * @see BeanContext.Builder#disableIgnoreUnknownNullBeanProperties()
4078    * @return
4079    *    <jk>true</jk> if trying to set a <jk>null</jk> value on a non-existent bean property should throw a {@link BeanRuntimeException}.
4080    */
4081   public final boolean isIgnoreUnknownNullBeanProperties() { return ignoreUnknownNullBeanProperties; }
4082
4083   /**
4084    * Sort bean properties.
4085    *
4086    * @see BeanContext.Builder#sortProperties()
4087    * @return
4088    *    <jk>true</jk> if all bean properties will be serialized and access in alphabetical order.
4089    */
4090   public final boolean isSortProperties() { return sortProperties; }
4091
4092   /**
4093    * Use enum names.
4094    *
4095    * @see BeanContext.Builder#useEnumNames()
4096    * @return
4097    *    <jk>true</jk> if enums are always serialized by name, not using {@link Object#toString()}.
4098    */
4099   public final boolean isUseEnumNames() { return useEnumNames; }
4100
4101   /**
4102    * Use interface proxies.
4103    *
4104    * @see BeanContext.Builder#disableInterfaceProxies()
4105    * @return
4106    *    <jk>true</jk> if interfaces will be instantiated as proxy classes through the use of an
4107    *    {@link InvocationHandler} if there is no other way of instantiating them.
4108    */
4109   public final boolean isUseInterfaceProxies() { return useInterfaceProxies; }
4110
4111   /**
4112    * Use Java Introspector.
4113    *
4114    * @see BeanContext.Builder#useJavaBeanIntrospector()
4115    * @return
4116    *    <jk>true</jk> if the built-in Java bean introspector should be used for bean introspection.
4117    */
4118   public final boolean isUseJavaBeanIntrospector() { return useJavaBeanIntrospector; }
4119
4120   /**
4121    * Creates a new {@link BeanMap} object (a modifiable {@link Map}) of the given class with uninitialized
4122    * property values.
4123    *
4124    * <p>
4125    * This is a shortcut for the following code:  <c>createSession().build().newBeanMap(<jv>_class</jv>);</c>
4126    *
4127    * <h5 class='section'>Example:</h5>
4128    * <p class='bjava'>
4129    *    <jc>// Construct a new bean map wrapped around a new Person object</jc>
4130    *    BeanMap&lt;Person&gt; <jv>beanMap</jv> = BeanContext.<jsf>DEFAULT</jsf>.newBeanMap(Person.<jk>class</jk>);
4131    * </p>
4132    *
4133    * @param <T> The class of the object being wrapped.
4134    * @param c The name of the class to create a new instance of.
4135    *    <br>Cannot be <jk>null</jk>.
4136    * @return A new instance of the class.
4137    * @see BeanSession#newBeanMap(Class)
4138    */
4139   public <T> BeanMap<T> newBeanMap(Class<T> c) {
4140      assertArgNotNull("c", c);
4141      return defaultSession.newBeanMap(c);
4142   }
4143
4144   /**
4145    * Wraps an object inside a {@link BeanMap} object (a modifiable {@link Map}).
4146    *
4147    * <p>
4148    * This is a shortcut for the following code:  <c>createSession().build().toBeanMap(<jv>object</jv>);</c>
4149    *
4150    * <h5 class='section'>Example:</h5>
4151    * <p class='bjava'>
4152    *    <jc>// Construct a bean map around a bean instance</jc>
4153    *    BeanMap&lt;Person&gt; <jv>beanMap</jv> = BeanContext.<jsf>DEFAULT</jsf>.toBeanMap(<jk>new</jk> Person());
4154    * </p>
4155    *
4156    * @param <T> The class of the object being wrapped.
4157    * @param object The object to wrap in a map interface.
4158    *    <br>Cannot be <jk>null</jk>.
4159    * @return The wrapped object.
4160    * @see BeanSession#toBeanMap(Object)
4161    */
4162   public <T> BeanMap<T> toBeanMap(T object) {
4163      assertArgNotNull("object", object);
4164      return defaultSession.toBeanMap(object);
4165   }
4166
4167   /**
4168    * Returns the lookup table for resolving bean types by name.
4169    *
4170    * @return The lookup table for resolving bean types by name.
4171    */
4172   protected final BeanRegistry getBeanRegistry() { return beanRegistry; }
4173
4174   /**
4175    * Returns the serializer to use for serializing beans when using the {@link BeanSession#convertToType(Object, Class)}
4176    * and related methods.
4177    *
4178    * @return The serializer.  May be <jk>null</jk> if all initialization has occurred.
4179    */
4180   protected WriterSerializer getBeanToStringSerializer() {
4181      return beanToStringSerializer.get();
4182   }
4183
4184   /**
4185    * Class metadata cache.
4186    *
4187    * @return The class metadata cache.
4188    */
4189   protected final Cache<Class,ClassMeta> getCmCache() { return cmCache; }
4190
4191
4192   /**
4193    * Hash key.
4194    *
4195    * @return The hash key.
4196    */
4197   protected final HashKey getHashKey() { return hashKey; }
4198
4199   /**
4200    * Locale.
4201    *
4202    * @return The locale.
4203    */
4204   protected final Locale getLocale() { return locale; }
4205
4206   /**
4207    * Media type.
4208    *
4209    * @return The media type.
4210    */
4211   protected final MediaType getMediaType() { return mediaType; }
4212
4213   /**
4214    * Bean class exclusions.
4215    *
4216    * @see BeanContext.Builder#notBeanClasses(ClassInfo...)
4217    * @return
4218    *    The list of classes that are explicitly not beans.
4219    *    <br>Never <jk>null</jk>.
4220    *    <br>List is unmodifiable.
4221    */
4222   protected final List<ClassInfo> getNotBeanClasses() { return notBeanClasses; }
4223
4224   /**
4225    * Time zone.
4226    *
4227    * @return The time zone.
4228    */
4229   protected final TimeZone getTimeZone() { return timeZone; }
4230
4231   /**
4232    * Ignore transient fields.
4233    *
4234    * @see BeanContext.Builder#disableIgnoreTransientFields()
4235    * @return
4236    *    <jk>true</jk> if fields and methods marked as transient should not be ignored.
4237    */
4238   protected final boolean isIgnoreTransientFields() { return ignoreTransientFields; }
4239
4240   /**
4241    * Determines whether the specified class is ignored as a bean class based on the various exclusion parameters
4242    * specified on this context class.
4243    *
4244    * @param ci The class info being tested.
4245    * @return <jk>true</jk> if the specified class matches any of the exclusion parameters.
4246    */
4247   protected final boolean isNotABean(ClassInfo ci) {
4248      if (ci.isArray() || ci.isPrimitive() || ci.isEnum() || ci.isAnnotation())
4249         return true;
4250      var p = ci.getPackage();
4251      if (nn(p)) {
4252         var pn = p.getName();
4253         for (var p2 : notBeanPackageNames)
4254            if (pn.equals(p2))
4255               return true;
4256         for (var p2 : notBeanPackagePrefixes)
4257            if (pn.startsWith(p2))
4258               return true;
4259      }
4260      for (var exclude : notBeanClasses)
4261         if (ci.isChildOf(exclude))
4262            return true;
4263      return false;
4264   }
4265
4266   /**
4267    * Returns a reusable {@link ClassMeta} representation for the class <c>Object</c>.
4268    *
4269    * <p>
4270    * This <c>ClassMeta</c> is often used to represent "any object type" when an object type is not known.
4271    *
4272    * <p>
4273    * This method is identical to calling <code>getClassMeta(Object.<jk>class</jk>)</code> but uses a cached copy to
4274    * avoid a hashmap lookup.
4275    *
4276    * @return The {@link ClassMeta} object associated with the <c>Object</c> class.
4277    */
4278   protected final ClassMeta<Object> object() {
4279      return cmObject;
4280   }
4281
4282   @Override /* Overridden from Context */
4283   protected FluentMap<String,Object> properties() {
4284      return super.properties()
4285         .a("beanClassVisibility", beanClassVisibility)
4286         .a("beanConstructorVisibility", beanConstructorVisibility)
4287         .a("beanDictionary", beanDictionary)
4288         .a("beanFieldVisibility", beanFieldVisibility)
4289         .a("beanMethodVisibility", beanMethodVisibility)
4290         .a("beansRequireDefaultConstructor", beansRequireDefaultConstructor)
4291         .a("beansRequireSerializable", beansRequireSerializable)
4292         .a("beansRequireSettersForGetters", beansRequireSettersForGetters)
4293         .a("beansRequireSomeProperties", beansRequireSomeProperties)
4294         .a("id", System.identityHashCode(this))
4295         .a("ignoreInvocationExceptionsOnGetters", ignoreInvocationExceptionsOnGetters)
4296         .a("ignoreInvocationExceptionsOnSetters", ignoreInvocationExceptionsOnSetters)
4297         .a("ignoreTransientFields", ignoreTransientFields)
4298         .a("ignoreUnknownBeanProperties", ignoreUnknownBeanProperties)
4299         .a("ignoreUnknownNullBeanProperties", ignoreUnknownNullBeanProperties)
4300         .a("notBeanClasses", notBeanClasses)
4301         .a("notBeanPackageNames", notBeanPackageNames)
4302         .a("notBeanPackagePrefixes", notBeanPackagePrefixes)
4303         .a("sortProperties", sortProperties)
4304         .a("swaps", swaps)
4305         .a("useEnumNames", useEnumNames)
4306         .a("useInterfaceProxies", useInterfaceProxies)
4307         .a("useJavaBeanIntrospector", useJavaBeanIntrospector);
4308   }
4309
4310   /**
4311    * Used for determining the class type on a method or field where a {@code @Beanp} annotation may be present.
4312    *
4313    * @param <T> The class type we're wrapping.
4314    * @param p The property annotation info on the type if there is one.
4315    * @param ci The class info for the type.
4316    * @param typeVarImpls
4317    *    Contains known resolved type parameters on the specified class so that we can result
4318    *    {@code ParameterizedTypes} and {@code TypeVariables}.
4319    *    Can be <jk>null</jk> if the information is not known.
4320    * @return The new {@code ClassMeta} object wrapped around the type.
4321    */
4322   protected final <T> ClassMeta<T> resolveClassMeta(AnnotationInfo<Beanp> p, ClassInfo ci, TypeVariables typeVarImpls) {
4323      var cm = resolveClassMeta(ci, typeVarImpls);
4324      var cm2 = cm;
4325
4326      if (nn(p)) {
4327         var beanp = p.inner();
4328
4329         if (isNotVoid(beanp.type()))
4330            cm2 = resolveClassMeta(beanp.type(), typeVarImpls);
4331
4332         if (cm2.isMap()) {
4333            var pParams = (beanp.params().length == 0 ? a(Object.class, Object.class) : beanp.params());
4334            if (pParams.length != 2)
4335               throw rex("Invalid number of parameters specified for Map (must be 2): {0}", pParams.length);
4336            var keyType = resolveType(pParams[0], cm2.getKeyType(), cm.getKeyType());
4337            var valueType = resolveType(pParams[1], cm2.getValueType(), cm.getValueType());
4338            if (keyType.isObject() && valueType.isObject())
4339               return cm2;
4340            return new ClassMeta<>(cm2, keyType, valueType, null);
4341         }
4342
4343         if (cm2.isCollection() || cm2.isOptional()) {
4344            var pParams = (beanp.params().length == 0 ? a(Object.class) : beanp.params());
4345            if (pParams.length != 1)
4346               throw rex("Invalid number of parameters specified for {1} (must be 1): {0}", pParams.length, (cm2.isCollection() ? "Collection" : cm2.isOptional() ? "Optional" : "Array"));
4347            var elementType = resolveType(pParams[0], cm2.getElementType(), cm.getElementType());
4348            if (elementType.isObject())
4349               return cm2;
4350            return new ClassMeta<>(cm2, null, null, elementType);
4351         }
4352
4353         return cm2;
4354      }
4355
4356      return cm;
4357   }
4358
4359   /**
4360    * Returns a reusable {@link ClassMeta} representation for the class <c>String</c>.
4361    *
4362    * <p>
4363    * This <c>ClassMeta</c> is often used to represent key types in maps.
4364    *
4365    * <p>
4366    * This method is identical to calling <code>getClassMeta(String.<jk>class</jk>)</code> but uses a cached copy to
4367    * avoid a hashmap lookup.
4368    *
4369    * @return The {@link ClassMeta} object associated with the <c>String</c> class.
4370    */
4371   protected final ClassMeta<String> string() {
4372      return cmString;
4373   }
4374
4375   final ClassMeta[] findParameters(Type o, Class c) {
4376      if (o == null)
4377         o = c;
4378
4379      // Loop until we find a ParameterizedType
4380      if (! (o instanceof ParameterizedType)) {
4381         loop: do {
4382            o = c.getGenericSuperclass();
4383            if (o instanceof ParameterizedType)
4384               break loop;
4385            for (var t : c.getGenericInterfaces()) {
4386               o = t;
4387               if (o instanceof ParameterizedType)
4388                  break loop;
4389            }
4390            c = c.getSuperclass();
4391         } while (nn(c));
4392      }
4393
4394      if (o instanceof ParameterizedType o2) {
4395         if (! o2.getRawType().equals(Enum.class)) {
4396            var l = new LinkedList<ClassMeta<?>>();
4397            for (var pt2 : o2.getActualTypeArguments()) {
4398               if (pt2 instanceof WildcardType || pt2 instanceof TypeVariable)
4399                  return null;
4400               l.add(resolveClassMeta(pt2, null));
4401            }
4402            if (l.isEmpty())
4403               return null;
4404            return l.toArray(new ClassMeta[l.size()]);
4405         }
4406      }
4407
4408      return null;
4409   }
4410
4411   final ClassMeta resolveClassMeta(Type o, TypeVariables typeVars) {
4412      if (o == null)
4413         return null;
4414
4415      if (o instanceof ClassMeta<?> cm) {
4416
4417         // This classmeta could have been created by a different context.
4418         // Need to re-resolve it to pick up ObjectSwaps and stuff on this context.
4419         if (cm.getBeanContext() == this)
4420            return cm;
4421         if (cm.isMap())
4422            return getClassMeta(cm.inner(), cm.getKeyType(), cm.getValueType());
4423         if (cm.isCollection() || cm.isOptional())
4424            return getClassMeta(cm.inner(), cm.getElementType());
4425         return getClassMeta(cm.inner());
4426      }
4427
4428      // Handle ClassInfo by extracting the underlying Type
4429      if (o instanceof ClassInfo ci) {
4430         return resolveClassMeta(ci.innerType(), typeVars);
4431      }
4432
4433      var c = TypeVariables.resolve(o, typeVars);
4434
4435      // This can happen when trying to resolve the "E getFirst()" method on LinkedList, whose type is a TypeVariable
4436      // These should just resolve to Object.
4437      if (c == null)
4438         return object();
4439
4440      var rawType = getClassMeta(c);
4441
4442      // If this is a Map or Collection, and the parameter types aren't part
4443      // of the class definition itself (e.g. class AddressBook extends List<Person>),
4444      // then we need to figure out the parameters.
4445      if (rawType.isMap() || rawType.isCollection() || rawType.isOptional()) {
4446         var params = findParameters(o, c);
4447         if (params == null)
4448            return rawType;
4449         if (rawType.isMap()) {
4450            if (params.length != 2 || (params[0].isObject() && params[1].isObject()))
4451               return rawType;
4452            return new ClassMeta(rawType, params[0], params[1], null);
4453         }
4454         if (rawType.isCollection() || rawType.isOptional()) {
4455            if (params.length != 1 || params[0].isObject())
4456               return rawType;
4457            return new ClassMeta(rawType, null, null, params[0]);
4458         }
4459      }
4460
4461      if (rawType.isArray()) {
4462         if (o instanceof GenericArrayType o2) {
4463            var elementType = resolveClassMeta(o2.getGenericComponentType(), typeVars);
4464            return new ClassMeta(rawType, null, null, elementType);
4465         }
4466      }
4467
4468      return rawType;
4469   }
4470
4471   /*
4472    * Resolves the 'genericized' class meta at the specified position in the ClassMeta array.
4473    */
4474   private ClassMeta<?> getTypedClassMeta(ClassMeta<?>[] c, int pos) {
4475      var cm = c[pos++];
4476      if (cm.isCollection() || cm.isOptional()) {
4477         var ce = c.length == pos ? object() : getTypedClassMeta(c, pos);
4478         return (ce.isObject() ? cm : new ClassMeta(cm, null, null, ce));
4479      } else if (cm.isMap()) {
4480         var ck = c.length == pos ? object() : c[pos++];
4481         var cv = c.length == pos ? object() : getTypedClassMeta(c, pos);
4482         return (ck.isObject() && cv.isObject() ? cm : new ClassMeta(cm, ck, cv, null));
4483      }
4484      return cm;
4485   }
4486
4487
4488   private ClassMeta<?> resolveType(Type...t) {
4489      for (var tt : t) {
4490         if (nn(tt)) {
4491            var cm = getClassMeta(tt);
4492            if (tt != cmObject)
4493               return cm;
4494         }
4495      }
4496      return cmObject;
4497   }
4498}