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.marshall;
018
019import static org.apache.juneau.commons.function.Suppliers.*;
020import static org.apache.juneau.commons.reflect.ReflectionUtils.*;
021import static org.apache.juneau.commons.reflect.Visibility.*;
022import static org.apache.juneau.commons.utils.ClassUtils.*;
023import static org.apache.juneau.commons.utils.CollectionUtils.*;
024import static org.apache.juneau.commons.utils.Shorts.*;
025import static org.apache.juneau.commons.utils.StringUtils.*;
026import static org.apache.juneau.commons.utils.SystemUtils.*;
027import static org.apache.juneau.commons.utils.ThrowableUtils.*;
028
029import java.beans.*;
030import java.io.*;
031import java.lang.reflect.*;
032import java.math.*;
033import java.net.*;
034import java.nio.charset.*;
035import java.time.*;
036import java.time.temporal.*;
037import java.util.*;
038import java.util.stream.*;
039
040import org.apache.juneau.commons.*;
041import org.apache.juneau.commons.bean.*;
042import org.apache.juneau.commons.collections.*;
043import org.apache.juneau.commons.conversion.*;
044import org.apache.juneau.commons.function.*;
045import org.apache.juneau.commons.http.*;
046import org.apache.juneau.commons.httppart.*;
047import org.apache.juneau.commons.inject.*;
048import org.apache.juneau.commons.reflect.*;
049import org.apache.juneau.commons.reflect.Visibility;
050import org.apache.juneau.marshall.collections.*;
051import org.apache.juneau.marshall.json5.*;
052import org.apache.juneau.marshall.marshaller.*;
053import org.apache.juneau.marshall.parser.*;
054import org.apache.juneau.marshall.serializer.*;
055import org.apache.juneau.marshall.swap.spi.*;
056import org.apache.juneau.marshall.utils.*;
057
058/**
059 * Bean context.
060 *
061 * <p>
062 * This class servers multiple purposes:
063 * <ul class='spaced-list'>
064 *    <li>
065 *       Provides the ability to wrap beans inside {@link Map} interfaces.
066 *    <li>
067 *       Serves as a repository for metadata on POJOs, such as associated {@link Bean @Marshalled} annotations,
068 *       {@link PropertyNamer PropertyNamers}, etc...  which are used to tailor how POJOs are serialized and parsed.
069 * </ul>
070 *
071 * <p>
072 * All serializers and parsers use this context so that they can handle POJOs using a common framework.
073 *
074 * <h5 class='topic'>Bean Contexts</h5>
075 *
076 * <p>
077 * Bean contexts are created through the {@link MarshallingContext#create() MarshallingContext.create()} and {@link Builder#build()} methods.
078 * <br>These context objects are read-only, reusable, and thread-safe.
079 *
080 * <p>
081 * Each bean context maintains a cache of {@link ClassMeta} objects that describe information about classes encountered.
082 * These <c>ClassMeta</c> objects are time-consuming to construct.
083 * Therefore, instances of {@link MarshallingContext} that share the same <js>"MarshallingContext.*"</js> property values share
084 * the same cache.  This allows for efficient reuse of <c>ClassMeta</c> objects so that the information about
085 * classes only needs to be calculated once.
086 * Because of this, many of the properties defined on the {@link MarshallingContext} class cannot be overridden on the session.
087 *
088 * <h5 class='topic'>Bean Sessions</h5>
089 *
090 * <p>
091 * Whereas <c>MarshallingContext</c> objects are permanent, unchangeable, cached, and thread-safe,
092 * {@link MarshallingSession} objects are ephemeral and not thread-safe.
093 * They are meant to be used as quickly-constructed scratchpads for creating bean maps.
094 * {@link BeanMap} objects can only be created through the session.
095 *
096 * <h5 class='topic'>MarshallingContext configuration properties</h5>
097 *
098 * <p>
099 * <c>BeanContexts</c> have several configuration properties that can be used to tweak behavior on how beans are
100 * handled.  These are denoted as the static <jsf>BEAN_*</jsf> fields on this class.
101 *
102 * <p>
103 * Some settings (e.g. {@link Builder#beansRequireDefaultConstructor()}) are used to differentiate between bean
104 * and non-bean classes.
105 * Attempting to create a bean map around one of these objects will throw a {@link BeanRuntimeException}.
106 * The purpose for this behavior is so that the serializers can identify these non-bean classes and convert them to
107 * plain strings using the {@link Object#toString()} method.
108 *
109 * <p>
110 * Some settings (e.g. {@link Builder#beanFieldVisibility(Visibility)}) are used to determine what kinds of properties are
111 * detected on beans.
112 *
113 * <p>
114 * Some settings (e.g. {@link Builder#beanMapPutReturnsOldValue()}) change the runtime behavior of bean maps.
115 *
116 * <h5 class='section'>Example:</h5>
117 *
118 * <p class='bjava'>
119 *    <jc>// Construct a context from scratch.</jc>
120 *    MarshallingContext <jv>marshallingContext</jv> = MarshallingContext
121 *       .<jsm>create</jsm>()
122 *       .beansRequireDefaultConstructor()
123 *       .notBeanClasses(Foo.<jk>class</jk>)
124 *       .build();
125 * </p>
126 *
127 * <h5 class='topic'>Bean Maps</h5>
128 *
129 * <p>
130 * {@link BeanMap BeanMaps} are wrappers around Java beans that allow properties to be retrieved and
131 * set using the common {@link Map#put(Object,Object)} and {@link Map#get(Object)} methods.
132 *
133 * <p>
134 * Bean maps are created in two ways...
135 * <ol>
136 *    <li>{@link MarshallingSession#toBeanMap(Object) MarshallingSession.toBeanMap()} - Wraps an existing bean inside a {@code Map}
137 *       wrapper.
138 *    <li>{@link MarshallingSession#newBeanMap(Class) MarshallingSession.newBeanMap()} - Create a new bean instance wrapped in a
139 *       {@code Map} wrapper.
140 * </ol>
141 *
142 * <h5 class='section'>Example:</h5>
143 *
144 * <p class='bjava'>
145 *    <jc>// A sample bean class</jc>
146 *    <jk>public class</jk> Person {
147 *       <jk>public</jk> String getName();
148 *       <jk>public void</jk> setName(String <jv>name</jv>);
149 *       <jk>public int</jk> getAge();
150 *       <jk>public void</jk> setAge(<jk>int</jk> <jv>age</jv>);
151 *    }
152 *
153 *    <jc>// Create a new bean session</jc>
154 *    MarshallingSession <jv>session</jv> = MarshallingContext.<jsf>DEFAULT</jsf>.createSession();
155 *
156 *    <jc>// Wrap an existing bean in a new bean map</jc>
157 *    BeanMap&lt;Person&gt; <jv>map1</jv> = <jv>session</jv>.toBeanMap(<jk>new</jk> Person());
158 *    <jv>map1</jv>.put(<js>"name"</js>, <js>"John Smith"</js>);
159 *    <jv>map1</jv>.put(<js>"age"</js>, 45);
160 *
161 *    <jc>// Create a new bean instance wrapped in a new bean map</jc>
162 *    BeanMap&lt;Person&gt; <jv>map2</jv> = <jv>session</jv>.newBeanMap(Person.<jk>class</jk>);
163 *    <jv>map2</jv>.put(<js>"name"</js>, <js>"John Smith"</js>);
164 *    <jv>map2</jv>.put(<js>"age"</js>, 45);
165 *    Person <jv>person</jv> = <jv>map2</jv>.getBean();  <jc>// Get the bean instance that was created.</jc>
166 * </p>
167 *
168 * <h5 class='section'>Notes:</h5><ul>
169 *    <li class='note'>This class is thread safe and reusable.
170 * </ul>
171 *
172 * <h5 class='section'>See Also:</h5><ul>
173 *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/BeanContexts">Bean Contexts</a>
174 * </ul>
175 */
176@SuppressWarnings({
177   "java:S1192", // Duplicated literals (argument/property names) read more clearly inline than as constants
178   "java:S1452", // Wildcard required - ClassMeta<?> for parameter resolution and type variables
179   "java:S1612", // Lambdas used instead of method references for readability in complex chained expressions
180   "java:S3776", // findConversion() registers the whole conversion matrix in one method, and resolveClassMeta(Type, ...) dispatches over every Type shape
181   "java:S6539", // Monster class; MarshallingContext is intentionally the central bean-context configuration hub (also covers Collection.toArray() usage)
182   "rawtypes", // Raw types necessary for generic type handling
183   "unchecked" // Type erasure requires unchecked casts
184})
185public class MarshallingContext extends Context implements ConversionFinder, BeanTypeResolver {
186
187   /**
188    * Builder class.
189    */
190   public static class Builder extends Context.Builder<Builder> {
191
192      private static final Cache<HashKey,MarshallingContext> CACHE = Cache.of(HashKey.class, MarshallingContext.class).build();
193
194      private static int integer(boolean...values) {
195         var n = 0;
196         for (var b : values)
197            n = (n << 1) | (b ? 1 : 0);
198         return n;
199      }
200      private Visibility beanClassVisibility;
201      private Visibility beanConstructorVisibility;
202      private Visibility beanMethodVisibility;
203      private Visibility beanFieldVisibility;
204      private boolean disableBeansRequireSomeProperties;
205      private boolean beanMapPutReturnsOldValue;
206      private boolean beansRequireDefaultConstructor;
207      private boolean beansRequireSerializable;
208      private boolean beansRequireSettersForGetters;
209      private boolean disableIgnoreTransientFields;
210      private boolean disableIgnoreUnknownNullBeanProperties;
211      private boolean disableIgnoreMissingSetters;
212      private boolean disableInterfaceProxies;
213      private boolean findFluentSetters;
214      private boolean ignoreInvocationExceptionsOnGetters;
215      private boolean ignoreInvocationExceptionsOnSetters;
216      private boolean ignoreUnknownBeanProperties;
217      private boolean ignoreUnknownEnumValues;
218      private boolean unsortedProperties;
219      private boolean recordComponentOrder;
220      private boolean useJavaBeanIntrospector;
221      private boolean validateSchema;
222      private String typePropertyName;
223      private MediaType mediaType;
224      private Locale locale;
225      private TimeZone timeZone;
226      private DurationFormat durationFormat;
227      private PeriodFormat periodFormat;
228      private CalendarFormat calendarFormat;
229      private DateFormat dateFormat;
230      private TemporalFormat temporalFormat;
231      private TimeZoneFormat timeZoneFormat;
232      private LocaleFormat localeFormat;
233      private BinaryFormat binaryFormat;
234      private EnumFormat enumFormat;
235      private UuidFormat uuidFormat;
236      private BitSetFormat bitSetFormat;
237      private BigNumberFormat bigNumberFormat;
238      private BooleanFormat booleanFormat;
239      private FloatFormat floatFormat;
240      private CurrencyFormat currencyFormat;
241      private ClassFormat classFormat;
242      private ClassLoader classLoader;
243      private Class<? extends PropertyNamer> propertyNamer;
244      private final List<ClassInfo> beanDictionary;
245      private final List<Object> swaps;
246      private final Set<ClassInfo> notBeanClasses;
247      private final Set<String> notBeanPackages;
248      private BeanStore beanStore;
249      private String activeView;
250      private boolean disableDefaultViewInclusion;
251
252      /**
253       * Constructor.
254       *
255       * All default settings.
256       */
257      protected Builder() {
258         beanClassVisibility = env("MarshallingContext.beanClassVisibility", PUBLIC);
259         beanConstructorVisibility = env("MarshallingContext.beanConstructorVisibility", PUBLIC);
260         beanDictionary = list();
261         beanFieldVisibility = env("MarshallingContext.beanFieldVisibility", PUBLIC);
262         beanMapPutReturnsOldValue = env("MarshallingContext.beanMapPutReturnsOldValue", false);
263         beanMethodVisibility = env("MarshallingContext.beanMethodVisibility", PUBLIC);
264         beansRequireDefaultConstructor = env("MarshallingContext.beansRequireDefaultConstructor", false);
265         beansRequireSerializable = env("MarshallingContext.beansRequireSerializable", false);
266         beansRequireSettersForGetters = env("MarshallingContext.beansRequireSettersForGetters", false);
267         disableBeansRequireSomeProperties = env("MarshallingContext.disableBeansRequireSomeProperties", false);
268         disableIgnoreMissingSetters = env("MarshallingContext.disableIgnoreMissingSetters", false);
269         disableIgnoreTransientFields = env("MarshallingContext.disableIgnoreTransientFields", false);
270         disableIgnoreUnknownNullBeanProperties = env("MarshallingContext.disableIgnoreUnknownNullBeanProperties", false);
271         disableInterfaceProxies = env("MarshallingContext.disableInterfaceProxies", false);
272         findFluentSetters = env("MarshallingContext.findFluentSetters", false);
273         ignoreInvocationExceptionsOnGetters = env("MarshallingContext.ignoreInvocationExceptionsOnGetters", false);
274         ignoreInvocationExceptionsOnSetters = env("MarshallingContext.ignoreInvocationExceptionsOnSetters", false);
275         ignoreUnknownBeanProperties = env("MarshallingContext.ignoreUnknownBeanProperties", false);
276         ignoreUnknownEnumValues = env("MarshallingContext.ignoreUnknownEnumValues", false);
277         locale = env("MarshallingContext.locale").map(Locale::forLanguageTag).orElse(Locale.getDefault());
278         mediaType = env("MarshallingContext.mediaType").map(MediaType::of).orElse(null);
279         notBeanClasses = new TreeSet<>();
280         notBeanPackages = new TreeSet<>();
281         propertyNamer = null;
282         unsortedProperties = env("MarshallingContext.unsortedProperties", false);
283         recordComponentOrder = env("MarshallingContext.recordComponentOrder", false);
284         swaps = list();
285         timeZone = env("MarshallingContext.timeZone").map(TimeZone::getTimeZone).orElse(null);
286         durationFormat = env("MarshallingContext.durationFormat", DurationFormat.ISO_8601_WITH_DAYS);
287         periodFormat = env("MarshallingContext.periodFormat", PeriodFormat.ISO_8601);
288         calendarFormat = env("MarshallingContext.calendarFormat", CalendarFormat.ISO_OFFSET_DATE_TIME);
289         dateFormat = env("MarshallingContext.dateFormat", DateFormat.ISO_LOCAL_DATE_TIME);
290         temporalFormat = env("MarshallingContext.temporalFormat", TemporalFormat.DEFAULT);
291         timeZoneFormat = env("MarshallingContext.timeZoneFormat", TimeZoneFormat.ID);
292         localeFormat = env("MarshallingContext.localeFormat", LocaleFormat.BCP_47);
293         binaryFormat = env("MarshallingContext.binaryFormat", BinaryFormat.NOT_SET);
294         enumFormat = env("MarshallingContext.enumFormat", EnumFormat.TO_STRING);
295         uuidFormat = env("MarshallingContext.uuidFormat", UuidFormat.STANDARD);
296         bitSetFormat = env("MarshallingContext.bitSetFormat", BitSetFormat.INDICES);
297         bigNumberFormat = env("MarshallingContext.bigNumberFormat", BigNumberFormat.NUMBER);
298         booleanFormat = env("MarshallingContext.booleanFormat", BooleanFormat.TRUE_FALSE);
299         floatFormat = env("MarshallingContext.floatFormat", FloatFormat.NaN_AS_NULL);
300         currencyFormat = env("MarshallingContext.currencyFormat", CurrencyFormat.ISO_CODE);
301         classFormat = env("MarshallingContext.classFormat", ClassFormat.FQCN);
302         typePropertyName = env("MarshallingContext.typePropertyName", "_type");
303         useJavaBeanIntrospector = env("MarshallingContext.useJavaBeanIntrospector", false);
304         validateSchema = env("MarshallingContext.validateSchema", false);
305         beanStore = null;
306      }
307
308      /**
309       * Copy constructor.
310       *
311       * @param copyFrom The bean to copy from.
312       */
313      protected Builder(MarshallingContext copyFrom) {
314         super(copyFrom);
315         beanClassVisibility = copyFrom.beanClassVisibility;
316         beanConstructorVisibility = copyFrom.beanConstructorVisibility;
317         beanDictionary = cp(copyFrom.beanDictionary);
318         beanFieldVisibility = copyFrom.beanFieldVisibility;
319         beanMapPutReturnsOldValue = copyFrom.beanMapPutReturnsOldValue;
320         beanMethodVisibility = copyFrom.beanMethodVisibility;
321         beansRequireDefaultConstructor = copyFrom.beansRequireDefaultConstructor;
322         beansRequireSerializable = copyFrom.beansRequireSerializable;
323         beansRequireSettersForGetters = copyFrom.beansRequireSettersForGetters;
324         disableBeansRequireSomeProperties = ! copyFrom.beansRequireSomeProperties;
325         disableIgnoreMissingSetters = ! copyFrom.ignoreMissingSetters;
326         disableIgnoreTransientFields = ! copyFrom.ignoreTransientFields;
327         disableIgnoreUnknownNullBeanProperties = ! copyFrom.ignoreUnknownNullBeanProperties;
328         disableInterfaceProxies = ! copyFrom.useInterfaceProxies;
329         findFluentSetters = copyFrom.findFluentSetters;
330         ignoreInvocationExceptionsOnGetters = copyFrom.ignoreInvocationExceptionsOnGetters;
331         ignoreInvocationExceptionsOnSetters = copyFrom.ignoreInvocationExceptionsOnSetters;
332         ignoreUnknownBeanProperties = copyFrom.ignoreUnknownBeanProperties;
333         ignoreUnknownEnumValues = copyFrom.ignoreUnknownEnumValues;
334         locale = copyFrom.locale;
335         mediaType = copyFrom.mediaType;
336         notBeanClasses = new TreeSet<>(copyFrom.notBeanClasses);
337         notBeanPackages = toSortedSet(copyFrom.notBeanPackages, false);
338         propertyNamer = copyFrom.propertyNamer;
339         unsortedProperties = copyFrom.unsortedProperties;
340         recordComponentOrder = copyFrom.recordComponentOrder;
341         swaps = cp(copyFrom.swaps);
342         timeZone = copyFrom.timeZone;
343         durationFormat = copyFrom.durationFormat;
344         periodFormat = copyFrom.periodFormat;
345         calendarFormat = copyFrom.calendarFormat;
346         dateFormat = copyFrom.dateFormat;
347         temporalFormat = copyFrom.temporalFormat;
348         timeZoneFormat = copyFrom.timeZoneFormat;
349         localeFormat = copyFrom.localeFormat;
350         binaryFormat = copyFrom.binaryFormat;
351         enumFormat = copyFrom.enumFormat;
352         uuidFormat = copyFrom.uuidFormat;
353         bitSetFormat = copyFrom.bitSetFormat;
354         bigNumberFormat = copyFrom.bigNumberFormat;
355         booleanFormat = copyFrom.booleanFormat;
356         floatFormat = copyFrom.floatFormat;
357         currencyFormat = copyFrom.currencyFormat;
358         classFormat = copyFrom.classFormat;
359         classLoader = copyFrom.classLoader;
360         typePropertyName = copyFrom.typePropertyName;
361         useJavaBeanIntrospector = copyFrom.useJavaBeanIntrospector;
362         validateSchema = copyFrom.validateSchema;
363         beanStore = copyFrom.beanStore;
364         activeView = copyFrom.activeView;
365         disableDefaultViewInclusion = ! copyFrom.defaultViewInclusion;
366      }
367
368      /**
369       * Copy constructor.
370       *
371       * @param copyFrom The builder to copy from.
372       */
373      protected Builder(Builder copyFrom) {
374         super(copyFrom);
375         beanClassVisibility = copyFrom.beanClassVisibility;
376         beanConstructorVisibility = copyFrom.beanConstructorVisibility;
377         beanDictionary = cp(copyFrom.beanDictionary);
378         beanFieldVisibility = copyFrom.beanFieldVisibility;
379         beanMapPutReturnsOldValue = copyFrom.beanMapPutReturnsOldValue;
380         beanMethodVisibility = copyFrom.beanMethodVisibility;
381         beansRequireDefaultConstructor = copyFrom.beansRequireDefaultConstructor;
382         beansRequireSerializable = copyFrom.beansRequireSerializable;
383         beansRequireSettersForGetters = copyFrom.beansRequireSettersForGetters;
384         disableBeansRequireSomeProperties = copyFrom.disableBeansRequireSomeProperties;
385         disableIgnoreMissingSetters = copyFrom.disableIgnoreMissingSetters;
386         disableIgnoreTransientFields = copyFrom.disableIgnoreTransientFields;
387         disableIgnoreUnknownNullBeanProperties = copyFrom.disableIgnoreUnknownNullBeanProperties;
388         disableInterfaceProxies = copyFrom.disableInterfaceProxies;
389         findFluentSetters = copyFrom.findFluentSetters;
390         ignoreInvocationExceptionsOnGetters = copyFrom.ignoreInvocationExceptionsOnGetters;
391         ignoreInvocationExceptionsOnSetters = copyFrom.ignoreInvocationExceptionsOnSetters;
392         ignoreUnknownBeanProperties = copyFrom.ignoreUnknownBeanProperties;
393         ignoreUnknownEnumValues = copyFrom.ignoreUnknownEnumValues;
394         locale = copyFrom.locale;
395         mediaType = copyFrom.mediaType;
396         notBeanClasses = new TreeSet<>(copyFrom.notBeanClasses);
397         notBeanPackages = toSortedSet(copyFrom.notBeanPackages);
398         propertyNamer = copyFrom.propertyNamer;
399         unsortedProperties = copyFrom.unsortedProperties;
400         recordComponentOrder = copyFrom.recordComponentOrder;
401         swaps = cp(copyFrom.swaps);
402         timeZone = copyFrom.timeZone;
403         durationFormat = copyFrom.durationFormat;
404         periodFormat = copyFrom.periodFormat;
405         calendarFormat = copyFrom.calendarFormat;
406         dateFormat = copyFrom.dateFormat;
407         temporalFormat = copyFrom.temporalFormat;
408         timeZoneFormat = copyFrom.timeZoneFormat;
409         localeFormat = copyFrom.localeFormat;
410         binaryFormat = copyFrom.binaryFormat;
411         enumFormat = copyFrom.enumFormat;
412         uuidFormat = copyFrom.uuidFormat;
413         bitSetFormat = copyFrom.bitSetFormat;
414         bigNumberFormat = copyFrom.bigNumberFormat;
415         booleanFormat = copyFrom.booleanFormat;
416         floatFormat = copyFrom.floatFormat;
417         currencyFormat = copyFrom.currencyFormat;
418         classFormat = copyFrom.classFormat;
419         classLoader = copyFrom.classLoader;
420         typePropertyName = copyFrom.typePropertyName;
421         useJavaBeanIntrospector = copyFrom.useJavaBeanIntrospector;
422         validateSchema = copyFrom.validateSchema;
423         beanStore = copyFrom.beanStore;
424         activeView = copyFrom.activeView;
425         disableDefaultViewInclusion = copyFrom.disableDefaultViewInclusion;
426      }
427
428      /**
429       * Minimum bean class visibility.
430       *
431       * <p>
432       * Classes are not considered beans unless they meet the minimum visibility requirements.
433       * For example, if the visibility is <jsf>PUBLIC</jsf> and the bean class is <jk>protected</jk>, then the class
434       * will not be interpreted as a bean class and be serialized as a string.
435       * Use this setting to reduce the visibility requirement.
436       *
437       * <h5 class='section'>Example:</h5>
438       * <p class='bjava'>
439       *    <jc>// A bean with a protected class and one field.</jc>
440       *    <jk>protected class</jk> MyBean {
441       *       <jk>public</jk> String <jf>foo</jf> = <js>"bar"</js>;
442       *    }
443       *
444       *    <jc>// Create a serializer that's capable of serializing the class.</jc>
445       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
446       *       .<jsm>create</jsm>()
447       *       .beanClassVisibility(<jsf>PROTECTED</jsf>)
448       *       .build();
449       *
450       *    <jc>// Produces:  {"foo","bar"}</jc>
451       *    String <jv>json</jv> = <jv>serializer</jv>.write(<jk>new</jk> MyBean());
452       * </p>
453       *
454       * <h5 class='section'>Notes:</h5><ul>
455       *    <li class='note'>The {@link Bean @Marshalled} annotation can be used on a non-public bean class to override this setting.
456       *    <li class='note'>The {@link BeanIgnore @BeanIgnore} annotation can also be used on a public bean class to ignore it as a bean.
457       * </ul>
458       *
459       * <h5 class='section'>See Also:</h5><ul>
460       *    <li class='ja'>{@link BeanConfig#beanClassVisibility()}
461       * </ul>
462       *
463       * @param value
464       *    The new value for this setting.
465       *    <br>The default is {@link Visibility#PUBLIC}.
466       *    <br>Cannot be <jk>null</jk>.
467       * @return This object.
468       */
469      public Builder beanClassVisibility(Visibility value) {
470         beanClassVisibility = reqnn("value", value);
471         return this;
472      }
473
474      /**
475       * Minimum bean constructor visibility.
476       *
477       * <p>
478       * Only look for constructors with the specified minimum visibility.
479       *
480       * <p>
481       * This setting affects the logic for finding no-arg constructors for bean.  Normally, only <jk>public</jk> no-arg
482       * constructors are used.  Use this setting if you want to reduce the visibility requirement.
483       *
484       * <h5 class='section'>Example:</h5>
485       * <p class='bjava'>
486       *    <jc>// A bean with a protected constructor and one field.</jc>
487       *    <jk>public class</jk> MyBean {
488       *       <jk>public</jk> String <jf>foo</jf>;
489       *
490       *       <jk>protected</jk> MyBean() {}
491       *    }
492       *
493       *    <jc>// Create a parser capable of calling the protected constructor.</jc>
494       *    ReaderParser <jv>parser</jv> = ReaderParser
495       *       .<jsm>create</jsm>()
496       *       .beanConstructorVisibility(<jsf>PROTECTED</jsf>)
497       *       .build();
498       *
499       *    <jc>// Use it.</jc>
500       *    MyBean <jv>myBean</jv> = <jv>parser</jv>.read(<js>"{foo:'bar'}"</js>, MyBean.<jk>class</jk>);
501       * </p>
502       *
503       * <h5 class='section'>Notes:</h5><ul>
504       *    <li class='note'>The {@link BeanCtor @BeanCtor} annotation can also be used to expose a non-public constructor.
505       *    <li class='note'>The {@link BeanIgnore @BeanIgnore} annotation can also be used on a public bean constructor to ignore it.
506       * </ul>
507       *
508       * <h5 class='section'>See Also:</h5><ul>
509       *    <li class='ja'>{@link BeanConfig#beanConstructorVisibility()}
510       * </ul>
511       *
512       * @param value
513       *    The new value for this setting.
514       *    <br>The default is {@link Visibility#PUBLIC}.
515       *    <br>Cannot be <jk>null</jk>.
516       * @return This object.
517       */
518      public Builder beanConstructorVisibility(Visibility value) {
519         beanConstructorVisibility = reqnn("value", value);
520         return this;
521      }
522
523      /**
524       * Returns the bean dictionary list.
525       *
526       * <p>
527       * Gives access to the inner list if you need to make more than simple additions via {@link #beanDictionary(Class...)}.
528       *
529       * @return The bean dictionary list.
530       * @see #beanDictionary(Class...)
531       */
532      public List<ClassInfo> beanDictionary() {
533         return beanDictionary;
534      }
535
536      /**
537       * Convenience method for {@link #beanDictionary(ClassInfo...)} that accepts {@link Class} objects.
538       *
539       * @param values
540       *    The values to add to this setting.
541       *    <br>Cannot contain <jk>null</jk> values.
542       * @return This object.
543       * @see #beanDictionary(ClassInfo...)
544       */
545      public Builder beanDictionary(Class<?>...values) {
546         reqnns("values", values);
547         return beanDictionary(Stream.of(values).map(x -> info(x)).toArray(ClassInfo[]::new));
548      }
549
550      /**
551       * Bean dictionary.
552       *
553       * <p>
554       * The list of classes that make up the bean dictionary in this bean context.
555       *
556       * <p>
557       * Values are prepended to the list so that later calls can override classes of earlier calls.
558       *
559       * <p>
560       * A dictionary is a name/class mapping used to find class types during parsing when they cannot be inferred
561       * through reflection.  The names are defined through the {@link Marshalled#typeName() @Marshalled(typeName)} annotation defined
562       * 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
563       * serialized as <js>"{_type:'myfoo',...}"</js> in JSON
564       * or <js>"&lt;myfoo&gt;...&lt;/myfoo&gt;"</js> in XML.
565       *
566       * <p>
567       * This setting tells the parsers which classes to look for when resolving <js>"_type"</js> attributes.
568       *
569       * <p>
570       * Values can consist of any of the following types:
571       * <ul>
572       *    <li>Any bean class that specifies a value for {@link Marshalled#typeName() @Marshalled(typeName)}.
573       *    <li>Any subclass of {@link BeanDictionaryList} containing a collection of bean classes with type name annotations.
574       *    <li>Any subclass of {@link BeanDictionaryMap} containing a mapping of type names to classes without type name annotations.
575       *    <li>Any array or collection of the objects above.
576       * </ul>
577       *
578       * <h5 class='section'>Example:</h5>
579       * <p class='bjava'>
580       *    <jc>// POJOs with @Marshalled(name) annotations.</jc>
581       *    <ja>@Marshalled</ja>(typeName=<js>"foo"</js>)
582       *    <jk>public class</jk> Foo {...}
583       *    <ja>@Marshalled</ja>(typeName=<js>"bar"</js>)
584       *    <jk>public class</jk> Bar {...}
585       *
586       *    <jc>// Create a parser and tell it which classes to try to resolve.</jc>
587       *    ReaderParser <jv>parser</jv> = JsonParser
588       *       .<jsm>create</jsm>()
589       *       .dictionary(Foo.<jk>class</jk>, Bar.<jk>class</jk>)
590       *       .addBeanTypes()
591       *       .build();
592       *
593       *    <jc>// A bean with a field with an indeterminate type.</jc>
594       *    <jk>public class</jk> MyBean {
595       *       <jk>public</jk> Object <jf>mySimpleField</jf>;
596       *    }
597       *
598       *    <jc>// Parse bean.</jc>
599       *    MyBean <jv>myBean</jv> = <jv>parser</jv>.read(<js>"{mySimpleField:{_type:'foo',...}}"</js>, MyBean.<jk>class</jk>);
600       * </p>
601       *
602       * <p>
603       * Another option is to use the {@link Marshalled#dictionary()} annotation on the POJO class itself:
604       *
605       * <p class='bjava'>
606       *    <jc>// Instead of by parser, define a bean dictionary on a class through an annotation.</jc>
607       *    <jc>// This applies to all properties on this class and all subclasses.</jc>
608       *    <ja>@Marshalled</ja>(dictionary={Foo.<jk>class</jk>,Bar.<jk>class</jk>})
609       *    <jk>public class</jk> MyBean {
610       *       <jk>public</jk> Object <jf>mySimpleField</jf>;  <jc>// May contain Foo or Bar object.</jc>
611       *       <jk>public</jk> Map&lt;String,Object&gt; <jf>myMapField</jf>;  <jc>// May contain Foo or Bar objects.</jc>
612       *    }
613       * </p>
614       *
615       * <p>
616       *    A typical usage is to allow for HTML documents to be parsed back into HTML beans:
617       * <p class='bjava'>
618       *    <jc>// Use the predefined HTML5 bean dictionary which is a BeanDictionaryList.</jc>
619       *    ReaderParser <jv>parser</jv> = HtmlParser
620       *       .<jsm>create</jsm>()
621       *       .dictionary(HtmlBeanDictionary.<jk>class</jk>)
622       *       .build();
623       *
624       *    <jc>// Parse an HTML body into HTML beans.</jc>
625       *    Body <jv>body</jv> = <jv>parser</jv>.read(<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>);
626       * </p>
627       *
628       * <h5 class='section'>See Also:</h5><ul>
629       *    <li class='ja'>{@link Marshalled#dictionary()}
630       *    <li class='ja'>{@link MarshalledProp#dictionary()}
631       *    <li class='ja'>{@link MarshalledConfig#dictionary()}
632       *    <li class='ja'>{@link MarshalledConfig#dictionary_replace()}
633       *    <li class='jm'>{@link MarshallingContext.Builder#beanDictionary(ClassInfo...)}
634       * </ul>
635       *
636       * @param values
637       *    The values to add to this setting.
638       *    <br>Cannot contain <jk>null</jk> values.
639       * @return This object.
640       */
641      public Builder beanDictionary(ClassInfo...values) {
642         reqnns("values", values);
643         return beanDictionary(l(values));
644      }
645
646      /**
647       * Same as {@link #beanDictionary(ClassInfo...)} but allows you to pass in a collection of class info objects.
648       *
649       * @param values
650       *    The values to add to this setting.
651       *    <br>Cannot be <jk>null</jk> or contain <jk>null</jk> values.
652       * @return This object.
653       * @see #beanDictionary(ClassInfo...)
654       */
655      public Builder beanDictionary(Collection<ClassInfo> values) {
656         reqnns("values", values);
657         beanDictionary().addAll(0, values);
658         return this;
659      }
660
661      /**
662       * Minimum bean field visibility.
663       *
664       * <p>
665       * Only look for bean fields with the specified minimum visibility.
666       *
667       * <p>
668       * This affects which fields on a bean class are considered bean properties.  Normally only <jk>public</jk> fields are considered.
669       * Use this setting if you want to reduce the visibility requirement.
670       *
671       * <h5 class='section'>Example:</h5>
672       * <p class='bjava'>
673       *    <jc>// A bean with a protected field.</jc>
674       *    <jk>public class</jk> MyBean {
675       *       <jk>protected</jk> String <jf>foo</jf> = <js>"bar"</js>;
676       *    }
677       *
678       *    <jc>// Create a serializer that recognizes the protected field.</jc>
679       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
680       *       .<jsm>create</jsm>()
681       *       .beanFieldVisibility(<jsf>PROTECTED</jsf>)
682       *       .build();
683       *
684       *    <jc>// Produces:  {"foo":"bar"}</jc>
685       *    String <jv>json</jv> = <jv>serializer</jv>.write(<jk>new</jk> MyBean());
686       * </p>
687       *
688       * <p>
689       * Bean fields can be ignored as properties entirely by setting the value to {@link Visibility#NONE}
690       *
691       * <p class='bjava'>
692       *    <jc>// Disable using fields as properties entirely.</jc>
693       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
694       *       .<jsm>create</jsm>()
695       *       .beanFieldVisibility(<jsf>NONE</jsf>)
696       *       .build();
697       * </p>
698       *
699       * <h5 class='section'>Notes:</h5><ul>
700       *    <li class='note'>The {@link BeanProp @BeanProp} annotation can also be used to expose a non-public field.
701       *    <li class='note'>The {@link BeanIgnore @BeanIgnore} annotation can also be used on a public bean field to ignore it as a bean property.
702       * </ul>
703       *
704       * <h5 class='section'>See Also:</h5><ul>
705       *    <li class='ja'>{@link BeanConfig#beanFieldVisibility()}
706       * </ul>
707       *
708       * @param value
709       *    The new value for this setting.
710       *    <br>The default is {@link Visibility#PUBLIC}.
711       *    <br>Cannot be <jk>null</jk>.
712       * @return This object.
713       */
714      public Builder beanFieldVisibility(Visibility value) {
715         beanFieldVisibility = reqnn("value", value);
716         return this;
717      }
718
719      /**
720       * Bean interceptor.
721       *
722       * <p>
723       * Bean interceptors can be used to intercept calls to getters and setters and alter their values in transit.
724       *
725       * <h5 class='section'>Example:</h5>
726       * <p class='bjava'>
727       *    <jc>// Interceptor that strips out sensitive information.</jc>
728       *    <jk>public class</jk> AddressInterceptor <jk>extends</jk> BeanInterceptor&lt;Address&gt; {
729       *
730       *       <jk>public</jk> Object readProperty(Address <jv>bean</jv>, String <jv>name</jv>, Object <jv>value</jv>) {
731       *          <jk>if</jk> (<js>"taxInfo"</js>.equals(<jv>name</jv>))
732       *             <jk>return</jk> <js>"redacted"</js>;
733       *          <jk>return</jk> <jv>value</jv>;
734       *       }
735       *
736       *       <jk>public</jk> Object writeProperty(Address <jv>bean</jv>, String <jv>name</jv>, Object <jv>value</jv>) {
737       *          <jk>if</jk> (<js>"taxInfo"</js>.equals(<jv>name</jv>) &amp;&amp; <js>"redacted"</js>.equals(<jv>value</jv>))
738       *             <jk>return</jk> TaxInfoUtils.<jsm>lookup</jsm>(<jv>bean</jv>.getStreet(), <jv>bean</jv>.getCity(), <jv>bean</jv>.getState());
739       *          <jk>return</jk> <jv>value</jv>;
740       *       }
741       *    }
742       *
743       *    <jc>// Our bean class.</jc>
744       *    <jk>public class</jk> Address {
745       *       <jk>public</jk> String getTaxInfo() {...}
746       *       <jk>public void</jk> setTaxInfo(String <jv>value</jv>) {...}
747       *    }
748       *
749       *    <jc>// Register filter on serializer or parser.</jc>
750       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
751       *       .<jsm>create</jsm>()
752       *       .beanInterceptor(Address.<jk>class</jk>, AddressInterceptor.<jk>class</jk>)
753       *       .build();
754       *
755       *    <jc>// Produces:  {"taxInfo":"redacted"}</jc>
756       *    String <jv>json</jv> = <jv>serializer</jv>.write(<jk>new</jk> Address());
757       * </p>
758       *
759       * <h5 class='section'>See Also:</h5><ul>
760       *    <li class='jc'>{@link BeanInterceptor}
761       *    <li class='ja'>{@link Marshalled#interceptor() @Marshalled(interceptor)}
762       * </ul>
763       *
764       * @param on The bean that the filter applies to.
765       *    <br>Cannot be <jk>null</jk>.
766       * @param value
767       *    The new value for this setting.
768       *    <br>Cannot be <jk>null</jk>.
769       * @return This object.
770       */
771      public Builder beanInterceptor(Class<?> on, Class<? extends BeanInterceptor<?>> value) {
772         reqnn("on", on);
773         reqnn("value", value);
774         return annotations(MarshalledApplyAnnotation.create(on).value(MarshalledAnnotation.create().interceptor(value).build()).build());
775      }
776
777      /**
778       * BeanMap.put() returns old property value.
779       *
780       * <p>
781       * When enabled, then the {@link BeanMap#put(String,Object) BeanMap.put()} method will return old property
782       * values.  Otherwise, it returns <jk>null</jk>.
783       *
784       * <p>
785       * Disabled by default because it introduces a slight performance penalty during serialization.
786       *
787       * <h5 class='section'>Example:</h5>
788       * <p class='bjava'>
789       *    <jc>// Create a context that creates BeanMaps with normal put() behavior.</jc>
790       *    MarshallingContext <jv>context</jv> = MarshallingContext
791       *       .<jsm>create</jsm>()
792       *       .beanMapPutReturnsOldValue()
793       *       .build();
794       *
795       *    BeanMap&lt;MyBean&gt; <jv>myBeanMap</jv> = <jv>context</jv>.createSession().toBeanMap(<jk>new</jk> MyBean());
796       *    <jv>myBeanMap</jv>.put(<js>"foo"</js>, <js>"bar"</js>);
797       *    Object <jv>oldValue</jv> = <jv>myBeanMap</jv>.put(<js>"foo"</js>, <js>"baz"</js>);  <jc>// oldValue == "bar"</jc>
798       * </p>
799       *
800       * <h5 class='section'>See Also:</h5><ul>
801       *    <li class='ja'>{@link BeanConfig#beanMapPutReturnsOldValue()}
802       * </ul>
803       *
804       * @return This object.
805       */
806      public Builder beanMapPutReturnsOldValue() {
807         return beanMapPutReturnsOldValue(true);
808      }
809
810      /**
811       * Same as {@link #beanMapPutReturnsOldValue()} but allows you to explicitly specify the value.
812       *
813       * @param value The value for this setting.
814       * @return This object.
815       */
816      public Builder beanMapPutReturnsOldValue(boolean value) {
817         beanMapPutReturnsOldValue = value;
818         return this;
819      }
820
821      /**
822       * Minimum bean method visibility.
823       *
824       * <p>
825       * Only look for bean methods with the specified minimum visibility.
826       *
827       * <p>
828       * This affects which methods are detected as getters and setters on a bean class. Normally only <jk>public</jk> getters and setters are considered.
829       * Use this setting if you want to reduce the visibility requirement.
830       *
831       * <h5 class='section'>Example:</h5>
832       * <p class='bjava'>
833       *    <jc>// A bean with a protected getter.</jc>
834       *    <jk>public class</jk> MyBean {
835       *       <jk>public</jk> String getFoo() { <jk>return</jk> <js>"foo"</js>; }
836       *       <jk>protected</jk> String getBar() { <jk>return</jk> <js>"bar"</js>; }
837       *    }
838       *
839       *    <jc>// Create a serializer that looks for protected getters and setters.</jc>
840       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
841       *       .<jsm>create</jsm>()
842       *       .beanMethodVisibility(<jsf>PROTECTED</jsf>)
843       *       .build();
844       *
845       *    <jc>// Produces:  {"foo":"foo","bar":"bar"}</jc>
846       *    String <jv>json</jv> = <jv>serializer</jv>.write(<jk>new</jk> MyBean());
847       * </p>
848       *
849       * <h5 class='section'>Notes:</h5><ul>
850       *    <li class='note'>The {@link BeanProp @BeanProp} annotation can also be used to expose a non-public method.
851       *    <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.
852       * </ul>
853       *
854       * <h5 class='section'>See Also:</h5><ul>
855       *    <li class='ja'>{@link BeanConfig#beanMethodVisibility()}
856       * </ul>
857       *
858       * @param value
859       *    The new value for this setting.
860       *    <br>The default is {@link Visibility#PUBLIC}
861       * @return This object.
862       */
863      public Builder beanMethodVisibility(Visibility value) {
864         beanMethodVisibility = reqnn("value", value);
865         return this;
866      }
867
868      /**
869       * Bean property includes.
870       *
871       * <p>
872       * Specifies the set and order of names of properties associated with the bean class.
873       *
874       * <p>
875       * For example, <c>beanProperties(MyBean.<jk>class</jk>, <js>"foo,bar"</js>)</c> means only serialize the <c>foo</c> and
876       * <c>bar</c> properties on the specified bean.  Likewise, parsing will ignore any bean properties not specified
877       * and either throw an exception or silently ignore them depending on whether {@link #ignoreUnknownBeanProperties()}
878       * has been called.
879       *
880       * <p>
881       * This value is entirely optional if you simply want to expose all the getters and public fields on
882       * a class as bean properties.  However, it's useful if you want certain getters to be ignored or you want the properties to be
883       * serialized in a particular order.  Note that on IBM JREs, the property order is the same as the order in the source code,
884       * whereas on Oracle JREs, the order is entirely random.
885       *
886       * <p>
887       * Setting applies to specified class and all subclasses.
888       *
889       * <h5 class='section'>Example:</h5>
890       * <p class='bjava'>
891       *    <jc>// A bean with 3 properties.</jc>
892       *    <jk>public class</jk> MyBean {
893       *       <jk>public</jk> String
894       *          <jf>foo</jf> = <js>"foo"</js>,
895       *          <jf>bar</jf> = <js>"bar"</js>,
896       *          <jf>baz</jf> = <js>"baz"</js>;
897       *    }
898       *
899       *    <jc>// Create a serializer that includes only the 'foo' and 'bar' properties on the MyBean class.</jc>
900       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
901       *       .<jsm>create</jsm>()
902       *       .beanProperties(MyBean.<jk>class</jk>, <js>"foo,bar"</js>)
903       *       .build();
904       *
905       *    <jc>// Produces:  {"foo":"foo","bar":"bar"}</jc>
906       *    String <jv>json</jv> = <jv>serializer</jv>.write(<jk>new</jk> MyBean());
907       * </p>
908       *
909       * <p>
910       * This method is functionally equivalent to the following code:
911       * <p class='bjava'>
912       *    <jv>builder</jv>.annotations(MarshalledAnnotation.<jsm>create</jsm>(<jv>beanClass</jv>).properties(<jv>properties</jv>).build());
913       * </p>
914       *
915       * <h5 class='section'>See Also:</h5><ul>
916       *    <li class='jma'>{@link BeanType#properties()}/{@link BeanType#p()} - On an annotation on the bean class itself.
917       * </ul>
918       *
919       * @param beanClass The bean class.
920       *    <br>Cannot be <jk>null</jk>.
921       * @param properties Comma-delimited list of property names.
922       *    <br>Cannot be <jk>null</jk>.
923       * @return This object.
924       */
925      public Builder beanProperties(Class<?> beanClass, String properties) {
926         reqnn("beanClass", beanClass);
927         reqnn("properties", properties);
928         return annotations(BeanTypeApplyAnnotation.create(beanClass).value(BeanTypeAnnotation.create().p(properties).build()).build());
929      }
930
931      /**
932       * Bean property includes.
933       *
934       * <p>
935       * Specifies the set and order of names of properties associated with bean classes.
936       *
937       * <p>
938       * For example, <c>beanProperties(AMap.<jsm>of</jsm>(<js>"MyBean"</js>, <js>"foo,bar"</js>))</c> means only serialize the <c>foo</c> and
939       * <c>bar</c> properties on the specified bean.  Likewise, parsing will ignore any bean properties not specified
940       * and either throw an exception or silently ignore them depending on whether {@link #ignoreUnknownBeanProperties()}
941       * has been called.
942       *
943       * <p>
944       * This value is entirely optional if you simply want to expose all the getters and public fields on
945       * a class as bean properties.  However, it's useful if you want certain getters to be ignored or you want the properties to be
946       * serialized in a particular order.  Note that on IBM JREs, the property order is the same as the order in the source code,
947       * whereas on Oracle JREs, the order is entirely random.
948       *
949       * <p>
950       * Setting applies to specified class and all subclasses.
951       *
952       * <h5 class='section'>Example:</h5>
953       * <p class='bjava'>
954       *    <jc>// A bean with 3 properties.</jc>
955       *    <jk>public class</jk> MyBean {
956       *       <jk>public</jk> String
957       *          <jf>foo</jf> = <js>"foo"</js>,
958       *          <jf>bar</jf> = <js>"bar"</js>,
959       *          <jf>baz</jf> = <js>"baz"</js>;
960       *    }
961       *
962       *    <jc>// Create a serializer that includes only the 'foo' and 'bar' properties on the MyBean class.</jc>
963       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
964       *       .<jsm>create</jsm>()
965       *       .beanProperties(AMap.<jsm>of</jsm>(<js>"MyBean"</js>, <js>"foo,bar"</js>))
966       *       .build();
967       *
968       *    <jc>// Produces:  {"foo":"foo","bar":"bar"}</jc>
969       *    String <jv>json</jv> = <jv>serializer</jv>.write(<jk>new</jk> MyBean());
970       * </p>
971       *
972       * <p>
973       * This method is functionally equivalent to the following code for each entry:
974       * <p class='bjava'>
975       *    <jv>builder</jv>.annotations(MarshalledAnnotation.<jsm>create</jsm>(<jv>key</jv>).properties(<jv>value</jv>.toString()).build());
976       * </p>
977       *
978       * <h5 class='section'>See Also:</h5><ul>
979       *    <li class='jma'>{@link BeanType#properties()} / {@link BeanType#p()}- On an annotation on the bean class itself.
980       * </ul>
981       *
982       * @param values
983       *    The values to add to this builder.
984       *    <br>Keys are bean class names which can be a simple name, fully-qualified name, or <js>"*"</js> for all beans.
985       *    <br>Values are comma-delimited lists of property names.  Non-String objects are first converted to Strings.
986       *    <br>Cannot be <jk>null</jk>.
987       * @return This object.
988       */
989      public Builder beanProperties(Map<String,Object> values) {
990         reqnn("values", values);
991         values.forEach((k, v) -> annotations(BeanTypeApplyAnnotation.create(k).value(BeanTypeAnnotation.create().p(s(v)).build()).build()));
992         return this;
993      }
994
995      /**
996       * Bean property includes.
997       *
998       * <p>
999       * Specifies the set and order of names of properties associated with the bean class.
1000       *
1001       * <p>
1002       * For example, <c>beanProperties(<js>"MyBean"</js>, <js>"foo,bar"</js>)</c> means only serialize the <c>foo</c> and
1003       * <c>bar</c> properties on the specified bean.  Likewise, parsing will ignore any bean properties not specified
1004       * and either throw an exception or silently ignore them depending on whether {@link #ignoreUnknownBeanProperties()}
1005       * has been called.
1006       *
1007       * <p>
1008       * This value is entirely optional if you simply want to expose all the getters and public fields on
1009       * a class as bean properties.  However, it's useful if you want certain getters to be ignored or you want the properties to be
1010       * serialized in a particular order.  Note that on IBM JREs, the property order is the same as the order in the source code,
1011       * whereas on Oracle JREs, the order is entirely random.
1012       *
1013       * <p>
1014       * Setting applies to specified class and all subclasses.
1015       *
1016       * <h5 class='section'>Example:</h5>
1017       * <p class='bjava'>
1018       *    <jc>// A bean with 3 properties.</jc>
1019       *    <jk>public class</jk> MyBean {
1020       *       <jk>public</jk> String
1021       *          <jf>foo</jf> = <js>"foo"</js>,
1022       *          <jf>bar</jf> = <js>"bar"</js>,
1023       *          <jf>baz</jf> = <js>"baz"</js>;
1024       *    }
1025       *
1026       *    <jc>// Create a serializer that includes only the 'foo' and 'bar' properties on the MyBean class.</jc>
1027       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
1028       *       .<jsm>create</jsm>()
1029       *       .beanProperties(<js>"MyBean"</js>, <js>"foo,bar"</js>)
1030       *       .build();
1031       *
1032       *    <jc>// Produces:  {"foo":"foo","bar":"bar"}</jc>
1033       *    String <jv>json</jv> = <jv>serializer</jv>.write(<jk>new</jk> MyBean());
1034       * </p>
1035       *
1036       * <p>
1037       * This method is functionally equivalent to the following code:
1038       * <p class='bjava'>
1039       *    <jv>builder</jv>.annotations(MarshalledAnnotation.<jsm>create</jsm>(<jv>beanClassName</jv>).properties(<jv>properties</jv>).build());
1040       * </p>
1041       *
1042       * <h5 class='section'>See Also:</h5><ul>
1043       *    <li class='jma'>{@link BeanType#properties()} / {@link BeanType#p()} - On an annotation on the bean class itself.
1044       * </ul>
1045       *
1046       * @param beanClassName
1047       *    The bean class name.
1048       *    <br>Can be a simple name, fully-qualified name, or <js>"*"</js> for all beans.
1049       * @param properties Comma-delimited list of property names.
1050       *    <br>Cannot be <jk>null</jk>.
1051       * @return This object.
1052       */
1053      public Builder beanProperties(String beanClassName, String properties) {
1054         reqnn("beanClassName", beanClassName);
1055         reqnn("properties", properties);
1056         return annotations(BeanTypeApplyAnnotation.create(beanClassName).value(BeanTypeAnnotation.create().p(properties).build()).build());
1057      }
1058
1059      /**
1060       * Bean property excludes.
1061       *
1062       * <p>
1063       * Specifies to exclude the specified list of properties for the specified bean class.
1064       *
1065       * <p>
1066       * Same as {@link #beanProperties(Class, String)} except you specify a list of bean property names that you want to exclude from
1067       * serialization.
1068       *
1069       * <p>
1070       * Setting applies to specified class and all subclasses.
1071       *
1072       * <h5 class='section'>Example:</h5>
1073       * <p class='bjava'>
1074       *    <jc>// A bean with 3 properties.</jc>
1075       *    <jk>public class</jk> MyBean {
1076       *       <jk>public</jk> String
1077       *          <jf>foo</jf> = <js>"foo"</js>,
1078       *          <jf>bar</jf> = <js>"bar"</js>,
1079       *          <jf>baz</jf> = <js>"baz"</js>;
1080       *    }
1081       *
1082       *    <jc>// Create a serializer that excludes the "bar" and "baz" properties on the MyBean class.</jc>
1083       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
1084       *       .<jsm>create</jsm>()
1085       *       .beanPropertiesExcludes(MyBean.<jk>class</jk>, <js>"bar,baz"</js>)
1086       *       .build();
1087       *
1088       *    <jc>// Produces:  {"foo":"foo"}</jc>
1089       *    String <jv>json</jv> = <jv>serializer</jv>.write(<jk>new</jk> MyBean());
1090       * </p>
1091       *
1092       * <p>
1093       * This method is functionally equivalent to the following code:
1094       * <p class='bjava'>
1095       *    <jv>builder</jv>.annotations(MarshalledAnnotation.<jsm>create</jsm>(<jv>beanClass</jv>).excludeProperties(<jv>properties</jv>).build());
1096       * </p>
1097       *
1098       * <h5 class='section'>See Also:</h5><ul>
1099       *    <li class='jma'>{@link BeanType#excludeProperties()} / {@link BeanType#xp()}
1100       * </ul>
1101       *
1102       * @param beanClass The bean class.
1103       *    <br>Cannot be <jk>null</jk>.
1104       * @param properties Comma-delimited list of property names.
1105       *    <br>Cannot be <jk>null</jk>.
1106       * @return This object.
1107       */
1108      public Builder beanPropertiesExcludes(Class<?> beanClass, String properties) {
1109         reqnn("beanClass", beanClass);
1110         reqnn("properties", properties);
1111         return annotations(BeanTypeApplyAnnotation.create(beanClass).value(BeanTypeAnnotation.create().xp(properties).build()).build());
1112      }
1113
1114      /**
1115       * Bean property excludes.
1116       *
1117       * <p>
1118       * Specifies to exclude the specified list of properties for the specified bean classes.
1119       *
1120       * <p>
1121       * Same as {@link #beanProperties(Map)} except you specify a list of bean property names that you want to exclude from
1122       * serialization.
1123       *
1124       * <p>
1125       * Setting applies to specified class and all subclasses.
1126       *
1127       * <h5 class='section'>Example:</h5>
1128       * <p class='bjava'>
1129       *    <jc>// A bean with 3 properties.</jc>
1130       *    <jk>public class</jk> MyBean {
1131       *       <jk>public</jk> String
1132       *          <jf>foo</jf> = <js>"foo"</js>,
1133       *          <jf>bar</jf> = <js>"bar"</js>,
1134       *          <jf>baz</jf> = <js>"baz"</js>;
1135       *    }
1136       *
1137       *    <jc>// Create a serializer that excludes the "bar" and "baz" properties on the MyBean class.</jc>
1138       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
1139       *       .<jsm>create</jsm>()
1140       *       .beanPropertiesExcludes(AMap.of(<js>"MyBean"</js>, <js>"bar,baz"</js>))
1141       *       .build();
1142       *
1143       *    <jc>// Produces:  {"foo":"foo"}</jc>
1144       *    String <jv>json</jv> = <jv>serializer</jv>.write(<jk>new</jk> MyBean());
1145       * </p>
1146       *
1147       * <p>
1148       * This method is functionally equivalent to the following code for each entry:
1149       * <p class='bjava'>
1150       *    <jv>builder</jv>.annotations(MarshalledAnnotation.<jsm>create</jsm>(<jv>key</jv>).excludeProperties(<jv>value</jv>.toString()).build());
1151       * </p>
1152       *
1153       * <h5 class='section'>See Also:</h5><ul>
1154       *    <li class='jma'>{@link BeanType#excludeProperties()} / {@link BeanType#xp()}
1155       * </ul>
1156       *
1157       * @param values
1158       *    The values to add to this builder.
1159       *    <br>Keys are bean class names which can be a simple name, fully-qualified name, or <js>"*"</js> for all beans.
1160       *    <br>Values are comma-delimited lists of property names.  Non-String objects are first converted to Strings.
1161       *    <br>Cannot be <jk>null</jk>.
1162       * @return This object.
1163       */
1164      public Builder beanPropertiesExcludes(Map<String,Object> values) {
1165         reqnn("values", values);
1166         values.forEach((k, v) -> annotations(BeanTypeApplyAnnotation.create(k).value(BeanTypeAnnotation.create().xp(s(v)).build()).build()));
1167         return this;
1168      }
1169
1170      /**
1171       * Bean property excludes.
1172       *
1173       * <p>
1174       * Specifies to exclude the specified list of properties for the specified bean class.
1175       *
1176       * <p>
1177       * Same as {@link #beanPropertiesExcludes(String, String)} except you specify a list of bean property names that you want to exclude from
1178       * serialization.
1179       *
1180       * <p>
1181       * Setting applies to specified class and all subclasses.
1182       *
1183       * <h5 class='section'>Example:</h5>
1184       * <p class='bjava'>
1185       *    <jc>// A bean with 3 properties.</jc>
1186       *    <jk>public class</jk> MyBean {
1187       *       <jk>public</jk> String
1188       *          <jf>foo</jf> = <js>"foo"</js>,
1189       *          <jf>bar</jf> = <js>"bar"</js>,
1190       *          <jf>baz</jf> = <js>"baz"</js>;
1191       *    }
1192       *
1193       *    <jc>// Create a serializer that excludes the "bar" and "baz" properties on the MyBean class.</jc>
1194       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
1195       *       .<jsm>create</jsm>()
1196       *       .beanPropertiesExcludes(<js>"MyBean"</js>, <js>"bar,baz"</js>)
1197       *       .build();
1198       *
1199       *    <jc>// Produces:  {"foo":"foo"}</jc>
1200       *    String <jv>json</jv> = <jv>serializer</jv>.write(<jk>new</jk> MyBean());
1201       * </p>
1202       *
1203       * <p>
1204       * This method is functionally equivalent to the following code:
1205       * <p class='bjava'>
1206       *    <jv>builder</jv>.annotations(MarshalledAnnotation.<jsm>create</jsm>(<jv>beanClassName</jv>).excludeProperties(<jv>properties</jv>).build());
1207       * </p>
1208       *
1209       * <h5 class='section'>See Also:</h5><ul>
1210       *    <li class='jma'>{@link BeanType#excludeProperties()} / {@link BeanType#xp()}
1211       * </ul>
1212       *
1213       * @param beanClassName
1214       *    The bean class name.
1215       *    <br>Can be a simple name, fully-qualified name, or <js>"*"</js> for all bean classes.
1216       *    <br>Cannot be <jk>null</jk>.
1217       * @param properties Comma-delimited list of property names.
1218       *    <br>Cannot be <jk>null</jk>.
1219       * @return This object.
1220       */
1221      public Builder beanPropertiesExcludes(String beanClassName, String properties) {
1222         reqnn("beanClassName", beanClassName);
1223         reqnn("properties", properties);
1224         return annotations(BeanTypeApplyAnnotation.create(beanClassName).value(BeanTypeAnnotation.create().xp(properties).build()).build());
1225      }
1226
1227      /**
1228       * Read-only bean properties.
1229       *
1230       * <p>
1231       * Specifies one or more properties on a bean that are read-only despite having valid getters.
1232       * Serializers will serialize such properties as usual, but parsers will silently ignore them.
1233       * Note that this is different from the {@link #beanProperties(Class,String) beanProperties}/{@link #beanPropertiesExcludes(Class,String) beanPropertiesExcludes} settings which include or exclude properties
1234       * for both serializers and parsers.
1235       *
1236       * <h5 class='section'>Example:</h5>
1237       * <p class='bjava'>
1238       *    <jc>// A bean with 3 properties.</jc>
1239       *    <jk>public class</jk> MyBean {
1240       *       <jk>public</jk> String <jf>foo</jf>, <jf>bar</jf>, <jf>baz</jf>;
1241       *    }
1242       *
1243       *    <jc>// Create a serializer with read-only property settings.</jc>
1244       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
1245       *       .<jsm>create</jsm>()
1246       *       .beanPropertiesReadOnly(MyBean.<jk>class</jk>, <js>"bar,baz"</js>)
1247       *       .build();
1248       *
1249       *    <jc>// All 3 properties will be serialized.</jc>
1250       *    String <jv>json</jv> = <jv>serializer</jv>.write(<jk>new</jk> MyBean());
1251       *
1252       *    <jc>// Create a parser with read-only property settings.</jc>
1253       *    ReaderParser <jv>parser</jv> = JsonParser
1254       *       .<jsm>create</jsm>()
1255       *       .beanPropertiesReadOnly(MyBean.<jk>class</jk>, <js>"bar,baz"</js>)
1256       *       .ignoreUnknownBeanProperties()
1257       *       .build();
1258       *
1259       *    <jc>// Parser ignores bar and baz properties.</jc>
1260       *    MyBean <jv>myBean</jv> = <jv>parser</jv>.read(<js>"{foo:'foo',bar:'bar',baz:'baz'}"</js>, MyBean.<jk>class</jk>);
1261       * </p>
1262       *
1263       * <p>
1264       * This method is functionally equivalent to the following code:
1265       * <p class='bjava'>
1266       *    <jv>builder</jv>.annotations(MarshalledAnnotation.<jsm>create</jsm>(<jv>beanClass</jv>).readOnlyProperties(<jv>properties</jv>).build());
1267       * </p>
1268       *
1269       * <h5 class='section'>See Also:</h5><ul>
1270       *    <li class='jma'>{@link BeanType#readOnlyProperties()} / {@link BeanType#ro()}
1271       * </ul>
1272       *
1273       * @param beanClass The bean class.
1274       *    <br>Cannot be <jk>null</jk>.
1275       * @param properties Comma-delimited list of property names.
1276       *    <br>Cannot be <jk>null</jk>.
1277       * @return This object.
1278       */
1279      public Builder beanPropertiesReadOnly(Class<?> beanClass, String properties) {
1280         reqnn("beanClass", beanClass);
1281         reqnn("properties", properties);
1282         return annotations(BeanTypeApplyAnnotation.create(beanClass).value(BeanTypeAnnotation.create().ro(properties).build()).build());
1283      }
1284
1285      /**
1286       * Read-only bean properties.
1287       *
1288       * <p>
1289       * Specifies one or more properties on beans that are read-only despite having valid getters.
1290       * Serializers will serialize such properties as usual, but parsers will silently ignore them.
1291       * Note that this is different from the {@link #beanProperties(Class,String) beanProperties}/{@link #beanPropertiesExcludes(Class,String) beanPropertiesExcludes} settings which include or exclude properties
1292       * for both serializers and parsers.
1293       *
1294       * <h5 class='section'>Example:</h5>
1295       * <p class='bjava'>
1296       *    <jc>// A bean with 3 properties.</jc>
1297       *    <jk>public class</jk> MyBean {
1298       *       <jk>public</jk> String <jf>foo</jf>, <jf>bar</jf>, <jf>baz</jf>;
1299       *    }
1300       *
1301       *    <jc>// Create a serializer with read-only property settings.</jc>
1302       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
1303       *       .<jsm>create</jsm>()
1304       *       .beanPropertiesReadOnly(AMap.<jsm>of</jsm>(<js>"MyBean"</js>, <js>"bar,baz"</js>))
1305       *       .build();
1306       *
1307       *    <jc>// All 3 properties will be serialized.</jc>
1308       *    String <jv>json</jv> = <jv>serializer</jv>.write(<jk>new</jk> MyBean());
1309       *
1310       *    <jc>// Create a parser with read-only property settings.</jc>
1311       *    ReaderParser <jv>parser</jv> = JsonParser
1312       *       .<jsm>create</jsm>()
1313       *       .beanPropertiesReadOnly(AMap.<jsm>of</jsm>(<js>"MyBean"</js>, <js>"bar,baz"</js>))
1314       *       .ignoreUnknownBeanProperties()
1315       *       .build();
1316       *
1317       *    <jc>// Parser ignores bar and baz properties.</jc>
1318       *    MyBean <jv>myBean</jv> = <jv>parser</jv>.read(<js>"{foo:'foo',bar:'bar',baz:'baz'}"</js>, MyBean.<jk>class</jk>);
1319       * </p>
1320       *
1321       * <p>
1322       * This method is functionally equivalent to the following code for each entry:
1323       * <p class='bjava'>
1324       *    <jv>builder</jv>.annotations(MarshalledAnnotation.<jsm>create</jsm>(<jv>key</jv>).readOnlyProperties(<jv>value</jv>.toString()).build());
1325       * </p>
1326       *
1327       * <h5 class='section'>See Also:</h5><ul>
1328       *    <li class='jma'>{@link BeanType#readOnlyProperties()} / {@link BeanType#ro()}
1329       * </ul>
1330       *
1331       * @param values
1332       *    The values to add to this builder.
1333       *    <br>Keys are bean class names which can be a simple name, fully-qualified name, or <js>"*"</js> for all beans.
1334       *    <br>Values are comma-delimited lists of property names.  Non-String objects are first converted to Strings.
1335       *    <br>Cannot be <jk>null</jk>.
1336       * @return This object.
1337       */
1338      public Builder beanPropertiesReadOnly(Map<String,Object> values) {
1339         reqnn("values", values);
1340         values.forEach((k, v) -> annotations(BeanTypeApplyAnnotation.create(k).value(BeanTypeAnnotation.create().ro(s(v)).build()).build()));
1341         return this;
1342      }
1343
1344      /**
1345       * Read-only bean properties.
1346       *
1347       * <p>
1348       * Specifies one or more properties on a bean that are read-only despite having valid getters.
1349       * Serializers will serialize such properties as usual, but parsers will silently ignore them.
1350       * Note that this is different from the {@link #beanProperties(Class,String) beanProperties}/{@link #beanPropertiesExcludes(Class,String) beanPropertiesExcludes} settings which include or exclude properties
1351       * for both serializers and parsers.
1352       *
1353       * <h5 class='section'>Example:</h5>
1354       * <p class='bjava'>
1355       *    <jc>// A bean with 3 properties.</jc>
1356       *    <jk>public class</jk> MyBean {
1357       *       <jk>public</jk> String <jf>foo</jf>, <jf>bar</jf>, <jf>baz</jf>;
1358       *    }
1359       *
1360       *    <jc>// Create a serializer with read-only property settings.</jc>
1361       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
1362       *       .<jsm>create</jsm>()
1363       *       .beanPropertiesReadOnly(<js>"MyBean"</js>, <js>"bar,baz"</js>)
1364       *       .build();
1365       *
1366       *    <jc>// All 3 properties will be serialized.</jc>
1367       *    String <jv>json</jv> = <jv>serializer</jv>.write(<jk>new</jk> MyBean());
1368       *
1369       *    <jc>// Create a parser with read-only property settings.</jc>
1370       *    ReaderParser <jv>parser</jv> = JsonParser
1371       *       .<jsm>create</jsm>()
1372       *       .beanPropertiesReadOnly(<js>"MyBean"</js>, <js>"bar,baz"</js>)
1373       *       .ignoreUnknownBeanProperties()
1374       *       .build();
1375       *
1376       *    <jc>// Parser ignores bar and baz properties.</jc>
1377       *    MyBean <jv>myBean</jv> = <jv>parser</jv>.read(<js>"{foo:'foo',bar:'bar',baz:'baz'}"</js>, MyBean.<jk>class</jk>);
1378       * </p>
1379       *
1380       * <p>
1381       * This method is functionally equivalent to the following code:
1382       * <p class='bjava'>
1383       *    <jv>builder</jv>.annotations(MarshalledAnnotation.<jsm>create</jsm>(<jv>beanClassName</jv>).readOnlyProperties(<jv>properties</jv>).build());
1384       * </p>
1385       *
1386       * <h5 class='section'>See Also:</h5><ul>
1387       *    <li class='jma'>{@link BeanType#readOnlyProperties()} / {@link BeanType#ro()}
1388       * </ul>
1389       *
1390       * @param beanClassName
1391       *    The bean class name.
1392       *    <br>Can be a simple name, fully-qualified name, or <js>"*"</js> for all bean classes.
1393       * @param properties Comma-delimited list of property names.
1394       * @return This object.
1395       */
1396      public Builder beanPropertiesReadOnly(String beanClassName, String properties) {
1397         reqnn("beanClassName", beanClassName);
1398         reqnn("properties", properties);
1399         return annotations(BeanTypeApplyAnnotation.create(beanClassName).value(BeanTypeAnnotation.create().ro(properties).build()).build());
1400      }
1401
1402      /**
1403       * Write-only bean properties.
1404       *
1405       * <p>
1406       * Specifies one or more properties on a bean that are write-only despite having valid setters.
1407       * Parsers will parse such properties as usual, but serializers will silently ignore them.
1408       * Note that this is different from the {@link #beanProperties(Class,String) beanProperties}/{@link #beanPropertiesExcludes(Class,String) beanPropertiesExcludes} settings which include or exclude properties
1409       * for both serializers and parsers.
1410       *
1411       * <h5 class='section'>Example:</h5>
1412       * <p class='bjava'>
1413       *    <jc>// A bean with 3 properties.</jc>
1414       *    <jk>public class</jk> MyBean {
1415       *       <jk>public</jk> String <jf>foo</jf>, <jf>bar</jf>, <jf>baz</jf>;
1416       *    }
1417       *
1418       *    <jc>// Create a serializer with write-only property settings.</jc>
1419       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
1420       *       .<jsm>create</jsm>()
1421       *       .beanPropertiesWriteOnly(MyBean.<jk>class</jk>, <js>"bar,baz"</js>)
1422       *       .build();
1423       *
1424       *    <jc>// Only foo will be serialized.</jc>
1425       *    String <jv>json</jv> = <jv>serializer</jv>.write(<jk>new</jk> MyBean());
1426       *
1427       *    <jc>// Create a parser with write-only property settings.</jc>
1428       *    ReaderParser <jv>parser</jv> = JsonParser
1429       *       .<jsm>create</jsm>()
1430       *       .beanPropertiesWriteOnly(MyBean.<jk>class</jk>, <js>"bar,baz"</js>)
1431       *       .build();
1432       *
1433       *    <jc>// Parser parses all 3 properties.</jc>
1434       *    MyBean <jv>myBean</jv> = <jv>parser</jv>.read(<js>"{foo:'foo',bar:'bar',baz:'baz'}"</js>, MyBean.<jk>class</jk>);
1435       * </p>
1436       *
1437       * <p>
1438       * This method is functionally equivalent to the following code:
1439       * <p class='bjava'>
1440       *    <jv>builder</jv>.annotations(MarshalledAnnotation.<jsm>create</jsm>(<jv>beanClass</jv>).writeOnlyProperties(<jv>properties</jv>).build());
1441       * </p>
1442       *
1443       * <h5 class='section'>See Also:</h5><ul>
1444       *    <li class='jma'>{@link BeanType#writeOnlyProperties()} / {@link BeanType#wo()}
1445       * </ul>
1446       *
1447       * @param beanClass The bean class.
1448       *    <br>Cannot be <jk>null</jk>.
1449       * @param properties Comma-delimited list of property names.
1450       *    <br>Cannot be <jk>null</jk>.
1451       * @return This object.
1452       */
1453      public Builder beanPropertiesWriteOnly(Class<?> beanClass, String properties) {
1454         reqnn("beanClass", beanClass);
1455         reqnn("properties", properties);
1456         return annotations(BeanTypeApplyAnnotation.create(beanClass).value(BeanTypeAnnotation.create().wo(properties).build()).build());
1457      }
1458
1459      /**
1460       * Write-only bean properties.
1461       *
1462       * <p>
1463       * Specifies one or more properties on a bean that are write-only despite having valid setters.
1464       * Parsers will parse such properties as usual, but serializers will silently ignore them.
1465       * Note that this is different from the {@link #beanProperties(Class,String) beanProperties}/{@link #beanPropertiesExcludes(Class,String) beanPropertiesExcludes} settings which include or exclude properties
1466       * for both serializers and parsers.
1467       *
1468       * <h5 class='section'>Example:</h5>
1469       * <p class='bjava'>
1470       *    <jc>// A bean with 3 properties.</jc>
1471       *    <jk>public class</jk> MyBean {
1472       *       <jk>public</jk> String <jf>foo</jf>, <jf>bar</jf>, <jf>baz</jf>;
1473       *    }
1474       *
1475       *    <jc>// Create a serializer with write-only property settings.</jc>
1476       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
1477       *       .<jsm>create</jsm>()
1478       *       .beanPropertiesWriteOnly(AMap.<jsm>of</jsm>(<js>"MyBean"</js>, <js>"bar,baz"</js>))
1479       *       .build();
1480       *
1481       *    <jc>// Only foo will be serialized.</jc>
1482       *    String <jv>json</jv> = <jv>serializer</jv>.write(<jk>new</jk> MyBean());
1483       *
1484       *    <jc>// Create a parser with write-only property settings.</jc>
1485       *    ReaderParser <jv>parser</jv> = JsonParser
1486       *       .<jsm>create</jsm>()
1487       *       .beanPropertiesWriteOnly(AMap.<jsm>of</jsm>(<js>"MyBean"</js>, <js>"bar,baz"</js>))
1488       *       .build();
1489       *
1490       *    <jc>// Parser parses all 3 properties.</jc>
1491       *    MyBean <jv>myBean</jv> = <jv>parser</jv>.read(<js>"{foo:'foo',bar:'bar',baz:'baz'}"</js>, MyBean.<jk>class</jk>);
1492       * </p>
1493       *
1494       * <p>
1495       * This method is functionally equivalent to the following code for each entry:
1496       * <p class='bjava'>
1497       *    <jv>builder</jv>.annotations(MarshalledAnnotation.<jsm>create</jsm>(<jv>key</jv>).writeOnlyProperties(<jv>value</jv>.toString()).build());
1498       * </p>
1499       *
1500       * <h5 class='section'>See Also:</h5><ul>
1501       *    <li class='jma'>{@link BeanType#writeOnlyProperties()} / {@link BeanType#wo()}
1502       * </ul>
1503       *
1504       * @param values
1505       *    The values to add to this builder.
1506       *    <br>Keys are bean class names which can be a simple name, fully-qualified name, or <js>"*"</js> for all beans.
1507       *    <br>Values are comma-delimited lists of property names.  Non-String objects are first converted to Strings.
1508       *    <br>Cannot be <jk>null</jk>.
1509       * @return This object.
1510       */
1511      public Builder beanPropertiesWriteOnly(Map<String,Object> values) {
1512         reqnn("values", values);
1513         values.forEach((k, v) -> annotations(BeanTypeApplyAnnotation.create(k).value(BeanTypeAnnotation.create().wo(s(v)).build()).build()));
1514         return this;
1515      }
1516
1517      /**
1518       * Write-only bean properties.
1519       *
1520       * <p>
1521       * Specifies one or more properties on a bean that are write-only despite having valid setters.
1522       * Parsers will parse such properties as usual, but serializers will silently ignore them.
1523       * Note that this is different from the {@link #beanProperties(Class,String) beanProperties}/{@link #beanPropertiesExcludes(Class,String) beanPropertiesExcludes} settings which include or exclude properties
1524       * for both serializers and parsers.
1525       *
1526       * <h5 class='section'>Example:</h5>
1527       * <p class='bjava'>
1528       *    <jc>// A bean with 3 properties.</jc>
1529       *    <jk>public class</jk> MyBean {
1530       *       <jk>public</jk> String <jf>foo</jf>, <jf>bar</jf>, <jf>baz</jf>;
1531       *    }
1532       *
1533       *    <jc>// Create a serializer with write-only property settings.</jc>
1534       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
1535       *       .<jsm>create</jsm>()
1536       *       .beanPropertiesWriteOnly(<js>"MyBean"</js>, <js>"bar,baz"</js>)
1537       *       .build();
1538       *
1539       *    <jc>// Only foo will be serialized.</jc>
1540       *    String <jv>json</jv> = <jv>serializer</jv>.write(<jk>new</jk> MyBean());
1541       *
1542       *    <jc>// Create a parser with write-only property settings.</jc>
1543       *    ReaderParser <jv>parser</jv> = JsonParser
1544       *       .<jsm>create</jsm>()
1545       *       .beanPropertiesWriteOnly(<js>"MyBean"</js>, <js>"bar,baz"</js>)
1546       *       .build();
1547       *
1548       *    <jc>// Parser parses all 3 properties.</jc>
1549       *    MyBean <jv>myBean</jv> = <jv>parser</jv>.read(<js>"{foo:'foo',bar:'bar',baz:'baz'}"</js>, MyBean.<jk>class</jk>);
1550       * </p>
1551       *
1552       * <p>
1553       * This method is functionally equivalent to the following code:
1554       * <p class='bjava'>
1555       *    <jv>builder</jv>.annotations(MarshalledAnnotation.<jsm>create</jsm>(<jv>beanClassName</jv>).writeOnlyProperties(<jv>properties</jv>).build());
1556       * </p>
1557       *
1558       * <h5 class='section'>See Also:</h5><ul>
1559       *    <li class='jma'>{@link BeanType#writeOnlyProperties()} / {@link BeanType#wo()}
1560       * </ul>
1561       *
1562       * @param beanClassName
1563       *    The bean class name.
1564       *    <br>Can be a simple name, fully-qualified name, or <js>"*"</js> for all bean classes.
1565       * @param properties Comma-delimited list of property names.
1566       * @return This object.
1567       */
1568      public Builder beanPropertiesWriteOnly(String beanClassName, String properties) {
1569         reqnn("beanClassName", beanClassName);
1570         reqnn("properties", properties);
1571         return annotations(BeanTypeApplyAnnotation.create(beanClassName).value(BeanTypeAnnotation.create().wo(properties).build()).build());
1572      }
1573
1574      /**
1575       * Beans require no-arg constructors.
1576       *
1577       * <p>
1578       * When enabled, a Java class must implement a default no-arg constructor to be considered a bean.
1579       * Otherwise, the bean will be serialized as a string using the {@link Object#toString()} method.
1580       *
1581       * <h5 class='section'>Example:</h5>
1582       * <p class='bjava'>
1583       *    <jc>// A bean without a no-arg constructor.</jc>
1584       *    <jk>public class</jk> MyBean {
1585       *
1586       *       <jc>// A property method.</jc>
1587       *       <jk>public</jk> String <jf>foo</jf> = <js>"bar"</js>;
1588       *
1589       *       <jc>// A no-arg constructor</jc>
1590       *       <jk>public</jk> MyBean(String <jv>foo</jv>) {
1591       *          <jk>this</jk>.<jf>foo</jf> = <jv>foo</jv>;
1592       *       }
1593       *
1594       *       <ja>@Override</ja>
1595       *       <jk>public</jk> String toString() {
1596       *          <jk>return</jk> <js>"bar"</js>;
1597       *       }
1598       *    }
1599       *
1600       *    <jc>// Create a serializer that ignores beans without default constructors.</jc>
1601       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
1602       *       .<jsm>create</jsm>()
1603       *       .beansRequireDefaultConstructor()
1604       *       .build();
1605       *
1606       *    <jc>// Produces:  "bar"</jc>
1607       *    String <jv>json</jv> = <jv>serializer</jv>.write(<jk>new</jk> MyBean());
1608       * </p>
1609       *
1610       * <h5 class='section'>Notes:</h5><ul>
1611       *    <li class='note'>The {@link Bean @Marshalled} annotation can be used on a bean class to override this setting.
1612       *    <li class='note'>The {@link BeanIgnore @BeanIgnore} annotation can also be used on a class to ignore it as a bean.
1613       * </ul>
1614       *
1615       * <h5 class='section'>See Also:</h5><ul>
1616       *    <li class='ja'>{@link BeanConfig#beansRequireDefaultConstructor()}
1617       * </ul>
1618       *
1619       * @return This object.
1620       */
1621      public Builder beansRequireDefaultConstructor() {
1622         return beansRequireDefaultConstructor(true);
1623      }
1624
1625      /**
1626       * Same as {@link #beansRequireDefaultConstructor()} but allows you to explicitly specify the value.
1627       *
1628       * @param value The value for this setting.
1629       * @return This object.
1630       */
1631      public Builder beansRequireDefaultConstructor(boolean value) {
1632         beansRequireDefaultConstructor = value;
1633         return this;
1634      }
1635
1636      /**
1637       * Beans require Serializable interface.
1638       *
1639       * <p>
1640       * When enabled, a Java class must implement the {@link Serializable} interface to be considered a bean.
1641       * Otherwise, the bean will be serialized as a string using the {@link Object#toString()} method.
1642       *
1643       * <h5 class='section'>Example:</h5>
1644       * <p class='bjava'>
1645       *    <jc>// A bean without a Serializable interface.</jc>
1646       *    <jk>public class</jk> MyBean {
1647       *
1648       *       <jc>// A property method.</jc>
1649       *       <jk>public</jk> String <jf>foo</jf> = <js>"bar"</js>;
1650       *
1651       *       <ja>@Override</ja>
1652       *       <jk>public</jk> String toString() {
1653       *          <jk>return</jk> <js>"bar"</js>;
1654       *       }
1655       *    }
1656       *
1657       *    <jc>// Create a serializer that ignores beans not implementing Serializable.</jc>
1658       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
1659       *       .<jsm>create</jsm>()
1660       *       .beansRequireSerializable()
1661       *       .build();
1662       *
1663       *    <jc>// Produces:  "bar"</jc>
1664       *    String <jv>json</jv> = <jv>serializer</jv>.write(<jk>new</jk> MyBean());
1665       * </p>
1666       *
1667       * <h5 class='section'>Notes:</h5><ul>
1668       *    <li class='note'>The {@link Bean @Marshalled} annotation can be used on a bean class to override this setting.
1669       *    <li class='note'>The {@link BeanIgnore @BeanIgnore} annotation can also be used on a class to ignore it as a bean.
1670       * </ul>
1671       *
1672       * <h5 class='section'>See Also:</h5><ul>
1673       *    <li class='ja'>{@link BeanConfig#beansRequireSerializable()}
1674       * </ul>
1675       *
1676       * @return This object.
1677       */
1678      public Builder beansRequireSerializable() {
1679         return beansRequireSerializable(true);
1680      }
1681
1682      /**
1683       * Same as {@link #beansRequireSerializable()} but allows you to explicitly specify the value.
1684       *
1685       * @param value The value for this setting.
1686       * @return This object.
1687       */
1688      public Builder beansRequireSerializable(boolean value) {
1689         beansRequireSerializable = value;
1690         return this;
1691      }
1692
1693      /**
1694       * Beans require setters for getters.
1695       *
1696       * <p>
1697       * When enabled, ignore read-only properties (properties with getters but not setters).
1698       *
1699       * <h5 class='section'>Example:</h5>
1700       * <p class='bjava'>
1701       *    <jc>// A bean without a Serializable interface.</jc>
1702       *    <jk>public class</jk> MyBean {
1703       *
1704       *       <jc>// A read/write property.</jc>
1705       *       <jk>public</jk> String getFoo() { <jk>return</jk> <js>"foo"</js>; }
1706       *       <jk>public void</jk> setFoo(String <jv>foo</jv>) { ... }
1707       *
1708       *       <jc>// A read-only property.</jc>
1709       *       <jk>public</jk> String getBar() { <jk>return</jk> <js>"bar"</js>; }
1710       *    }
1711       *
1712       *    <jc>// Create a serializer that ignores bean properties without setters.</jc>
1713       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
1714       *       .<jsm>create</jsm>()
1715       *       .beansRequireSettersForGetters()
1716       *       .build();
1717       *
1718       *    <jc>// Produces:  {"foo":"foo"}</jc>
1719       *    String <jv>json</jv> = <jv>serializer</jv>.write(<jk>new</jk> MyBean());
1720       * </p>
1721       *
1722       * <h5 class='section'>Notes:</h5><ul>
1723       *    <li class='note'>The {@link BeanProp @BeanProp} annotation can be used on the getter to override this setting.
1724       *    <li class='note'>The {@link BeanIgnore @BeanIgnore} annotation can also be used on getters to ignore them as bean properties.
1725       * </ul>
1726       *
1727       * @return This object.
1728       */
1729      public Builder beansRequireSettersForGetters() {
1730         return beansRequireSettersForGetters(true);
1731      }
1732
1733      /**
1734       * Same as {@link #beansRequireSettersForGetters()} but allows you to explicitly specify the value.
1735       *
1736       * @param value The value for this setting.
1737       * @return This object.
1738       */
1739      public Builder beansRequireSettersForGetters(boolean value) {
1740         beansRequireSettersForGetters = value;
1741         return this;
1742      }
1743
1744      /**
1745       * Sets the bean store used for factory-based instantiation.
1746       *
1747       * <p>
1748       * The bean store is used to resolve {@link BeanFactory} instances registered via
1749       * <ja>@BeanType</ja><c>(factory=X.class)</c> and <ja>@BeanProp</ja><c>(factory=X.class)</c> annotations.
1750       * When a factory class is encountered, the framework first looks it up in the bean store
1751       * before attempting direct instantiation.
1752       *
1753       * <p>
1754       * Typically set to a {@code SpringBeanStore} wrapping the application's
1755       * {@code ApplicationContext} so that Spring-managed factories are resolved automatically.
1756       *
1757       * <h5 class='section'>Example:</h5>
1758       * <p class='bjava'>
1759       *    <jk>public class</jk> MyRestServlet <jk>extends</jk> BasicRestServlet {
1760       *       <ja>@Autowired</ja> ApplicationContext <jv>ctx</jv>;
1761       *
1762       *       <ja>@Override</ja>
1763       *       <jk>protected</jk> MarshallingContext createBeanContext(MarshallingContext.Builder&lt;?&gt; <jv>builder</jv>) {
1764       *          <jk>return</jk> <jv>builder</jv>.beanStore(<jk>new</jk> SpringBeanStore(<jv>ctx</jv>)).build();
1765       *       }
1766       *    }
1767       * </p>
1768       *
1769       * @param value The bean store, or <jk>null</jk> to use direct instantiation only.
1770       * @return This object.
1771       */
1772      public Builder beanStore(BeanStore value) {
1773         beanStore = value;
1774         return this;
1775      }
1776
1777      @Override /* Overridden from Context.Builder<?> */
1778      public MarshallingContext build() {
1779         return cache(CACHE).build(MarshallingContext.class);
1780      }
1781
1782      @Override /* Overridden from Context.Builder<?> */
1783      public Builder copy() {
1784         return new Builder(this);
1785      }
1786
1787      /**
1788       * Null-safe copy: returns a deep copy of the specified value, or <jk>null</jk> if the value is <jk>null</jk>.
1789       *
1790    * @param value The value to copy.  Can be <jk>null</jk> (returns <jk>null</jk>).
1791    * @return A copy of the value, or <jk>null</jk> if the value was <jk>null</jk>.
1792       */
1793      public static Builder copyOrNull(Builder value) {
1794         return value == null ? null : value.copy();
1795      }
1796
1797      /**
1798       * Bean dictionary.
1799       *
1800       * <p>
1801       * This is identical to {@link #beanDictionary(Class...)}, but specifies a dictionary within the context of
1802       * a single class as opposed to globally.
1803       *
1804       * <h5 class='section'>Example:</h5>
1805       * <p class='bjava'>
1806       *    <jc>// POJOs with @Marshalled(name) annotations.</jc>
1807       *    <ja>@Marshalled</ja>(typeName=<js>"foo"</js>)
1808       *    <jk>public class</jk> Foo {...}
1809       *    <ja>@Marshalled</ja>(typeName=<js>"bar"</js>)
1810       *    <jk>public class</jk> Bar {...}
1811       *
1812       *    <jc>// A bean with a field with an indeterminate type.</jc>
1813       *    <jk>public class</jk> MyBean {
1814       *       <jk>public</jk> Object <jf>mySimpleField</jf>;
1815       *    }
1816       *
1817       *    <jc>// Create a parser and tell it which classes to try to resolve.</jc>
1818       *    ReaderParser <jv>parser</jv> = JsonParser
1819       *       .<jsm>create</jsm>()
1820       *       .dictionaryOn(MyBean.<jk>class</jk>, Foo.<jk>class</jk>, Bar.<jk>class</jk>)
1821       *       .build();
1822       *
1823       *    <jc>// Parse bean.</jc>
1824       *    MyBean <jv>myBean</jv> = <jv>parser</jv>.read(<js>"{mySimpleField:{_type:'foo',...}}"</js>, MyBean.<jk>class</jk>);
1825       * </p>
1826       *
1827       * <p>
1828       * This is functionally equivalent to the {@link Marshalled#dictionary()} annotation.
1829       *
1830       * <h5 class='section'>See Also:</h5><ul>
1831       *    <li class='jma'>{@link Marshalled#dictionary()}
1832       *    <li class='jm'>{@link #beanDictionary(Class...)}
1833       * </ul>
1834       *
1835       * @param on The class that the dictionary values apply to.
1836       * @param values
1837       *    The new values for this setting.
1838       * @return This object.
1839       */
1840      public Builder dictionaryOn(Class<?> on, Class<?>...values) {
1841         reqnn("on", on);
1842         reqnns("values", values);
1843         return annotations(MarshalledApplyAnnotation.create(on).value(MarshalledAnnotation.create().dictionary(values).build()).build());
1844      }
1845
1846      /**
1847       * Beans don't require at least one property.
1848       *
1849       * <p>
1850       * When enabled, then a Java class doesn't need to contain at least 1 property to be considered a bean.
1851       * Otherwise, the bean will be serialized as a string using the {@link Object#toString()} method.
1852       *
1853       * <p>
1854       * The {@link Bean @Marshalled} annotation can be used on a class to override this setting when <jk>true</jk>.
1855       *
1856       * <h5 class='section'>Example:</h5>
1857       * <p class='bjava'>
1858       *    <jc>// A bean with no properties.</jc>
1859       *    <jk>public class</jk> MyBean {
1860       *    }
1861       *
1862       *    <jc>// Create a serializer that serializes beans even if they have zero properties.</jc>
1863       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
1864       *       .<jsm>create</jsm>()
1865       *       .disableBeansRequireSomeProperties()
1866       *       .build();
1867       *
1868       *    <jc>// Produces:  {}</jc>
1869       *    String <jv>json</jv> = <jv>serializer</jv>.write(<jk>new</jk> MyBean());
1870       * </p>
1871       *
1872       * <h5 class='section'>Notes:</h5><ul>
1873       *    <li class='note'>The {@link Bean @Marshalled} annotation can be used on the class to force it to be recognized as a bean class
1874       *       even if it has no properties.
1875       * </ul>
1876       *
1877       * <h5 class='section'>See Also:</h5><ul>
1878       *    <li class='ja'>{@link BeanConfig#disableBeansRequireSomeProperties()}
1879       * </ul>
1880       *
1881       * @return This object.
1882       */
1883      public Builder disableBeansRequireSomeProperties() {
1884         return disableBeansRequireSomeProperties(true);
1885      }
1886
1887      /**
1888       * Same as {@link #disableBeansRequireSomeProperties()} but allows you to explicitly specify the value.
1889       *
1890       * @param value The value for this setting.
1891       * @return This object.
1892       */
1893      public Builder disableBeansRequireSomeProperties(boolean value) {
1894         disableBeansRequireSomeProperties = value;
1895         return this;
1896      }
1897
1898      /**
1899       * Don't silently ignore missing setters.
1900       *
1901       * <p>
1902       * When enabled, trying to set a value on a bean property without a setter will throw a {@link BeanRuntimeException}.
1903       * Otherwise, it will be silently ignored.
1904       *
1905       * <h5 class='section'>Example:</h5>
1906       * <p class='bjava'>
1907       *    <jc>// A bean with a property with a getter but not a setter.</jc>
1908       *    <jk>public class</jk> MyBean {
1909       *       <jk>public void</jk> getFoo() {
1910       *          <jk>return</jk> <js>"foo"</js>;
1911       *       }
1912       *    }
1913       *
1914       *    <jc>// Create a parser that throws an exception if a setter is not found but a getter is.</jc>
1915       *    ReaderParser <jv>parser</jv> = JsonParser
1916       *       .<jsm>create</jsm>()
1917       *       .disableIgnoreMissingSetters()
1918       *       .build();
1919       *
1920       *    <jc>// Throws a ParseException.</jc>
1921       *    MyBean <jv>myBean</jv> = <jv>parser</jv>.read(<js>"{foo:'bar'}"</js>, MyBean.<jk>class</jk>);
1922       * </p>
1923       *
1924       * <h5 class='section'>Notes:</h5><ul>
1925       *    <li class='note'>The {@link BeanIgnore @BeanIgnore} annotation can also be used on getters and fields to ignore them.
1926       * </ul>
1927       *
1928       * <h5 class='section'>See Also:</h5><ul>
1929       *    <li class='ja'>{@link BeanConfig#disableIgnoreMissingSetters()}
1930       * </ul>
1931       *
1932       * @return This object.
1933       */
1934      public Builder disableIgnoreMissingSetters() {
1935         return disableIgnoreMissingSetters(true);
1936      }
1937
1938      /**
1939       * Same as {@link #disableIgnoreMissingSetters()} but allows you to explicitly specify the value.
1940       *
1941       * @param value The value for this setting.
1942       * @return This object.
1943       */
1944      public Builder disableIgnoreMissingSetters(boolean value) {
1945         disableIgnoreMissingSetters = value;
1946         return this;
1947      }
1948
1949      /**
1950       * Don't ignore transient fields.
1951       *
1952       * <p>
1953       * When enabled, methods and fields marked as <jk>transient</jk> will not be ignored as bean properties.
1954       *
1955       * <h5 class='section'>Example:</h5>
1956       * <p class='bjava'>
1957       *    <jc>// A bean with a transient field.</jc>
1958       *    <jk>public class</jk> MyBean {
1959       *       <jk>public transient</jk> String <jf>foo</jf> = <js>"foo"</js>;
1960       *    }
1961       *
1962       *    <jc>// Create a serializer that doesn't ignore transient fields.</jc>
1963       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
1964       *       .<jsm>create</jsm>()
1965       *       .disableIgnoreTransientFields()
1966       *       .build();
1967       *
1968       *    <jc>// Produces:  {"foo":"foo"}</jc>
1969       *    String <jv>json</jv> = <jv>serializer</jv>.write(<jk>new</jk> MyBean());
1970       * </p>
1971       *
1972       * <h5 class='section'>Notes:</h5><ul>
1973       *    <li class='note'>The {@link BeanProp @BeanProp} annotation can also be used on transient fields to keep them from being ignored.
1974       * </ul>
1975       *
1976       * <h5 class='section'>See Also:</h5><ul>
1977       *    <li class='ja'>{@link BeanConfig#disableIgnoreTransientFields()}
1978       * </ul>
1979       *
1980       * @return This object.
1981       */
1982      public Builder disableIgnoreTransientFields() {
1983         return disableIgnoreTransientFields(true);
1984      }
1985
1986      /**
1987       * Same as {@link #disableIgnoreTransientFields()} but allows you to explicitly specify the value.
1988       *
1989       * @param value The value for this setting.
1990       * @return This object.
1991       */
1992      public Builder disableIgnoreTransientFields(boolean value) {
1993         disableIgnoreTransientFields = value;
1994         return this;
1995      }
1996
1997      /**
1998       * Don't ignore unknown properties with null values.
1999       *
2000       * <p>
2001       * When enabled, trying to set a <jk>null</jk> value on a non-existent bean property will throw a {@link BeanRuntimeException}.
2002       * Otherwise it will be silently ignored.
2003       *
2004       * <h5 class='section'>Example:</h5>
2005       * <p class='bjava'>
2006       *    <jc>// A bean with a single property.</jc>
2007       *    <jk>public class</jk> MyBean {
2008       *       <jk>public</jk> String <jf>foo</jf>;
2009       *    }
2010       *
2011       *    <jc>// Create a parser that throws an exception on an unknown property even if the value being set is null.</jc>
2012       *    ReaderParser <jv>parser</jv> = JsonParser
2013       *       .<jsm>create</jsm>()
2014       *       .disableIgnoreUnknownNullBeanProperties()
2015       *       .build();
2016       *
2017       *    <jc>// Throws a BeanRuntimeException wrapped in a ParseException on the unknown 'bar' property.</jc>
2018       *    MyBean <jv>myBean</jv> = <jv>parser</jv>.read(<js>"{foo:'foo',bar:null}"</js>, MyBean.<jk>class</jk>);
2019       * </p>
2020       *
2021       * <h5 class='section'>See Also:</h5><ul>
2022       *    <li class='ja'>{@link BeanConfig#disableIgnoreUnknownNullBeanProperties()}
2023       * </ul>
2024       *
2025       * @return This object.
2026       */
2027      public Builder disableIgnoreUnknownNullBeanProperties() {
2028         return disableIgnoreUnknownNullBeanProperties(true);
2029      }
2030
2031      /**
2032       * Same as {@link #disableIgnoreUnknownNullBeanProperties()} but allows you to explicitly specify the value.
2033       *
2034       * @param value The value for this setting.
2035       * @return This object.
2036       */
2037      public Builder disableIgnoreUnknownNullBeanProperties(boolean value) {
2038         disableIgnoreUnknownNullBeanProperties = value;
2039         return this;
2040      }
2041
2042      /**
2043       * Don't use interface proxies.
2044       *
2045       * <p>
2046       * When enabled, interfaces will be instantiated as proxy classes through the use of an
2047       * {@link InvocationHandler} if there is no other way of instantiating them.
2048       * Otherwise, throws a {@link BeanRuntimeException}.
2049       *
2050       * <h5 class='section'>See Also:</h5><ul>
2051       *    <li class='ja'>{@link BeanConfig#disableInterfaceProxies()}
2052       * </ul>
2053       *
2054       * @return This object.
2055       */
2056      public Builder disableInterfaceProxies() {
2057         return disableInterfaceProxies(true);
2058      }
2059
2060      /**
2061       * Same as {@link #disableInterfaceProxies()} but allows you to explicitly specify the value.
2062       *
2063       * @param value The value for this setting.
2064       * @return This object.
2065       */
2066      public Builder disableInterfaceProxies(boolean value) {
2067         disableInterfaceProxies = value;
2068         return this;
2069      }
2070
2071      /**
2072       * POJO example.
2073       *
2074       * <p>
2075       * Specifies an example in JSON of the specified class.
2076       *
2077       * <p>
2078       * Examples are used in cases such as POJO examples in Swagger documents.
2079       *
2080       * <p>
2081       * Setting applies to specified class and all subclasses.
2082       *
2083       * <h5 class='section'>Example:</h5>
2084       * <p class='bjava'>
2085       *    <jc>// Create a serializer that excludes the 'foo' and 'bar' properties on the MyBean class.</jc>
2086       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
2087       *       .<jsm>create</jsm>()
2088       *       .example(MyBean.<jk>class</jk>, <js>"{foo:'bar'}"</js>)
2089       *       .build();
2090       * </p>
2091       *
2092       * <p>
2093       * This is a shorthand method for the following code:
2094       * <p class='bjava'>
2095       *    <jv>builder</jv>.annotations(MarshalledAnnotation.<jsm>create</jsm>(<jv>pojoClass</jv>).example(<jv>json</jv>).build())
2096       * </p>
2097       *
2098       * <p>
2099       * POJO examples can also be defined on classes via the following:
2100       * <ul class='spaced-list'>
2101       *    <li>A static field annotated with {@link Example @Example}.
2102       *    <li>A static method annotated with {@link Example @Example} with zero arguments or one {@link MarshallingSession} argument.
2103       *    <li>A static method with name <c>example</c> with no arguments or one {@link MarshallingSession} argument.
2104       * </ul>
2105       *
2106       * <h5 class='section'>See Also:</h5><ul>
2107       *    <li class='ja'>{@link Marshalled#example()}
2108       * </ul>
2109       *
2110       * @param <T> The POJO class type.
2111       * @param pojoClass The POJO class.
2112       *    <br>Cannot be <jk>null</jk>.
2113       * @param json The JSON 5 representation of the example.
2114       *    <br>Can be <jk>null</jk> or empty (treated as no example).
2115       * @return This object.
2116       */
2117      public <T> Builder example(Class<T> pojoClass, String json) {
2118         return annotations(MarshalledApplyAnnotation.create(reqnn("pojoClass", pojoClass)).value(MarshalledAnnotation.create().example(json).build()).build());
2119      }
2120
2121      /**
2122       * POJO example.
2123       *
2124       * <p>
2125       * Specifies an example of the specified class.
2126       *
2127       * <p>
2128       * Examples are used in cases such as POJO examples in Swagger documents.
2129       *
2130       * <h5 class='section'>Example:</h5>
2131       * <p class='bjava'>
2132       *    <jc>// Create a serializer that excludes the 'foo' and 'bar' properties on the MyBean class.</jc>
2133       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
2134       *       .<jsm>create</jsm>()
2135       *       .example(MyBean.<jk>class</jk>, <jk>new</jk> MyBean().setFoo(<js>"foo"</js>).setBar(123))
2136       *       .build();
2137       * </p>
2138       *
2139       * <p>
2140       * This is a shorthand method for the following code:
2141       * <p class='bjava'>
2142       *       <jv>builder</jv>.annotations(MarshalledAnnotation.<jsm>create</jsm>(<jv>pojoClass</jv>).example(Json5.<jsf>DEFAULT</jsf>.toString(<jv>object</jv>)).build())
2143       * </p>
2144       *
2145       * <h5 class='section'>Notes:</h5><ul>
2146       *    <li class='note'>Using this method assumes the serialized form of the object is the same as that produced
2147       *       by the default serializer.  This may not be true based on settings or swaps on the constructed serializer.
2148       * </ul>
2149       *
2150       * <p>
2151       * POJO examples can also be defined on classes via the following:
2152       * <ul class='spaced-list'>
2153       *    <li>The {@link Marshalled#example()} annotation on the class itself.
2154       *    <li>A static field annotated with {@link Example @Example}.
2155       *    <li>A static method annotated with {@link Example @Example} with zero arguments or one {@link MarshallingSession} argument.
2156       *    <li>A static method with name <c>example</c> with no arguments or one {@link MarshallingSession} argument.
2157       * </ul>
2158       *
2159       * @param <T> The POJO class.
2160       * @param pojoClass The POJO class.
2161       *    <br>Cannot be <jk>null</jk>.
2162       * @param o
2163       *    An instance of the POJO class used for examples.
2164       *    <br>Can be <jk>null</jk> (will be serialized as <js>"null"</js>).
2165       * @return This object.
2166       */
2167      public <T> Builder example(Class<T> pojoClass, T o) {
2168         return annotations(MarshalledApplyAnnotation.create(reqnn("pojoClass", pojoClass)).value(MarshalledAnnotation.create().example(Json5.of(o)).build()).build());
2169      }
2170
2171      /**
2172       * Find fluent setters.
2173       *
2174       * <p>
2175       * When enabled, fluent setters are detected on beans during parsing.
2176       *
2177       * <p>
2178       * Fluent setters must have the following attributes:
2179       * <ul>
2180       *    <li>Public.
2181       *    <li>Not static.
2182       *    <li>Take in one parameter.
2183       *    <li>Return the bean itself.
2184       * </ul>
2185       *
2186       * <h5 class='section'>Example:</h5>
2187       * <p class='bjava'>
2188       *    <jc>// A bean with a fluent setter.</jc>
2189       *    <jk>public class</jk> MyBean {
2190       *       <jk>public</jk> MyBean foo(String <jv>value</jv>) {...}
2191       *    }
2192       *
2193       *    <jc>// Create a parser that finds fluent setters.</jc>
2194       *    ReaderParser <jv>parser</jv> = JsonParser
2195       *       .<jsm>create</jsm>()
2196       *       .findFluentSetters()
2197       *       .build();
2198       *
2199       *    <jc>// Parse into bean using fluent setter.</jc>
2200       *    MyBean <jv>myBean</jv> = <jv>parser</jv>.read(<js>"{foo:'bar'}"</js>);
2201       * </p>
2202       *
2203       * <h5 class='section'>Notes:</h5><ul>
2204       *    <li class='note'>The {@link BeanProp @BeanProp} annotation can also be used on methods to individually identify them as fluent setters.
2205       *    <li class='note'>The {@link BeanType#findFluentSetters() @BeanType.findFluentSetters()} annotation can also be used on classes to specify to look for fluent setters.
2206       * </ul>
2207       *
2208       * <h5 class='section'>See Also:</h5><ul>
2209       *    <li class='ja'>{@link BeanType#findFluentSetters()}
2210       *    <li class='ja'>{@link BeanConfig#findFluentSetters()}
2211       * </ul>
2212       *
2213       * @return This object.
2214       */
2215      public Builder findFluentSetters() {
2216         return findFluentSetters(true);
2217      }
2218
2219      /**
2220       * Same as {@link #findFluentSetters()} but allows you to explicitly specify the value.
2221       *
2222       * @param value The value for this setting.
2223       * @return This object.
2224       */
2225      public Builder findFluentSetters(boolean value) {
2226         findFluentSetters = value;
2227         return this;
2228      }
2229
2230      /**
2231       * Find fluent setters.
2232       *
2233       * <p>
2234       * Identical to {@link #findFluentSetters()} but enables it on a specific class only.
2235       *
2236       * <h5 class='section'>Example:</h5>
2237       * <p class='bjava'>
2238       *    <jc>// A bean with a fluent setter.</jc>
2239       *    <jk>public class</jk> MyBean {
2240       *       <jk>public</jk> MyBean foo(String <jv>value</jv>) {...}
2241       *    }
2242       *
2243       *    <jc>// Create a parser that finds fluent setters.</jc>
2244       *    ReaderParser <jv>parser</jv> = JsonParser
2245       *       .<jsm>create</jsm>()
2246       *       .findFluentSetters(MyBean.<jk>class</jk>)
2247       *       .build();
2248       *
2249       *    <jc>// Parse into bean using fluent setter.</jc>
2250       *    MyBean <jv>myBean</jv> = <jv>parser</jv>.read(<js>"{foo:'bar'}"</js>);
2251       * </p>
2252       *
2253       * <h5 class='section'>Notes:</h5><ul>
2254       *    <li class='note'>This method is functionally equivalent to using the {@link BeanType#findFluentSetters()} annotation.
2255       * </ul>
2256       *
2257       * <h5 class='section'>See Also:</h5><ul>
2258       *    <li class='ja'>{@link BeanType#findFluentSetters()}
2259       *    <li class='jm'>{@link #findFluentSetters()}
2260       * </ul>
2261       *
2262       * @param on The class that this applies to.
2263       *    <br>Cannot be <jk>null</jk>.
2264       * @return This object.
2265       */
2266      public Builder findFluentSetters(Class<?> on) {
2267         reqnn("on", on);
2268         return annotations(BeanTypeApplyAnnotation.create(on).value(BeanTypeAnnotation.create().findFluentSetters(true).build()).build());
2269      }
2270
2271      @Override /* Overridden from Context.Builder<?> */
2272      public HashKey hashKey() {
2273         // @formatter:off
2274         return HashKey.of(
2275            super.hashKey(),
2276            beanClassVisibility,
2277            beanConstructorVisibility,
2278            beanMethodVisibility,
2279            beanFieldVisibility,
2280            beanDictionary,
2281            swaps,
2282            notBeanClasses,
2283            notBeanPackages,
2284         integer(
2285            disableBeansRequireSomeProperties,
2286            beanMapPutReturnsOldValue,
2287            beansRequireDefaultConstructor,
2288            beansRequireSerializable,
2289            beansRequireSettersForGetters,
2290            disableIgnoreTransientFields,
2291            disableIgnoreUnknownNullBeanProperties,
2292            disableIgnoreMissingSetters,
2293            disableInterfaceProxies,
2294            findFluentSetters,
2295            ignoreInvocationExceptionsOnGetters,
2296            ignoreInvocationExceptionsOnSetters,
2297            ignoreUnknownBeanProperties,
2298            ignoreUnknownEnumValues,
2299            recordComponentOrder,
2300            unsortedProperties,
2301            useJavaBeanIntrospector,
2302            validateSchema,
2303            disableDefaultViewInclusion
2304         ),
2305         activeView,
2306            typePropertyName,
2307            mediaType,
2308            timeZone,
2309            durationFormat,
2310            periodFormat,
2311            calendarFormat,
2312            dateFormat,
2313            temporalFormat,
2314            timeZoneFormat,
2315            localeFormat,
2316            binaryFormat,
2317            enumFormat,
2318            uuidFormat,
2319            bitSetFormat,
2320            bigNumberFormat,
2321            booleanFormat,
2322            floatFormat,
2323            currencyFormat,
2324            classFormat,
2325            locale,
2326            propertyNamer,
2327            System.identityHashCode(beanStore),
2328            System.identityHashCode(classLoader)
2329         );
2330         // @formatter:on
2331      }
2332
2333      /**
2334       * Sets the default active view name for all sessions created from this context.
2335       *
2336       * <p>
2337       * When set, only bean properties whose declared {@link MarshalledProp#view()} set contains this view name
2338       * will be included during serialization.  On the parse side, properties outside the active view are routed
2339       * through the existing unknown/ignored-property mechanism governed by
2340       * {@link #ignoreUnknownBeanProperties()}.
2341       *
2342       * <p>
2343       * Untagged properties (those whose declared view set is empty) follow the default-view-inclusion policy:
2344       * included under every active view unless {@link #disableDefaultViewInclusion()} has been called.
2345       *
2346       * <p>
2347       * This value can be overridden per serialization or parse call via the session builder (e.g.
2348       * {@link MarshallingSession.Builder#activeView(String)}).
2349       *
2350       * <h5 class='section'>Example:</h5>
2351       * <p class='bjava'>
2352       *    JsonSerializer <jv>serializer</jv> = JsonSerializer.<jsm>create</jsm>()
2353       *       .activeView(<js>"summary"</js>)
2354       *       .build();
2355       * </p>
2356       *
2357       * <h5 class='section'>See Also:</h5><ul>
2358       *    <li class='ja'>{@link MarshalledProp#view()}
2359       *    <li class='jm'>{@link MarshallingSession.Builder#activeView(String)}
2360       * </ul>
2361       *
2362       * @param value The active view name.  Use <jk>null</jk> to disable view filtering.
2363       * @return This object.
2364       * @since 10.0.0
2365       */
2366      public Builder activeView(String value) {
2367         activeView = value;
2368         return this;
2369      }
2370
2371      /**
2372       * Disables the default-view-inclusion policy.
2373       *
2374       * <p>
2375       * By default, bean properties that carry no {@link MarshalledProp#view()} declaration are included under
2376       * every active view (matching Jackson's {@code DEFAULT_VIEW_INCLUSION} behavior).
2377       * Calling this method reverses the policy: untagged properties are <em>excluded</em> when any active view
2378       * is set.
2379       *
2380       * <h5 class='section'>See Also:</h5><ul>
2381       *    <li class='ja'>{@link MarshalledProp#view()}
2382       *    <li class='jm'>{@link #activeView(String)}
2383       * </ul>
2384       *
2385       * @return This object.
2386       * @since 10.0.0
2387       */
2388      public Builder disableDefaultViewInclusion() {
2389         return disableDefaultViewInclusion(true);
2390      }
2391
2392      /**
2393       * Same as {@link #disableDefaultViewInclusion()} but allows you to explicitly specify the value.
2394       *
2395       * @param value The value for this setting.
2396       * @return This object.
2397       * @since 10.0.0
2398       */
2399      public Builder disableDefaultViewInclusion(boolean value) {
2400         disableDefaultViewInclusion = value;
2401         return this;
2402      }
2403
2404      /**
2405       * Ignore invocation errors on getters.
2406       *
2407       * <p>
2408       * When enabled, errors thrown when calling bean getter methods will silently be ignored.
2409       * Otherwise, a {@code BeanRuntimeException} is thrown.
2410       *
2411       * <h5 class='section'>Example:</h5>
2412       * <p class='bjava'>
2413       *    <jc>// A bean with a property that throws an exception.</jc>
2414       *    <jk>public class</jk> MyBean {
2415       *       <jk>public</jk> String getFoo() {
2416       *          <jk>throw new</jk> RuntimeException(<js>"foo"</js>);
2417       *       }
2418       *    }
2419       *
2420       *    <jc>// Create a serializer that ignores bean getter exceptions.</jc>
2421       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
2422       *       .<jsm>create</jsm>()
2423       *       .ingoreInvocationExceptionsOnGetters()
2424       *       .build();
2425       *
2426       *    <jc>// Exception is ignored.</jc>
2427       *    String <jv>json</jv> = <jv>serializer</jv>.write(<jk>new</jk> MyBean());
2428       * </p>
2429       *
2430       * <h5 class='section'>See Also:</h5><ul>
2431       *    <li class='ja'>{@link BeanConfig#ignoreInvocationExceptionsOnGetters()}
2432       * </ul>
2433       *
2434       * @return This object.
2435       */
2436      public Builder ignoreInvocationExceptionsOnGetters() {
2437         return ignoreInvocationExceptionsOnGetters(true);
2438      }
2439
2440      /**
2441       * Same as {@link #ignoreInvocationExceptionsOnGetters()} but allows you to explicitly specify the value.
2442       *
2443       * @param value The value for this setting.
2444       * @return This object.
2445       */
2446      public Builder ignoreInvocationExceptionsOnGetters(boolean value) {
2447         ignoreInvocationExceptionsOnGetters = value;
2448         return this;
2449      }
2450
2451      /**
2452       * Ignore invocation errors on setters.
2453       *
2454       * <p>
2455       * When enabled, errors thrown when calling bean setter methods will silently be ignored.
2456       * Otherwise, a {@code BeanRuntimeException} is thrown.
2457       *
2458       * <h5 class='section'>Example:</h5>
2459       * <p class='bjava'>
2460       *    <jc>// A bean with a property that throws an exception.</jc>
2461       *    <jk>public class</jk> MyBean {
2462       *       <jk>public void</jk> setFoo(String <jv>foo</jv>) {
2463       *          <jk>throw new</jk> RuntimeException(<js>"foo"</js>);
2464       *       }
2465       *    }
2466       *
2467       *    <jc>// Create a parser that ignores bean setter exceptions.</jc>
2468       *    ReaderParser <jv>parser</jv> = JsonParser
2469       *       .<jsm>create</jsm>()
2470       *       .ignoreInvocationExceptionsOnSetters()
2471       *       .build();
2472       *
2473       *    <jc>// Exception is ignored.</jc>
2474       *    MyBean <jv>myBean</jv> = <jv>parser</jv>.read(<js>"{foo:'bar'}"</js>, MyBean.<jk>class</jk>);
2475       * </p>
2476       *
2477       * <h5 class='section'>See Also:</h5><ul>
2478       *    <li class='ja'>{@link BeanConfig#ignoreInvocationExceptionsOnSetters()}
2479       * </ul>
2480       *
2481       * @return This object.
2482       */
2483      public Builder ignoreInvocationExceptionsOnSetters() {
2484         return ignoreInvocationExceptionsOnSetters(true);
2485      }
2486
2487      /**
2488       * Same as {@link #ignoreInvocationExceptionsOnSetters()} but allows you to explicitly specify the value.
2489       *
2490       * @param value The value for this setting.
2491       * @return This object.
2492       */
2493      public Builder ignoreInvocationExceptionsOnSetters(boolean value) {
2494         ignoreInvocationExceptionsOnSetters = value;
2495         return this;
2496      }
2497
2498      /**
2499       * Ignore unknown properties.
2500       *
2501       * <p>
2502       * When enabled, trying to set a value on a non-existent bean property will silently be ignored.
2503       * Otherwise, a {@code BeanRuntimeException} is thrown.
2504       *
2505       * <h5 class='section'>Example:</h5>
2506       * <p class='bjava'>
2507       *    <jc>// A bean with a single property.</jc>
2508       *    <jk>public class</jk> MyBean {
2509       *       <jk>public</jk> String <jf>foo</jf>;
2510       *    }
2511       *
2512       *    <jc>// Create a parser that ignores missing bean properties.</jc>
2513       *    ReaderParser <jv>parser</jv> = JsonParser
2514       *       .<jsm>create</jsm>()
2515       *       .ignoreUnknownBeanProperties()
2516       *       .build();
2517       *
2518       *    <jc>// Doesn't throw an exception on unknown 'bar' property.</jc>
2519       *    MyBean <jv>myBean</jv> = <jv>parser</jv>.read(<js>"{foo:'foo',bar:'bar'}"</js>, MyBean.<jk>class</jk>);
2520       * </p>
2521       *
2522       * <h5 class='section'>See Also:</h5><ul>
2523       *    <li class='ja'>{@link BeanConfig#ignoreUnknownBeanProperties()}
2524       * </ul>
2525       *
2526       * @return This object.
2527       */
2528      public Builder ignoreUnknownBeanProperties() {
2529         return ignoreUnknownBeanProperties(true);
2530      }
2531
2532      /**
2533       * Same as {@link #ignoreUnknownBeanProperties()} but allows you to explicitly specify the value.
2534       *
2535       * @param value The value for this setting.
2536       * @return This object.
2537       */
2538      public Builder ignoreUnknownBeanProperties(boolean value) {
2539         ignoreUnknownBeanProperties = value;
2540         return this;
2541      }
2542
2543      /**
2544       * Schema validation mode.
2545       *
2546       * <p>
2547       * When enabled, bean property values are validated against the constraints declared by
2548       * {@link Schema @Schema} annotations on those properties.  Validation runs
2549       * during both <b>parsing</b> (value set on the bean) and <b>serialization</b> (value read from the bean).
2550       *
2551       * <p>
2552       * Backed by the typed {@code JsonSchema} bean in {@code juneau-bean-jsonschema} and JSON Schema Draft 2020-12
2553       * semantics.  Validation failures throw {@link SchemaValidationException}
2554       * wrapped in {@code BeanRuntimeException}; the parser surfaces them as
2555       * {@link ParseException} and the serializer surfaces them as
2556       * {@link SerializeException}.
2557       *
2558       * <p>
2559       * If {@code juneau-bean-jsonschema} is not on the classpath, this flag becomes a silent no-op.
2560       *
2561       * <h5 class='section'>Example:</h5>
2562       * <p class='bjava'>
2563       *    <jc>// A bean with a length-constrained property.</jc>
2564       *    <jk>public class</jk> MyBean {
2565       *       <ja>&#64;Schema</ja>(minLength=<js>"2"</js>, maxLength=<js>"10"</js>)
2566       *       <jk>public</jk> String <jf>name</jf>;
2567       *    }
2568       *
2569       *    <jc>// Parser that validates inbound values.</jc>
2570       *    ReaderParser <jv>p</jv> = JsonParser.<jsm>create</jsm>().validateSchema().build();
2571       *
2572       *    <jv>p</jv>.read(<js>"{name:'a'}"</js>, MyBean.<jk>class</jk>);  <jc>// throws ParseException - too short</jc>
2573       * </p>
2574       *
2575       * <h5 class='section'>See Also:</h5><ul>
2576       *    <li class='ja'>{@link BeanConfig#validateSchema()}
2577       * </ul>
2578       *
2579       * @return This object.
2580       * @since 10.0.0
2581       */
2582      public Builder validateSchema() {
2583         return validateSchema(true);
2584      }
2585
2586      /**
2587       * Same as {@link #validateSchema()} but allows you to explicitly specify the value.
2588       *
2589       * @param value The value for this setting.
2590       * @return This object.
2591       * @since 10.0.0
2592       */
2593      public Builder validateSchema(boolean value) {
2594         validateSchema = value;
2595         return this;
2596      }
2597
2598      /**
2599       * Ignore unknown properties.
2600       *
2601       * <p>
2602       * When enabled, unknown enum values will be set to <jk>null</jk> instead of throwing an exception.
2603       *
2604       * <h5 class='section'>See Also:</h5><ul>
2605       *    <li class='ja'>{@link BeanConfig#ignoreUnknownEnumValues()}
2606       * </ul>
2607       *
2608       * @return This object.
2609       */
2610      public Builder ignoreUnknownEnumValues() {
2611         return ignoreUnknownEnumValues(true);
2612      }
2613
2614      /**
2615       * Same as {@link #ignoreUnknownEnumValues()} but allows you to explicitly specify the value.
2616       *
2617       * @param value The value for this setting.
2618       * @return This object.
2619       */
2620      public Builder ignoreUnknownEnumValues(boolean value) {
2621         ignoreUnknownEnumValues = value;
2622         return this;
2623      }
2624
2625      /**
2626       * Implementation classes.
2627       *
2628       * <p>
2629       * For interfaces and abstract classes this method can be used to specify an implementation class for the
2630       * interface/abstract class so that instances of the implementation class are used when instantiated (e.g. during a
2631       * parse).
2632       *
2633       * <h5 class='section'>Example:</h5>
2634       * <p class='bjava'>
2635       *    <jc>// A bean interface.</jc>
2636       *    <jk>public interface</jk> MyBean {
2637       *       ...
2638       *    }
2639       *
2640       *    <jc>// A bean implementation.</jc>
2641       *    <jk>public class</jk> MyBeanImpl <jk>implements</jk> MyBean {
2642       *       ...
2643       *    }
2644
2645       *    <jc>// Create a parser that instantiates MyBeanImpls when parsing MyBeans.</jc>
2646       *    ReaderParser <jv>parser</jv> = JsonParser
2647       *       .<jsm>create</jsm>()
2648       *       .implClass(MyBean.<jk>class</jk>, MyBeanImpl.<jk>class</jk>)
2649       *       .build();
2650       *
2651       *    <jc>// Instantiates a MyBeanImpl,</jc>
2652       *    MyBean <jv>myBean</jv> = <jv>parser</jv>.read(<js>"..."</js>, MyBean.<jk>class</jk>);
2653       * </p>
2654       *
2655       * @param interfaceClass The interface class.
2656       *    <br>Cannot be <jk>null</jk>.
2657       * @param implClass The implementation class.
2658       *    <br>Cannot be <jk>null</jk>.
2659       * @return This object.
2660       */
2661      public Builder implClass(Class<?> interfaceClass, Class<?> implClass) {
2662         reqnn("interfaceClass", interfaceClass);
2663         reqnn("implClass", implClass);
2664         return annotations(MarshalledApplyAnnotation.create(interfaceClass).value(MarshalledAnnotation.create().implClass(implClass).build()).build());
2665      }
2666
2667      /**
2668       * Implementation classes.
2669       *
2670       * <p>
2671       * For interfaces and abstract classes this method can be used to specify an implementation class for the
2672       * interface/abstract class so that instances of the implementation class are used when instantiated (e.g. during a
2673       * parse).
2674       *
2675       * <h5 class='section'>Example:</h5>
2676       * <p class='bjava'>
2677       *    <jc>// A bean with a single property.</jc>
2678       *    <jk>public interface</jk> MyBean {
2679       *       ...
2680       *    }
2681       *
2682       *    <jc>// A bean with a single property.</jc>
2683       *    <jk>public class</jk> MyBeanImpl <jk>implements</jk> MyBean {
2684       *       ...
2685       *    }
2686
2687       *    <jc>// Create a parser that instantiates MyBeanImpls when parsing MyBeans.</jc>
2688       *    ReaderParser <jv>parser</jv> = JsonParser
2689       *       .<jsm>create</jsm>()
2690       *       .implClasses(AMap.<jsm>of</jsm>(MyBean.<jk>class</jk>, MyBeanImpl.<jk>class</jk>))
2691       *       .build();
2692       *
2693       *    <jc>// Instantiates a MyBeanImpl,</jc>
2694       *    MyBean <jv>myBean</jv> = <jv>parser</jv>.read(<js>"..."</js>, MyBean.<jk>class</jk>);
2695       * </p>
2696       *
2697       * @param values
2698       *    The new value for this setting.
2699       *    <br>Cannot be <jk>null</jk>.
2700       * @return This object.
2701       */
2702      public Builder implClasses(Map<Class<?>,Class<?>> values) {
2703         reqnn("values", values);
2704         values.forEach((k, v) -> annotations(MarshalledApplyAnnotation.create(k).value(MarshalledAnnotation.create().implClass(v).build()).build()));
2705         return this;
2706      }
2707
2708      /**
2709       * Identifies a class to be used as the interface class for the specified class and all subclasses.
2710       *
2711       * <p>
2712       * When specified, only the list of properties defined on the interface class will be used during serialization.
2713       * Additional properties on subclasses will be ignored.
2714       *
2715       * <p class='bjava'>
2716       *    <jc>// Parent class or interface</jc>
2717       *    <jk>public abstract class</jk> A {
2718       *       <jk>public</jk> String <jf>foo</jf> = <js>"foo"</js>;
2719       *    }
2720       *
2721       *    <jc>// Sub class</jc>
2722       *    <jk>public class</jk> A1 <jk>extends</jk> A {
2723       *       <jk>public</jk> String <jf>bar</jf> = <js>"bar"</js>;
2724       *    }
2725       *
2726       *    <jc>// Create a serializer and define our interface class mapping.</jc>
2727       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
2728       *       .<jsm>create</jsm>()
2729       *       .interfaceClass(A1.<jk>class</jk>, A.<jk>class</jk>)
2730       *       .build();
2731       *
2732       *    <jc>// Produces "{"foo":"foo"}"</jc>
2733       *    String <jv>json</jv> = <jv>serializer</jv>.write(<jk>new</jk> A1());
2734       * </p>
2735       *
2736       * <p>
2737       * This annotation can be used on the parent class so that it filters to all child classes, or can be set
2738       * individually on the child classes.
2739       *
2740       * <h5 class='section'>Notes:</h5><ul>
2741       *    <li class='note'>The {@link BeanType#interfaceClass() @BeanType(interfaceClass)} annotation is the equivalent annotation-based solution.
2742       * </ul>
2743       *
2744       * @param on The class that the interface class applies to.
2745       *    <br>Cannot be <jk>null</jk>.
2746       * @param value
2747       *    The new value for this setting.
2748       *    <br>Cannot be <jk>null</jk>.
2749       * @return This object.
2750       */
2751      public Builder interfaceClass(Class<?> on, Class<?> value) {
2752         reqnn("on", on);
2753         reqnn("value", value);
2754         return annotations(BeanTypeApplyAnnotation.create(on).value(BeanTypeAnnotation.create().interfaceClass(value).build()).build());
2755      }
2756
2757      /**
2758       * Identifies a set of interfaces.
2759       *
2760       * <p>
2761       * When specified, only the list of properties defined on the interface class will be used during serialization
2762       * of implementation classes.  Additional properties on subclasses will be ignored.
2763       *
2764       * <p class='bjava'>
2765       *    <jc>// Parent class or interface</jc>
2766       *    <jk>public abstract class</jk> A {
2767       *       <jk>public</jk> String <jf>foo</jf> = <js>"foo"</js>;
2768       *    }
2769       *
2770       *    <jc>// Sub class</jc>
2771       *    <jk>public class</jk> A1 <jk>extends</jk> A {
2772       *       <jk>public</jk> String <jf>bar</jf> = <js>"bar"</js>;
2773       *    }
2774       *
2775       *    <jc>// Create a serializer and define our interface class mapping.</jc>
2776       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
2777       *       .<jsm>create</jsm>()
2778       *       .interfaces(A.<jk>class</jk>)
2779       *       .build();
2780       *
2781       *    <jc>// Produces "{"foo":"foo"}"</jc>
2782       *    String <jv>json</jv> = <jv>serializer</jv>.write(<jk>new</jk> A1());
2783       * </p>
2784       *
2785       * <p>
2786       * This annotation can be used on the parent class so that it filters to all child classes, or can be set
2787       * individually on the child classes.
2788       *
2789       * <h5 class='section'>Notes:</h5><ul>
2790       *    <li class='note'>The {@link BeanType#interfaceClass() @BeanType(interfaceClass)} annotation is the equivalent annotation-based solution.
2791       * </ul>
2792       *
2793       * @param value
2794       *    The new value for this setting.
2795       *    <br>Cannot be <jk>null</jk>.
2796       * @return This object.
2797       */
2798      public Builder interfaces(Class<?>...value) {
2799         reqnns("value", value);
2800         for (var v : value)
2801            annotations(BeanTypeApplyAnnotation.create(v).value(BeanTypeAnnotation.create().interfaceClass(v).build()).build());
2802         return this;
2803      }
2804
2805      /**
2806       * <i><l>Context</l> configuration property:&emsp;</i>  Locale.
2807       *
2808       * <p>
2809       * Specifies the default locale for serializer and parser sessions when not specified via {@link MarshallingSession.Builder#locale(Locale)}.
2810       * Typically used for POJO swaps that need to deal with locales such as swaps that convert <l>Date</l> and <l>Calendar</l>
2811       * objects to strings by accessing it via the session passed into the {@link ObjectSwap#swap(MarshallingSession, Object)} and
2812       * {@link ObjectSwap#unswap(MarshallingSession, Object, ClassMeta, String)} methods.
2813       *
2814       * <h5 class='section'>Example:</h5>
2815       * <p class='bjava'>
2816       *    <jc>// Define a POJO swap that skips serializing beans if we're in the UK.</jc>
2817       *    <jk>public class</jk> MyBeanSwap <jk>extends</jk> StringSwap&lt;MyBean&gt; {
2818       *       <ja>@Override</ja>
2819       *       <jk>public</jk> String swap(MarshallingSession <jv>session</jv>, MyBean <jv>bean</jv>) <jk>throws</jk> Exception {
2820       *          <jk>if</jk> (<jv>session</jv>.getLocale().equals(Locale.<jsf>UK</jsf>))
2821       *             <jk>return null</jk>;
2822       *          <jk>return</jk> <jv>bean</jv>.toString();
2823       *       }
2824       *    }
2825       *
2826       *    <jc>// Create a serializer that uses the specified locale if it's not passed in through session args.</jc>
2827       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
2828       *       .<jsm>create</jsm>()
2829       *       .locale(Locale.<jsf>UK</jsf>)
2830       *       .swaps(MyBeanSwap.<jk>class</jk>)
2831       *       .build();
2832       * </p>
2833       *
2834       * <h5 class='section'>See Also:</h5><ul>
2835       *    <li class='ja'>{@link MarshalledConfig#locale()}
2836       *    <li class='jm'>{@link MarshallingSession.Builder#locale(Locale)}
2837       * </ul>
2838       *
2839       * @param value The new value for this property.
2840       *    <br>Cannot be <jk>null</jk>.
2841       * @return This object.
2842       */
2843      public Builder locale(Locale value) {
2844         locale = reqnn("value", value);
2845         return this;
2846      }
2847
2848      /**
2849       * <i><l>Context</l> configuration property:&emsp;</i>  Media type.
2850       *
2851       * <p>
2852       * Specifies the default media type for serializer and parser sessions when not specified via {@link MarshallingSession.Builder#mediaType(MediaType)}.
2853       * Typically used for POJO swaps that need to serialize the same POJO classes differently depending on
2854       * the specific requested media type.   For example, a swap could handle a request for media types <js>"application/json"</js>
2855       * and <js>"application/json+foo"</js> slightly differently even though they're both being handled by the same JSON
2856       * serializer or parser.
2857       *
2858       * <h5 class='section'>Example:</h5>
2859       * <p class='bjava'>
2860       *    <jc>// Define a POJO swap that skips serializing beans if the media type is application/json.</jc>
2861       *    <jk>public class</jk> MyBeanSwap <jk>extends</jk> StringSwap&lt;MyBean&gt; {
2862       *       <ja>@Override</ja>
2863       *       <jk>public</jk> String swap(MarshallingSession <jv>session</jv>, MyBean <jv>bean</jv>) <jk>throws</jk> Exception {
2864       *          <jk>if</jk> (<jv>session</jv>.getMediaType().equals(<js>"application/json"</js>))
2865       *             <jk>return null</jk>;
2866       *          <jk>return</jk> <jv>bean</jv>.toString();
2867       *       }
2868       *    }
2869       *
2870       *    <jc>// Create a serializer that uses the specified media type if it's not passed in through session args.</jc>
2871       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
2872       *       .<jsm>create</jsm>()
2873       *       .mediaType(MediaType.<jsf>JSON</jsf>)
2874       *       .build();
2875       * </p>
2876       *
2877       * <h5 class='section'>See Also:</h5><ul>
2878       *    <li class='ja'>{@link MarshalledConfig#mediaType()}
2879       *    <li class='jm'>{@link MarshallingSession.Builder#mediaType(MediaType)}
2880       * </ul>
2881       *
2882       * @param value The new value for this property.
2883       *    <br>Can be <jk>null</jk> (no default media type will be set).
2884       * @return This object.
2885       */
2886      public Builder mediaType(MediaType value) {
2887         mediaType = value;
2888         return this;
2889      }
2890
2891      /**
2892       * Returns the set of not-bean classes.
2893       *
2894       * <p>
2895       * Gives access to the inner set if you need to make more than simple additions via {@link #notBeanClasses(ClassInfo...)}.
2896       *
2897       * @return The set of not-bean classes.
2898       * @see #notBeanClasses(ClassInfo...)
2899       */
2900      public Set<ClassInfo> notBeanClasses() {
2901         return notBeanClasses;
2902      }
2903
2904      /**
2905       * Convenience method for {@link #notBeanClasses(ClassInfo...)} that accepts {@link Class} objects.
2906       *
2907       * @param values
2908       *    The values to add to this setting.
2909       *    <br>Cannot contain <jk>null</jk> values.
2910       * @return This object.
2911       * @see #notBeanClasses(ClassInfo...)
2912       */
2913      public Builder notBeanClasses(Class<?>...values) {
2914         reqnns("values", values);
2915         return notBeanClasses(Stream.of(values).map(x -> info(x)).toArray(ClassInfo[]::new));
2916      }
2917
2918      /**
2919       * Bean class exclusions.
2920       *
2921       * <p>
2922       * List of classes that should not be treated as beans even if they appear to be bean-like.
2923       * Not-bean classes are converted to <c>Strings</c> during serialization.
2924       *
2925       * <p>
2926       * Values can consist of any of the following types:
2927       * <ul>
2928       *    <li>Classes.
2929       *    <li>Arrays and collections of classes.
2930       * </ul>
2931       *
2932       * <h5 class='section'>Example:</h5>
2933       * <p class='bjava'>
2934       *    <jc>// A bean with a single property.</jc>
2935       *    <jk>public class</jk> MyBean {
2936       *       <jk>public</jk> String <jf>foo</jf> = <js>"bar"</js>;
2937       *
2938       *       <jk>public</jk> String toString() {
2939       *          <jk>return</jk> <js>"baz"</js>;
2940       *       }
2941       *    }
2942       *
2943       *    <jc>// Create a serializer that doesn't treat MyBean as a bean class.</jc>
2944       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
2945       *       .<jsm>create</jsm>()
2946       *       .notBeanClasses(MyBean.<jk>class</jk>)
2947       *       .build();
2948       *
2949       *    <jc>// Produces "baz" instead of {"foo":"bar"}</jc>
2950       *    String <jv>json</jv> = <jv>serializer</jv>.write(<jk>new</jk> MyBean());
2951       * </p>
2952       *
2953       * <h5 class='section'>Notes:</h5><ul>
2954       *    <li class='note'>The {@link BeanIgnore @BeanIgnore} annotation can also be used on classes to prevent them from being recognized as beans.
2955       * </ul>
2956       *
2957       * <h5 class='section'>See Also:</h5><ul>
2958       *    <li class='ja'>{@link BeanIgnore}
2959       *    <li class='ja'>{@link BeanConfig#notBeanClasses()}
2960       * </ul>
2961       *
2962       * @param values
2963       *    The values to add to this setting.
2964       *    <br>Cannot contain <jk>null</jk> values.
2965       * @return This object.
2966       */
2967      public Builder notBeanClasses(ClassInfo...values) {
2968         reqnns("values", values);
2969         notBeanClasses().addAll(l(values));
2970         return this;
2971      }
2972
2973      /**
2974       * Same as {@link #notBeanClasses(ClassInfo...)} but allows you to pass in a collection of class info objects.
2975       *
2976       * @param values
2977       *    The values to add to this setting.
2978       *    <br>Cannot be <jk>null</jk> or contain <jk>null</jk> values.
2979       * @return This object.
2980       * @see #notBeanClasses(ClassInfo...)
2981       */
2982      public Builder notBeanClasses(Collection<ClassInfo> values) {
2983         reqnns("values", values);
2984         notBeanClasses().addAll(values);
2985         return this;
2986      }
2987
2988      /**
2989       * Returns the list of not-bean Java package names.
2990       *
2991       * <p>
2992       * Gives access to the inner list if you need to make more than simple additions via {@link #notBeanPackages(String...)}.
2993       *
2994       * @return The list of not-bean Java package names.
2995       * @see #notBeanPackages(String...)
2996       */
2997      public Set<String> notBeanPackages() {
2998         return notBeanPackages;
2999      }
3000
3001      /**
3002       * Same as {@link #notBeanPackages(String...)} but allows you to pass in a collection of classes.
3003       *
3004       * @param values
3005       *    The values to add to this setting.
3006       *    <br>Cannot be <jk>null</jk> or contain <jk>null</jk> values.
3007       * @return This object.
3008       * @see #notBeanPackages(String...)
3009       */
3010      public Builder notBeanPackages(Collection<String> values) {
3011         reqnns("values", values);
3012         notBeanPackages().addAll(values);
3013         return this;
3014      }
3015
3016      /**
3017       * Bean package exclusions.
3018       *
3019       * <p>
3020       * Used as a convenient way of defining the {@link #notBeanClasses(Class...)} property for entire packages.
3021       * Any classes within these packages will be serialized to strings using {@link Object#toString()}.
3022       *
3023       * <p>
3024       * Note that you can specify suffix patterns to include all subpackages.
3025       *
3026       * <p>
3027       * Values can consist of any of the following types:
3028       * <ul>
3029       *    <li>Strings.
3030       *    <li>Arrays and collections of strings.
3031       * </ul>
3032       *
3033       * <h5 class='section'>Example:</h5>
3034       * <p class='bjava'>
3035       *    <jc>// Create a serializer that ignores beans in the specified packages.</jc>
3036       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
3037       *       .<jsm>create</jsm>()
3038       *       .notBeanPackages(<js>"org.apache.foo"</js>, <js>"org.apache.bar.*"</js>)
3039       *       .build();
3040       * </p>
3041       *
3042       * @param values
3043       *    The values to add to this setting.
3044       *    <br>Values can consist of any of the following types:
3045       *    <ul>
3046       *       <li>{@link Package} objects.
3047       *       <li>Strings.
3048       *       <li>Arrays and collections of anything in this list.
3049       *    </ul>
3050       *    <br>Cannot contain <jk>null</jk> values.
3051       * @return This object.
3052       */
3053      public Builder notBeanPackages(String...values) {
3054         reqnns("values", values);
3055         return notBeanPackages(l(values));
3056      }
3057
3058      /**
3059       * Bean property namer
3060       *
3061       * <p>
3062       * Same as {@link #propertyNamer(Class)} but allows you to specify a namer for a specific class.
3063       *
3064       * <h5 class='section'>Example:</h5>
3065       * <p class='bjava'>
3066       *    <jc>// A bean with a single property.</jc>
3067       *    <jk>public class</jk> MyBean {
3068       *       <jk>public</jk> String <jf>fooBarBaz</jf> = <js>"fooBarBaz"</js>;
3069       *    }
3070       *
3071       *    <jc>// Create a serializer that uses Dashed-Lower-Case property names for the MyBean class only.</jc>
3072       *    <jc>// (e.g. "foo-bar-baz" instead of "fooBarBaz")</jc>
3073       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
3074       *       .<jsm>create</jsm>()
3075       *       .propertyNamer(MyBean.<jk>class</jk>, PropertyNamerDLC.<jk>class</jk>)
3076       *       .build();
3077       *
3078       *    <jc>// Produces:  {"foo-bar-baz":"fooBarBaz"}</jc>
3079       *    String <jv>json</jv> = <jv>serializer</jv>.write(<jk>new</jk> MyBean());
3080       * </p>
3081       *
3082       * <h5 class='section'>See Also:</h5><ul>
3083       *    <li class='ja'>{@link BeanType#propertyNamer() @BeanType(propertyNamer)}
3084       *    <li class='jm'>{@link #propertyNamer(Class)}
3085       * </ul>
3086       *
3087       * @param on The class that the namer applies to.
3088       *    <br>Cannot be <jk>null</jk>.
3089       * @param value
3090       *    The new value for this setting.
3091       *    <br>The default is {@link BasicPropertyNamer}.
3092       *    <br>Cannot be <jk>null</jk>.
3093       * @return This object.
3094       */
3095      public Builder propertyNamer(Class<?> on, Class<? extends PropertyNamer> value) {
3096         reqnn("on", on);
3097         reqnn("value", value);
3098         return annotations(BeanTypeApplyAnnotation.create(on).value(BeanTypeAnnotation.create().propertyNamer(value).build()).build());
3099      }
3100
3101      /**
3102       * Bean property namer
3103       *
3104       * <p>
3105       * The class to use for calculating bean property names.
3106       *
3107       * <p>
3108       * Predefined classes:
3109       * <ul>
3110       *    <li>{@link BasicPropertyNamer} - Default.
3111       *    <li>{@link PropertyNamerDLC} - Dashed-lower-case names.
3112       *    <li>{@link PropertyNamerULC} - Dashed-upper-case names.
3113       * </ul>
3114       *
3115       * <h5 class='section'>Example:</h5>
3116       * <p class='bjava'>
3117       *    <jc>// A bean with a single property.</jc>
3118       *    <jk>public class</jk> MyBean {
3119       *       <jk>public</jk> String <jf>fooBarBaz</jf> = <js>"fooBarBaz"</js>;
3120       *    }
3121       *
3122       *    <jc>// Create a serializer that uses Dashed-Lower-Case property names.</jc>
3123       *    <jc>// (e.g. "foo-bar-baz" instead of "fooBarBaz")</jc>
3124       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
3125       *       .<jsm>create</jsm>()
3126       *       .propertyNamer(PropertyNamerDLC.<jk>class</jk>)
3127       *       .build();
3128       *
3129       *    <jc>// Produces:  {"foo-bar-baz":"fooBarBaz"}</jc>
3130       *    String <jv>json</jv> = <jv>serializer</jv>.write(<jk>new</jk> MyBean());
3131       * </p>
3132       *
3133       * @param value
3134       *    The new value for this setting.
3135       *    <br>Can be <jk>null</jk> (will use {@link BasicPropertyNamer} as the default).
3136       * @return This object.
3137       */
3138      public Builder propertyNamer(Class<? extends PropertyNamer> value) {
3139         propertyNamer = value;
3140         return this;
3141      }
3142
3143      /**
3144       * Disable sorted bean properties.
3145       *
3146       * <p>
3147       * By default, all bean properties are serialized and accessed in alphabetical order.
3148       * Calling this method opts out of that behavior so that declaration order is used instead: record component order for records, field declaration order (superclass first) for other classes, then method-only properties alphabetically.
3149       *
3150       * <h5 class='section'>Example:</h5>
3151       * <p class='bjava'>
3152       *    <jc>// A bean with 3 properties.</jc>
3153       *    <jk>public class</jk> MyBean {
3154       *       <jk>public</jk> String <jf>c</jf> = <js>"1"</js>;
3155       *       <jk>public</jk> String <jf>b</jf> = <js>"2"</js>;
3156       *       <jk>public</jk> String <jf>a</jf> = <js>"3"</js>;
3157       *    }
3158       *
3159       *    <jc>// Create a serializer that does NOT sort bean properties.</jc>
3160       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
3161       *       .<jsm>create</jsm>()
3162       *       .unsortedProperties()
3163       *       .build();
3164       *
3165       *    <jc>// Produces:  {"c":"1","b":"2","a":"3"} (declaration order)</jc>
3166       *    String <jv>json</jv> = <jv>serializer</jv>.write(<jk>new</jk> MyBean());
3167       * </p>
3168       *
3169       * <h5 class='section'>Notes:</h5><ul>
3170       *    <li class='note'>The {@link BeanType#unsorted() @BeanType.unsorted()} annotation can also be used to opt out of sorting on a single class.
3171       * </ul>
3172       *
3173       * @return This object.
3174       */
3175      public Builder unsortedProperties() {
3176         return unsortedProperties(true);
3177      }
3178
3179      /**
3180       * Same as {@link #unsortedProperties()} but allows you to explicitly specify the value.
3181       *
3182       * @param value The value for this setting.
3183       * @return This object.
3184       */
3185      public Builder unsortedProperties(boolean value) {
3186         unsortedProperties = value;
3187         return this;
3188      }
3189
3190      /**
3191       * Use record component order for {@link Record} beans.
3192       *
3193       * <p>
3194       * By default, record properties are sorted alphabetically like every other bean.  Calling this method makes
3195       * records keep their component (declaration) order, even when other beans are sorted.  Non-record beans are
3196       * unaffected.
3197       *
3198       * <h5 class='section'>Example:</h5>
3199       * <p class='bjava'>
3200       *    <jk>public record</jk> Person(String <jv>name</jv>, <jk>int</jk> <jv>age</jv>) {}
3201       *
3202       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
3203       *       .<jsm>create</jsm>()
3204       *       .recordComponentOrder()
3205       *       .build();
3206       *
3207       *    <jc>// Produces:  {"name":"Alice","age":30}</jc>
3208       *    String <jv>json</jv> = <jv>serializer</jv>.write(<jk>new</jk> Person(<js>"Alice"</js>, 30));
3209       * </p>
3210       *
3211       * <h5 class='section'>See Also:</h5><ul>
3212       *    <li class='jm'>{@link #unsortedProperties()} (declaration order for every bean, records included)
3213       *    <li class='ja'>{@link BeanConfig#recordComponentOrder()}
3214       * </ul>
3215       *
3216       * @return This object.
3217       */
3218      public Builder recordComponentOrder() {
3219         return recordComponentOrder(true);
3220      }
3221
3222      /**
3223       * Same as {@link #recordComponentOrder()} but allows you to explicitly specify the value.
3224       *
3225       * @param value The value for this setting.
3226       * @return This object.
3227       */
3228      public Builder recordComponentOrder(boolean value) {
3229         recordComponentOrder = value;
3230         return this;
3231      }
3232
3233      /**
3234       * Opt specific bean classes out of alphabetical property sorting.
3235       *
3236       * <p>
3237       * Applies the {@link BeanType#unsorted() @BeanType(unsorted=true)} annotation to the specified classes,
3238       * overriding the default sorted behavior for those specific beans.
3239       *
3240       * <h5 class='section'>See Also:</h5><ul>
3241       *    <li class='ja'>{@link BeanType#unsorted() @BeanType(unsorted)}
3242       * </ul>
3243       *
3244       * @param on The bean classes to opt out of sorted properties.
3245       *    <br>Cannot contain <jk>null</jk> values.
3246       * @return This object.
3247       */
3248      public Builder unsortedProperties(Class<?>...on) {
3249         reqnns("on", on);
3250         for (var c : on)
3251            annotations(BeanTypeApplyAnnotation.create(c).value(BeanTypeAnnotation.create().unsorted(true).build()).build());
3252         return this;
3253      }
3254
3255      /**
3256       * Identifies a stop class for the annotated class.
3257       *
3258       * <p>
3259       * Identical in purpose to the stop class specified by {@link Introspector#getBeanInfo(Class, Class)}.
3260       * Any properties in the stop class or in its base classes will be ignored during analysis.
3261       *
3262       * <p>
3263       * For example, in the following class hierarchy, instances of <c>C3</c> will include property <c>p3</c>,
3264       * but not <c>p1</c> or <c>p2</c>.
3265       *
3266       * <h5 class='section'>Example:</h5>
3267       * <p class='bjava'>
3268       *    <jk>public class</jk> C1 {
3269       *       <jk>public int</jk> getP1();
3270       *    }
3271       *
3272       *    <jk>public class</jk> C2 <jk>extends</jk> C1 {
3273       *       <jk>public int</jk> getP2();
3274       *    }
3275       *
3276       *    <jk>public class</jk> C3 <jk>extends</jk> C2 {
3277       *       <jk>public int</jk> getP3();
3278       *    }
3279       *
3280       *    <jc>// Create a serializer specifies a stop class for C3.</jc>
3281       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
3282       *       .<jsm>create</jsm>()
3283       *       .stopClass(C3.<jk>class</jk>, C2.<jk>class</jk>)
3284       *       .build();
3285       *
3286       *    <jc>// Produces:  {"p3":"..."}</jc>
3287       *    String <jv>json</jv> = <jv>serializer</jv>.write(<jk>new</jk> C3());
3288       * </p>
3289       *
3290       * @param on The class on which the stop class is being applied.
3291       *    <br>Cannot be <jk>null</jk>.
3292       * @param value
3293       *    The new value for this setting.
3294       *    <br>Cannot be <jk>null</jk>.
3295       * @return This object.
3296       */
3297      public Builder stopClass(Class<?> on, Class<?> value) {
3298         reqnn("on", on);
3299         reqnn("value", value);
3300         return annotations(BeanTypeApplyAnnotation.create(on).value(BeanTypeAnnotation.create().stopClass(value).build()).build());
3301      }
3302
3303      /**
3304       * A shortcut for defining a {@link FunctionalSwap}.
3305       *
3306       * <h5 class='section'>Example:</h5>
3307       * <p class='bjava'>
3308       *    <jc>// Create a serializer that performs a custom format for DAte objects.</jc>
3309       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
3310       *       .<jsm>create</jsm>()
3311       *       .swap(Date.<jk>class</jk>, String.<jk>class</jk>, <jv>x</jv> -&gt; <jsm>format</jsm>(<jv>x</jv>))
3312       *       .build();
3313       * </p>
3314       *
3315       * @param <T> The object type being swapped out.
3316       * @param <S> The object type being swapped in.
3317       * @param normalClass The object type being swapped out.
3318       *    <br>Cannot be <jk>null</jk>.
3319       * @param swappedClass The object type being swapped in.
3320       *    <br>Cannot be <jk>null</jk>.
3321       * @param swapFunction The function to convert the object.
3322       *    <br>Cannot be <jk>null</jk>.
3323       * @return This object.
3324       */
3325      public <T,S> Builder swap(Class<T> normalClass, Class<S> swappedClass, ThrowingFunction<T,S> swapFunction) {
3326         reqnn("normalClass", normalClass);
3327         reqnn("swappedClass", swappedClass);
3328         reqnn("swapFunction", swapFunction);
3329         swaps().add(0, new FunctionalSwap<>(normalClass, swappedClass, swapFunction, null));
3330         return this;
3331      }
3332
3333      /**
3334       * A shortcut for defining a {@link FunctionalSwap}.
3335       *
3336       * <h5 class='section'>Example:</h5>
3337       * <p class='bjava'>
3338       *    <jc>// Create a serializer that performs a custom format for Date objects.</jc>
3339       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
3340       *       .<jsm>create</jsm>()
3341       *       .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>))
3342       *       .build();
3343       * </p>
3344       *
3345       * @param <T> The object type being swapped out.
3346       * @param <S> The object type being swapped in.
3347       * @param normalClass The object type being swapped out.
3348       *    <br>Cannot be <jk>null</jk>.
3349       * @param swappedClass The object type being swapped in.
3350       *    <br>Cannot be <jk>null</jk>.
3351       * @param swapFunction The function to convert the object during serialization.
3352       *    <br>Cannot be <jk>null</jk>.
3353       * @param unswapFunction The function to convert the object during parsing.
3354       *    <br>Cannot be <jk>null</jk>.
3355       * @return This object.
3356       */
3357      public <T,S> Builder swap(Class<T> normalClass, Class<S> swappedClass, ThrowingFunction<T,S> swapFunction, ThrowingFunction<S,T> unswapFunction) {
3358         reqnn("normalClass", normalClass);
3359         reqnn("swappedClass", swappedClass);
3360         reqnn("swapFunction", swapFunction);
3361         reqnn("unswapFunction", unswapFunction);
3362         swaps().add(0, new FunctionalSwap<>(normalClass, swappedClass, swapFunction, unswapFunction));
3363         return this;
3364      }
3365
3366      /**
3367       * Returns the bean swaps list.
3368       *
3369       * <p>
3370       * Gives access to the inner list if you need to make more than simple additions via {@link #swaps(Class...)}.
3371       *
3372       * @return The bean swaps list.
3373       * @see #swaps(Class...)
3374       */
3375      public List<Object> swaps() {
3376         return swaps;
3377      }
3378
3379      /**
3380       * Same as {@link #swaps(Object...)} but explicitly specifies an array of classes to avoid compilation warnings.
3381       *
3382       * @param values
3383       *    The values to add to this setting.
3384       *    <br>Values can consist of any of the following types:
3385       *    <ul>
3386       *       <li>Any subclass of {@link ObjectSwap}.
3387       *       <li>Any surrogate class.  A shortcut for defining a {@link SurrogateSwap}.
3388       *    </ul>
3389       *    <br>Cannot be <jk>null</jk>.
3390       * @return This object.
3391       */
3392      public Builder swaps(Class<?>...values) {
3393         reqnns("values", values);
3394         swaps().addAll(0, accumulate((Object[])values));
3395         return this;
3396      }
3397
3398      /**
3399       * Java object swaps.
3400       *
3401       * <p>
3402       * Swaps are used to "swap out" non-serializable classes with serializable equivalents during serialization,
3403       * and "swap in" the non-serializable class during parsing.
3404       *
3405       * <p>
3406       * An example of a swap would be a <c>Calendar</c> object that gets swapped out for an ISO8601 string.
3407       *
3408       * <p>
3409       * Multiple swaps can be associated with a single class.
3410       * When multiple swaps are applicable to the same class, the media type pattern defined by
3411       * {@link ObjectSwap#forMediaTypes()} or {@link Swap#mediaTypes() @Swap(mediaTypes)} are used to come up with the best match.
3412       *
3413       * <p>
3414       * Values can consist of any of the following types:
3415       * <ul>
3416       *    <li>Any subclass of {@link ObjectSwap}.
3417       *    <li>Any instance of {@link ObjectSwap}.
3418       *    <li>Any surrogate class.  A shortcut for defining a {@link SurrogateSwap}.
3419       *    <li>Any array or collection of the objects above.
3420       * </ul>
3421       *
3422       * <h5 class='section'>Example:</h5>
3423       * <p class='bjava'>
3424       *    <jc>// Sample swap for converting Dates to ISO8601 strings.</jc>
3425       *    <jk>public class</jk> MyDateSwap <jk>extends</jk> StringSwap&lt;Date&gt; {
3426       *       <jc>// ISO8601 formatter.</jc>
3427       *       <jk>private</jk> DateFormat <jf>format</jf> = <jk>new</jk> SimpleDateFormat(<js>"yyyy-MM-dd'T'HH:mm:ssZ"</js>);
3428       *
3429       *       <ja>@Override</ja>
3430       *       <jk>public</jk> String swap(MarshallingSession <jv>session</jv>, Date <jv>date</jv>) {
3431       *          <jk>return</jk> <jf>format</jf>.format(<jv>date</jv>);
3432       *       }
3433       *
3434       *       <ja>@Override</ja>
3435       *       <jk>public</jk> Date unswap(MarshallingSession <jv>session</jv>, String <jv>string</jv>, ClassMeta <jv>hint</jv>) <jk>throws</jk> Exception {
3436       *          <jk>return</jk> <jf>format</jf>.parse(<jv>string</jv>);
3437       *       }
3438       *    }
3439       *
3440       *    <jc>// Sample bean with a Date field.</jc>
3441       *    <jk>public class</jk> MyBean {
3442       *       <jk>public</jk> Date <jf>date</jf> = <jk>new</jk> Date(112, 2, 3, 4, 5, 6);
3443       *    }
3444       *
3445       *    <jc>// Create a serializer that uses our date swap.</jc>
3446       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
3447       *       .<jsm>create</jsm>()
3448       *       .swaps(MyDateSwap.<jk>class</jk>)
3449       *       .build();
3450       *
3451       *    <jc>// Produces:  {"date":"2012-03-03T04:05:06-0500"}</jc>
3452       *    String <jv>json</jv> = <jv>serializer</jv>.write(<jk>new</jk> MyBean());
3453       *
3454       *    <jc>// Create a serializer that uses our date swap.</jc>
3455       *    ReaderParser <jv>parser</jv> = JsonParser
3456       *       .<jsm>create</jsm>()
3457       *       .swaps(MyDateSwap.<jk>class</jk>)
3458       *       .build();
3459       *
3460       *    <jc>// Use our parser to parse a bean.</jc>
3461       *    MyBean <jv>bean</jv> = <jv>parser</jv>.read(<jv>json</jv>, MyBean.<jk>class</jk>);
3462       * </p>
3463       *
3464       * <h5 class='section'>Notes:</h5><ul>
3465       *    <li class='note'>The {@link Swap @Swap} annotation can also be used on classes to identify swaps for the class.
3466       *    <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.
3467       * </ul>
3468       *
3469       * @param values
3470       *    The values to add to this setting.
3471       *    <br>Values can consist of any of the following types:
3472       *    <ul>
3473       *       <li>Any subclass of {@link ObjectSwap}.
3474       *       <li>Any surrogate class.  A shortcut for defining a {@link SurrogateSwap}.
3475       *       <li>Any array/collection/stream of the objects above.
3476       *    </ul>
3477       *    <br>Cannot be <jk>null</jk>.
3478       * @return This object.
3479       */
3480      public Builder swaps(Object...values) {
3481         reqnns("values", values);
3482         swaps().addAll(0, accumulate(values));
3483         return this;
3484      }
3485
3486      /**
3487       * <i><l>Context</l> configuration property:&emsp;</i>  TimeZone.
3488       *
3489       * <p>
3490       * Specifies the default time zone for serializer and parser sessions when not specified via {@link MarshallingSession.Builder#timeZone(TimeZone)}.
3491       * Typically used for POJO swaps that need to deal with timezones such as swaps that convert <l>Date</l> and <l>Calendar</l>
3492       * objects to strings by accessing it via the session passed into the {@link ObjectSwap#swap(MarshallingSession, Object)} and
3493       * {@link ObjectSwap#unswap(MarshallingSession, Object, ClassMeta, String)} methods.
3494       *
3495       * <h5 class='section'>Example:</h5>
3496       * <p class='bjava'>
3497       *    <jc>// Define a POJO swap that skips serializing beans if the time zone is GMT.</jc>
3498       *    <jk>public class</jk> MyBeanSwap <jk>extends</jk> StringSwap&lt;MyBean&gt; {
3499       *       <ja>@Override</ja>
3500       *       <jk>public</jk> String swap(MarshallingSession <jv>session</jv>, MyBean <jv>bean</jv>) <jk>throws</jk> Exception {
3501       *          <jk>if</jk> (<jv>session</jv>.getTimeZone().equals(TimeZone.<jsf>GMT</jsf>))
3502       *             <jk>return null</jk>;
3503       *          <jk>return</jk> <jv>bean</jv>.toString();
3504       *       }
3505       *    }
3506       *
3507       *    <jc>// Create a serializer that uses GMT if the timezone is not specified in the session args.</jc>
3508       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
3509       *       .<jsm>create</jsm>()
3510       *       .timeZone(TimeZone.<jsf>GMT</jsf>)
3511       *       .build();
3512       * </p>
3513       *
3514       * <h5 class='section'>See Also:</h5><ul>
3515       *    <li class='ja'>{@link MarshalledConfig#timeZone()}
3516       *    <li class='jm'>{@link MarshallingSession.Builder#timeZone(TimeZone)}
3517       * </ul>
3518       *
3519       * @param value The new value for this property.
3520       *    <br>Can be <jk>null</jk> (timezone will not be set, defaults to system timezone).
3521       * @return This object.
3522       */
3523      public Builder timeZone(TimeZone value) {
3524         timeZone = value;
3525         return this;
3526      }
3527
3528      /**
3529       * Duration wire format.
3530       *
3531       * @param value The value for this setting.
3532       *    <br>Can be <jk>null</jk> (defaults to {@link DurationFormat#ISO_8601_WITH_DAYS}).
3533       * @return This object.
3534       */
3535      public Builder durationFormat(DurationFormat value) {
3536         durationFormat = value == null ? DurationFormat.ISO_8601_WITH_DAYS : value;
3537         return this;
3538      }
3539
3540      /**
3541       * Period wire format.
3542       *
3543       * @param value The value for this setting.
3544       *    <br>Can be <jk>null</jk> (defaults to {@link PeriodFormat#ISO_8601}).
3545       * @return This object.
3546       */
3547      public Builder periodFormat(PeriodFormat value) {
3548         periodFormat = value == null ? PeriodFormat.ISO_8601 : value;
3549         return this;
3550      }
3551
3552      /**
3553       * Calendar wire format.
3554       *
3555       * @param value The value for this setting.
3556       *    <br>Can be <jk>null</jk> (defaults to {@link CalendarFormat#ISO_OFFSET_DATE_TIME}).
3557       * @return This object.
3558       */
3559      public Builder calendarFormat(CalendarFormat value) {
3560         calendarFormat = value == null ? CalendarFormat.ISO_OFFSET_DATE_TIME : value;
3561         return this;
3562      }
3563
3564      /**
3565       * Date wire format.
3566       *
3567       * @param value The value for this setting.
3568       *    <br>Can be <jk>null</jk> (defaults to {@link DateFormat#ISO_LOCAL_DATE_TIME}).
3569       * @return This object.
3570       */
3571      public Builder dateFormat(DateFormat value) {
3572         dateFormat = value == null ? DateFormat.ISO_LOCAL_DATE_TIME : value;
3573         return this;
3574      }
3575
3576      /**
3577       * Temporal wire format.
3578       *
3579       * @param value The value for this setting.
3580       *    <br>Can be <jk>null</jk> (defaults to {@link TemporalFormat#DEFAULT}).
3581       * @return This object.
3582       */
3583      public Builder temporalFormat(TemporalFormat value) {
3584         temporalFormat = value == null ? TemporalFormat.DEFAULT : value;
3585         return this;
3586      }
3587
3588      /**
3589       * Time-zone wire format.
3590       *
3591       * @param value The value for this setting.
3592       *    <br>Can be <jk>null</jk> (defaults to {@link TimeZoneFormat#ID}).
3593       * @return This object.
3594       */
3595      public Builder timeZoneFormat(TimeZoneFormat value) {
3596         timeZoneFormat = value == null ? TimeZoneFormat.ID : value;
3597         return this;
3598      }
3599
3600      /**
3601       * Locale wire format.
3602       *
3603       * @param value The value for this setting.
3604       *    <br>Can be <jk>null</jk> (defaults to {@link LocaleFormat#BCP_47}).
3605       * @return This object.
3606       */
3607      public Builder localeFormat(LocaleFormat value) {
3608         localeFormat = value == null ? LocaleFormat.BCP_47 : value;
3609         return this;
3610      }
3611
3612      /**
3613       * Binary wire format.
3614       *
3615       * <p>
3616       * Controls how <code><jk>byte</jk>[]</code> values are written to and read from text-based
3617       * serializer / parser wire formats, and the encoding used by stream-based serializers when
3618       * converting their byte output to a string.
3619       *
3620       * @param value The value for this setting.
3621       *    <br>Can be <jk>null</jk> (defaults to {@link BinaryFormat#NOT_SET}).
3622       * @return This object.
3623       */
3624      public Builder binaryFormat(BinaryFormat value) {
3625         binaryFormat = value == null ? BinaryFormat.NOT_SET : value;
3626         return this;
3627      }
3628
3629      /**
3630       * Enum wire format.
3631       *
3632       * @param value The value for this setting.
3633       *    <br>Can be <jk>null</jk> (defaults to {@link EnumFormat#TO_STRING}).
3634       * @return This object.
3635       */
3636      public Builder enumFormat(EnumFormat value) {
3637         enumFormat = value == null ? EnumFormat.TO_STRING : value;
3638         return this;
3639      }
3640
3641      /**
3642       * UUID wire format.
3643       *
3644       * <p>
3645       * Controls how {@link UUID} values are written to text-based wire formats. Binary
3646       * serializers (BSON / CBOR / MsgPack / Prototext) emit native 16-byte binary regardless of this setting.
3647       *
3648       * @param value The value for this setting.
3649       *    <br>Can be <jk>null</jk> (defaults to {@link UuidFormat#STANDARD}).
3650       * @return This object.
3651       */
3652      public Builder uuidFormat(UuidFormat value) {
3653         uuidFormat = value == null ? UuidFormat.STANDARD : value;
3654         return this;
3655      }
3656
3657      /**
3658       * BitSet wire format.
3659       *
3660       * <p>
3661       * Controls how {@link BitSet} values are written to text-based wire formats.
3662       *
3663       * @param value The value for this setting.
3664       *    <br>Can be <jk>null</jk> (defaults to {@link BitSetFormat#INDICES}).
3665       * @return This object.
3666       */
3667      public Builder bitSetFormat(BitSetFormat value) {
3668         bitSetFormat = value == null ? BitSetFormat.INDICES : value;
3669         return this;
3670      }
3671
3672      /**
3673       * Big-number wire format.
3674       *
3675       * <p>
3676       * Controls how {@link BigInteger} and {@link BigDecimal} values are written to
3677       * text-based wire formats. Useful for safe JS interop where values outside
3678       * {@code ±(2^53 − 1)} would silently lose precision.
3679       *
3680       * @param value The value for this setting.
3681       *    <br>Can be <jk>null</jk> (defaults to {@link BigNumberFormat#NUMBER}).
3682       * @return This object.
3683       */
3684      public Builder bigNumberFormat(BigNumberFormat value) {
3685         bigNumberFormat = value == null ? BigNumberFormat.NUMBER : value;
3686         return this;
3687      }
3688
3689      /**
3690       * Boolean wire format.
3691       *
3692       * <p>
3693       * Controls how {@link Boolean} / <code><jk>boolean</jk></code> values are written to text-based
3694       * wire formats. Binary serializers (BSON / CBOR / MsgPack / Prototext / Parquet) emit a native
3695       * boolean wire type regardless of this setting.
3696       *
3697       * @param value The value for this setting.
3698       *    <br>Can be <jk>null</jk> (defaults to {@link BooleanFormat#TRUE_FALSE}).
3699       * @return This object.
3700       */
3701      public Builder booleanFormat(BooleanFormat value) {
3702         booleanFormat = value == null ? BooleanFormat.TRUE_FALSE : value;
3703         return this;
3704      }
3705
3706      /**
3707       * Float / Double non-finite wire format.
3708       *
3709       * <p>
3710       * Controls how non-finite {@link Float} / {@link Double} values ({@code NaN} / {@code ±Infinity})
3711       * are written to text-based wire formats. The default {@link FloatFormat#NaN_AS_NULL} is
3712       * JSON-spec-compliant. Binary serializers emit native IEEE-754 floats regardless of this setting.
3713       *
3714       * @param value The value for this setting.
3715       *    <br>Can be <jk>null</jk> (defaults to {@link FloatFormat#NaN_AS_NULL}).
3716       * @return This object.
3717       */
3718      public Builder floatFormat(FloatFormat value) {
3719         floatFormat = value == null ? FloatFormat.NaN_AS_NULL : value;
3720         return this;
3721      }
3722
3723      /**
3724       * Currency wire format.
3725       *
3726       * <p>
3727       * Controls how {@link Currency} values are written to text-based wire formats. The
3728       * default {@link CurrencyFormat#ISO_CODE} is the only setting safe for machine-to-machine wires;
3729       * {@link CurrencyFormat#SYMBOL} and {@link CurrencyFormat#DISPLAY_NAME} are locale-sensitive and
3730       * best-effort on the parse side.
3731       *
3732       * @param value The value for this setting.
3733       *    <br>Can be <jk>null</jk> (defaults to {@link CurrencyFormat#ISO_CODE}).
3734       * @return This object.
3735       */
3736      public Builder currencyFormat(CurrencyFormat value) {
3737         currencyFormat = value == null ? CurrencyFormat.ISO_CODE : value;
3738         return this;
3739      }
3740
3741      /**
3742       * Class wire format.
3743       *
3744       * <p>
3745       * Controls how {@link Class} values are written to text-based wire formats. The default
3746       * {@link ClassFormat#FQCN} matches the historical {@code ClassSwap} behavior.
3747       * {@link ClassFormat#SIMPLE_NAME} is serialize-only — the parser path throws
3748       * {@link UnsupportedOperationException}.
3749       *
3750       * @param value The value for this setting.
3751       *    <br>Can be <jk>null</jk> (defaults to {@link ClassFormat#FQCN}).
3752       * @return This object.
3753       */
3754      public Builder classFormat(ClassFormat value) {
3755         classFormat = value == null ? ClassFormat.FQCN : value;
3756         return this;
3757      }
3758
3759      /**
3760       * Session classloader.
3761       *
3762       * <p>
3763       * Sets the classloader used when parsing wire-format class names (e.g. FQCN or binary-name strings
3764       * written by {@link org.apache.juneau.marshall.swaps.ClassFormatSwap}).  When <jk>null</jk>, the thread-context classloader is
3765       * used as a fallback — which is the historical behavior.
3766       *
3767       * <p>
3768       * Useful in OSGi bundles, webapp classloaders, and plugin systems where the thread-context
3769       * classloader does not have visibility into the classes that the session needs to resolve.
3770       *
3771       * @param value The classloader to use for class resolution. Can be <jk>null</jk> to reset to thread-context fallback.
3772       * @return This object.
3773       */
3774      public Builder classLoader(ClassLoader value) {
3775         classLoader = value;
3776         return this;
3777      }
3778
3779      @Override /* Overridden from Builder */
3780      public Builder type(Class<? extends Context> value) {
3781         reqnn("value", value);
3782         super.type(value);
3783         return this;
3784      }
3785
3786      /**
3787       * An identifying name for this class.
3788       *
3789       * <p>
3790       * The name is used to identify the class type during parsing when it cannot be inferred through reflection.
3791       * For example, if a bean property is of type <c>Object</c>, then the serializer will add the name to the
3792       * output so that the class can be determined during parsing.
3793       *
3794       * <p>
3795       * It is also used to specify element names in XML.
3796       *
3797       * <h5 class='section'>Example:</h5>
3798       * <p class='bjava'>
3799       *    <jc>// Use _type='mybean' to identify this bean.</jc>
3800       *    <jk>public class</jk> MyBean {...}
3801       *
3802       *    <jc>// Create a serializer and specify the type name..</jc>
3803       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
3804       *       .<jsm>create</jsm>()
3805       *       .typeName(MyBean.<jk>class</jk>, <js>"mybean"</js>)
3806       *       .build();
3807       *
3808       *    <jc>// Produces:  {"_type":"mybean",...}</jc>
3809       *    String <jv>json</jv> = <jv>serializer</jv>.write(<jk>new</jk> MyBean());
3810       * </p>
3811       *
3812       * <h5 class='section'>Notes:</h5><ul>
3813       *    <li class='note'>Equivalent to the {@link Marshalled#typeName() @Marshalled(typeName)} annotation.
3814       * </ul>
3815       *
3816       * <h5 class='section'>See Also:</h5><ul>
3817       *    <li class='jc'>{@link Marshalled#typeName() @Marshalled(typeName)}
3818       *    <li class='jm'>{@link #beanDictionary(Class...)}
3819       * </ul>
3820       *
3821       * @param on
3822       *    The class the type name is being defined on.
3823       *    <br>Cannot be <jk>null</jk>.
3824       * @param value
3825       *    The new value for this setting.
3826       *    <br>Cannot be <jk>null</jk>.
3827       * @return This object.
3828       */
3829      public Builder typeName(Class<?> on, String value) {
3830         reqnn("on", on);
3831         reqnn("value", value);
3832         return annotations(MarshalledApplyAnnotation.create(on).value(MarshalledAnnotation.create().typeName(value).build()).build());
3833      }
3834
3835      /**
3836       * Bean type property name.
3837       *
3838       * <p>
3839       * Same as {@link #typePropertyName(String)} except targets a specific bean class instead of globally.
3840       *
3841       * <h5 class='section'>Example:</h5>
3842       * <p class='bjava'>
3843       *    <jc>// POJOs with @Marshalled(name) annotations.</jc>
3844       *    <ja>@Marshalled</ja>(typeName=<js>"foo"</js>)
3845       *    <jk>public class</jk> Foo {...}
3846       *    <ja>@Marshalled</ja>(typeName=<js>"bar"</js>)
3847       *    <jk>public class</jk> Bar {...}
3848       *
3849       *    <jc>// A bean with a field with an indeterminate type.</jc>
3850       *    <jk>public class</jk> MyBean {
3851       *       <jk>public</jk> Object <jf>mySimpleField</jf>;
3852       *    }
3853       *
3854       *    <jc>// Create a serializer that uses 't' instead of '_type' for dictionary names.</jc>
3855       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
3856       *       .<jsm>create</jsm>()
3857       *       .typePropertyName(MyBean.<jk>class</jk>, <js>"t"</js>)
3858       *       .dictionary(Foo.<jk>class</jk>, Bar.<jk>class</jk>)
3859       *       .build();
3860       *
3861       *    <jc>// Produces "{mySimpleField:{t:'foo',...}}".</jc>
3862       *    String <jv>json</jv> = <jv>serializer</jv>.write(<jk>new</jk> MyBean());
3863       * </p>
3864       *
3865       * <h5 class='section'>See Also:</h5><ul>
3866       *    <li class='ja'>{@link Marshalled#typePropertyName() @Marshalled(typePropertyName)}
3867       * </ul>
3868       *
3869       * @param on The class the type property name applies to.
3870       *    <br>Cannot be <jk>null</jk>.
3871       * @param value
3872       *    The new value for this setting.
3873       *    <br>The default is <js>"_type"</js>.
3874       *    <br>Cannot be <jk>null</jk>.
3875       * @return This object.
3876       */
3877      public Builder typePropertyName(Class<?> on, String value) {
3878         reqnn("on", on);
3879         reqnn("value", value);
3880         return annotations(MarshalledApplyAnnotation.create(on).value(MarshalledAnnotation.create().typePropertyName(value).build()).build());
3881      }
3882
3883      /**
3884       * Bean type property name.
3885       *
3886       * <p>
3887       * This specifies the name of the bean property used to store the dictionary name of a bean type so that the
3888       * parser knows the data type to reconstruct.
3889       *
3890       * <h5 class='section'>Example:</h5>
3891       * <p class='bjava'>
3892       *    <jc>// POJOs with @Marshalled(name) annotations.</jc>
3893       *    <ja>@Marshalled</ja>(typeName=<js>"foo"</js>)
3894       *    <jk>public class</jk> Foo {...}
3895       *    <ja>@Marshalled</ja>(typeName=<js>"bar"</js>)
3896       *    <jk>public class</jk> Bar {...}
3897       *
3898       *    <jc>// Create a serializer that uses 't' instead of '_type' for dictionary names.</jc>
3899       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
3900       *       .<jsm>create</jsm>()
3901       *       .typePropertyName(<js>"t"</js>)
3902       *       .dictionary(Foo.<jk>class</jk>, Bar.<jk>class</jk>)
3903       *       .build();
3904       *
3905       *    <jc>// Create a serializer that uses 't' instead of '_type' for dictionary names.</jc>
3906       *    ReaderParser <jv>parser</jv> = JsonParser
3907       *       .<jsm>create</jsm>()
3908       *       .typePropertyName(<js>"t"</js>)
3909       *       .dictionary(Foo.<jk>class</jk>, Bar.<jk>class</jk>)
3910       *       .build();
3911       *
3912       *    <jc>// A bean with a field with an indeterminate type.</jc>
3913       *    <jk>public class</jk> MyBean {
3914       *       <jk>public</jk> Object <jf>mySimpleField</jf>;
3915       *    }
3916       *
3917       *    <jc>// Produces "{mySimpleField:{t:'foo',...}}".</jc>
3918       *    String <jv>json</jv> = <jv>serializer</jv>.write(<jk>new</jk> MyBean());
3919       *
3920       *    <jc>// Parse bean.</jc>
3921       *    MyBean <jv>bean</jv> = <jv>parser</jv>.read(<jv>json</jv>, MyBean.<jk>class</jk>);
3922       * </p>
3923       *
3924       * <h5 class='section'>See Also:</h5><ul>
3925       *    <li class='ja'>{@link Marshalled#typePropertyName()}
3926       *    <li class='ja'>{@link MarshalledConfig#typePropertyName()}
3927       * </ul>
3928       *
3929       * @param value
3930       *    The new value for this setting.
3931       *    <br>The default is <js>"_type"</js>.
3932       *    <br>Cannot be <jk>null</jk>.
3933       * @return This object.
3934       */
3935      public Builder typePropertyName(String value) {
3936         typePropertyName = reqnn("value", value);
3937         return this;
3938      }
3939
3940      /**
3941       * Use Java Introspector.
3942       *
3943       * <p>
3944       * Using the built-in Java bean introspector will not pick up fields or non-standard getters/setters.
3945       * <br>Most {@link Bean @Marshalled} annotations will be ignored.
3946       *
3947       * <h5 class='section'>Example:</h5>
3948       * <p class='bjava'>
3949       *    <jc>// Create a serializer that only uses the built-in java bean introspector for finding properties.</jc>
3950       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
3951       *       .<jsm>create</jsm>()
3952       *       .useJavaBeanIntrospector()
3953       *       .build();
3954       * </p>
3955       *
3956       * @return This object.
3957       */
3958      public Builder useJavaBeanIntrospector() {
3959         return useJavaBeanIntrospector(true);
3960      }
3961
3962      /**
3963       * Same as {@link #useJavaBeanIntrospector()} but allows you to explicitly specify the value.
3964       *
3965       * @param value The value for this setting.
3966       * @return This object.
3967       */
3968      public Builder useJavaBeanIntrospector(boolean value) {
3969         useJavaBeanIntrospector = value;
3970         return this;
3971      }
3972   }
3973
3974   /*
3975    * The default package pattern exclusion list.
3976    * Any beans in packages in this list will not be considered beans.
3977    */
3978   // @formatter:off
3979   private static final List<String> DEFAULT_NOTBEAN_PACKAGES = l(
3980      "java.lang",
3981      "java.lang.annotation",
3982      "java.lang.ref",
3983      "java.lang.reflect",
3984      "java.io",
3985      "java.net",
3986      "java.nio.*",
3987      "java.util.*"
3988   );
3989   // @formatter:on
3990
3991   /*
3992    * The default bean class exclusion list.
3993    * Anything in this list will not be considered beans.
3994    */
3995   // @formatter:off
3996   private static final List<ClassInfo> DEFAULT_NOTBEAN_CLASSES = l(
3997      info(Map.class),
3998      info(Collection.class),
3999      info(Reader.class),
4000      info(Writer.class),
4001      info(InputStream.class),
4002      info(OutputStream.class),
4003      info(Throwable.class)
4004   );
4005   // @formatter:on
4006
4007   /** Default config.  All default settings. */
4008   public static final MarshallingContext DEFAULT = create().build();
4009
4010   /** Default reusable unmodifiable session.  Can be used to avoid overhead of creating a session (for creating BeanMaps for example).*/
4011   public static final MarshallingSession DEFAULT_SESSION = DEFAULT.createSession().unmodifiable().build();
4012
4013   /**
4014    * Creates a new builder for this object.
4015    *
4016    * @return A new builder.
4017    */
4018   public static Builder create() {
4019      return new Builder();
4020   }
4021
4022   /** Runs the @BeanProp(required) check for a Map-to-bean conversion, adding the parse position when called from a parser. */
4023   private static <T> BeanMap<T> checkRequired(MarshallingSession bs, BeanMap<T> bm) {
4024      return MissingRequiredPropertyException.check(bs instanceof ParserSession ps ? ps : null, bm);
4025   }
4026
4027   /**
4028    * Checks if the specified class should be cached.
4029    *
4030    * <p>
4031    * Generated classes (proxies, lambda expressions, etc.) shouldn't be cacheable to prevent
4032    * needlessly filling up the cache.
4033    *
4034    * @param c The class to check.
4035    * @return <jk>true</jk> if the class should be cached.
4036    */
4037   private static boolean isCacheable(Class<?> c) {
4038      var n = c.getName();
4039      var x = n.charAt(n.length() - 1);  // All generated classes appear to end with digits.
4040      return !((x >= '0' && x <= '9') && (n.indexOf("$$") != -1 || n.startsWith("sun") || n.startsWith("com.sun") || n.indexOf("$Proxy") != -1));
4041   }
4042
4043   private final NullableSupplier<WriterSerializer> beanToStringSerializer;
4044   private final NullableSupplier<BeanConfigContext> beanConfigContext;
4045   private final BeanRegistry beanRegistry;
4046   private final MarshallingSession defaultSession;
4047   private final ConfigurableConverter converter;
4048   private final boolean beanMapPutReturnsOldValue;
4049   private final boolean beansRequireDefaultConstructor;
4050   private final boolean beansRequireSerializable;
4051   private final boolean beansRequireSettersForGetters;
4052   private final boolean beansRequireSomeProperties;
4053   private final boolean findFluentSetters;
4054   private final boolean ignoreInvocationExceptionsOnGetters;
4055   private final boolean ignoreInvocationExceptionsOnSetters;
4056   private final boolean ignoreMissingSetters;
4057   private final boolean ignoreTransientFields;
4058   private final boolean ignoreUnknownBeanProperties;
4059   private final boolean ignoreUnknownEnumValues;
4060   private final boolean ignoreUnknownNullBeanProperties;
4061   private final boolean unsortedProperties;
4062   private final boolean recordComponentOrder;
4063   private final boolean useInterfaceProxies;
4064   private final boolean useJavaBeanIntrospector;
4065   private final boolean validateSchema;
4066   private final Class<? extends PropertyNamer> propertyNamer;
4067   private final ClassMeta<Object> cmObject;  // Reusable ClassMeta that represents general Objects.
4068   private final ClassMeta<String> cmString;  // Reusable ClassMeta that represents general Strings.
4069   private final HashKey hashKey;
4070   private final List<ClassInfo> beanDictionary;
4071   private final List<ClassInfo> notBeanClasses;
4072   private final List<Object> swaps;
4073   private final List<String> notBeanPackages;
4074   private final Locale locale;
4075   private final Cache<Class,ClassMeta> cmCache;
4076   private final MediaType mediaType;
4077   private final List<ObjectSwap<?,?>> objectSwaps;
4078   private final PropertyNamer propertyNamerBean;
4079   private final String typePropertyName;
4080   private final Set<String> notBeanPackageNames;
4081   private final List<String> notBeanPackagePrefixes;
4082   private final TimeZone timeZone;
4083   private final DurationFormat durationFormat;
4084   private final PeriodFormat periodFormat;
4085   private final CalendarFormat calendarFormat;
4086   private final DateFormat dateFormat;
4087   private final TemporalFormat temporalFormat;
4088   private final TimeZoneFormat timeZoneFormat;
4089   private final LocaleFormat localeFormat;
4090   private final BinaryFormat binaryFormat;
4091   private final EnumFormat enumFormat;
4092   private final UuidFormat uuidFormat;
4093   private final BitSetFormat bitSetFormat;
4094   private final BigNumberFormat bigNumberFormat;
4095   private final BooleanFormat booleanFormat;
4096   private final FloatFormat floatFormat;
4097   private final CurrencyFormat currencyFormat;
4098   private final ClassFormat classFormat;
4099   private final ClassLoader classLoader;
4100   private final Visibility beanClassVisibility;
4101   private final Visibility beanConstructorVisibility;
4102   private final Visibility beanFieldVisibility;
4103   private final Visibility beanMethodVisibility;
4104   private final BeanStore beanStore;
4105   private final String activeView;
4106   private final boolean defaultViewInclusion;
4107
4108   /**
4109    * Constructor.
4110    *
4111    * @param builder The builder for this object.
4112    *    <br>Cannot be <jk>null</jk>.
4113    */
4114   public MarshallingContext(Builder builder) {
4115      super(builder);
4116
4117      beanClassVisibility = builder.beanClassVisibility;
4118      beanConstructorVisibility = builder.beanConstructorVisibility;
4119      beanDictionary = u(cp(builder.beanDictionary));
4120      beanFieldVisibility = builder.beanFieldVisibility;
4121      beanMapPutReturnsOldValue = builder.beanMapPutReturnsOldValue;
4122      beanMethodVisibility = builder.beanMethodVisibility;
4123      beansRequireDefaultConstructor = builder.beansRequireDefaultConstructor;
4124      beansRequireSerializable = builder.beansRequireSerializable;
4125      beansRequireSettersForGetters = builder.beansRequireSettersForGetters;
4126      beansRequireSomeProperties = ! builder.disableBeansRequireSomeProperties;
4127      findFluentSetters = builder.findFluentSetters;
4128      hashKey = builder.hashKey();
4129      ignoreInvocationExceptionsOnGetters = builder.ignoreInvocationExceptionsOnGetters;
4130      ignoreInvocationExceptionsOnSetters = builder.ignoreInvocationExceptionsOnSetters;
4131      ignoreMissingSetters = ! builder.disableIgnoreMissingSetters;
4132      ignoreTransientFields = ! builder.disableIgnoreTransientFields;
4133      ignoreUnknownBeanProperties = builder.ignoreUnknownBeanProperties;
4134      ignoreUnknownEnumValues = builder.ignoreUnknownEnumValues;
4135      ignoreUnknownNullBeanProperties = ! builder.disableIgnoreUnknownNullBeanProperties;
4136      locale = o(builder.locale).orElse(Locale.getDefault());
4137      mediaType = builder.mediaType;
4138      notBeanPackages = u(new ArrayList<>(builder.notBeanPackages));
4139      propertyNamer = nn(builder.propertyNamer) ? builder.propertyNamer : BasicPropertyNamer.class;
4140      unsortedProperties = builder.unsortedProperties;
4141      recordComponentOrder = builder.recordComponentOrder;
4142      swaps = u(cp(builder.swaps));
4143      timeZone = builder.timeZone;
4144      durationFormat = builder.durationFormat;
4145      periodFormat = builder.periodFormat;
4146      calendarFormat = builder.calendarFormat;
4147      dateFormat = builder.dateFormat;
4148      temporalFormat = builder.temporalFormat;
4149      timeZoneFormat = builder.timeZoneFormat;
4150      localeFormat = builder.localeFormat;
4151      binaryFormat = builder.binaryFormat;
4152      enumFormat = builder.enumFormat;
4153      uuidFormat = builder.uuidFormat;
4154      bitSetFormat = builder.bitSetFormat;
4155      bigNumberFormat = builder.bigNumberFormat;
4156      booleanFormat = builder.booleanFormat;
4157      floatFormat = builder.floatFormat;
4158      currencyFormat = builder.currencyFormat;
4159      classFormat = builder.classFormat;
4160      classLoader = builder.classLoader;
4161      typePropertyName = o(builder.typePropertyName).orElse("_type");
4162      useInterfaceProxies = ! builder.disableInterfaceProxies;
4163      useJavaBeanIntrospector = builder.useJavaBeanIntrospector;
4164      validateSchema = builder.validateSchema;
4165      beanStore = builder.beanStore;
4166      activeView = builder.activeView;
4167      defaultViewInclusion = ! builder.disableDefaultViewInclusion;
4168
4169      var builderNotBeanClasses = new ArrayList<>(builder.notBeanClasses);
4170      notBeanClasses = builderNotBeanClasses.isEmpty() ? DEFAULT_NOTBEAN_CLASSES : Stream.concat(builderNotBeanClasses.stream(), DEFAULT_NOTBEAN_CLASSES.stream()).distinct().toList();
4171
4172      List<String> notBeanPackagesList = notBeanPackages.isEmpty() ? DEFAULT_NOTBEAN_PACKAGES : Stream.concat(notBeanPackages.stream(), DEFAULT_NOTBEAN_PACKAGES.stream()).toList();
4173      LinkedHashSet<String> notBeanPackageNamesTemp = notBeanPackagesList.stream().filter(x -> ! x.endsWith(".*")).collect(Collectors.toCollection(LinkedHashSet::new));
4174      notBeanPackageNames = u(notBeanPackageNamesTemp);
4175      notBeanPackagePrefixes = notBeanPackagesList.stream().filter(x -> x.endsWith(".*")).map(x -> x.substring(0, x.length() - 2)).toList();
4176
4177      propertyNamerBean = safe(()->propertyNamer.getDeclaredConstructor().newInstance());
4178
4179      var objectSwapsList = new LinkedList<ObjectSwap<?,?>>();
4180      swaps.forEach(x -> {
4181         if (x instanceof ObjectSwap<?,?> x2) {
4182            objectSwapsList.add(x2);
4183         } else {
4184            var ci = info((Class<?>)x);
4185            if (ci.isAssignableTo(ObjectSwap.class))
4186               objectSwapsList.add(BeanInstantiator.of(ObjectSwap.class).type(ci).run());
4187            else if (ci.isAssignableTo(Surrogate.class))
4188               objectSwapsList.addAll(SurrogateSwap.findObjectSwaps(ci.inner(), this));
4189            else
4190               throw rex("Invalid class %s specified in MarshallingContext.swaps property.  Must be a subclass of ObjectSwap or Surrogate.", cn(ci.inner()));
4191         }
4192      });
4193      objectSwaps = u(objectSwapsList);
4194      converter = new ConfigurableConverter(this);
4195
4196      cmCache = Cache.<Class,ClassMeta>create().supplier(type -> new ClassMeta<>(type, this)).build();
4197      cmString = cmCache.get(String.class);
4198      cmObject = cmCache.get(Object.class);
4199
4200      beanRegistry = new BeanRegistry(this, null, list());
4201      defaultSession = createSession().unmodifiable().build();
4202      beanToStringSerializer = memoize(() -> Json5Serializer.create().marshallingContext(this).build());
4203      beanConfigContext = memoize(this::buildBeanConfigContext);
4204   }
4205
4206   /**
4207    * Builds the {@link BeanConfigContext} snapshot exposed by {@link #getBeanConfigContext()}.
4208    *
4209    * Lifts the bean-modeling subset of this context's settings into a portable POJO that the bean-modeling
4210    * runtime in {@code commons.bean} can consume without referencing any marshalling-aware types.
4211    */
4212   private BeanConfigContext buildBeanConfigContext() {
4213      return BeanConfigContext.create()
4214         .beanClassVisibility(beanClassVisibility)
4215         .beanConstructorVisibility(beanConstructorVisibility)
4216         .beanFieldVisibility(beanFieldVisibility)
4217         .beanMethodVisibility(beanMethodVisibility)
4218         .beanMapPutReturnsOldValue(beanMapPutReturnsOldValue)
4219         .beansRequireDefaultConstructor(beansRequireDefaultConstructor)
4220         .beansRequireSerializable(beansRequireSerializable)
4221         .beansRequireSettersForGetters(beansRequireSettersForGetters)
4222         .beansRequireSomeProperties(beansRequireSomeProperties)
4223         .findFluentSetters(findFluentSetters)
4224         .ignoreInvocationExceptionsOnGetters(ignoreInvocationExceptionsOnGetters)
4225         .ignoreInvocationExceptionsOnSetters(ignoreInvocationExceptionsOnSetters)
4226         .ignoreMissingSetters(ignoreMissingSetters)
4227         .ignoreTransientFields(ignoreTransientFields)
4228         .ignoreUnknownBeanProperties(ignoreUnknownBeanProperties)
4229         .ignoreUnknownNullBeanProperties(ignoreUnknownNullBeanProperties)
4230         .unsortedProperties(unsortedProperties)
4231         .recordComponentOrder(recordComponentOrder)
4232         .useInterfaceProxies(useInterfaceProxies)
4233         .useJavaBeanIntrospector(useJavaBeanIntrospector)
4234         .propertyNamer(propertyNamerBean)
4235         .beanTypePropertyName(typePropertyName)
4236         .notBeanPackageNames(notBeanPackageNames)
4237         .notBeanPackagePrefixes(notBeanPackagePrefixes)
4238         .notBeanClasses(notBeanClasses.stream().map(ClassInfo::inner).toList())
4239         .beanStore(beanStore)
4240         .annotationProvider(getAnnotationProvider())
4241         .beanMetaInitializer(MarshalledBeanMetaInitializer.INSTANCE)
4242         .beanPropertyPostProcessor(MarshalledPropertyPostProcessor.INSTANCE)
4243         .build();
4244   }
4245
4246   /**
4247    * Converts the specified value to the specified class type.
4248    *
4249    * <p>
4250    * This is a shortcut for the following code:  <c>createSession().build().convertToType(<jv>value</jv>, <jv>type</jv>);</c>
4251    *
4252    * @param <T> The class type to convert the value to.
4253    * @param value The value to convert.
4254    *    <br>Can be <jk>null</jk> (returns <jk>null</jk>).
4255    * @param type The class type to convert the value to.
4256    *    <br>Cannot be <jk>null</jk>.
4257    * @throws InvalidDataConversionException If the specified value cannot be converted to the specified type.
4258    * @return The converted value.
4259    * @see MarshallingSession#convertToType(Object, Class)
4260    */
4261   public final <T> T convertToType(Object value, Class<T> type) throws InvalidDataConversionException {
4262      return defaultSession.convertToType(value, type);
4263   }
4264
4265   @Override /* Overridden from Context */
4266   public Builder copy() {
4267      return new Builder(this);
4268   }
4269
4270   @Override /* Overridden from Context */
4271   public MarshallingSession.Builder<?> createSession() {
4272      return MarshallingSession.create(this);
4273   }
4274
4275   /**
4276    * Minimum bean class visibility.
4277    *
4278    * @see MarshallingContext.Builder#beanClassVisibility(Visibility)
4279    * @return
4280    *    Classes are not considered beans unless they meet the minimum visibility requirements.
4281    */
4282   public final Visibility getBeanClassVisibility() { return beanClassVisibility; }
4283
4284   /**
4285    * Minimum bean constructor visibility.
4286    *
4287    * @see MarshallingContext.Builder#beanConstructorVisibility(Visibility)
4288    * @return
4289    *    Only look for constructors with this specified minimum visibility.
4290    */
4291   public final Visibility getBeanConstructorVisibility() { return beanConstructorVisibility; }
4292
4293   /**
4294    * The bean store used for factory-based instantiation.
4295    *
4296    * @see MarshallingContext.Builder#beanStore(BeanStore)
4297    * @return The bean store, or <jk>null</jk> if none configured.
4298    */
4299   public final BeanStore getBeanStore() { return beanStore; }
4300
4301   /**
4302    * Bean dictionary.
4303    *
4304    * @see MarshallingContext.Builder#beanDictionary()
4305    * @return
4306    *    The list of classes that make up the bean dictionary in this bean context.
4307    *    <br>Never <jk>null</jk>.
4308    *    <br>List is unmodifiable.
4309    */
4310   public final List<ClassInfo> getBeanDictionary() { return beanDictionary; }
4311
4312   /**
4313    * Returns the {@link BeanConfigContext} snapshot for this marshalling context.
4314    *
4315    * <p>
4316    * The snapshot lifts the bean-modeling subset of this context's settings into a portable POJO that the
4317    * bean-modeling runtime in {@code commons.bean} can consume without referencing any marshalling-aware types.
4318    * It is computed lazily on first access and cached for the lifetime of this context.
4319    *
4320    * <p>
4321    * Mutating the returned snapshot's settings (via {@link BeanConfigContext#copy()} and a fresh build) does not
4322    * affect this marshalling context.
4323    *
4324    * @return The bean-modeling configuration snapshot.  Never <jk>null</jk>.
4325    */
4326   public final BeanConfigContext getBeanConfigContext() { return beanConfigContext.get(); }
4327
4328   /**
4329    * Minimum bean field visibility.
4330    *
4331    *
4332    * @see MarshallingContext.Builder#beanFieldVisibility(Visibility)
4333    * @return
4334    *    Only look for bean fields with this specified minimum visibility.
4335    */
4336   public final Visibility getBeanFieldVisibility() { return beanFieldVisibility; }
4337
4338   /**
4339    * Returns the converter for this context.
4340    *
4341    * @return The converter.
4342    */
4343   public final ConfigurableConverter getConverter() { return converter; }
4344
4345   /**
4346    * Fallback for an ObjectSwap-conversion whose swap-class doesn't bridge to the input, but where the input
4347    * is already a {@link Map} matching the target's own Map shape -- copies its entries into a new instance
4348    * of the target type rather than dropping the value as {@code null}.
4349    *
4350    * @param toMeta The target type.
4351    * @param in The input value.
4352    * @return A new map instance of the target type populated with the input's entries, or <jk>null</jk> if
4353    *    the target isn't Map-shaped or the input isn't a {@link Map}.
4354    */
4355   private static Object copyMapEntries(ClassMeta<?> toMeta, Object in) {
4356      if (! (toMeta.isMap() && in instanceof Map<?,?> in2))
4357         return null;
4358      var result = (Map<Object,Object>) (toMeta.canCreateNewInstance() ? toMeta.newInstance() : new LinkedHashMap<>());
4359      result.putAll(in2);
4360      return result;
4361   }
4362
4363   /**
4364    * Implements {@link ConversionFinder} to provide all MarshallingContext-specific type conversions that cannot
4365    * be expressed in {@link BasicConverter} (which has no dependency on {@code juneau-marshall}).
4366    *
4367    * <p>
4368    * Conversions are resolved in this priority order:
4369    * <ol>
4370    *    <li>ObjectSwap-based conversions (highest priority)
4371    *    <li>Iso8601 date/time formatting and parsing
4372    *    <li>Epoch-millis to date/time
4373    *    <li>Map/Bean/Collection/Array to String via serializer
4374    *    <li>String/CharSequence to Array, Map, Collection via JSON parsing
4375    *    <li>Map to Bean and String to Bean via BeanMap
4376    *    <li>Calendar/Date specialized copies
4377    *    <li>InputStream and Reader construction
4378    * </ol>
4379    *
4380    * @param inType The input type class.
4381    * @param outType The output type class.
4382    * @return A matching {@link Conversion}, or {@code null} if none applies.
4383    */
4384   @Override
4385   @SuppressWarnings({
4386      "java:S6541", // Brain Method: conversion dispatch inherently requires handling many type pairs in one place
4387      "null" // `builder` is guarded by `nn(builder)` before access; Eclipse doesn't recognise `nn()` as a null-check function.
4388   })
4389   public Conversion<?,?> findConversion(Class<?> inType, Class<?> outType) {
4390      var toMeta = getClassMeta(outType);
4391      var fromMeta = getClassMeta(inType);
4392
4393      // --- ObjectSwap conversions (must come first) ---
4394      for (var swap : objectSwaps) {
4395         var nc = swap.getNormalClass().inner();
4396         var fc = swap.getSwapClass().inner();
4397         // Unswap: input is swap class (or convertible to it), output is normal class
4398         if (nc.isAssignableFrom(outType) && (fc.isAssignableFrom(inType) || Map.class.isAssignableFrom(inType) || Number.class.isAssignableFrom(inType))) {
4399            return (in, memberOf, session, args) -> {
4400               try {
4401                  var bs = marshallingSession(session);
4402                  var resolvedSwap = bs != null ? toMeta.getSwap(bs) : null;
4403                  var activeSwap = (ObjectSwap<Object,Object>) or(resolvedSwap, swap);
4404                  var swapClass = activeSwap.getSwapClass().inner();
4405                  // Direct match
4406                  if (swapClass.isInstance(in))
4407                     return activeSwap.unswap(bs, in, toMeta);
4408                  // Intermediate Map conversion
4409                  if (Map.class.isAssignableFrom(swapClass) && in instanceof Map)
4410                     return activeSwap.unswap(bs, converter.to(in, memberOf, bs, swapClass), toMeta);
4411                  // Intermediate Number conversion
4412                  if (Number.class.isAssignableFrom(swapClass) && in instanceof Number)
4413                     return activeSwap.unswap(bs, converter.to(in, memberOf, bs, swapClass), toMeta);
4414                  // The swap's own swap-class is shaped like neither Map nor Number, so it doesn't apply to
4415                  // this input -- but if the input is already a Map matching toMeta's own Map shape, copy
4416                  // its entries directly rather than dropping the value.
4417                  return copyMapEntries(toMeta, in);
4418               } catch (Exception e) {
4419                  throw rex(e);
4420               }
4421            };
4422         }
4423         // Swap: input is normal class, output is swap class
4424         if (nc.isAssignableFrom(inType) && fc.isAssignableFrom(outType)) {
4425            return (in, memberOf, session, args) -> {
4426               try {
4427                  var bs = marshallingSession(session);
4428                  return ((ObjectSwap<Object,Object>) swap).swap(bs, in);
4429               } catch (Exception e) {
4430                  throw rex(e);
4431               }
4432            };
4433         }
4434      }
4435
4436      // --- Inline/auto-detected swaps from ClassMeta (e.g. AutoNumberSwap, AutoObjectSwap) ---
4437      // These are swaps found on the class itself (via swap() methods, toXxx() patterns, etc.)
4438      // and not registered in the objectSwaps list.
4439      var toSwap = toMeta.getSwap(null);
4440      if (toSwap != null) {
4441         // Use boxed version of swap class to handle primitive swap types (e.g. toInt() → int.class → Integer.class)
4442         var fcBoxed = info(toSwap.getSwapClass().inner()).getWrapperIfPrimitive().inner();
4443         if (fcBoxed.isAssignableFrom(inType) || Map.class.isAssignableFrom(inType) || Number.class.isAssignableFrom(inType)) {
4444            return (in, memberOf, session, args) -> {
4445               try {
4446               var bs = marshallingSession(session);
4447               var activeSwap = (ObjectSwap<Object,Object>) toMeta.getSwap(bs);
4448                  if (activeSwap == null) return null;
4449                  // Use boxed swap class to handle primitive return types (e.g. int.class → Integer.class)
4450                  var swapClass = info(activeSwap.getSwapClass().inner()).getWrapperIfPrimitive().inner();
4451                  if (swapClass.isInstance(in))
4452                     return activeSwap.unswap(bs, in, toMeta);
4453                  if (Map.class.isAssignableFrom(swapClass) && in instanceof Map)
4454                     return activeSwap.unswap(bs, converter.to(in, memberOf, bs, swapClass), toMeta);
4455                  if (Number.class.isAssignableFrom(swapClass) && in instanceof Number)
4456                     return activeSwap.unswap(bs, converter.to(in, memberOf, bs, swapClass), toMeta);
4457                  // See the analogous fallback in the objectSwaps loop above.
4458                  return copyMapEntries(toMeta, in);
4459               } catch (Exception e) {
4460                  throw rex(e);
4461               }
4462            };
4463         }
4464      }
4465      var fromSwap = fromMeta.getSwap(null);
4466      if (fromSwap != null) {
4467         var fcBoxed = info(fromSwap.getSwapClass().inner()).getWrapperIfPrimitive().inner();
4468         if (fcBoxed.isAssignableFrom(outType) || outType == Object.class) {
4469            return (in, memberOf, session, args) -> {
4470               try {
4471               var bs = marshallingSession(session);
4472               var activeSwap = (ObjectSwap<Object,Object>) fromMeta.getSwap(bs);
4473                  if (activeSwap == null) return null;
4474                  return activeSwap.swap(bs, in);
4475               } catch (Exception e) {
4476                  throw rex(e);
4477               }
4478            };
4479         }
4480      }
4481
4482      // --- Date/time → CharSequence via Iso8601Utils (Gap 5) ---
4483      if (CharSequence.class.isAssignableFrom(outType) && (fromMeta.isDateOrCalendarOrTemporal() || fromMeta.isDuration()))
4484         return (in, memberOf, session, args) -> Iso8601Utils.format(in, fromMeta, sessionTimeZone(session));
4485
4486      // --- CharSequence → date/time via Iso8601Utils (Gap 6) ---
4487      if (CharSequence.class.isAssignableFrom(inType) && (toMeta.isDateOrCalendarOrTemporal() || toMeta.isDuration()))
4488         return (in, memberOf, session, args) -> Iso8601Utils.parse(in.toString(), toMeta, sessionTimeZone(session));
4489
4490      // --- Number → date/time via epoch millis (Gap 7) ---
4491      if (Number.class.isAssignableFrom(inType) && toMeta.isDateOrCalendarOrTemporal())
4492         return (in, memberOf, session, args) -> Iso8601Utils.fromEpochMillis(((Number)in).longValue(), toMeta, sessionTimeZone(session));
4493
4494      // --- Map/Bean/Collection/Array/Optional → String via serializer (Gap 14) ---
4495      if (outType == String.class) {
4496         // byte[] → String must come before isCollectionOrArrayOrOptional since byte[] is an array type
4497         if (byte[].class == inType)
4498            return (in, memberOf, session, args) -> new String((byte[]) in, StandardCharsets.UTF_8);
4499         if (fromMeta.isMapOrBean() || fromMeta.isCollectionOrArrayOrOptional()) {
4500            return (in, memberOf, session, args) -> {
4501               try {
4502                  var ws = getBeanToStringSerializer();
4503                  return ws != null ? ws.write(in) : in.toString();
4504               } catch (Exception e) {
4505                  throw rex(e);
4506               }
4507            };
4508         }
4509         if (Class.class == inType)
4510            return (in, memberOf, session, args) -> ((Class<?>) in).getName();
4511      }
4512
4513      // --- CharSequence → Array via JSON parsing (Gap 10) ---
4514      // Excludes byte[] since that is handled by BasicConverter.findSpecialConversion (getBytes(UTF_8)).
4515      if (CharSequence.class.isAssignableFrom(inType) && outType.isArray() && outType != byte[].class) {
4516         return (in, memberOf, session, args) -> {
4517            try {
4518               var bs = beanSessionOrDefault(session);
4519               var str = in.toString();
4520               Json5List list;
4521               if (startsWith(str, '['))
4522                  list = Json5List.ofString(str).setBeanSession(bs);
4523               else
4524                  list = new Json5List((Object[]) splita(str)).setBeanSession(bs);
4525               return bs.convertToType(list, outType);
4526            } catch (Exception e) {
4527               throw rex(e);
4528            }
4529         };
4530      }
4531
4532      // --- CharSequence → Map via JSON parsing (Gap 11) ---
4533      if (CharSequence.class.isAssignableFrom(inType) && Map.class.isAssignableFrom(outType) && !toMeta.canCreateNewInstanceFromString(null)) {
4534         return (in, memberOf, session, args) -> {
4535            try {
4536               var bs = beanSessionOrDefault(session);
4537               var m = Json5Map.ofString(in.toString());
4538               m.setBeanSession(bs);
4539               return bs.convertToType(m, outType);
4540            } catch (Exception e) {
4541               throw rex(e);
4542            }
4543         };
4544      }
4545
4546      // --- Collection/Array → Collection with session-aware element conversion ---
4547      // When the target is an abstract collection type (List, Collection), uses JsonList instead of ArrayList
4548      // to preserve the session-aware default behavior from the original convertToCollectionType.
4549      if ((Collection.class.isAssignableFrom(inType) || inType.isArray()) && Collection.class.isAssignableFrom(outType)) {
4550         return (in, memberOf, session, args) -> {
4551            // Treat Object.class as "no element type" (untyped/raw, needs no element conversion).
4552            var elemType = args.length > 0 && args[0] != Object.class ? (Class<?>) args[0] : null;
4553            if (elemType == null && !inType.isArray() && outType.isAssignableFrom(in.getClass()))
4554               return in;
4555            var bs = beanSessionOrDefault(session);
4556            Collection<Object> result;
4557            if (outType.isAssignableFrom(JsonList.class)) {
4558               result = new JsonList(bs);  // Use JsonList for abstract types (List, Collection, Iterable)
4559            } else {
4560               result = newCollection(outType);
4561            }
4562            if (in instanceof Collection<?> col2) {
4563               for (var elem : col2)
4564                  result.add(elemType != null ? converter.to(elem, memberOf, session, elemType) : elem);
4565            } else {
4566               var len = Array.getLength(in);
4567               for (var i = 0; i < len; i++) {
4568                  var elem = Array.get(in, i);
4569                  result.add(elemType != null ? converter.to(elem, memberOf, session, elemType) : elem);
4570               }
4571            }
4572            return result;
4573         };
4574      }
4575
4576      // --- Map → Collection (wraps map as single element, preserving old convertToCollectionType behavior) ---
4577      if (Map.class.isAssignableFrom(inType) && Collection.class.isAssignableFrom(outType)) {
4578         return (in, memberOf, session, args) -> {
4579            var bs = beanSessionOrDefault(session);
4580            Collection<Object> result;
4581            if (outType.isAssignableFrom(JsonList.class)) {
4582               result = new JsonList(bs);
4583            } else {
4584               result = newCollection(outType);
4585            }
4586            var elemType = args.length > 0 && args[0] != Object.class ? (Class<?>) args[0] : null;
4587            result.add(elemType != null ? converter.to(in, memberOf, session, elemType) : in);
4588            return result;
4589         };
4590      }
4591
4592      // --- CharSequence → Collection via JSON parsing (Gap 12) ---
4593      if (CharSequence.class.isAssignableFrom(inType) && Collection.class.isAssignableFrom(outType)) {
4594         return (in, memberOf, session, args) -> {
4595            try {
4596               var bs = beanSessionOrDefault(session);
4597               var str = in.toString();
4598               if (!isProbablyJsonArray(str, false))
4599                  throw rex("Cannot convert string to %s: %s", outType.getName(), str);
4600               var elemType = args.length > 0 ? args[0] : null;
4601               var l2 = Json5List.ofString(str).setBeanSession(bs);
4602               var result = newCollection(outType);
4603               l2.forEach(x -> result.add(elemType != null && x != null ? converter.to(x, elemType) : x));
4604               return result;
4605            } catch (Exception e) {
4606               throw rex(e);
4607            }
4608         };
4609      }
4610
4611      // --- Map → Bean via BeanMap/BuilderSwap/BeanRegistry (Gap 17) ---
4612      if (Map.class.isAssignableFrom(inType) && toMeta.isBean()) {
4613         return (in, memberOf, session, args) -> {
4614            try {
4615               var bs = beanSessionOrDefault(session);
4616               var m2 = (Map<?,?>) in;
4617               var builder = (BuilderSwap<Object,Object>) toMeta.getBuilderSwap(bs);
4618               if (m2 instanceof MarshalledMap mm && builder == null) {
4619                  var typeName = mm.getString(bs.getBeanTypePropertyName(toMeta));
4620                  if (nn(typeName)) {
4621                     var cm = toMeta.getBeanRegistry().getClassMeta(typeName);
4622                     if (nn(cm) && toMeta.isAssignableFrom(cm.inner()))
4623                        return mm.cast(cm);
4624                  }
4625               }
4626               if (nn(builder)) {
4627                  var created = builder.create(bs, toMeta);
4628                  if (created != null) {
4629                     var bm = bs.toBeanMap(created);
4630                     bm.load(m2);
4631                     return builder.build(bs, checkRequired(bs, bm).getBean(), toMeta);
4632                  }
4633               }
4634               return checkRequired(bs, bs.newBeanMap(toMeta.inner()).load(m2)).getBean();
4635            } catch (Exception e) {
4636               var mrpe = MissingRequiredPropertyException.find(e);
4637               throw nn(mrpe) ? mrpe : rex(e);
4638            }
4639         };
4640      }
4641
4642      // --- CharSequence → URL (URL(String) is deprecated in Java 20+, use URI.create().toURL() instead) ---
4643      if (CharSequence.class.isAssignableFrom(inType) && outType == URL.class)
4644         return (in, memberOf, session, args) -> {
4645            try {
4646               return new URI(in.toString()).toURL();
4647            } catch (Exception e) {
4648               throw rex(e);
4649            }
4650         };
4651
4652      // --- CharSequence → Bean via BeanMap (Gap 21) ---
4653      if (CharSequence.class.isAssignableFrom(inType) && toMeta.isBean()) {
4654         return (in, memberOf, session, args) -> {
4655            try {
4656               var bs = beanSessionOrDefault(session);
4657               return BeanMapLoader.load(bs.newBeanMap(toMeta.inner()), in.toString()).getBean();
4658            } catch (Exception e) {
4659               throw rex(e);
4660            }
4661         };
4662      }
4663
4664      // --- Calendar/Date specialized conversions (Gap 19) ---
4665      if (toMeta.isCalendar()) {
4666         if (Calendar.class.isAssignableFrom(inType))
4667            return (in, memberOf, session, args) -> {
4668               var c = (Calendar) in;
4669               var c2 = new GregorianCalendar(c.getTimeZone());
4670               c2.setTime(c.getTime());
4671               return c2;
4672            };
4673         if (Date.class.isAssignableFrom(inType))
4674            return (in, memberOf, session, args) -> {
4675               var c2 = new GregorianCalendar(TimeZone.getDefault());
4676               c2.setTime((Date) in);
4677               return c2;
4678            };
4679         if (Temporal.class.isAssignableFrom(inType))
4680            return (in, memberOf, session, args) -> {
4681               var temporal = (Temporal) in;
4682               Instant instant;
4683               try {
4684               instant = Instant.from(temporal);
4685               } catch (@SuppressWarnings("unused") DateTimeException e) {
4686               // LocalDateTime lacks offset info - interpret using session/system timezone
4687               var tz = sessionTimeZone(session);
4688               var zoneId = tz != null ? tz.toZoneId() : ZoneId.systemDefault();
4689               instant = LocalDateTime.from(temporal).atZone(zoneId).toInstant();
4690            }
4691            return Iso8601Utils.fromEpochMillis(instant.toEpochMilli(), toMeta, sessionTimeZone(session));
4692            };
4693      }
4694      if (toMeta.isDate() && outType == Date.class) {
4695         if (Calendar.class.isAssignableFrom(inType))
4696            return (in, memberOf, session, args) -> ((Calendar) in).getTime();
4697         if (Temporal.class.isAssignableFrom(inType))
4698            return (in, memberOf, session, args) -> {
4699               var temporal = (Temporal) in;
4700               Instant instant;
4701               try {
4702               instant = Instant.from(temporal);
4703               } catch (@SuppressWarnings("unused") DateTimeException e) {
4704               // LocalDateTime lacks offset info - interpret using session/system timezone
4705               var tz = sessionTimeZone(session);
4706               var zoneId = tz != null ? tz.toZoneId() : ZoneId.systemDefault();
4707               instant = LocalDateTime.from(temporal).atZone(zoneId).toInstant();
4708            }
4709            return Date.from(instant);
4710            };
4711      }
4712
4713      // --- byte[]/CharSequence → InputStream (Gap 18) ---
4714      if (InputStream.class.isAssignableFrom(outType)) {
4715         if (byte[].class == inType)
4716            return (in, memberOf, session, args) -> { var b = (byte[]) in; return new ByteArrayInputStream(b, 0, b.length); };
4717         if (CharSequence.class.isAssignableFrom(inType))
4718            return (in, memberOf, session, args) -> { var b = in.toString().getBytes(); return new ByteArrayInputStream(b, 0, b.length); };
4719      }
4720
4721      // --- byte[]/CharSequence → Reader (Gap 18) ---
4722      if (Reader.class.isAssignableFrom(outType)) {
4723         if (byte[].class == inType)
4724            return (in, memberOf, session, args) -> new StringReader(new String((byte[]) in));
4725         if (CharSequence.class.isAssignableFrom(inType))
4726            return (in, memberOf, session, args) -> new StringReader(in.toString());
4727      }
4728
4729      // --- CharSequence → Enum using ClassMeta (respects ignoreUnknownEnumValues) (Gap 13) ---
4730      if (CharSequence.class.isAssignableFrom(inType) && outType.isEnum()) {
4731         return (in, memberOf, session, args) -> {
4732            try {
4733               return toMeta.newInstanceFromString(memberOf, in.toString());
4734            } catch (Exception e) {
4735               throw rex(e);
4736            }
4737         };
4738      }
4739
4740      // --- CharSequence → CharSequence subtype via ClassMeta (Gap 15) ---
4741      if (CharSequence.class.isAssignableFrom(inType) && toMeta.isCharSequence() && outType != String.class && toMeta.canCreateNewInstanceFromString(null)) {
4742         return (in, memberOf, session, args) -> {
4743            try {
4744               return toMeta.newInstanceFromString(memberOf, in.toString());
4745            } catch (Exception e) {
4746               throw rex(e);
4747            }
4748         };
4749      }
4750
4751      // --- Array → CharSequence subtype via serializer (Gap 15) ---
4752      if (inType.isArray() && toMeta.isCharSequence() && outType != String.class && toMeta.canCreateNewInstanceFromString(null)) {
4753         return (in, memberOf, session, args) -> {
4754            try {
4755               var ws = getBeanToStringSerializer();
4756               var str = ws != null ? ws.write(in) : in.toString();
4757               return toMeta.newInstanceFromString(memberOf, str);
4758            } catch (Exception e) {
4759               throw rex(e);
4760            }
4761         };
4762      }
4763
4764      // --- Enum → T via toString() (allows Enum→Boolean, Enum→Number, etc.) ---
4765      // Excludes Enum→Enum (handled by BasicConverter) and Enum→String (handled by BasicConverter/CharSequence path).
4766      if (inType.isEnum() && !outType.isEnum() && !CharSequence.class.isAssignableFrom(outType)) {
4767         return (in, memberOf, session, args) -> converter.to(in.toString(), memberOf, session, outType, args);
4768      }
4769
4770      // --- Object → Boolean via toString() (lenient: any non-"true" string is false) ---
4771      // Excludes CharSequence types (handled by BasicConverter), primitives (handled by CachingConverter nullDefault),
4772      // and types that BasicConverter already handles (e.g. via toBoolean() instance method).
4773      if ((outType == Boolean.class || outType == boolean.class) && !CharSequence.class.isAssignableFrom(inType) && !Number.class.isAssignableFrom(inType) && inType != boolean.class && inType != Boolean.class && !BasicConverter.INSTANCE.canConvert(inType, Boolean.class)) {
4774         return (in, memberOf, session, args) -> converter.to(in.toString(), memberOf, session, Boolean.class);
4775      }
4776
4777   // --- Object → Bean via toString() + BeanMap.load() (fallback for bean-compatible types) ---
4778   // Replicates the old convertToMemberType fallback for beans (newBeanMap + load + getBean).
4779   // Excludes cases where input is already assignable to output (handled by MarshallingSession isInstance shortcut).
4780      if (toMeta.isBean() && !Map.class.isAssignableFrom(inType) && !CharSequence.class.isAssignableFrom(inType)
4781            && !outType.isAssignableFrom(inType)) {
4782         return (in, memberOf, session, args) -> {
4783            try {
4784               var bs = beanSessionOrDefault(session);
4785               return BeanMapLoader.load(bs.newBeanMap(toMeta.inner()), in.toString()).getBean();
4786            } catch (Exception e) {
4787               throw rex(e);
4788            }
4789         };
4790      }
4791
4792      return null;
4793   }
4794
4795   private static TimeZone sessionTimeZone(ConverterSession session) {
4796      return session == null ? null : session.get(TimeZone.class).orElse(null);
4797   }
4798
4799   private static MarshallingSession marshallingSession(ConverterSession session) {
4800      return session instanceof MarshallingSession session2 ? session2 : null;
4801   }
4802
4803   private MarshallingSession beanSessionOrDefault(ConverterSession session) {
4804      return session instanceof MarshallingSession session2 ? session2 : defaultSession;
4805   }
4806
4807   private static Collection<Object> newCollection(Class<?> outType) {
4808      if (outType == List.class || outType == Collection.class || outType == Iterable.class || outType == AbstractList.class)
4809         return l();
4810      if (outType == Set.class || outType == LinkedHashSet.class || outType == AbstractSet.class)
4811         return new LinkedHashSet<>();
4812      if (outType == SortedSet.class || outType == NavigableSet.class || outType == TreeSet.class)
4813         return new TreeSet<>();
4814      try {
4815         return (Collection<Object>) outType.getDeclaredConstructor().newInstance();
4816      } catch (@SuppressWarnings("unused") Exception e) {
4817         return l();
4818      }
4819   }
4820
4821   /**
4822    * Returns the {@link BeanMeta} class for the specified class.
4823    *
4824    * @param <T> The class type to get the meta-data on.
4825    * @param c The class to get the meta-data on.
4826    *    <br>Cannot be <jk>null</jk>.
4827    * @return
4828    *    The {@link BeanMeta} for the specified class, or <jk>null</jk> if the class is not a bean per the settings on
4829    *    this context.
4830    */
4831   public final <T> BeanMeta<T> getBeanMeta(Class<T> c) {
4832      reqnn("c", c);
4833      return getClassMeta(c).getBeanMeta();
4834   }
4835
4836   /**
4837    * Minimum bean method visibility.
4838    *
4839    * @see MarshallingContext.Builder#beanMethodVisibility(Visibility)
4840    * @return
4841    *    Only look for bean methods with this specified minimum visibility.
4842    */
4843   public final Visibility getBeanMethodVisibility() { return beanMethodVisibility; }
4844
4845
4846   /**
4847    * Bean type property name.
4848    *
4849    * @see MarshallingContext.Builder#typePropertyName(String)
4850    * @return
4851    * 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.
4852    */
4853   public final String getBeanTypePropertyName() { return typePropertyName; }
4854
4855   /**
4856    * Construct a {@code ClassMeta} wrapper around a {@link Class} object.
4857    *
4858    * @param <T> The class type being wrapped.
4859    * @param type The class to resolve.
4860    *    <br>Cannot be <jk>null</jk>.
4861    * @return
4862    *    If the class is not an array, returns a cached {@link ClassMeta} object.
4863    *    Otherwise, returns a new {@link ClassMeta} object every time.
4864    */
4865   public final <T> ClassMeta<T> getClassMeta(Class<T> type) {
4866      // Non-cacheable classes (proxies, generated classes) should not be cached
4867      if (! isCacheable(type))
4868         return new ClassMeta<>(type, this);
4869      return cmCache.get(type);
4870   }
4871
4872   /**
4873    * Used to resolve <c>ClassMetas</c> of type <c>Collection</c> and <c>Map</c> that have
4874    * <c>ClassMeta</c> values that themselves could be collections or maps.
4875    *
4876    * <p>
4877    * <c>Collection</c> meta objects are assumed to be followed by zero or one meta objects indicating the element type.
4878    *
4879    * <p>
4880    * <c>Map</c> meta objects are assumed to be followed by zero or two meta objects indicating the key and value types.
4881    *
4882    * <p>
4883    * The array can be arbitrarily long to indicate arbitrarily complex data structures.
4884    *
4885    * <h5 class='section'>Examples:</h5>
4886    * <ul>
4887    *    <li><code>getClassMeta(String.<jk>class</jk>);</code> - A normal type.
4888    *    <li><code>getClassMeta(List.<jk>class</jk>);</code> - A list containing objects.
4889    *    <li><code>getClassMeta(List.<jk>class</jk>, String.<jk>class</jk>);</code> - A list containing strings.
4890    *    <li><code>getClassMeta(LinkedList.<jk>class</jk>, String.<jk>class</jk>);</code> - A linked-list containing
4891    *       strings.
4892    *    <li><code>getClassMeta(LinkedList.<jk>class</jk>, LinkedList.<jk>class</jk>, String.<jk>class</jk>);</code> -
4893    *       A linked-list containing linked-lists of strings.
4894    *    <li><code>getClassMeta(Map.<jk>class</jk>);</code> - A map containing object keys/values.
4895    *    <li><code>getClassMeta(Map.<jk>class</jk>, String.<jk>class</jk>, String.<jk>class</jk>);</code> - A map
4896    *       containing string keys/values.
4897    *    <li><code>getClassMeta(Map.<jk>class</jk>, String.<jk>class</jk>, List.<jk>class</jk>, MyBean.<jk>class</jk>);</code> -
4898    *       A map containing string keys and values of lists containing beans.
4899    * </ul>
4900    *
4901    * @param <T>
4902    *    The class to resolve.
4903    * @param type
4904    *    The class to resolve.
4905    *    <br>Can be any of the following: {@link ClassMeta}, {@link ClassInfo}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
4906    *    <br>Can be <jk>null</jk> (returns <jk>null</jk>).
4907    * @param args
4908    *    The type arguments of the class if it's a collection or map.
4909    *    <br>Can be any of the following: {@link ClassMeta}, {@link ClassInfo}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
4910    *    <br>Ignored if the main type is not a map or collection.
4911    * @return The resolved class meta, or <jk>null</jk> if the type was <jk>null</jk>.
4912    */
4913   public final <T> ClassMeta<T> getClassMeta(Type type, Type...args) {
4914      if (type == null)
4915         return null;
4916      ClassMeta<T> cm = null;
4917      if (type instanceof Class type2)
4918         cm = getClassMeta(type2);
4919      else
4920         cm = resolveClassMeta(type, null);
4921      if (args.length == 0)
4922         return cm;
4923      var cma = new ClassMeta<?>[args.length + 1];
4924      cma[0] = cm;
4925      for (var i = 0; i < length(args); i++) {
4926         var arg = (Type)Array.get(args, i);
4927         if (arg instanceof Class arg2)
4928            cma[i + 1] = getClassMeta(arg2);
4929         else
4930            cma[i + 1] = resolveClassMeta(arg, null);
4931      }
4932      return (ClassMeta<T>)getTypedClassMeta(cma, 0);
4933   }
4934
4935   /**
4936    * Returns the {@link ClassMeta} for the object's class, unwrapping recognized proxies first.
4937    *
4938    * <p>
4939    * Same contract as {@link MarshallingSession#getClassMetaForObject(Object, ClassMeta)}:
4940    * {@link org.apache.juneau.commons.utils.ClassUtils#getProxyFor(Object)} if non-<jk>null</jk>,
4941    * else {@code o.getClass()}. Used by object-tools and other context callers; parsers do not
4942    * call this method.
4943    *
4944    * @param <T> The class of the object being passed in.
4945    * @param o The object to find the class type for.
4946    *    <br>Cannot be <jk>null</jk>.
4947    * @return The ClassMeta object.
4948    */
4949   public final <T> ClassMeta<T> getClassMetaForObject(T o) {
4950      reqnn("o", o);
4951      var unwrapped = getProxyFor(o);
4952      Class<?> k = unwrapped != null ? unwrapped : o.getClass();
4953      return (ClassMeta<T>)getClassMeta(k);
4954   }
4955
4956   /**
4957    * Locale.
4958    *
4959    * @see MarshallingContext.Builder#locale(Locale)
4960    * @return
4961    *    The default locale for serializer and parser sessions.
4962    */
4963   public final Locale getDefaultLocale() { return locale; }
4964
4965   /**
4966    * Media type.
4967    *
4968    * @see MarshallingContext.Builder#mediaType(MediaType)
4969    * @return
4970    *    The default media type value for serializer and parser sessions.
4971    *    <br>Can be <jk>null</jk> if no default media type has been configured.
4972    */
4973   public final MediaType getDefaultMediaType() { return mediaType; }
4974
4975   /**
4976    * Time zone.
4977    *
4978    * @see MarshallingContext.Builder#timeZone(TimeZone)
4979    * @return
4980    *    The default timezone for serializer and parser sessions.
4981    *    <br>Can be <jk>null</jk> if no default time zone has been configured.
4982    */
4983   public final TimeZone getDefaultTimeZone() { return timeZone; }
4984
4985   /**
4986    * Bean package exclusions.
4987    *
4988    * @see MarshallingContext.Builder#notBeanPackages(String...)
4989    * @return
4990    *    The set of fully-qualified package names to exclude from being classified as beans.
4991    *    <br>Never <jk>null</jk>.
4992    *    <br>Set is unmodifiable.
4993    *    <br>Backed by a {@link LinkedHashSet} to preserve insertion order.
4994    */
4995   public final Set<String> getNotBeanPackagesNames() { return notBeanPackageNames; }
4996
4997   /**
4998    * Bean property namer.
4999    *
5000    * @see MarshallingContext.Builder#propertyNamer(Class)
5001    * @return
5002    *    The interface used to calculate bean property names.
5003    */
5004   public final PropertyNamer getPropertyNamer() { return propertyNamerBean; }
5005
5006   @Override /* Overridden from Context */
5007   public MarshallingSession getSession() { return defaultSession; }
5008
5009   /**
5010    * Java object swaps.
5011    *
5012    * @see MarshallingContext.Builder#swaps(Class...)
5013    * @return
5014    *    The list POJO swaps defined.
5015    *    <br>Never <jk>null</jk>.
5016    *    <br>List is unmodifiable.
5017    */
5018   public final List<ObjectSwap<?,?>> getSwaps() { return objectSwaps; }
5019
5020   /**
5021    * Returns <jk>true</jk> if the specified bean context shares the same cache as this bean context.
5022    *
5023    * <p>
5024    * Useful for testing purposes.
5025    *
5026    * @param bc The bean context to compare to.
5027    *    <br>Cannot be <jk>null</jk>.
5028    * @return <jk>true</jk> if the bean contexts have equivalent settings and thus share caches.
5029    */
5030   public final boolean hasSameCache(MarshallingContext bc) {
5031      reqnn("bc", bc);
5032      return bc.getCmCache() == this.getCmCache();
5033   }
5034
5035   /**
5036    * BeanMap.put() returns old property value.
5037    *
5038    * @see MarshallingContext.Builder#beanMapPutReturnsOldValue()
5039    * @return
5040    *    <jk>true</jk> if the {@link BeanMap#put(String,Object) BeanMap.put()} method will return old property values.
5041    *    <br>Otherwise, it returns <jk>null</jk>.
5042    */
5043   public final boolean isBeanMapPutReturnsOldValue() { return beanMapPutReturnsOldValue; }
5044
5045   /**
5046    * Beans require no-arg constructors.
5047    *
5048    * @see MarshallingContext.Builder#beansRequireDefaultConstructor()
5049    * @return
5050    *    <jk>true</jk> if a Java class must implement a default no-arg constructor to be considered a bean.
5051    *    <br>Otherwise, the bean will be serialized as a string using the {@link Object#toString()} method.
5052    */
5053   public final boolean isBeansRequireDefaultConstructor() { return beansRequireDefaultConstructor; }
5054
5055   /**
5056    * Beans require Serializable interface.
5057    *
5058    * @see MarshallingContext.Builder#beansRequireSerializable()
5059    * @return
5060    *    <jk>true</jk> if a Java class must implement the {@link Serializable} interface to be considered a bean.
5061    *    <br>Otherwise, the bean will be serialized as a string using the {@link Object#toString()} method.
5062    */
5063   public final boolean isBeansRequireSerializable() { return beansRequireSerializable; }
5064
5065   /**
5066    * Beans require setters for getters.
5067    *
5068    * @see MarshallingContext.Builder#beansRequireSettersForGetters()
5069    * @return
5070    *    <jk>true</jk> if only getters that have equivalent setters will be considered as properties on a bean.
5071    *    <br>Otherwise, they are ignored.
5072    */
5073   public final boolean isBeansRequireSettersForGetters() { return beansRequireSettersForGetters; }
5074
5075   /**
5076    * Beans require at least one property.
5077    *
5078    * @see MarshallingContext.Builder#disableBeansRequireSomeProperties()
5079    * @return
5080    *    <jk>true</jk> if a Java class doesn't need to contain at least 1 property to be considered a bean.
5081    *    <br>Otherwise, the bean is serialized as a string using the {@link Object#toString()} method.
5082    */
5083   public final boolean isBeansRequireSomeProperties() { return beansRequireSomeProperties; }
5084
5085   /**
5086    * Find fluent setters.
5087    *
5088    * <h5 class='section'>Description:</h5>
5089    * <p>
5090    *
5091    * @see MarshallingContext.Builder#findFluentSetters()
5092    * @return
5093    *    <jk>true</jk> if fluent setters are detected on beans.
5094    */
5095   public final boolean isFindFluentSetters() { return findFluentSetters; }
5096
5097   /**
5098    * Ignore invocation errors on getters.
5099    *
5100    * @see MarshallingContext.Builder#ignoreInvocationExceptionsOnGetters()
5101    * @return
5102    *    <jk>true</jk> if errors thrown when calling bean getter methods are silently ignored.
5103    */
5104   public final boolean isIgnoreInvocationExceptionsOnGetters() { return ignoreInvocationExceptionsOnGetters; }
5105
5106   /**
5107    * Ignore invocation errors on setters.
5108    *
5109    * @see MarshallingContext.Builder#ignoreInvocationExceptionsOnSetters()
5110    * @return
5111    *    <jk>true</jk> if errors thrown when calling bean setter methods are silently ignored.
5112    */
5113   public final boolean isIgnoreInvocationExceptionsOnSetters() { return ignoreInvocationExceptionsOnSetters; }
5114
5115   /**
5116    * Silently ignore missing setters.
5117    *
5118    * @see MarshallingContext.Builder#disableIgnoreMissingSetters()
5119    * @return
5120    *    <jk>true</jk> if trying to set a value on a bean property without a setter should throw a {@link BeanRuntimeException}.
5121    */
5122   public final boolean isIgnoreMissingSetters() { return ignoreMissingSetters; }
5123
5124   /**
5125    * Ignore unknown properties.
5126    *
5127    * @see MarshallingContext.Builder#ignoreUnknownBeanProperties()
5128    * @return
5129    *    <jk>true</jk> if trying to set a value on a non-existent bean property is silently ignored.
5130    *    <br>Otherwise, a {@code RuntimeException} is thrown.
5131    */
5132   public final boolean isIgnoreUnknownBeanProperties() { return ignoreUnknownBeanProperties; }
5133
5134   /**
5135    * Schema validation mode.
5136    *
5137    * @see MarshallingContext.Builder#validateSchema()
5138    * @return
5139    *    <jk>true</jk> if bean property values should be validated against their {@code @Schema}-declared constraints
5140    *    during parsing and serialization.
5141    * @since 10.0.0
5142    */
5143   public final boolean isValidateSchema() { return validateSchema; }
5144
5145   /**
5146    * Ignore unknown enum values.
5147    *
5148    * @see MarshallingContext.Builder#ignoreUnknownEnumValues()
5149    * @return
5150    *    <jk>true</jk> if unknown enum values should be set as <jk>null</jk> instead of throwing an exception.
5151    */
5152   public final boolean isIgnoreUnknownEnumValues() { return ignoreUnknownEnumValues; }
5153
5154   /**
5155    * Ignore unknown properties with null values.
5156    *
5157    * @see MarshallingContext.Builder#disableIgnoreUnknownNullBeanProperties()
5158    * @return
5159    *    <jk>true</jk> if trying to set a <jk>null</jk> value on a non-existent bean property should throw a {@link BeanRuntimeException}.
5160    */
5161   public final boolean isIgnoreUnknownNullBeanProperties() { return ignoreUnknownNullBeanProperties; }
5162
5163   /**
5164    * Returns whether bean properties are unsorted (i.e. in declaration order rather than alphabetical).
5165    *
5166    * @see MarshallingContext.Builder#unsortedProperties()
5167    * @return
5168    *    <jk>true</jk> if bean properties are in declaration order; <jk>false</jk> (the default) means alphabetical order.
5169    */
5170   public final boolean isUnsortedProperties() { return unsortedProperties; }
5171
5172   /**
5173    * Returns whether {@link Record} beans use record component order.
5174    *
5175    * @see MarshallingContext.Builder#recordComponentOrder()
5176    * @return <jk>true</jk> if record properties are in component order regardless of {@link #isUnsortedProperties()}.
5177    */
5178   public final boolean isRecordComponentOrder() { return recordComponentOrder; }
5179
5180   /**
5181    * Use interface proxies.
5182    *
5183    * @see MarshallingContext.Builder#disableInterfaceProxies()
5184    * @return
5185    *    <jk>true</jk> if interfaces will be instantiated as proxy classes through the use of an
5186    *    {@link InvocationHandler} if there is no other way of instantiating them.
5187    */
5188   public final boolean isUseInterfaceProxies() { return useInterfaceProxies; }
5189
5190   /**
5191    * Use Java Introspector.
5192    *
5193    * @see MarshallingContext.Builder#useJavaBeanIntrospector()
5194    * @return
5195    *    <jk>true</jk> if the built-in Java bean introspector should be used for bean introspection.
5196    */
5197   public final boolean isUseJavaBeanIntrospector() { return useJavaBeanIntrospector; }
5198
5199   /**
5200    * Creates a new {@link BeanMap} object (a modifiable {@link Map}) of the given class with uninitialized
5201    * property values.
5202    *
5203    * <p>
5204    * This is a shortcut for the following code:  <c>createSession().build().newBeanMap(<jv>_class</jv>);</c>
5205    *
5206    * <h5 class='section'>Example:</h5>
5207    * <p class='bjava'>
5208    *    <jc>// Construct a new bean map wrapped around a new Person object</jc>
5209    *    BeanMap&lt;Person&gt; <jv>beanMap</jv> = MarshallingContext.<jsf>DEFAULT</jsf>.newBeanMap(Person.<jk>class</jk>);
5210    * </p>
5211    *
5212    * @param <T> The class of the object being wrapped.
5213    * @param c The name of the class to create a new instance of.
5214    *    <br>Cannot be <jk>null</jk>.
5215    * @return A new instance of the class, or <jk>null</jk> if the class is not a bean.
5216    * @see MarshallingSession#newBeanMap(Class)
5217    */
5218   public <T> BeanMap<T> newBeanMap(Class<T> c) {
5219      reqnn("c", c);
5220      return defaultSession.newBeanMap(c);
5221   }
5222
5223   /**
5224    * Wraps an object inside a {@link BeanMap} object (a modifiable {@link Map}).
5225    *
5226    * <p>
5227    * This is a shortcut for the following code:  <c>createSession().build().toBeanMap(<jv>object</jv>);</c>
5228    *
5229    * <h5 class='section'>Example:</h5>
5230    * <p class='bjava'>
5231    *    <jc>// Construct a bean map around a bean instance</jc>
5232    *    BeanMap&lt;Person&gt; <jv>beanMap</jv> = MarshallingContext.<jsf>DEFAULT</jsf>.toBeanMap(<jk>new</jk> Person());
5233    * </p>
5234    *
5235    * @param <T> The class of the object being wrapped.
5236    * @param object The object to wrap in a map interface.
5237    *    <br>Cannot be <jk>null</jk>.
5238    * @return The wrapped object.
5239    * @see MarshallingSession#toBeanMap(Object)
5240    */
5241   public <T> BeanMap<T> toBeanMap(T object) {
5242      reqnn("object", object);
5243      return defaultSession.toBeanMap(object);
5244   }
5245
5246   /**
5247    * Returns the lookup table for resolving bean types by name.
5248    *
5249    * @return The lookup table for resolving bean types by name.
5250    */
5251   protected final BeanRegistry getBeanRegistry() { return beanRegistry; }
5252
5253   /**
5254    * Returns the serializer to use for serializing beans when using the {@link MarshallingSession#convertToType(Object, Class)}
5255    * and related methods.
5256    *
5257    * @return The serializer.  May be <jk>null</jk> if all initialization has occurred.
5258    */
5259   protected WriterSerializer getBeanToStringSerializer() {
5260      return beanToStringSerializer.get();
5261   }
5262
5263   /**
5264    * Class metadata cache.
5265    *
5266    * @return The class metadata cache.
5267    */
5268   protected final Cache<Class,ClassMeta> getCmCache() { return cmCache; }
5269
5270
5271   /**
5272    * Hash key.
5273    *
5274    * @return The hash key.
5275    */
5276   protected final HashKey getHashKey() { return hashKey; }
5277
5278   /**
5279    * Locale.
5280    *
5281    * @return The locale.
5282    */
5283   protected final Locale getLocale() { return locale; }
5284
5285   /**
5286    * The default active view for sessions created from this context.
5287    *
5288    * <p>
5289    * Returns the view name set via {@link Builder#activeView(String)}, or <jk>null</jk> if no default
5290    * active view has been configured (all properties visible).
5291    *
5292    * @return The default active view, or <jk>null</jk>.
5293    * @since 10.0.0
5294    */
5295   public final String getActiveView() { return activeView; }
5296
5297   /**
5298    * Default-view-inclusion policy.
5299    *
5300    * <p>
5301    * Returns <jk>true</jk> (the default) when untagged properties — those carrying no
5302    * {@link MarshalledProp#view()} declaration — are included under every active view.
5303    * Returns <jk>false</jk> when {@link Builder#disableDefaultViewInclusion()} has been called,
5304    * in which case untagged properties are excluded when any active view is in effect.
5305    *
5306    * @return <jk>true</jk> if untagged properties are included under every active view.
5307    * @since 10.0.0
5308    */
5309   public final boolean isDefaultViewInclusion() { return defaultViewInclusion; }
5310
5311   /**
5312    * Media type.
5313    *
5314    * @return The media type, or <jk>null</jk> if no default media type has been configured.
5315    */
5316   protected final MediaType getMediaType() { return mediaType; }
5317
5318   /**
5319    * Bean class exclusions.
5320    *
5321    * @see MarshallingContext.Builder#notBeanClasses(ClassInfo...)
5322    * @return
5323    *    The list of classes that are explicitly not beans.
5324    *    <br>Never <jk>null</jk>.
5325    *    <br>List is unmodifiable.
5326    */
5327   protected final List<ClassInfo> getNotBeanClasses() { return notBeanClasses; }
5328
5329   /**
5330    * Time zone.
5331    *
5332    * @return The time zone, or <jk>null</jk> if no default time zone has been configured.
5333    */
5334   protected final TimeZone getTimeZone() { return timeZone; }
5335
5336   /**
5337    * Duration wire format.
5338    *
5339    * @return The duration wire format.
5340    */
5341   public final DurationFormat getDurationFormat() { return durationFormat; }
5342
5343   /**
5344    * Period wire format.
5345    *
5346    * @return The period wire format.
5347    */
5348   public final PeriodFormat getPeriodFormat() { return periodFormat; }
5349
5350   /**
5351    * Calendar wire format.
5352    *
5353    * @return The calendar wire format.
5354    */
5355   public final CalendarFormat getCalendarFormat() { return calendarFormat; }
5356
5357   /**
5358    * Date wire format.
5359    *
5360    * @return The date wire format.
5361    */
5362   public final DateFormat getDateFormat() { return dateFormat; }
5363
5364   /**
5365    * Temporal wire format.
5366    *
5367    * @return The temporal wire format.
5368    */
5369   public final TemporalFormat getTemporalFormat() { return temporalFormat; }
5370
5371   /**
5372    * Time-zone wire format.
5373    *
5374    * @return The time-zone wire format.
5375    */
5376   public final TimeZoneFormat getTimeZoneFormat() { return timeZoneFormat; }
5377
5378   /**
5379    * Locale wire format.
5380    *
5381    * @return The locale wire format.
5382    */
5383   public final LocaleFormat getLocaleFormat() { return localeFormat; }
5384
5385   /**
5386    * Binary wire format.
5387    *
5388    * @return The binary wire format.
5389    */
5390   public final BinaryFormat getBinaryFormat() { return binaryFormat; }
5391
5392   /**
5393    * Enum wire format.
5394    *
5395    * @return The enum wire format.
5396    */
5397   public final EnumFormat getEnumFormat() { return enumFormat; }
5398
5399   /**
5400    * UUID wire format.
5401    *
5402    * @return The UUID wire format.
5403    */
5404   public final UuidFormat getUuidFormat() { return uuidFormat; }
5405
5406   /**
5407    * BitSet wire format.
5408    *
5409    * @return The BitSet wire format.
5410    */
5411   public final BitSetFormat getBitSetFormat() { return bitSetFormat; }
5412
5413   /**
5414    * Big-number wire format.
5415    *
5416    * @return The big-number wire format.
5417    */
5418   public final BigNumberFormat getBigNumberFormat() { return bigNumberFormat; }
5419
5420   /**
5421    * Boolean wire format.
5422    *
5423    * @return The boolean wire format.
5424    */
5425   public final BooleanFormat getBooleanFormat() { return booleanFormat; }
5426
5427   /**
5428    * Float / Double non-finite wire format.
5429    *
5430    * @return The float wire format.
5431    */
5432   public final FloatFormat getFloatFormat() { return floatFormat; }
5433
5434   /**
5435    * Currency wire format.
5436    *
5437    * @return The currency wire format.
5438    */
5439   public final CurrencyFormat getCurrencyFormat() { return currencyFormat; }
5440
5441   /**
5442    * Class wire format.
5443    *
5444    * @return The class wire format.
5445    */
5446   public final ClassFormat getClassFormat() { return classFormat; }
5447
5448   /**
5449    * Session classloader.
5450    *
5451    * <p>
5452    * Returns the classloader explicitly configured via {@link Builder#classLoader(ClassLoader)}, or
5453    * <jk>null</jk> if none was set (callers should fall back to the thread-context classloader).
5454    *
5455    * @return The session classloader, or <jk>null</jk> if not set.
5456    */
5457   public final ClassLoader getClassLoader() { return classLoader; }
5458
5459   /**
5460    * Ignore transient fields.
5461    *
5462    * @see MarshallingContext.Builder#disableIgnoreTransientFields()
5463    * @return
5464    *    <jk>true</jk> if fields and methods marked as transient should not be ignored.
5465    */
5466   protected final boolean isIgnoreTransientFields() { return ignoreTransientFields; }
5467
5468   /**
5469    * Returns a reusable {@link ClassMeta} representation for the class <c>Object</c>.
5470    *
5471    * <p>
5472    * This <c>ClassMeta</c> is often used to represent "any object type" when an object type is not known.
5473    *
5474    * <p>
5475    * This method is identical to calling <code>getClassMeta(Object.<jk>class</jk>)</code> but uses a cached copy to
5476    * avoid a hashmap lookup.
5477    *
5478    * @return The {@link ClassMeta} object associated with the <c>Object</c> class.
5479    */
5480   protected final ClassMeta<Object> object() {
5481      return cmObject;
5482   }
5483
5484   //-----------------------------------------------------------------------------------------------------------------
5485   // BeanTypeResolver implementation — bridges the marshalling-side ClassMeta resolution into the bean-modeling
5486   // SPI seam that BeanPropertyMeta.Builder.validate() consumes.
5487   //-----------------------------------------------------------------------------------------------------------------
5488
5489   @Override /* Overridden from BeanTypeResolver */
5490   public org.apache.juneau.commons.bean.BeanInfo<?> resolveType(AnnotationInfo<BeanProp> lastBeanProp, ClassInfo type, TypeVariables typeVarImpls) {
5491      return resolveClassMeta(lastBeanProp, type, typeVarImpls);
5492   }
5493
5494   @Override /* Overridden from BeanTypeResolver */
5495   public org.apache.juneau.commons.bean.BeanInfo<?> objectType() {
5496      return cmObject;
5497   }
5498
5499   @Override /* Overridden from Context */
5500   protected FluentMap<String,Object> properties() {
5501      return super.properties()
5502         .a("beanClassVisibility", beanClassVisibility)
5503         .a("beanConstructorVisibility", beanConstructorVisibility)
5504         .a("beanDictionary", beanDictionary)
5505         .a("beanFieldVisibility", beanFieldVisibility)
5506         .a("beanMethodVisibility", beanMethodVisibility)
5507         .a("beansRequireDefaultConstructor", beansRequireDefaultConstructor)
5508         .a("beansRequireSerializable", beansRequireSerializable)
5509         .a("beansRequireSettersForGetters", beansRequireSettersForGetters)
5510         .a("beansRequireSomeProperties", beansRequireSomeProperties)
5511         .a("id", System.identityHashCode(this))
5512         .a("ignoreInvocationExceptionsOnGetters", ignoreInvocationExceptionsOnGetters)
5513         .a("ignoreInvocationExceptionsOnSetters", ignoreInvocationExceptionsOnSetters)
5514         .a("ignoreTransientFields", ignoreTransientFields)
5515         .a("ignoreUnknownBeanProperties", ignoreUnknownBeanProperties)
5516         .a("ignoreUnknownNullBeanProperties", ignoreUnknownNullBeanProperties)
5517         .a("notBeanClasses", notBeanClasses)
5518         .a("notBeanPackageNames", notBeanPackageNames)
5519         .a("notBeanPackagePrefixes", notBeanPackagePrefixes)
5520         .a("unsortedProperties", unsortedProperties)
5521         .a("recordComponentOrder", recordComponentOrder)
5522         .a("swaps", swaps)
5523         .a("durationFormat", durationFormat)
5524         .a("periodFormat", periodFormat)
5525         .a("calendarFormat", calendarFormat)
5526         .a("dateFormat", dateFormat)
5527         .a("temporalFormat", temporalFormat)
5528         .a("timeZoneFormat", timeZoneFormat)
5529         .a("localeFormat", localeFormat)
5530         .a("binaryFormat", binaryFormat)
5531         .a("enumFormat", enumFormat)
5532         .a("uuidFormat", uuidFormat)
5533         .a("bitSetFormat", bitSetFormat)
5534         .a("bigNumberFormat", bigNumberFormat)
5535         .a("booleanFormat", booleanFormat)
5536         .a("floatFormat", floatFormat)
5537         .a("currencyFormat", currencyFormat)
5538         .a("classFormat", classFormat)
5539         .a("classLoader", classLoader)
5540         .a("useInterfaceProxies", useInterfaceProxies)
5541         .a("useJavaBeanIntrospector", useJavaBeanIntrospector)
5542         .a("validateSchema", validateSchema);
5543   }
5544
5545   /**
5546    * Used for determining the class type on a method or field where a {@code @BeanProp} annotation may be present.
5547    *
5548    * @param <T> The class type we're wrapping.
5549    * @param p The property annotation info on the type if there is one.
5550    *    <br>Can be <jk>null</jk> (the class type is resolved from <c>ci</c> alone, with no <ja>@BeanProp</ja>-based narrowing).
5551    * @param ci The class info for the type.
5552    * @param typeVarImpls
5553    *    Contains known resolved type parameters on the specified class so that we can result
5554    *    {@code ParameterizedTypes} and {@code TypeVariables}.
5555    *    Can be <jk>null</jk> if the information is not known.
5556    * @return The new {@code ClassMeta} object wrapped around the type.
5557    */
5558   protected final <T> ClassMeta<T> resolveClassMeta(AnnotationInfo<BeanProp> p, ClassInfo ci, TypeVariables typeVarImpls) {
5559      var cm = resolveClassMeta(ci, typeVarImpls);
5560      var cm2 = cm;
5561
5562      if (nn(p)) {
5563         var beanp = p.inner();
5564
5565         if (isNotVoid(beanp.type()))
5566            cm2 = resolveClassMeta(beanp.type(), typeVarImpls);
5567
5568         if (cm2.isMap()) {
5569            var pParams = (beanp.params().length == 0 ? a(Object.class, Object.class) : beanp.params());
5570            if (pParams.length != 2)
5571               throw rex("Invalid number of parameters specified for Map (must be 2): %s", pParams.length);
5572            var keyType = resolveType(pParams[0], cm2.getKeyType(), cm.getKeyType());
5573            var valueType = resolveType(pParams[1], cm2.getValueType(), cm.getValueType());
5574            if (keyType.isObject() && valueType.isObject())
5575               return cm2;
5576            return new ClassMeta<>(cm2, keyType, valueType, null);
5577         }
5578
5579         if (cm2.isCollection() || cm2.isOptional()) {
5580            var pParams = (beanp.params().length == 0 ? a(Object.class) : beanp.params());
5581            if (pParams.length != 1) {
5582               String typeName;
5583               if (cm2.isCollection()) {
5584                  typeName = "Collection";
5585               } else if (cm2.isOptional()) {
5586                  typeName = "Optional";
5587               } else {
5588                  typeName = "Array";
5589               }
5590               throw rex("Invalid number of parameters specified for %2$s (must be 1): %1$s", pParams.length, typeName);
5591            }
5592            var elementType = resolveType(pParams[0], cm2.getElementType(), cm.getElementType());
5593            if (elementType.isObject())
5594               return cm2;
5595            return new ClassMeta<>(cm2, null, null, elementType);
5596         }
5597
5598         // Handle @BeanProp(elementType=) for BeanSupplier, BeanConsumer, BeanChannel, and Stream properties.
5599         if (isNotVoid(beanp.elementType()) && (cm2.isIterable() || cm2.isStream())) {
5600            var elementType = resolveClassMeta(beanp.elementType(), typeVarImpls);
5601            if (! elementType.isObject())
5602               return new ClassMeta<>(cm2, null, null, elementType);
5603         }
5604
5605         return cm2;
5606      }
5607
5608      return cm;
5609   }
5610
5611   /**
5612    * Returns a reusable {@link ClassMeta} representation for the class <c>String</c>.
5613    *
5614    * <p>
5615    * This <c>ClassMeta</c> is often used to represent key types in maps.
5616    *
5617    * <p>
5618    * This method is identical to calling <code>getClassMeta(String.<jk>class</jk>)</code> but uses a cached copy to
5619    * avoid a hashmap lookup.
5620    *
5621    * @return The {@link ClassMeta} object associated with the <c>String</c> class.
5622    */
5623   protected final ClassMeta<String> string() {
5624      return cmString;
5625   }
5626
5627   /**
5628    * Finds the type parameters for a parameterized type.
5629    *
5630    * @param o The generic type.
5631    * @param c The raw class.
5632    * @return The array of {@link ClassMeta} for each type parameter, or an empty array if parameters cannot be resolved.
5633    */
5634   final ClassMeta[] findParameters(Type o, Class c) {
5635      if (o == null)
5636         o = c;
5637
5638      // Loop until we find a ParameterizedType
5639      if (! (o instanceof ParameterizedType)) {
5640         while (nn(c)) {
5641            o = c.getGenericSuperclass();
5642            if (!(o instanceof ParameterizedType))
5643               o = Arrays.stream(c.getGenericInterfaces()).filter(t -> t instanceof ParameterizedType).findFirst().orElse(null);
5644            if (o instanceof ParameterizedType)
5645               break;
5646            c = c.getSuperclass();
5647         }
5648      }
5649
5650      if (o instanceof ParameterizedType o2 && ! o2.getRawType().equals(Enum.class)) {
5651         var l = new LinkedList<ClassMeta<?>>();
5652         for (var pt2 : o2.getActualTypeArguments()) {
5653            if (pt2 instanceof WildcardType || pt2 instanceof TypeVariable)
5654               return new ClassMeta[0];
5655            l.add(resolveClassMeta(pt2, null));
5656         }
5657         if (l.isEmpty())
5658            return new ClassMeta[0];
5659         return l.toArray(new ClassMeta[l.size()]);
5660      }
5661
5662      return new ClassMeta[0];
5663   }
5664
5665   final ClassMeta resolveClassMeta(Type o, TypeVariables typeVars) {
5666      if (o == null)
5667         return null;
5668
5669      if (o instanceof ClassMeta<?> o2) {
5670
5671         // This classmeta could have been created by a different context.
5672         // Need to re-resolve it to pick up ObjectSwaps and stuff on this context.
5673         if (o2.getMarshallingContext() == this)
5674            return o2;
5675         if (o2.isMap())
5676            return getClassMeta(o2.inner(), o2.getKeyType(), o2.getValueType());
5677         if (o2.isCollection() || o2.isOptional())
5678            return getClassMeta(o2.inner(), o2.getElementType());
5679         return getClassMeta(o2.inner());
5680      }
5681
5682      // Handle ClassInfo by extracting the underlying Type
5683      if (o instanceof ClassInfo o2) {
5684         return resolveClassMeta(o2.innerType(), typeVars);
5685      }
5686
5687      var c = TypeVariables.resolve(o, typeVars);
5688
5689      // This can happen when trying to resolve the "E getFirst()" method on LinkedList, whose type is a TypeVariable
5690      // These should just resolve to Object.
5691      if (c == null)
5692         return object();
5693
5694      var rawType = getClassMeta(c);
5695
5696      // If this is a Map or Collection, and the parameter types aren't part
5697      // of the class definition itself (e.g. class AddressBook extends List<Person>),
5698      // then we need to figure out the parameters.
5699      if (rawType.isMap() || rawType.isCollection() || rawType.isOptional()) {
5700         var params = findParameters(o, c);
5701         if (params.length == 0)
5702            return rawType;
5703         if (rawType.isMap()) {
5704            if (params.length != 2 || (params[0].isObject() && params[1].isObject()))
5705               return rawType;
5706            return new ClassMeta(rawType, params[0], params[1], null);
5707         }
5708         if (rawType.isCollection() || rawType.isOptional()) {
5709            if (params.length != 1 || params[0].isObject())
5710               return rawType;
5711            return new ClassMeta(rawType, null, null, params[0]);
5712         }
5713      }
5714
5715      if (rawType.isArray() && o instanceof GenericArrayType o2) {
5716         var elementType = resolveClassMeta(o2.getGenericComponentType(), typeVars);
5717         return new ClassMeta(rawType, null, null, elementType);
5718      }
5719
5720      return rawType;
5721   }
5722
5723   /*
5724    * Resolves the 'genericized' class meta at the specified position in the ClassMeta array.
5725    */
5726   private ClassMeta<?> getTypedClassMeta(ClassMeta<?>[] c, int pos) {
5727      var cm = c[pos++];
5728      if (cm.isCollection() || cm.isOptional()) {
5729         var ce = c.length == pos ? object() : getTypedClassMeta(c, pos);
5730         return (ce.isObject() ? cm : new ClassMeta(cm, null, null, ce));
5731      } else if (cm.isMap()) {
5732         var ck = c.length == pos ? object() : c[pos++];
5733         var cv = c.length == pos ? object() : getTypedClassMeta(c, pos);
5734         return (ck.isObject() && cv.isObject() ? cm : new ClassMeta(cm, ck, cv, null));
5735      }
5736      return cm;
5737   }
5738
5739
5740   private ClassMeta<?> resolveType(Type...t) {
5741      for (var tt : t) {
5742         if (nn(tt)) {
5743            var cm = getClassMeta(tt);
5744            if (tt != cmObject)
5745               return cm;
5746         }
5747      }
5748      return cmObject;
5749   }
5750}