001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.juneau;
018
019import static org.apache.juneau.commons.utils.AssertionUtils.*;
020import static org.apache.juneau.commons.utils.CollectionUtils.*;
021import static org.apache.juneau.commons.utils.IoUtils.*;
022import static org.apache.juneau.commons.utils.StringUtils.*;
023import static org.apache.juneau.commons.utils.ThrowableUtils.*;
024import static org.apache.juneau.commons.utils.Utils.*;
025
026import java.io.*;
027import java.lang.reflect.*;
028import java.nio.charset.*;
029import java.text.*;
030import java.time.*;
031import java.util.*;
032import java.util.concurrent.atomic.*;
033import java.util.function.*;
034import java.util.logging.*;
035
036import org.apache.juneau.annotation.*;
037import org.apache.juneau.collections.*;
038import org.apache.juneau.commons.collections.FluentMap;
039import org.apache.juneau.commons.lang.*;
040import org.apache.juneau.commons.reflect.*;
041import org.apache.juneau.commons.time.*;
042import org.apache.juneau.commons.utils.*;
043import org.apache.juneau.swap.*;
044
045/**
046 * Session object that lives for the duration of a single use of {@link BeanContext}.
047 *
048 * <ul class='spaced-list'>
049 *    <li class='info'>Typically session objects are not thread safe nor reusable.  However, bean sessions do not maintain any state and
050 *       thus can be safely cached and reused.
051 * </ul>
052 *
053 */
054@SuppressWarnings({ "unchecked", "rawtypes" })
055public class BeanSession extends ContextSession {
056
057   /**
058    * Builder class.
059    */
060   public static class Builder extends ContextSession.Builder {
061
062      private BeanContext ctx;
063      private Locale locale;
064      private MediaType mediaType;
065      private TimeZone timeZone;
066
067      /**
068       * Constructor
069       *
070       * @param ctx The context creating this session.
071       *    <br>Cannot be <jk>null</jk>.
072       */
073      protected Builder(BeanContext ctx) {
074         super(assertArgNotNull("ctx", ctx));
075         this.ctx = ctx;
076         mediaType = ctx.getMediaType();
077         timeZone = ctx.getTimeZone();
078      }
079
080      @Override /* Overridden from Builder */
081      public <T> Builder apply(Class<T> type, Consumer<T> apply) {
082         super.apply(type, apply);
083         return this;
084      }
085
086      /**
087       * Build the object.
088       *
089       * @return The built object.
090       */
091      @Override
092      public BeanSession build() {
093         return new BeanSession(this);
094      }
095
096      @Override /* Overridden from Builder */
097      public Builder debug(Boolean value) {
098         super.debug(value);
099         return this;
100      }
101
102      /**
103       * The session locale.
104       *
105       * <p>
106       * Specifies the default locale for serializer and parser sessions.
107       *
108       * <p>
109       * If not specified, defaults to {@link BeanContext.Builder#locale(Locale)}.
110       *
111       * <h5 class='section'>See Also:</h5><ul>
112       *    <li class='ja'>{@link BeanConfig#locale()}
113       *    <li class='jm'>{@link BeanContext.Builder#locale(Locale)}
114       * </ul>
115       *
116       * @param value
117       *    The new value for this property.
118       *    <br>If <jk>null</jk> defaults to {@link BeanContext#getLocale()}
119       * @return This object.
120       */
121      public Builder locale(Locale value) {
122         locale = value;
123         return this;
124      }
125
126      /**
127       * The session media type.
128       *
129       * <p>
130       * Specifies the default media type value for serializer and parser sessions.
131       *
132       * <p>
133       * If not specified, defaults to {@link BeanContext.Builder#mediaType(MediaType)}.
134       *
135       * <h5 class='section'>See Also:</h5><ul>
136       *    <li class='ja'>{@link BeanConfig#mediaType()}
137       *    <li class='jm'>{@link BeanContext.Builder#mediaType(MediaType)}
138       * </ul>
139       *
140       * @param value
141       *    The new value for this property.
142       *    <br>If <jk>null</jk> defaults to {@link BeanContext#getMediaType()}.
143       * @return This object.
144       */
145      public Builder mediaType(MediaType value) {
146         mediaType = value;
147         return this;
148      }
149
150      /**
151       * Same as {@link #mediaType(MediaType)} but doesn't overwrite the value if it is already set.
152       *
153       * @param value
154       *    The new value for this property.
155       *    <br>If <jk>null</jk>, then the locale defined on the context is used.
156       * @return This object.
157       */
158      public Builder mediaTypeDefault(MediaType value) {
159         if (mediaType == null)
160            mediaType = value;
161         return this;
162      }
163
164      @Override /* Overridden from Builder */
165      public Builder properties(Map<String,Object> value) {
166         super.properties(value);
167         return this;
168      }
169
170      @Override /* Overridden from Builder */
171      public Builder property(String key, Object value) {
172         super.property(key, value);
173         return this;
174      }
175
176      /**
177       * The session timezone.
178       *
179       * <p>
180       * Specifies the default timezone for serializer and parser sessions.
181       *
182       * <p>
183       * If not specified, defaults to {@link BeanContext.Builder#timeZone(TimeZone)}.
184       *
185       * <h5 class='section'>See Also:</h5><ul>
186       *    <li class='ja'>{@link BeanConfig#timeZone()}
187       *    <li class='jm'>{@link BeanContext.Builder#timeZone(TimeZone)}
188       * </ul>
189       *
190       * @param value
191       *    The new value for this property.
192       *    <br>If <jk>null</jk> defaults to {@link BeanContext#getTimeZone()}.
193       * @return This object.
194       */
195      public Builder timeZone(TimeZone value) {
196         timeZone = value;
197         return this;
198      }
199
200      /**
201       * Same as {@link #timeZone(TimeZone)} but doesn't overwrite the value if it is already set.
202       *
203       * @param value
204       *    The new value for this property.
205       *    <br>If <jk>null</jk>, then the locale defined on the context is used.
206       * @return This object.
207       */
208      public Builder timeZoneDefault(TimeZone value) {
209         if (timeZone == null)
210            timeZone = value;
211         return this;
212      }
213
214      @Override /* Overridden from Builder */
215      public Builder unmodifiable() {
216         super.unmodifiable();
217         return this;
218      }
219   }
220
221   private static Logger LOG = Logger.getLogger(cn(BeanSession.class));
222
223   /**
224    * Creates a builder of this object.
225    *
226    * @param ctx The context creating this builder.
227    *    <br>Cannot be <jk>null</jk>.
228    * @return A new builder.
229    */
230   public static Builder create(BeanContext ctx) {
231      return new Builder(assertArgNotNull("ctx", ctx));
232   }
233
234   /**
235    * Returns the name property name.
236    *
237    * <p>
238    * Currently this always returns <js>"_name"</js>.
239    *
240    * @return The name property name.  Never <jk>null</jk>.
241    */
242   public final static String getNamePropertyName() { return "_name"; }
243
244   private static int getMultiplier(String s) {
245      if (s.endsWith("G"))
246         return 1024 * 1024 * 1024;
247      if (s.endsWith("M"))
248         return 1024 * 1024;
249      if (s.endsWith("K"))
250         return 1024;
251      return 1;
252   }
253
254   private static boolean hasMutater(ClassMeta<?> from, ClassMeta<?> to) {
255      return to.hasMutaterFrom(from) || from.hasMutaterTo(to);
256   }
257
258   private static final boolean isNullOrEmpty(Object o) {
259      return o == null || o.toString().isEmpty() || o.toString().equals("null");
260   }
261   private final BeanContext ctx;
262   private final Locale locale;
263   private final MediaType mediaType;
264
265   private final TimeZone timeZone;
266
267   /**
268    * Constructor.
269    *
270    * @param builder The builder for this object.
271    */
272   protected BeanSession(Builder builder) {
273      super(builder);
274      ctx = builder.ctx;
275      locale = opt(builder.locale).orElse(ctx.getLocale());
276      mediaType = opt(builder.mediaType).orElse(builder.mediaType);
277      timeZone = opt(builder.timeZone).orElse(builder.timeZone);
278   }
279
280   /**
281    * Logs a warning message.
282    *
283    * @param msg The warning message.
284    * @param args Optional {@link MessageFormat}-style arguments.
285    */
286   @Override
287   public void addWarning(String msg, Object...args) {
288      if (isDebug())
289         LOG.log(Level.WARNING, () -> args.length == 0 ? msg : f(msg, args));
290      super.addWarning(msg, args);
291   }
292
293   /**
294    * Same as {@link #convertToType(Object, Class)}, except used for instantiating inner member classes that must
295    * be instantiated within another class instance.
296    *
297    * @param <T> The class type to convert the value to.
298    * @param outer
299    *    If class is a member class, this is the instance of the containing class.
300    *    Should be <jk>null</jk> if not a member class.
301    * @param value The value to convert.
302    * @param type The class type to convert the value to.
303    * @throws InvalidDataConversionException If the specified value cannot be converted to the specified type.
304    * @return The converted value.
305    */
306   public final <T> T convertToMemberType(Object outer, Object value, Class<T> type) throws InvalidDataConversionException {
307      return convertToMemberType(outer, value, getClassMeta(type));
308   }
309
310   /**
311    * Converts the specified value to the specified class type.
312    *
313    * <p>
314    * See {@link #convertToType(Object, ClassMeta)} for the list of valid conversions.
315    *
316    * @param <T> The class type to convert the value to.
317    * @param value The value to convert.
318    * @param type The class type to convert the value to.
319    * @throws InvalidDataConversionException If the specified value cannot be converted to the specified type.
320    * @return The converted value.
321    */
322   public final <T> T convertToType(Object value, Class<T> type) throws InvalidDataConversionException {
323      // Shortcut for most common case.
324      if (nn(value) && value.getClass() == type)
325         return (T)value;
326      return convertToMemberType(null, value, getClassMeta(type));
327   }
328
329   /**
330    * Casts the specified value into the specified type.
331    *
332    * <p>
333    * If the value isn't an instance of the specified type, then converts the value if possible.
334    *
335    * <p>
336    * The following conversions are valid:
337    * <table class='styled'>
338    *    <tr><th>Convert to type</th><th>Valid input value types</th><th>Notes</th></tr>
339    *    <tr>
340    *       <td>
341    *          A class that is the normal type of a registered {@link ObjectSwap}.
342    *       </td>
343    *       <td>
344    *          A value whose class matches the transformed type of that registered {@link ObjectSwap}.
345    *       </td>
346    *       <td>&nbsp;</td>
347    *    </tr>
348    *    <tr>
349    *       <td>
350    *          A class that is the transformed type of a registered {@link ObjectSwap}.
351    *       </td>
352    *       <td>
353    *          A value whose class matches the normal type of that registered {@link ObjectSwap}.
354    *       </td>
355    *       <td>&nbsp;</td>
356    *    </tr>
357    *    <tr>
358    *       <td>
359    *          {@code Number} (e.g. {@code Integer}, {@code Short}, {@code Float},...)
360    *          <br><code>Number.<jsf>TYPE</jsf></code> (e.g. <code>Integer.<jsf>TYPE</jsf></code>,
361    *          <code>Short.<jsf>TYPE</jsf></code>, <code>Float.<jsf>TYPE</jsf></code>,...)
362    *       </td>
363    *       <td>
364    *          {@code Number}, {@code String}, <jk>null</jk>
365    *       </td>
366    *       <td>
367    *          For primitive {@code TYPES}, <jk>null</jk> returns the JVM default value for that type.
368    *       </td>
369    *    </tr>
370    *    <tr>
371    *       <td>
372    *          {@code Map} (e.g. {@code Map}, {@code HashMap}, {@code TreeMap}, {@code JsonMap})
373    *       </td>
374    *       <td>
375    *          {@code Map}
376    *       </td>
377    *       <td>
378    *          If {@code Map} is not constructible, an {@code JsonMap} is created.
379    *       </td>
380    *    </tr>
381    *    <tr>
382    *       <td>
383    *       {@code Collection} (e.g. {@code List}, {@code LinkedList}, {@code HashSet}, {@code JsonList})
384    *       </td>
385    *       <td>
386    *          {@code Collection<Object>}
387    *          <br>{@code Object[]}
388    *       </td>
389    *       <td>
390    *          If {@code Collection} is not constructible, an {@code JsonList} is created.
391    *       </td>
392    *    </tr>
393    *    <tr>
394    *       <td>
395    *          {@code X[]} (array of any type X)
396    *       </td>
397    *       <td>
398    *          {@code List<X>}
399    *       </td>
400    *       <td>&nbsp;</td>
401    *    </tr>
402    *    <tr>
403    *       <td>
404    *          {@code X[][]} (multi-dimensional arrays)
405    *       </td>
406    *       <td>
407    *          {@code List<List<X>>}
408    *          <br>{@code List<X[]>}
409    *          <br>{@code List[]<X>}
410    *       </td>
411    *       <td>&nbsp;</td>
412    *    </tr>
413    *    <tr>
414    *       <td>
415    *          {@code Enum}
416    *       </td>
417    *       <td>
418    *          {@code String}
419    *       </td>
420    *       <td>&nbsp;</td>
421    *    </tr>
422    *    <tr>
423    *       <td>
424    *          Bean
425    *       </td>
426    *       <td>
427    *          {@code Map}
428    *       </td>
429    *       <td>&nbsp;</td>
430    *    </tr>
431    *    <tr>
432    *       <td>
433    *          {@code String}
434    *       </td>
435    *       <td>
436    *          Anything
437    *       </td>
438    *       <td>
439    *          Arrays are converted to JSON arrays
440    *       </td>
441    *    </tr>
442    *    <tr>
443    *       <td>
444    *          Anything with one of the following methods:
445    *          <br><code><jk>public static</jk> T fromString(String)</code>
446    *          <br><code><jk>public static</jk> T valueOf(String)</code>
447    *          <br><code><jk>public</jk> T(String)</code>
448    *       </td>
449    *       <td>
450    *          <c>String</c>
451    *       </td>
452    *       <td>
453    *          <br>
454    *       </td>
455    *    </tr>
456    * </table>
457    *
458    * @param <T> The class type to convert the value to.
459    * @param value The value to be converted.
460    * @param type The target object type.
461    * @return The converted type.
462    * @throws InvalidDataConversionException If the specified value cannot be converted to the specified type.
463    */
464   public final <T> T convertToType(Object value, ClassMeta<T> type) throws InvalidDataConversionException {
465      return convertToMemberType(null, value, type);
466   }
467
468   /**
469    * Same as {@link #convertToType(Object, Class)}, but allows for complex data types consisting of collections or maps.
470    *
471    * @param <T> The class type to convert the value to.
472    * @param value The value to be converted.
473    * @param type The target object type.
474    * @param args The target object parameter types.
475    * @return The converted type.
476    * @throws InvalidDataConversionException If the specified value cannot be converted to the specified type.
477    */
478   public final <T> T convertToType(Object value, Type type, Type...args) throws InvalidDataConversionException {
479      return (T)convertToMemberType(null, value, getClassMeta(type, args));
480   }
481
482   /**
483    * Returns the annotation provider for this session.
484    *
485    * @return The annotation provider for this session.
486    */
487   public AnnotationProvider getAnnotationProvider() {
488      return ctx.getAnnotationProvider();
489   }
490
491   /**
492    * Minimum bean class visibility.
493    *
494    * @see BeanContext.Builder#beanClassVisibility(Visibility)
495    * @return
496    *    Classes are not considered beans unless they meet the minimum visibility requirements.
497    */
498   public final Visibility getBeanClassVisibility() { return ctx.getBeanClassVisibility(); }
499
500   /**
501    * Minimum bean constructor visibility.
502    *
503    * @see BeanContext.Builder#beanConstructorVisibility(Visibility)
504    * @return
505    *    Only look for constructors with this specified minimum visibility.
506    */
507   public final Visibility getBeanConstructorVisibility() { return ctx.getBeanConstructorVisibility(); }
508
509   /**
510    * Bean dictionary.
511    *
512    * @see BeanContext.Builder#beanDictionary(ClassInfo...)
513    * @return
514    *    The list of classes that make up the bean dictionary in this bean context.
515    *    <br>Never <jk>null</jk>.
516    *    <br>List is unmodifiable.
517    */
518   public final List<ClassInfo> getBeanDictionary() { return ctx.getBeanDictionary(); }
519
520   /**
521    * Minimum bean field visibility.
522    *
523    *
524    * @see BeanContext.Builder#beanFieldVisibility(Visibility)
525    * @return
526    *    Only look for bean fields with this specified minimum visibility.
527    */
528   public final Visibility getBeanFieldVisibility() { return ctx.getBeanFieldVisibility(); }
529
530   /**
531    * Returns the {@link BeanMeta} class for the specified class.
532    *
533    * @param <T> The class type to get the meta-data on.
534    * @param c The class to get the meta-data on.
535    * @return
536    *    The {@link BeanMeta} for the specified class, or <jk>null</jk> if the class
537    *    is not a bean per the settings on this context.
538    */
539   public final <T> BeanMeta<T> getBeanMeta(Class<T> c) {
540      if (c == null)
541         return null;
542      return getClassMeta(c).getBeanMeta();
543   }
544
545   /**
546    * Minimum bean method visibility.
547    *
548    * @see BeanContext.Builder#beanMethodVisibility(Visibility)
549    * @return
550    *    Only look for bean methods with this specified minimum visibility.
551    */
552   public final Visibility getBeanMethodVisibility() { return ctx.getBeanMethodVisibility(); }
553
554   /**
555    * Returns the bean registry defined in this bean context defined by {@link BeanContext.Builder#beanDictionary(ClassInfo...)}.
556    *
557    * @return The bean registry defined in this bean context.  Never <jk>null</jk>.
558    */
559   public final BeanRegistry getBeanRegistry() { return ctx.getBeanRegistry(); }
560
561   /**
562    * Bean type property name.
563    *
564    * @see BeanContext.Builder#typePropertyName(String)
565    * @return
566    *    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.
567    */
568   public final String getBeanTypePropertyName() { return ctx.getBeanTypePropertyName(); }
569
570   /**
571    * Returns the type property name as defined by {@link BeanContext.Builder#typePropertyName(String)}.
572    *
573    * @param cm
574    *    The class meta of the type we're trying to resolve the type name for.
575    *    Can be <jk>null</jk>.
576    * @return The type property name.  Never <jk>null</jk>.
577    */
578   public final String getBeanTypePropertyName(ClassMeta cm) {
579      if (cm == null)
580         return getBeanTypePropertyName();
581      var beanMeta = cm.getBeanMeta();
582      if (beanMeta == null)
583         return getBeanTypePropertyName();
584      var s = beanMeta.getTypePropertyName();
585      return s == null ? getBeanTypePropertyName() : s;
586   }
587
588   /**
589    * Returns a {@code ClassMeta} wrapper around a {@link Class} object.
590    *
591    * @param <T> The class type being wrapped.
592    * @param c The class being wrapped.
593    * @return The class meta object containing information about the class.
594    */
595   public final <T> ClassMeta<T> getClassMeta(Class<T> c) {
596      return ctx.getClassMeta(c);
597   }
598
599   /**
600    * Used to resolve <c>ClassMetas</c> of type <c>Collection</c> and <c>Map</c> that have
601    * <c>ClassMeta</c> values that themselves could be collections or maps.
602    *
603    * <p>
604    * <c>Collection</c> meta objects are assumed to be followed by zero or one meta objects indicating the
605    * element type.
606    *
607    * <p>
608    * <c>Map</c> meta objects are assumed to be followed by zero or two meta objects indicating the key and value
609    * types.
610    *
611    * <p>
612    * The array can be arbitrarily long to indicate arbitrarily complex data structures.
613    *
614    * <h5 class='section'>Examples:</h5>
615    * <ul>
616    *    <li><code>getClassMeta(String.<jk>class</jk>);</code> - A normal type.
617    *    <li><code>getClassMeta(List.<jk>class</jk>);</code> - A list containing objects.
618    *    <li><code>getClassMeta(List.<jk>class</jk>, String.<jk>class</jk>);</code> - A list containing strings.
619    *    <li><code>getClassMeta(LinkedList.<jk>class</jk>, String.<jk>class</jk>);</code> - A linked-list containing
620    *       strings.
621    *    <li><code>getClassMeta(LinkedList.<jk>class</jk>, LinkedList.<jk>class</jk>, String.<jk>class</jk>);</code> -
622    *       A linked-list containing linked-lists of strings.
623    *    <li><code>getClassMeta(Map.<jk>class</jk>);</code> - A map containing object keys/values.
624    *    <li><code>getClassMeta(Map.<jk>class</jk>, String.<jk>class</jk>, String.<jk>class</jk>);</code> - A map
625    *       containing string keys/values.
626    *    <li><code>getClassMeta(Map.<jk>class</jk>, String.<jk>class</jk>, List.<jk>class</jk>, MyBean.<jk>class</jk>);</code> -
627    *       A map containing string keys and values of lists containing beans.
628    * </ul>
629    *
630    * @param <T>
631    *    The class to resolve.
632    * @param type
633    *    The class to resolve.
634    *    <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
635    * @param args
636    *    The type arguments of the class if it's a collection or map.
637    *    <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
638    *    <br>Ignored if the main type is not a map or collection.
639    * @return The class meta.
640    */
641   public final <T> ClassMeta<T> getClassMeta(Type type, Type...args) {
642      return ctx.getClassMeta(type, args);
643   }
644
645   /**
646    * Shortcut for calling {@code getClassMeta(o.getClass())}.
647    *
648    * @param <T> The class of the object being passed in.
649    * @param o The class to find the class type for.
650    * @return The ClassMeta object, or <jk>null</jk> if {@code o} is <jk>null</jk>.
651    */
652   public final <T> ClassMeta<T> getClassMetaForObject(T o) {
653      return (ClassMeta<T>)getClassMetaForObject(o, null);
654   }
655
656   /**
657    * Locale.
658    *
659    * <p>
660    * The locale is determined in the following order:
661    * <ol>
662    *    <li><c>locale</c> parameter passed in through constructor.
663    *    <li>{@link BeanContext.Builder#locale(Locale)} setting on bean context.
664    *    <li>Locale returned by {@link Locale#getDefault()}.
665    * </ol>
666    *
667    * @see BeanContext.Builder#locale(Locale)
668    * @return The session locale.
669    */
670   public Locale getLocale() { return locale; }
671
672   /**
673    * Media type.
674    *
675    * <p>
676    * For example, <js>"application/json"</js>.
677    *
678    * @see BeanContext.Builder#mediaType(MediaType)
679    * @return The media type for this session, or <jk>null</jk> if not specified.
680    */
681   public final MediaType getMediaType() { return mediaType; }
682
683   /**
684    * Bean class exclusions.
685    *
686    * @see BeanContext.Builder#notBeanClasses(ClassInfo...)
687    * @return
688    *    The list of classes that are explicitly not beans.
689    *    <br>Never <jk>null</jk>.
690    *    <br>List is unmodifiable.
691    */
692   public final List<ClassInfo> getNotBeanClasses() { return ctx.getNotBeanClasses(); }
693
694   /**
695    * Bean package exclusions.
696    *
697    * @see BeanContext.Builder#notBeanPackages(String...)
698    * @return
699    *    The set of fully-qualified package names to exclude from being classified as beans.
700    *    <br>Never <jk>null</jk>.
701    *    <br>Set is unmodifiable.
702    */
703   public final Set<String> getNotBeanPackagesNames() { return ctx.getNotBeanPackagesNames(); }
704
705   /**
706    * Bean property namer.
707    *
708    * @see BeanContext.Builder#propertyNamer(Class)
709    * @return
710    *    The interface used to calculate bean property names.
711    */
712   public final PropertyNamer getPropertyNamer() { return ctx.getPropertyNamer(); }
713
714   /**
715    * Java object swaps.
716    *
717    * @see BeanContext.Builder#swaps(Class...)
718    * @return
719    *    The list POJO swaps defined.
720    *    <br>Never <jk>null</jk>.
721    *    <br>List is unmodifiable.
722    */
723   public final List<ObjectSwap<?,?>> getSwaps() { return ctx.getSwaps(); }
724
725   /**
726    * Time zone.
727    *
728    * <p>
729    * The timezone is determined in the following order:
730    * <ol>
731    *    <li><c>timeZone</c> parameter passed in through constructor.
732    *    <li>{@link BeanContext.Builder#timeZone(TimeZone)} setting on bean context.
733    * </ol>
734    *
735    * @see BeanContext.Builder#timeZone(TimeZone)
736    * @return The session timezone, or <jk>null</jk> if timezone not specified.
737    */
738   public final TimeZone getTimeZone() { return timeZone; }
739
740   /**
741    * Time zone.
742    *
743    * <p>
744    * The timezone is determined in the following order:
745    * <ol>
746    *    <li><c>timeZone</c> parameter passed in through constructor.
747    *    <li>{@link BeanContext.Builder#timeZone(TimeZone)} setting on bean context.
748    * </ol>
749    *
750    * @see BeanContext.Builder#timeZone(TimeZone)
751    * @return The session timezone, or the system timezone if not specified.  Never <jk>null</jk>.
752    */
753   public final ZoneId getTimeZoneId() { return timeZone == null ? ZoneId.systemDefault() : timeZone.toZoneId(); }
754
755   /**
756    * Determines whether the specified class matches the requirements on this context of being a bean.
757    *
758    * @param c The class being tested.
759    * @return <jk>true</jk> if the specified class is considered a bean.
760    */
761   public final boolean isBean(Class<?> c) {
762      return nn(getBeanMeta(c));
763   }
764
765   /**
766    * Determines whether the specified object matches the requirements on this context of being a bean.
767    *
768    * @param o The object being tested.
769    * @return <jk>true</jk> if the specified object is considered a bean.
770    */
771   public final boolean isBean(Object o) {
772      if (o == null)
773         return false;
774      return isBean(o.getClass());
775   }
776
777   /**
778    * BeanMap.put() returns old property value.
779    *
780    * @see BeanContext.Builder#beanMapPutReturnsOldValue()
781    * @return
782    *    <jk>true</jk> if the {@link BeanMap#put(String,Object) BeanMap.put()} method will return old property values.
783    *    <br>Otherwise, it returns <jk>null</jk>.
784    */
785   public final boolean isBeanMapPutReturnsOldValue() { return ctx.isBeanMapPutReturnsOldValue(); }
786
787   /**
788    * Beans require no-arg constructors.
789    *
790    * @see BeanContext.Builder#beansRequireDefaultConstructor()
791    * @return
792    *    <jk>true</jk> if a Java class must implement a default no-arg constructor to be considered a bean.
793    *    <br>Otherwise, the bean will be serialized as a string using the {@link Object#toString()} method.
794    */
795   public final boolean isBeansRequireDefaultConstructor() { return ctx.isBeansRequireDefaultConstructor(); }
796
797   /**
798    * Beans require Serializable interface.
799    *
800    * @see BeanContext.Builder#beansRequireSerializable()
801    * @return
802    *    <jk>true</jk> if a Java class must implement the {@link Serializable} interface to be considered a bean.
803    *    <br>Otherwise, the bean will be serialized as a string using the {@link Object#toString()} method.
804    */
805   public final boolean isBeansRequireSerializable() { return ctx.isBeansRequireSerializable(); }
806
807   /**
808    * Beans require setters for getters.
809    *
810    * @see BeanContext.Builder#beansRequireSettersForGetters()
811    * @return
812    *    <jk>true</jk> if only getters that have equivalent setters will be considered as properties on a bean.
813    *    <br>Otherwise, they are ignored.
814    */
815   public final boolean isBeansRequireSettersForGetters() { return ctx.isBeansRequireSettersForGetters(); }
816
817   /**
818    * Beans require at least one property.
819    *
820    * @see BeanContext.Builder#disableBeansRequireSomeProperties()
821    * @return
822    *    <jk>true</jk> if a Java class doesn't need to contain at least 1 property to be considered a bean.
823    *    <br>Otherwise, the bean is serialized as a string using the {@link Object#toString()} method.
824    */
825   public final boolean isBeansRequireSomeProperties() { return ctx.isBeansRequireSomeProperties(); }
826
827   /**
828    * Find fluent setters.
829    *
830    * <h5 class='section'>Description:</h5>
831    * <p>
832    *
833    * @see BeanContext.Builder#findFluentSetters()
834    * @return
835    *    <jk>true</jk> if fluent setters are detected on beans.
836    */
837   public final boolean isFindFluentSetters() { return ctx.isFindFluentSetters(); }
838
839   /**
840    * Ignore invocation errors on getters.
841    *
842    * @see BeanContext.Builder#ignoreInvocationExceptionsOnGetters()
843    * @return
844    *    <jk>true</jk> if errors thrown when calling bean getter methods are silently ignored.
845    */
846   public final boolean isIgnoreInvocationExceptionsOnGetters() { return ctx.isIgnoreInvocationExceptionsOnGetters(); }
847
848   /**
849    * Ignore invocation errors on setters.
850    *
851    * @see BeanContext.Builder#ignoreInvocationExceptionsOnSetters()
852    * @return
853    *    <jk>true</jk> if errors thrown when calling bean setter methods are silently ignored.
854    */
855   public final boolean isIgnoreInvocationExceptionsOnSetters() { return ctx.isIgnoreInvocationExceptionsOnSetters(); }
856
857   /**
858    * Silently ignore missing setters.
859    *
860    * @see BeanContext.Builder#disableIgnoreMissingSetters()
861    * @return
862    *    <jk>true</jk> if trying to set a value on a bean property without a setter should throw a {@link BeanRuntimeException}.
863    */
864   public final boolean isIgnoreMissingSetters() { return ctx.isIgnoreMissingSetters(); }
865
866   /**
867    * Ignore unknown properties.
868    *
869    * @see BeanContext.Builder#ignoreUnknownBeanProperties()
870    * @return
871    *    <jk>true</jk> if trying to set a value on a non-existent bean property is silently ignored.
872    *    <br>Otherwise, a {@code RuntimeException} is thrown.
873    */
874   public final boolean isIgnoreUnknownBeanProperties() { return ctx.isIgnoreUnknownBeanProperties(); }
875
876   /**
877    * Ignore unknown properties with null values.
878    *
879    * @see BeanContext.Builder#disableIgnoreUnknownNullBeanProperties()
880    * @return
881    *    <jk>true</jk> if trying to set a <jk>null</jk> value on a non-existent bean property should not throw a {@link BeanRuntimeException}.
882    */
883   public final boolean isIgnoreUnknownNullBeanProperties() { return ctx.isIgnoreUnknownNullBeanProperties(); }
884
885   /**
886    * Sort bean properties.
887    *
888    * @see BeanContext.Builder#sortProperties()
889    * @return
890    *    <jk>true</jk> if all bean properties will be serialized and access in alphabetical order.
891    */
892   public final boolean isSortProperties() { return ctx.isSortProperties(); }
893
894   /**
895    * Use enum names.
896    *
897    * @see BeanContext.Builder#useEnumNames()
898    * @return
899    *    <jk>true</jk> if enums are always serialized by name, not using {@link Object#toString()}.
900    */
901   public final boolean isUseEnumNames() { return ctx.isUseEnumNames(); }
902
903   /**
904    * Use interface proxies.
905    *
906    * @see BeanContext.Builder#disableInterfaceProxies()
907    * @return
908    *    <jk>true</jk> if interfaces will be instantiated as proxy classes through the use of an
909    *    {@link InvocationHandler} if there is no other way of instantiating them.
910    */
911   public final boolean isUseInterfaceProxies() { return ctx.isUseInterfaceProxies(); }
912
913   /**
914    * Use Java Introspector.
915    *
916    * @see BeanContext.Builder#useJavaBeanIntrospector()
917    * @return
918    *    <jk>true</jk> if the built-in Java bean introspector should be used for bean introspection.
919    */
920   public final boolean isUseJavaBeanIntrospector() { return ctx.isUseJavaBeanIntrospector(); }
921
922   /**
923    * Creates a new empty bean of the specified type, except used for instantiating inner member classes that must
924    * be instantiated within another class instance.
925    *
926    * <h5 class='section'>Example:</h5>
927    * <p class='bjava'>
928    *    <jc>// Construct a new instance of the specified bean class</jc>
929    *    Person <jv>person</jv> = BeanContext.<jsf>DEFAULT</jsf>.newBean(Person.<jk>class</jk>);
930    * </p>
931    *
932    * @param <T> The class type of the bean being created.
933    * @param c The class type of the bean being created.
934    * @return A new bean object.
935    * @throws BeanRuntimeException If the specified class is not a valid bean.
936    */
937   public final <T> T newBean(Class<T> c) throws BeanRuntimeException {
938      return newBean(null, c);
939   }
940
941   /**
942    * Same as {@link #newBean(Class)}, except used for instantiating inner member classes that must be instantiated
943    * within another class instance.
944    *
945    * @param <T> The class type of the bean being created.
946    * @param c The class type of the bean being created.
947    * @param outer
948    *    If class is a member class, this is the instance of the containing class.
949    *    Should be <jk>null</jk> if not a member class.
950    * @return A new bean object.
951    * @throws BeanRuntimeException If the specified class is not a valid bean.
952    */
953   public final <T> T newBean(Object outer, Class<T> c) throws BeanRuntimeException {
954      var cm = getClassMeta(c);
955      var m = cm.getBeanMeta();
956      if (m == null)
957         return null;
958      try {
959         var o = m.newBean(outer);
960         if (o == null)
961            throw bex(c, "Class does not have a no-arg constructor.");
962         return o;
963      } catch (BeanRuntimeException e) {
964         throw e;
965      } catch (Exception e) {
966         throw bex(e);
967      }
968   }
969
970   /**
971    * Creates a new {@link BeanMap} object (a modifiable {@link Map}) of the given class with uninitialized
972    * property values.
973    *
974    * <p>
975    * If object is not a true bean, then throws a {@link BeanRuntimeException} with an explanation of why it's not a
976    * bean.
977    *
978    * <h5 class='section'>Example:</h5>
979    * <p class='bjava'>
980    *    <jc>// Construct a new bean map wrapped around a new Person object</jc>
981    *    BeanMap&lt;Person&gt; <jv>beanMap</jv> = BeanContext.<jsf>DEFAULT</jsf>.newBeanMap(Person.<jk>class</jk>);
982    * </p>
983    *
984    * @param <T> The class of the object being wrapped.
985    * @param c The name of the class to create a new instance of.
986    * @return A new instance of the class.
987    */
988   public final <T> BeanMap<T> newBeanMap(Class<T> c) {
989      return newBeanMap(null, c);
990   }
991
992   /**
993    * Same as {@link #newBeanMap(Class)}, except used for instantiating inner member classes that must be instantiated
994    * within another class instance.
995    *
996    * @param <T> The class of the object being wrapped.
997    * @param c The name of the class to create a new instance of.
998    * @param outer
999    *    If class is a member class, this is the instance of the containing class.
1000    *    Should be <jk>null</jk> if not a member class.
1001    * @return A new instance of the class.
1002    */
1003   public final <T> BeanMap<T> newBeanMap(Object outer, Class<T> c) {
1004      var m = getBeanMeta(c);
1005      if (m == null)
1006         return null;
1007      T bean = null;
1008      if (e(m.getConstructorArgs()))
1009         bean = newBean(outer, c);
1010      return new BeanMap<>(this, bean, m);
1011   }
1012
1013   /**
1014    * Returns a reusable {@link ClassMeta} representation for the class <c>Object</c>.
1015    *
1016    * <p>
1017    * This <c>ClassMeta</c> is often used to represent "any object type" when an object type is not known.
1018    *
1019    * <p>
1020    * This method is identical to calling <code>getClassMeta(Object.<jk>class</jk>)</code> but uses a cached copy to
1021    * avoid a hashmap lookup.
1022    *
1023    * @return The {@link ClassMeta} object associated with the <c>Object</c> class.
1024    */
1025   public final ClassMeta<Object> object() {
1026      return ctx.object();
1027   }
1028
1029   /**
1030    * Returns a reusable {@link ClassMeta} representation for the class <c>String</c>.
1031    *
1032    * <p>
1033    * This <c>ClassMeta</c> is often used to represent key types in maps.
1034    *
1035    * <p>
1036    * This method is identical to calling <code>getClassMeta(String.<jk>class</jk>)</code> but uses a cached copy to
1037    * avoid a hashmap lookup.
1038    *
1039    * @return The {@link ClassMeta} object associated with the <c>String</c> class.
1040    */
1041   public final ClassMeta<String> string() {
1042      return ctx.string();
1043   }
1044
1045   /**
1046    * Wraps an object inside a {@link BeanMap} object (a modifiable {@link Map}).
1047    *
1048    * <p>
1049    * If object is not a true bean, then throws a {@link BeanRuntimeException} with an explanation of why it's not a
1050    * bean.
1051    *
1052    * <p>
1053    * If object is already a {@link BeanMap}, simply returns the same object.
1054    *
1055    * <h5 class='section'>Example:</h5>
1056    * <p class='bjava'>
1057    *    <jc>// Construct a bean map around a bean instance</jc>
1058    *    BeanMap&lt;Person&gt; <jv>beanMap</jv> = BeanContext.<jsf>DEFAULT</jsf>.toBeanMap(<jk>new</jk> Person());
1059    * </p>
1060    *
1061    * @param <T> The class of the object being wrapped.
1062    * @param o The object to wrap in a map interface.  Must not be null.
1063    * @return The wrapped object.
1064    */
1065   public final <T> BeanMap<T> toBeanMap(T o) {
1066      if (o instanceof BeanMap o2)
1067         return o2;
1068      return this.toBeanMap(o, (Class<T>)o.getClass());
1069   }
1070
1071   /**
1072    * Wraps an object inside a {@link BeanMap} object (i.e.: a modifiable {@link Map}) defined as a bean for one of its
1073    * class, a super class, or an implemented interface.
1074    *
1075    * <p>
1076    * If object is not a true bean, throws a {@link BeanRuntimeException} with an explanation of why it's not a bean.
1077    *
1078    * <h5 class='section'>Example:</h5>
1079    * <p class='bjava'>
1080    *    <jc>// Construct a bean map for new bean using only properties defined in a superclass</jc>
1081    *    BeanMap&lt;MySubBean&gt; <jv>beanMap</jv> = BeanContext.<jsf>DEFAULT</jsf>.toBeanMap(<jk>new</jk> MySubBean(), MySuperBean.<jk>class</jk>);
1082    *
1083    *    <jc>// Construct a bean map for new bean using only properties defined in an interface</jc>
1084    *    BeanMap&lt;MySubBean&gt; <jv>beanMap</jv> = BeanContext.<jsf>DEFAULT</jsf>.toBeanMap(<jk>new</jk> MySubBean(), MySuperInterface.<jk>class</jk>);
1085    * </p>
1086    *
1087    * @param <T> The class of the object being wrapped.
1088    * @param o The object to wrap in a bean interface.  Must not be null.
1089    * @param c The superclass to narrow the bean properties to.  Must not be null.
1090    * @return The bean representation, or <jk>null</jk> if the object is not a true bean.
1091    * @throws NullPointerException If either parameter is null.
1092    * @throws IllegalArgumentException If the specified object is not an an instance of the specified class.
1093    * @throws
1094    *    BeanRuntimeException If specified object is not a bean according to the bean rules specified in this context
1095    * class.
1096    */
1097   public final <T> BeanMap<T> toBeanMap(T o, Class<? super T> c) throws BeanRuntimeException {
1098      assertArgNotNull("o", o);
1099      assertArgNotNull("c", c);
1100      assertArg(c.isInstance(o), "The specified object is not an instance of the specified class.  class=''{0}'', objectClass=''{1}'', object=''{2}''", cn(c), cn(o), 0);
1101
1102      var cm = getClassMeta(c);
1103
1104      BeanMeta m = cm.getBeanMeta();
1105      if (m == null)
1106         throw bex(c, "Class is not a bean.  Reason=''{0}''", cm.getNotABeanReason());
1107      return new BeanMap<>(this, o, m);
1108   }
1109
1110   /**
1111    * Wraps an object inside a {@link BeanMap} object (a modifiable {@link Map}).
1112    *
1113    * <p>
1114    * Same as {@link #toBeanMap(Object)} but allows you to specify a property namer instance.
1115    *
1116    * <h5 class='section'>Example:</h5>
1117    * <p class='bjava'>
1118    *    <jc>// Construct a bean map around a bean instance</jc>
1119    *    BeanMap&lt;Person&gt; <jv>beanMap</jv> = BeanContext.<jsf>DEFAULT</jsf>.toBeanMap(<jk>new</jk> Person(), PropertyNamerDLC.<jsf>INSTANCE</jsf>);
1120    * </p>
1121    *
1122    * @param <T> The class of the object being wrapped.
1123    * @param o The object to wrap in a map interface.  Must not be null.
1124    * @param propertyNamer The property namer to use.
1125    * @return The wrapped object.
1126    */
1127   public final <T> BeanMap<T> toBeanMap(T o, PropertyNamer propertyNamer) {
1128      return this.toBeanMap(o, (Class<T>)o.getClass());
1129   }
1130
1131   /**
1132    * Same as {@link #convertToType(Object, ClassMeta)}, except used for instantiating inner member classes that must
1133    * be instantiated within another class instance.
1134    *
1135    * @param <T> The class type to convert the value to.
1136    * @param outer
1137    *    If class is a member class, this is the instance of the containing class.
1138    *    Should be <jk>null</jk> if not a member class.
1139    * @param value The value to convert.
1140    * @param to The class type to convert the value to.
1141    * @throws InvalidDataConversionException If the specified value cannot be converted to the specified type.
1142    * @return The converted value.
1143    */
1144   @SuppressWarnings("null")
1145   protected final <T> T convertToMemberType(Object outer, Object value, ClassMeta<T> to) throws InvalidDataConversionException {
1146      if (to == null)
1147         to = (ClassMeta<T>)object();
1148
1149      try {
1150         // Handle the case of a null value.
1151         if (value == null) {
1152
1153            // If it's a primitive, then use the converters to get the default value for the primitive type.
1154            if (to.isPrimitive())
1155               return to.getPrimitiveDefault();
1156
1157            // Otherwise, just return null.
1158            return to.isOptional() ? (T)to.getOptionalDefault() : null;
1159         }
1160
1161         if (to.isOptional() && (! (value instanceof Optional)))
1162            return (T)opt(convertToMemberType(outer, value, to.getElementType()));
1163
1164         var tc = to.inner();
1165
1166         // If no conversion needed, then just return the value.
1167         // Don't include maps or collections, because child elements may need conversion.
1168         if (tc.isInstance(value))
1169            if (! ((to.isMap() && ! to.getValueType().is(Object.class)) || ((to.isCollection() || to.isOptional()) && ! to.getElementType().isObject())))
1170               return (T)value;
1171
1172         ObjectSwap swap = to.getSwap(this);
1173         if (nn(swap)) {
1174            var nc = swap.getNormalClass();
1175            var fc = swap.getSwapClass();
1176            if (nc.isParentOf(tc) && fc.isParentOf(value.getClass()))
1177               return (T)swap.unswap(this, value, to);
1178            var fcm = getClassMeta(fc);
1179            if (fcm.isNumber() && value instanceof Number value2) {
1180               value = convertToMemberType(null, value2, fc.inner());
1181               return (T)swap.unswap(this, value, to);
1182            }
1183         }
1184
1185         var from = getClassMetaForObject(value);
1186         swap = from.getSwap(this);
1187         if (nn(swap)) {
1188            var nc = swap.getNormalClass();
1189            var fc = swap.getSwapClass();
1190            if (nc.isParentOf(from.inner()) && fc.isParentOf(tc))
1191               return (T)swap.swap(this, value);
1192         }
1193
1194         if (to.isPrimitive()) {
1195            if (to.isNumber()) {
1196               if (from.isNumber()) {
1197                  var n = (Number)value;
1198                  if (tc == Integer.TYPE)
1199                     return (T)Integer.valueOf(n.intValue());
1200                  if (tc == Short.TYPE)
1201                     return (T)Short.valueOf(n.shortValue());
1202                  if (tc == Long.TYPE)
1203                     return (T)Long.valueOf(n.longValue());
1204                  if (tc == Float.TYPE)
1205                     return (T)Float.valueOf(n.floatValue());
1206                  if (tc == Double.TYPE)
1207                     return (T)Double.valueOf(n.doubleValue());
1208                  if (tc == Byte.TYPE)
1209                     return (T)Byte.valueOf(n.byteValue());
1210               } else if (from.isBoolean()) {
1211                  var b = (Boolean)value;
1212                  if (tc == Integer.TYPE)
1213                     return (T)(Integer.valueOf(b ? 1 : 0));
1214                  if (tc == Short.TYPE)
1215                     return (T)(Short.valueOf(b ? (short)1 : 0));
1216                  if (tc == Long.TYPE)
1217                     return (T)(Long.valueOf(b ? 1L : 0));
1218                  if (tc == Float.TYPE)
1219                     return (T)(Float.valueOf(b ? 1f : 0));
1220                  if (tc == Double.TYPE)
1221                     return (T)(Double.valueOf(b ? 1d : 0));
1222                  if (tc == Byte.TYPE)
1223                     return (T)(Byte.valueOf(b ? (byte)1 : 0));
1224               } else if (isNullOrEmpty(value)) {
1225                  return to.getPrimitiveDefault();
1226               } else {
1227                  var s = value.toString();
1228                  var multiplier = (tc == Integer.TYPE || tc == Short.TYPE || tc == Long.TYPE) ? getMultiplier(s) : 1;
1229                  if (multiplier != 1) {
1230                     s = s.substring(0, s.length() - 1).trim();
1231                     Long l = Long.valueOf(s) * multiplier;
1232                     if (tc == Integer.TYPE)
1233                        return (T)Integer.valueOf(l.intValue());
1234                     if (tc == Short.TYPE)
1235                        return (T)Short.valueOf(l.shortValue());
1236                     if (tc == Long.TYPE)
1237                        return (T)l;
1238                  } else {
1239                     if (tc == Integer.TYPE)
1240                        return (T)Integer.valueOf(s);
1241                     if (tc == Short.TYPE)
1242                        return (T)Short.valueOf(s);
1243                     if (tc == Long.TYPE)
1244                        return (T)Long.valueOf(s);
1245                     if (tc == Float.TYPE)
1246                        return (T)Float.valueOf(s);
1247                     if (tc == Double.TYPE)
1248                        return (T)Double.valueOf(s);
1249                     if (tc == Byte.TYPE)
1250                        return (T)Byte.valueOf(s);
1251                  }
1252               }
1253            } else if (to.isChar()) {
1254               if (isNullOrEmpty(value))
1255                  return to.getPrimitiveDefault();
1256               return (T)parseCharacter(value);
1257            } else if (to.isBoolean()) {
1258               if (from.isNumber()) {
1259                  var i = ((Number)value).intValue();
1260                  return (T)(i == 0 ? Boolean.FALSE : Boolean.TRUE);
1261               } else if (isNullOrEmpty(value)) {
1262                  return to.getPrimitiveDefault();
1263               } else {
1264                  return (T)Boolean.valueOf(value.toString());
1265               }
1266            }
1267         }
1268
1269         if (to.isNumber()) {
1270            if (from.isNumber()) {
1271               var n = (Number)value;
1272               if (tc == Integer.class)
1273                  return (T)Integer.valueOf(n.intValue());
1274               if (tc == Short.class)
1275                  return (T)Short.valueOf(n.shortValue());
1276               if (tc == Long.class)
1277                  return (T)Long.valueOf(n.longValue());
1278               if (tc == Float.class)
1279                  return (T)Float.valueOf(n.floatValue());
1280               if (tc == Double.class)
1281                  return (T)Double.valueOf(n.doubleValue());
1282               if (tc == Byte.class)
1283                  return (T)Byte.valueOf(n.byteValue());
1284               if (tc == AtomicInteger.class)
1285                  return (T)new AtomicInteger(n.intValue());
1286               if (tc == AtomicLong.class)
1287                  return (T)new AtomicLong(n.intValue());
1288            } else if (from.isBoolean()) {
1289               var b = (Boolean)value;
1290               if (tc == Integer.class)
1291                  return (T)Integer.valueOf(b ? 1 : 0);
1292               if (tc == Short.class)
1293                  return (T)Short.valueOf(b ? (short)1 : 0);
1294               if (tc == Long.class)
1295                  return (T)Long.valueOf(b ? 1 : 0);
1296               if (tc == Float.class)
1297                  return (T)Float.valueOf(b ? 1 : 0);
1298               if (tc == Double.class)
1299                  return (T)Double.valueOf(b ? 1 : 0);
1300               if (tc == Byte.class)
1301                  return (T)Byte.valueOf(b ? (byte)1 : 0);
1302               if (tc == AtomicInteger.class)
1303                  return (T)new AtomicInteger(b ? 1 : 0);
1304               if (tc == AtomicLong.class)
1305                  return (T)new AtomicLong(b ? 1 : 0);
1306            } else if (isNullOrEmpty(value)) {
1307               return null;
1308            } else if (! hasMutater(from, to)) {
1309               var s = value.toString();
1310
1311               var multiplier = (tc == Integer.class || tc == Short.class || tc == Long.class) ? getMultiplier(s) : 1;
1312               if (multiplier != 1) {
1313                  s = s.substring(0, s.length() - 1).trim();
1314                  Long l = Long.valueOf(s) * multiplier;
1315                  if (tc == Integer.TYPE)
1316                     return (T)Integer.valueOf(l.intValue());
1317                  if (tc == Short.TYPE)
1318                     return (T)Short.valueOf(l.shortValue());
1319                  if (tc == Long.TYPE)
1320                     return (T)Long.valueOf(l.longValue());
1321               } else {
1322                  if (tc == Integer.class)
1323                     return (T)Integer.valueOf(s);
1324                  if (tc == Short.class)
1325                     return (T)Short.valueOf(s);
1326                  if (tc == Long.class)
1327                     return (T)Long.valueOf(s);
1328                  if (tc == Float.class)
1329                     return (T)Float.valueOf(s);
1330                  if (tc == Double.class)
1331                     return (T)Double.valueOf(s);
1332                  if (tc == Byte.class)
1333                     return (T)Byte.valueOf(s);
1334                  if (tc == AtomicInteger.class)
1335                     return (T)new AtomicInteger(Integer.valueOf(s));
1336                  if (tc == AtomicLong.class)
1337                     return (T)new AtomicLong(Long.valueOf(s));
1338                  if (tc == Number.class)
1339                     return (T)StringUtils.parseNumber(s, Number.class);
1340               }
1341            }
1342         }
1343
1344         if (to.isChar()) {
1345            if (isNullOrEmpty(value))
1346               return null;
1347            var s = value.toString();
1348            if (s.length() == 1)
1349               return (T)Character.valueOf(s.charAt(0));
1350         }
1351
1352         if (to.isByteArray()) {
1353            if (from.isInputStream())
1354               return (T)readBytes((InputStream)value);
1355            if (from.isReader())
1356               return (T)read((Reader)value).getBytes();
1357            if (to.hasMutaterFrom(from))
1358               return to.mutateFrom(value);
1359            if (from.hasMutaterTo(to))
1360               return from.mutateTo(value, to);
1361            return (T)value.toString().getBytes(Charset.forName("UTF-8"));
1362         }
1363
1364         // Handle setting of array properties
1365         if (to.isArray()) {
1366            if (from.isCollection())
1367               return (T)toArray(to, (Collection)value);
1368            else if (from.isArray())
1369               return (T)toArray(to, l((Object[])value));
1370            else if (startsWith(value.toString(), '['))
1371               return (T)toArray(to, JsonList.ofJson(value.toString()).setBeanSession(this));
1372            else if (to.hasMutaterFrom(from))
1373               return to.mutateFrom(value);
1374            else if (from.hasMutaterTo(to))
1375               return from.mutateTo(value, to);
1376            else
1377               return (T)toArray(to, new JsonList((Object[])StringUtils.splita(value.toString())).setBeanSession(this));
1378         }
1379
1380         // Target type is some sort of Map that needs to be converted.
1381         if (to.isMap()) {
1382            try {
1383               if (from.isMap()) {
1384                  var m = to.canCreateNewInstance(outer) ? (Map)to.newInstance(outer) : newGenericMap(to);
1385                  var keyType = to.getKeyType();
1386                  var valueType = to.getValueType();
1387                  ((Map<?,?>)value).forEach((k, v) -> {
1388                     var k2 = k;
1389                     if (! keyType.isObject()) {
1390                        if (keyType.isString() && k.getClass() != Class.class)
1391                           k2 = k.toString();
1392                        else
1393                           k2 = convertToMemberType(m, k, keyType);
1394                     }
1395                     var v2 = v;
1396                     if (! valueType.isObject())
1397                        v2 = convertToMemberType(m, v, valueType);
1398                     m.put(k2, v2);
1399                  });
1400                  return (T)m;
1401               } else if (! to.canCreateNewInstanceFromString(outer)) {
1402                  var m = JsonMap.ofJson(value.toString());
1403                  m.setBeanSession(this);
1404                  return convertToMemberType(outer, m, to);
1405               }
1406            } catch (Exception e) {
1407               throw new InvalidDataConversionException(value.getClass(), to, e);
1408            }
1409         }
1410
1411         // Target type is some sort of Collection
1412         if (to.isCollection()) {
1413            try {
1414               var l = to.canCreateNewInstance(outer) ? (Collection)to.newInstance(outer) : to.isSet() ? set() : new JsonList(this);
1415               var elementType = to.getElementType();
1416
1417               if (from.isArray()) {
1418                  for (var i = 0; i < Array.getLength(value); i++) {
1419                     var o = Array.get(value, i);
1420                     l.add(elementType.isObject() ? o : convertToMemberType(l, o, elementType));
1421                  }
1422               } else if (from.isCollection())
1423                  ((Collection)value).forEach(x -> l.add(elementType.isObject() ? x : convertToMemberType(l, x, elementType)));
1424               else if (from.isMap())
1425                  l.add(elementType.isObject() ? value : convertToMemberType(l, value, elementType));
1426               else if (isNullOrEmpty(value))
1427                  return null;
1428               else if (from.isString()) {
1429                  var s = value.toString();
1430                  if (isProbablyJsonArray(s, false)) {
1431                     var l2 = JsonList.ofJson(s);
1432                     l2.setBeanSession(this);
1433                     l2.forEach(x -> l.add(elementType.isObject() ? x : convertToMemberType(l, x, elementType)));
1434                  } else {
1435                     throw new InvalidDataConversionException(value.getClass(), to, null);
1436                  }
1437               } else
1438                  throw new InvalidDataConversionException(value.getClass(), to, null);
1439               return (T)l;
1440            } catch (InvalidDataConversionException e) {
1441               throw e;
1442            } catch (Exception e) {
1443               throw new InvalidDataConversionException(value.getClass(), to, e);
1444            }
1445         }
1446
1447         if (to.isEnum()) {
1448            return to.newInstanceFromString(outer, value.toString());
1449         }
1450
1451         if (to.isString()) {
1452            if (from.isByteArray()) {
1453               return (T)new String((byte[])value);
1454            } else if (from.isMapOrBean() || from.isCollectionOrArrayOrOptional()) {
1455               var ws = ctx.getBeanToStringSerializer();
1456               if (nn(ws))
1457                  return (T)ws.serialize(value);
1458            } else if (from.is(Class.class)) {
1459               return (T)((Class<?>)value).getName();
1460            }
1461            return (T)value.toString();
1462         }
1463
1464         if (to.isCharSequence()) {
1465            var c = value.getClass();
1466            if (c.isArray()) {
1467               if (c.getComponentType().isPrimitive()) {
1468                  var l = new JsonList(this);
1469                  var size = Array.getLength(value);
1470                  for (var i = 0; i < size; i++)
1471                     l.add(Array.get(value, i));
1472                  value = l;
1473               }
1474               value = new JsonList((Object[])value).setBeanSession(this);
1475            }
1476
1477            return to.newInstanceFromString(outer, value.toString());
1478         }
1479
1480         if (to.isBoolean()) {
1481            if (from.isNumber())
1482               return (T)(Boolean.valueOf(((Number)value).intValue() != 0));
1483            if (isNullOrEmpty(value))
1484               return null;
1485            if (! hasMutater(from, to))
1486               return (T)Boolean.valueOf(value.toString());
1487         }
1488
1489         // It's a bean being initialized with a Map
1490         if (to.isBean() && value instanceof Map value2) {
1491            var builder = (BuilderSwap<T,Object>)to.getBuilderSwap(this);
1492
1493            if (value2 instanceof JsonMap m2 && builder == null) {
1494               var typeName = m2.getString(getBeanTypePropertyName(to));
1495               if (nn(typeName)) {
1496                  var cm = to.getBeanRegistry().getClassMeta(typeName);
1497                  if (nn(cm) && to.isParentOf(cm.inner()))
1498                     return (T)m2.cast(cm);
1499               }
1500            }
1501            if (nn(builder)) {
1502               var m = toBeanMap(builder.create(this, to));
1503               m.load(value2);
1504               return builder.build(this, m.getBean(), to);
1505            }
1506            return newBeanMap(tc).load(value2).getBean();
1507         }
1508
1509         if (to.isInputStream()) {
1510            if (from.isByteArray()) {
1511               var b = (byte[])value;
1512               return (T)new ByteArrayInputStream(b, 0, b.length);
1513            }
1514            var b = value.toString().getBytes();
1515            return (T)new ByteArrayInputStream(b, 0, b.length);
1516         }
1517
1518         if (to.isReader()) {
1519            if (from.isByteArray()) {
1520               var b = (byte[])value;
1521               return (T)new StringReader(new String(b));
1522            }
1523            return (T)new StringReader(value.toString());
1524         }
1525
1526         if (to.isCalendar()) {
1527            if (from.isCalendar()) {
1528               var c = (Calendar)value;
1529               if (value instanceof GregorianCalendar) {
1530                  var c2 = new GregorianCalendar(c.getTimeZone());
1531                  c2.setTime(c.getTime());
1532                  return (T)c2;
1533               }
1534            }
1535            if (from.isDate()) {
1536               var d = (Date)value;
1537               if (value instanceof GregorianCalendar) {
1538                  var c2 = new GregorianCalendar(TimeZone.getDefault());
1539                  c2.setTime(d);
1540                  return (T)c2;
1541               }
1542            }
1543            return (T)GregorianCalendar.from(GranularZonedDateTime.of(value.toString()).getZonedDateTime());
1544         }
1545
1546         if (to.isDate() && to.inner() == Date.class) {
1547            if (from.isCalendar())
1548               return (T)((Calendar)value).getTime();
1549            return (T)GregorianCalendar.from(GranularZonedDateTime.of(value.toString()).getZonedDateTime()).getTime();
1550         }
1551
1552         if (to.hasMutaterFrom(from))
1553            return to.mutateFrom(value);
1554
1555         if (from.hasMutaterTo(to))
1556            return from.mutateTo(value, to);
1557
1558         if (to.isBean())
1559            return newBeanMap(to.inner()).load(value.toString()).getBean();
1560
1561         if (to.canCreateNewInstanceFromString(outer))
1562            return to.newInstanceFromString(outer, value.toString());
1563
1564      } catch (Exception e) {
1565         throw new InvalidDataConversionException(value, to, e);
1566      }
1567
1568      throw new InvalidDataConversionException(value, to, null);
1569   }
1570
1571   /**
1572    * Given an array of {@link Type} objects, returns a {@link ClassMeta} representing those arguments.
1573    *
1574    * <p>
1575    * Constructs a new meta on each call.
1576    *
1577    * @param classes The array of classes to get class metas for.
1578    * @return The args {@link ClassMeta} object corresponding to the classes.  Never <jk>null</jk>.
1579    */
1580   protected final ClassMeta<Object[]> getArgsClassMeta(Type[] classes) {
1581      assertArgNotNull("classes", classes);
1582      return new ClassMeta(Arrays.stream(classes).map(x -> getClassMeta(x)).toList());
1583   }
1584
1585   /**
1586    * Shortcut for calling {@code getClassMeta(o.getClass())} but returns a default value if object is <jk>null</jk>.
1587    *
1588    * @param o The class to find the class type for.
1589    * @param def The default {@link ClassMeta} if the object is null.
1590    * @return The ClassMeta object, or the default value if {@code o} is <jk>null</jk>.
1591    */
1592   protected final ClassMeta<?> getClassMetaForObject(Object o, ClassMeta<?> def) {
1593      if (o == null)
1594         return def;
1595      return getClassMeta(o.getClass());
1596   }
1597
1598   /**
1599    * Creates either an {@link JsonMap} or {@link LinkedHashMap} depending on whether the key type is
1600    * String or something else.
1601    *
1602    * @param mapMeta The metadata of the map to create.
1603    * @return A new map.
1604    */
1605   protected Map newGenericMap(ClassMeta mapMeta) {
1606      var k = mapMeta.getKeyType();
1607      return (k == null || k.isString()) ? new JsonMap(this) : map();
1608   }
1609
1610   @Override /* Overridden from ContextSession */
1611   protected FluentMap<String,Object> properties() {
1612      return super.properties()
1613         .a("locale", locale)
1614         .a("mediaType", mediaType)
1615         .a("timeZone", timeZone);
1616   }
1617
1618   /**
1619    * Converts the contents of the specified list into an array.
1620    *
1621    * <p>
1622    * Works on both object and primitive arrays.
1623    *
1624    * <p>
1625    * In the case of multi-dimensional arrays, the incoming list must contain elements of type n-1 dimension.
1626    * i.e. if {@code type} is <code><jk>int</jk>[][]</code> then {@code list} must have entries of type
1627    * <code><jk>int</jk>[]</code>.
1628    *
1629    * @param type The type to convert to.  Must be an array type.
1630    * @param list The contents to populate the array with.
1631    * @return A new object or primitive array.
1632    */
1633   protected final Object toArray(ClassMeta<?> type, Collection<?> list) {
1634      if (list == null)
1635         return null;
1636      var componentType = type.isArgs() ? object() : type.getElementType();
1637      var array = Array.newInstance(componentType.inner(), list.size());
1638      var i = IntegerValue.create();
1639      list.forEach(x -> {
1640         var x2 = x;
1641         if (! type.isInstance(x)) {
1642            if (componentType.isArray() && x instanceof Collection<?> c)
1643               x2 = toArray(componentType, c);
1644            else if (x == null && componentType.isPrimitive())
1645               x2 = componentType.getPrimitiveDefault();
1646            else
1647               x2 = convertToType(x, componentType);
1648         }
1649         Array.set(array, i.getAndIncrement(), x2);
1650      });
1651      return array;
1652   }
1653}