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.utils.ClassUtils.*;
020import static org.apache.juneau.commons.utils.CollectionUtils.*;
021import static org.apache.juneau.commons.utils.Shorts.*;
022
023import java.io.*;
024import java.lang.reflect.*;
025import java.time.*;
026import java.util.*;
027import java.util.logging.*;
028
029import org.apache.juneau.commons.bean.*;
030import org.apache.juneau.commons.collections.*;
031import org.apache.juneau.commons.conversion.*;
032import org.apache.juneau.commons.http.*;
033import org.apache.juneau.commons.lang.*;
034import org.apache.juneau.commons.reflect.*;
035import org.apache.juneau.marshall.collections.*;
036import org.apache.juneau.marshall.json.*;
037import org.apache.juneau.marshall.json5.*;
038import org.apache.juneau.marshall.parser.*;
039import org.apache.juneau.marshall.swap.spi.*;
040
041/**
042 * Session object that lives for the duration of a single use of {@link MarshallingContext}.
043 *
044 * <ul class='spaced-list'>
045 *    <li class='info'>Typically session objects are not thread safe nor reusable.  However, bean sessions do not maintain any state and
046 *       thus can be safely cached and reused.
047 * </ul>
048 *
049 */
050@SuppressWarnings({
051   "java:S1192", // Duplicated literals (argument/property names) read more clearly inline than as constants
052   "java:S1452", // Wildcard required - ClassMeta<?>, ObjectSwap<?,?>, etc. for bean metadata
053   "rawtypes", // Raw types necessary for generic type handling
054   "unchecked" // Type erasure requires unchecked casts
055})
056public class MarshallingSession extends ContextSession implements ConverterSession, BeanSession {
057
058   /**
059    * Builder class.
060    */
061   @SuppressWarnings({
062      "java:S119" // 'SELF' (CRTP self-type) is intentional and clearer than a single-letter name.
063   })
064   public abstract static class Builder<SELF extends Builder<SELF>> extends ContextSession.Builder<SELF> {
065
066      private final MarshallingContext ctx;
067      private Locale locale;
068      private MediaType mediaType;
069      private TimeZone timeZone;
070      private String activeView;
071
072      /**
073       * Constructor
074       *
075       * @param ctx The context creating this session.
076       *    <br>Cannot be <jk>null</jk>.
077       */
078      protected Builder(MarshallingContext ctx) {
079         super(reqnn("ctx", ctx));
080         this.ctx = ctx;
081         mediaType = ctx.getMediaType();
082         timeZone = ctx.getTimeZone();
083         activeView = ctx.getActiveView();
084      }
085
086      /**
087       * Build the object.
088       *
089       * @return The built object.
090       */
091      @Override
092      public MarshallingSession build() {
093         return new MarshallingSession(this);
094      }
095
096      /**
097       * The session locale.
098       *
099       * <p>
100       * Specifies the default locale for serializer and parser sessions.
101       *
102       * <p>
103       * If not specified, defaults to {@link MarshallingContext.Builder#locale(Locale)}.
104       *
105       * <h5 class='section'>See Also:</h5><ul>
106       *    <li class='ja'>{@link MarshalledConfig#locale()}
107       *    <li class='jm'>{@link MarshallingContext.Builder#locale(Locale)}
108       * </ul>
109       *
110       * @param value
111       *    The new value for this property.
112       *    <br>If <jk>null</jk> defaults to {@link MarshallingContext#getLocale()}
113       * @return This object.
114       */
115      public SELF locale(Locale value) {
116         locale = value;
117         return self();
118      }
119
120      /**
121       * The session media type.
122       *
123       * <p>
124       * Specifies the default media type value for serializer and parser sessions.
125       *
126       * <p>
127       * If not specified, defaults to {@link MarshallingContext.Builder#mediaType(MediaType)}.
128       *
129       * <h5 class='section'>See Also:</h5><ul>
130       *    <li class='ja'>{@link MarshalledConfig#mediaType()}
131       *    <li class='jm'>{@link MarshallingContext.Builder#mediaType(MediaType)}
132       * </ul>
133       *
134       * @param value
135       *    The new value for this property.
136       *    <br>If <jk>null</jk> defaults to {@link MarshallingContext#getMediaType()}.
137       * @return This object.
138       */
139      public SELF mediaType(MediaType value) {
140         mediaType = value;
141         return self();
142      }
143
144      /**
145       * Same as {@link #mediaType(MediaType)} but doesn't overwrite the value if it is already set.
146       *
147       * @param value
148       *    The new value for this property.
149       *    <br>If <jk>null</jk>, then the media type defined on the context is used.
150       * @return This object.
151       */
152      public SELF mediaTypeDefault(MediaType value) {
153         if (mediaType == null)
154            mediaType = value;
155         return self();
156      }
157
158      /**
159       * Overrides the active view for this session.
160       *
161       * <p>
162       * When set, only bean properties whose declared {@link MarshalledProp#view()} set contains this view name
163       * will be included during serialization.  On the parse side, out-of-view properties are routed through
164       * the existing unknown/ignored-property mechanism.
165       *
166       * <p>
167       * This is a per-call override.  If not set, the value from
168       * {@link MarshallingContext.Builder#activeView(String)} is used.
169       *
170       * <h5 class='section'>See Also:</h5><ul>
171       *    <li class='ja'>{@link MarshalledProp#view()}
172       *    <li class='jm'>{@link MarshallingContext.Builder#activeView(String)}
173       * </ul>
174       *
175       * @param value The active view name.  Use <jk>null</jk> to disable view filtering for this call.
176       * @return This object.
177       * @since 10.0.0
178       */
179      public SELF activeView(String value) {
180         activeView = value;
181         return self();
182      }
183
184      @Override /* Overridden from Builder */
185      public SELF property(String key, Object value) {
186         if (key == null) {
187            super.property(key, value);  // delegates null-key validation to base class
188            return self();
189         }
190         switch (key) {
191            case "locale", "MarshallingSession.locale":
192               return locale(cvt(value, Locale.class));
193            case "mediaType", "MarshallingSession.mediaType":
194               return mediaType(cvt(value, MediaType.class));
195            case "timeZone", "MarshallingSession.timeZone":
196               return timeZone(cvt(value, TimeZone.class));
197            case "activeView", "MarshallingSession.activeView":
198               return activeView(cvt(value, String.class));
199            default:
200               super.property(key, value);
201               return self();
202         }
203      }
204
205      /**
206       * The session timezone.
207       *
208       * <p>
209       * Specifies the default timezone for serializer and parser sessions.
210       *
211       * <p>
212       * If not specified, defaults to {@link MarshallingContext.Builder#timeZone(TimeZone)}.
213       *
214       * <h5 class='section'>See Also:</h5><ul>
215       *    <li class='ja'>{@link MarshalledConfig#timeZone()}
216       *    <li class='jm'>{@link MarshallingContext.Builder#timeZone(TimeZone)}
217       * </ul>
218       *
219       * @param value
220       *    The new value for this property.
221       *    <br>If <jk>null</jk> defaults to {@link MarshallingContext#getTimeZone()}.
222       * @return This object.
223       */
224      public SELF timeZone(TimeZone value) {
225         timeZone = value;
226         return self();
227      }
228
229      /**
230       * Same as {@link #timeZone(TimeZone)} but doesn't overwrite the value if it is already set.
231       *
232       * @param value
233       *    The new value for this property.
234       *    <br>If <jk>null</jk>, then the time zone defined on the context is used.
235       * @return This object.
236       */
237      public SELF timeZoneDefault(TimeZone value) {
238         if (timeZone == null)
239            timeZone = value;
240         return self();
241      }
242
243   }
244
245   /**
246    * Concrete default builder leaf for the non-subclassed {@code create()} path (CRTP terminal).
247    */
248   public static final class DefaultBuilder extends Builder<DefaultBuilder> {
249
250      DefaultBuilder(MarshallingContext ctx) {
251         super(ctx);
252      }
253   }
254
255   private static final Logger LOG = Logger.getLogger(cn(MarshallingSession.class));
256
257   /**
258    * Creates a builder of this object.
259    *
260    * @param ctx The context creating this builder.
261    *    <br>Cannot be <jk>null</jk>.
262    * @return A new builder.
263    */
264   public static Builder<?> create(MarshallingContext ctx) {
265      return new DefaultBuilder(reqnn("ctx", ctx));
266   }
267
268   /**
269    * The name property name.
270    *
271    * <p>
272    * Currently this always returns <js>"_name"</js>.
273    */
274   public static final String NAME_PROPERTY_NAME = "_name";
275
276   private final MarshallingContext ctx;
277   private final Locale locale;
278   private final MediaType mediaType;
279   private final TimeZone timeZone;
280   private final String activeView;
281
282   /**
283    * Constructor.
284    *
285    * @param builder The builder for this object.  Cannot be <jk>null</jk>.
286    */
287   protected MarshallingSession(Builder<?> builder) {
288      super(builder);
289      ctx = builder.ctx;
290      locale = o(builder.locale).orElse(ctx.getLocale());
291      mediaType = o(builder.mediaType).orElse(builder.mediaType);
292      timeZone = o(builder.timeZone).orElse(builder.timeZone);
293      activeView = builder.activeView;
294   }
295
296   @Override /* ConverterSession */
297   public <T> Optional<T> get(Class<T> c) {
298      if (c == TimeZone.class) return o(c.cast(timeZone));
299      if (c == Locale.class) return o(c.cast(locale));
300      if (c == MediaType.class) return o(c.cast(mediaType));
301      return oe();
302   }
303
304   /**
305    * Logs a warning message.
306    *
307    * @param msg The warning message.
308    * @param args Optional {@link String#format(String, Object...) String.format}-style arguments.
309    */
310   @Override
311   public void addWarning(String msg, Object...args) {
312      if (isDebug())
313         LOG.log(Level.WARNING, () -> args.length == 0 ? msg : f(msg, args));
314      super.addWarning(msg, args);
315   }
316
317   /**
318    * Same as {@link #convertToType(Object, Class)}, except used for instantiating inner member classes that must
319    * be instantiated within another class instance.
320    *
321    * @param <T> The class type to convert the value to.
322    * @param outer
323    *    If class is a member class, this is the instance of the containing class.
324    *    Should be <jk>null</jk> if not a member class.
325    * @param value The value to convert.
326    * @param type The class type to convert the value to.
327    * @throws InvalidDataConversionException If the specified value cannot be converted to the specified type.
328    * @return The converted value.
329    */
330   public final <T> T convertToMemberType(Object outer, Object value, Class<T> type) throws InvalidDataConversionException {
331      return convertToMemberType(outer, value, getClassMeta(type));
332   }
333
334   /**
335    * Converts the specified value to the specified class type.
336    *
337    * <p>
338    * See {@link #convertToType(Object, ClassMeta)} for the list of valid conversions.
339    *
340    * @param <T> The class type to convert the value to.
341    * @param value The value to convert.  Can be <jk>null</jk> (returns <jk>null</jk>).
342    * @param type The class type to convert the value to.
343    * @throws InvalidDataConversionException If the specified value cannot be converted to the specified type.
344    * @return The converted value.
345    */
346   public final <T> T convertToType(Object value, Class<T> type) throws InvalidDataConversionException {
347      // Shortcut for most common case.
348      if (nn(value) && value.getClass() == type)
349         return (T)value;
350      return convertToMemberType(null, value, getClassMeta(type));
351   }
352
353   /**
354    * Casts the specified value into the specified type.
355    *
356    * <p>
357    * If the value isn't an instance of the specified type, then converts the value if possible.
358    *
359    * <p>
360    * The following conversions are valid:
361    * <table class='styled'>
362    *    <tr><th>Convert to type</th><th>Valid input value types</th><th>Notes</th></tr>
363    *    <tr>
364    *       <td>
365    *          A class that is the normal type of a registered {@link ObjectSwap}.
366    *       </td>
367    *       <td>
368    *          A value whose class matches the transformed type of that registered {@link ObjectSwap}.
369    *       </td>
370    *       <td>&nbsp;</td>
371    *    </tr>
372    *    <tr>
373    *       <td>
374    *          A class that is the transformed type of a registered {@link ObjectSwap}.
375    *       </td>
376    *       <td>
377    *          A value whose class matches the normal type of that registered {@link ObjectSwap}.
378    *       </td>
379    *       <td>&nbsp;</td>
380    *    </tr>
381    *    <tr>
382    *       <td>
383    *          {@code Number} (e.g. {@code Integer}, {@code Short}, {@code Float},...)
384    *          <br><code>Number.<jsf>TYPE</jsf></code> (e.g. <code>Integer.<jsf>TYPE</jsf></code>,
385    *          <code>Short.<jsf>TYPE</jsf></code>, <code>Float.<jsf>TYPE</jsf></code>,...)
386    *       </td>
387    *       <td>
388    *          {@code Number}, {@code String}, <jk>null</jk>
389    *       </td>
390    *       <td>
391    *          For primitive {@code TYPES}, <jk>null</jk> returns the JVM default value for that type.
392    *       </td>
393    *    </tr>
394    *    <tr>
395    *       <td>
396    *          {@code Map} (e.g. {@code Map}, {@code HashMap}, {@code TreeMap}, {@code JsonMap})
397    *       </td>
398    *       <td>
399    *          {@code Map}
400    *       </td>
401    *       <td>
402    *          If {@code Map} is not constructible, an {@code JsonMap} is created.
403    *       </td>
404    *    </tr>
405    *    <tr>
406    *       <td>
407    *       {@code Collection} (e.g. {@code List}, {@code LinkedList}, {@code HashSet}, {@code JsonList})
408    *       </td>
409    *       <td>
410    *          {@code Collection<Object>}
411    *          <br>{@code Object[]}
412    *       </td>
413    *       <td>
414    *          If {@code Collection} is not constructible, an {@code JsonList} is created.
415    *       </td>
416    *    </tr>
417    *    <tr>
418    *       <td>
419    *          {@code X[]} (array of any type X)
420    *       </td>
421    *       <td>
422    *          {@code List<X>}
423    *       </td>
424    *       <td>&nbsp;</td>
425    *    </tr>
426    *    <tr>
427    *       <td>
428    *          {@code X[][]} (multi-dimensional arrays)
429    *       </td>
430    *       <td>
431    *          {@code List<List<X>>}
432    *          <br>{@code List<X[]>}
433    *          <br>{@code List[]<X>}
434    *       </td>
435    *       <td>&nbsp;</td>
436    *    </tr>
437    *    <tr>
438    *       <td>
439    *          {@code Enum}
440    *       </td>
441    *       <td>
442    *          {@code String}
443    *       </td>
444    *       <td>&nbsp;</td>
445    *    </tr>
446    *    <tr>
447    *       <td>
448    *          Bean
449    *       </td>
450    *       <td>
451    *          {@code Map}
452    *       </td>
453    *       <td>&nbsp;</td>
454    *    </tr>
455    *    <tr>
456    *       <td>
457    *          {@code String}
458    *       </td>
459    *       <td>
460    *          Anything
461    *       </td>
462    *       <td>
463    *          Arrays are converted to JSON arrays
464    *       </td>
465    *    </tr>
466    *    <tr>
467    *       <td>
468    *          Anything with one of the following methods:
469    *          <br><code><jk>public static</jk> T fromString(String)</code>
470    *          <br><code><jk>public static</jk> T valueOf(String)</code>
471    *          <br><code><jk>public</jk> T(String)</code>
472    *       </td>
473    *       <td>
474    *          <c>String</c>
475    *       </td>
476    *       <td>
477    *          <br>
478    *       </td>
479    *    </tr>
480    * </table>
481    *
482    * @param <T> The class type to convert the value to.
483    * @param value The value to be converted.  Can be <jk>null</jk> (returns <jk>null</jk>).
484    * @param type The target object type.  Can be <jk>null</jk> (treated as the {@code Object} type).
485    * @return The converted type.
486    * @throws InvalidDataConversionException If the specified value cannot be converted to the specified type.
487    */
488   public final <T> T convertToType(Object value, ClassMeta<T> type) throws InvalidDataConversionException {
489      return convertToMemberType(null, value, type);
490   }
491
492   /**
493    * Same as {@link #convertToType(Object, Class)}, but allows for complex data types consisting of collections or maps.
494    *
495    * @param <T> The class type to convert the value to.
496    * @param value The value to be converted.
497    * @param type The target object type.
498    * @param args The target object parameter types.
499    * @return The converted type.
500    * @throws InvalidDataConversionException If the specified value cannot be converted to the specified type.
501    */
502   public final <T> T convertToType(Object value, Type type, Type...args) throws InvalidDataConversionException {
503      return (T)convertToMemberType(null, value, getClassMeta(type, args));
504   }
505
506   /**
507    * Returns the annotation provider for this session.
508    *
509    * @return The annotation provider for this session.
510    */
511   public AnnotationProvider getAnnotationProvider() {
512      return ctx.getAnnotationProvider();
513   }
514
515   /**
516    * Returns the {@link MarshallingContext} backing this session.
517    *
518    * @return The marshalling context.
519    */
520   public final MarshallingContext getMarshallingContext() {
521      return ctx;
522   }
523
524   /**
525    * Minimum bean class visibility.
526    *
527    * @see MarshallingContext.Builder#beanClassVisibility(Visibility)
528    * @return
529    *    Classes are not considered beans unless they meet the minimum visibility requirements.
530    */
531   public final Visibility getBeanClassVisibility() { return ctx.getBeanClassVisibility(); }
532
533   /**
534    * Minimum bean constructor visibility.
535    *
536    * @see MarshallingContext.Builder#beanConstructorVisibility(Visibility)
537    * @return
538    *    Only look for constructors with this specified minimum visibility.
539    */
540   public final Visibility getBeanConstructorVisibility() { return ctx.getBeanConstructorVisibility(); }
541
542   /**
543    * Bean dictionary.
544    *
545    * @see MarshallingContext.Builder#beanDictionary(ClassInfo...)
546    * @return
547    *    The list of classes that make up the bean dictionary in this bean context.
548    *    <br>Never <jk>null</jk>.
549    *    <br>List is unmodifiable.
550    */
551   public final List<ClassInfo> getBeanDictionary() { return ctx.getBeanDictionary(); }
552
553   /**
554    * Minimum bean field visibility.
555    *
556    *
557    * @see MarshallingContext.Builder#beanFieldVisibility(Visibility)
558    * @return
559    *    Only look for bean fields with this specified minimum visibility.
560    */
561   public final Visibility getBeanFieldVisibility() { return ctx.getBeanFieldVisibility(); }
562
563   /**
564    * Returns the {@link BeanMeta} class for the specified class.
565    *
566    * @param <T> The class type to get the meta-data on.
567    * @param c The class to get the meta-data on.  Can be <jk>null</jk> (returns <jk>null</jk>).
568    * @return
569    *    The {@link BeanMeta} for the specified class, or <jk>null</jk> if the class
570    *    is not a bean per the settings on this context.
571    */
572   public final <T> BeanMeta<T> getBeanMeta(Class<T> c) {
573      if (c == null)
574         return null;
575      return getClassMeta(c).getBeanMeta();
576   }
577
578   /**
579    * Minimum bean method visibility.
580    *
581    * @see MarshallingContext.Builder#beanMethodVisibility(Visibility)
582    * @return
583    *    Only look for bean methods with this specified minimum visibility.
584    */
585   public final Visibility getBeanMethodVisibility() { return ctx.getBeanMethodVisibility(); }
586
587   /**
588    * Returns the bean registry defined in this bean context defined by {@link MarshallingContext.Builder#beanDictionary(ClassInfo...)}.
589    *
590    * @return The bean registry defined in this bean context.  Never <jk>null</jk>.
591    */
592   public final BeanRegistry getBeanRegistry() { return ctx.getBeanRegistry(); }
593
594   /**
595    * Bean type property name.
596    *
597    * @see MarshallingContext.Builder#typePropertyName(String)
598    * @return
599    *    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.
600    */
601   public final String getBeanTypePropertyName() { return ctx.getBeanTypePropertyName(); }
602
603   /**
604    * Returns the type property name as defined by {@link MarshallingContext.Builder#typePropertyName(String)}.
605    *
606    * @param cm
607    *    The class meta of the type we're trying to resolve the type name for.
608    *    Can be <jk>null</jk> (falls back to the session-wide {@link MarshallingContext.Builder#typePropertyName(String) typePropertyName}).
609    * @return The type property name.  Never <jk>null</jk>.
610    */
611   public final String getBeanTypePropertyName(ClassMeta cm) {
612      if (cm == null)
613         return getBeanTypePropertyName();
614      var beanMeta = cm.getBeanMeta();
615      if (beanMeta == null)
616         return getBeanTypePropertyName();
617      var s = beanMeta.getTypePropertyName();
618      return s == null ? getBeanTypePropertyName() : s;
619   }
620
621   /**
622    * Returns a {@code ClassMeta} wrapper around a {@link Class} object.
623    *
624    * @param <T> The class type being wrapped.
625    * @param c The class being wrapped.
626    * @return The class meta object containing information about the class.
627    */
628   public final <T> ClassMeta<T> getClassMeta(Class<T> c) {
629      return ctx.getClassMeta(c);
630   }
631
632   /**
633    * Used to resolve <c>ClassMetas</c> of type <c>Collection</c> and <c>Map</c> that have
634    * <c>ClassMeta</c> values that themselves could be collections or maps.
635    *
636    * <p>
637    * <c>Collection</c> meta objects are assumed to be followed by zero or one meta objects indicating the
638    * element type.
639    *
640    * <p>
641    * <c>Map</c> meta objects are assumed to be followed by zero or two meta objects indicating the key and value
642    * types.
643    *
644    * <p>
645    * The array can be arbitrarily long to indicate arbitrarily complex data structures.
646    *
647    * <h5 class='section'>Examples:</h5>
648    * <ul>
649    *    <li><code>getClassMeta(String.<jk>class</jk>);</code> - A normal type.
650    *    <li><code>getClassMeta(List.<jk>class</jk>);</code> - A list containing objects.
651    *    <li><code>getClassMeta(List.<jk>class</jk>, String.<jk>class</jk>);</code> - A list containing strings.
652    *    <li><code>getClassMeta(LinkedList.<jk>class</jk>, String.<jk>class</jk>);</code> - A linked-list containing
653    *       strings.
654    *    <li><code>getClassMeta(LinkedList.<jk>class</jk>, LinkedList.<jk>class</jk>, String.<jk>class</jk>);</code> -
655    *       A linked-list containing linked-lists of strings.
656    *    <li><code>getClassMeta(Map.<jk>class</jk>);</code> - A map containing object keys/values.
657    *    <li><code>getClassMeta(Map.<jk>class</jk>, String.<jk>class</jk>, String.<jk>class</jk>);</code> - A map
658    *       containing string keys/values.
659    *    <li><code>getClassMeta(Map.<jk>class</jk>, String.<jk>class</jk>, List.<jk>class</jk>, MyBean.<jk>class</jk>);</code> -
660    *       A map containing string keys and values of lists containing beans.
661    * </ul>
662    *
663    * @param <T>
664    *    The class to resolve.
665    * @param type
666    *    The class to resolve.
667    *    <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
668    * @param args
669    *    The type arguments of the class if it's a collection or map.
670    *    <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
671    *    <br>Ignored if the main type is not a map or collection.
672    * @return The class meta.
673    */
674   public final <T> ClassMeta<T> getClassMeta(Type type, Type...args) {
675      return ctx.getClassMeta(type, args);
676   }
677
678   /**
679    * Returns the {@link ClassMeta} for the object's class, unwrapping recognized proxies first.
680    *
681    * <p>
682    * Delegates to {@link #getClassMetaForObject(Object,ClassMeta)} with a <jk>null</jk> default.
683    *
684    * @param <T> The class of the object being passed in.
685    * @param o The class to find the class type for.  Can be <jk>null</jk> (returns <jk>null</jk>).
686    * @return The ClassMeta object, or <jk>null</jk> if {@code o} is <jk>null</jk>.
687    */
688   public final <T> ClassMeta<T> getClassMetaForObject(T o) {
689      return (ClassMeta<T>)getClassMetaForObject(o, null);
690   }
691
692   /**
693    * Locale.
694    *
695    * <p>
696    * The locale is determined in the following order:
697    * <ol>
698    *    <li><c>locale</c> parameter passed in through constructor.
699    *    <li>{@link MarshallingContext.Builder#locale(Locale)} setting on bean context.
700    *    <li>Locale returned by {@link Locale#getDefault()}.
701    * </ol>
702    *
703    * @see MarshallingContext.Builder#locale(Locale)
704    * @return The session locale.
705    */
706   public Locale getLocale() { return locale; }
707
708   /**
709    * Active view.
710    *
711    * <p>
712    * Returns the active view name for this session.  When non-<jk>null</jk>, only bean properties whose
713    * declared {@link MarshalledProp#view()} set contains this name are included during serialization, and
714    * out-of-view properties encountered during parsing are treated as unknown.
715    *
716    * <p>
717    * This is the per-call override value, which defaults to {@link MarshallingContext#getActiveView()}.
718    *
719    * @see MarshallingContext.Builder#activeView(String)
720    * @see MarshallingSession.Builder#activeView(String)
721    * @return The active view for this session, or <jk>null</jk> if view filtering is not active.
722    * @since 10.0.0
723    */
724   public final String getActiveView() { return activeView; }
725
726   @Override /* BeanSession */
727   public boolean isPropertyInActiveView(BeanPropertyMeta pMeta) {
728      if (activeView == null)
729         return true;
730      var views = pMeta.getViews();
731      if (ie(views))
732         return ctx.isDefaultViewInclusion();
733      return views.contains(activeView);
734   }
735
736   /**
737    * Media type.
738    *
739    * <p>
740    * For example, <js>"application/json"</js>.
741    *
742    * @see MarshallingContext.Builder#mediaType(MediaType)
743    * @return The media type for this session, or <jk>null</jk> if not specified.
744    */
745   public final MediaType getMediaType() { return mediaType; }
746
747   /**
748    * Bean class exclusions.
749    *
750    * @see MarshallingContext.Builder#notBeanClasses(ClassInfo...)
751    * @return
752    *    The list of classes that are explicitly not beans.
753    *    <br>Never <jk>null</jk>.
754    *    <br>List is unmodifiable.
755    */
756   public final List<ClassInfo> getNotBeanClasses() { return ctx.getNotBeanClasses(); }
757
758   /**
759    * Bean package exclusions.
760    *
761    * @see MarshallingContext.Builder#notBeanPackages(String...)
762    * @return
763    *    The set of fully-qualified package names to exclude from being classified as beans.
764    *    <br>Never <jk>null</jk>.
765    *    <br>Set is unmodifiable.
766    */
767   public final Set<String> getNotBeanPackagesNames() { return ctx.getNotBeanPackagesNames(); }
768
769   /**
770    * Bean property namer.
771    *
772    * @see MarshallingContext.Builder#propertyNamer(Class)
773    * @return
774    *    The interface used to calculate bean property names.
775    */
776   public final PropertyNamer getPropertyNamer() { return ctx.getPropertyNamer(); }
777
778   /**
779    * Session classloader.
780    *
781    * <p>
782    * Returns the classloader explicitly configured via {@link MarshallingContext.Builder#classLoader(ClassLoader)},
783    * or <jk>null</jk> if none was set (callers should fall back to the thread-context classloader).
784    *
785    * @return The session classloader, or <jk>null</jk> if not set.
786    */
787   public final ClassLoader getClassLoader() { return ctx.getClassLoader(); }
788
789   /**
790    * Java object swaps.
791    *
792    * @see MarshallingContext.Builder#swaps(Class...)
793    * @return
794    *    The list POJO swaps defined.
795    *    <br>Never <jk>null</jk>.
796    *    <br>List is unmodifiable.
797    */
798   public final List<ObjectSwap<?,?>> getSwaps() { return ctx.getSwaps(); }
799
800   /**
801    * Time zone.
802    *
803    * <p>
804    * The timezone is determined in the following order:
805    * <ol>
806    *    <li><c>timeZone</c> parameter passed in through constructor.
807    *    <li>{@link MarshallingContext.Builder#timeZone(TimeZone)} setting on bean context.
808    * </ol>
809    *
810    * @see MarshallingContext.Builder#timeZone(TimeZone)
811    * @return The session timezone, or <jk>null</jk> if timezone not specified.
812    */
813   public final TimeZone getTimeZone() { return timeZone; }
814
815   /**
816    * Time zone.
817    *
818    * <p>
819    * The timezone is determined in the following order:
820    * <ol>
821    *    <li><c>timeZone</c> parameter passed in through constructor.
822    *    <li>{@link MarshallingContext.Builder#timeZone(TimeZone)} setting on bean context.
823    * </ol>
824    *
825    * @see MarshallingContext.Builder#timeZone(TimeZone)
826    * @return The session timezone, or the system timezone if not specified.  Never <jk>null</jk>.
827    */
828   public final ZoneId getTimeZoneId() { return timeZone == null ? ZoneId.systemDefault() : timeZone.toZoneId(); }
829
830   /**
831    * Determines whether the specified class matches the requirements on this context of being a bean.
832    *
833    * @param c The class being tested.
834    * @return <jk>true</jk> if the specified class is considered a bean.
835    */
836   public final boolean isBean(Class<?> c) {
837      return nn(getBeanMeta(c));
838   }
839
840   /**
841    * Determines whether the specified object matches the requirements on this context of being a bean.
842    *
843    * @param o The object being tested.
844    * @return <jk>true</jk> if the specified object is considered a bean.
845    */
846   public final boolean isBean(Object o) {
847      if (o == null)
848         return false;
849      return isBean(o.getClass());
850   }
851
852   /**
853    * BeanMap.put() returns old property value.
854    *
855    * @see MarshallingContext.Builder#beanMapPutReturnsOldValue()
856    * @return
857    *    <jk>true</jk> if the {@link BeanMap#put(String,Object) BeanMap.put()} method will return old property values.
858    *    <br>Otherwise, it returns <jk>null</jk>.
859    */
860   public final boolean isBeanMapPutReturnsOldValue() { return ctx.isBeanMapPutReturnsOldValue(); }
861
862   /**
863    * Beans require no-arg constructors.
864    *
865    * @see MarshallingContext.Builder#beansRequireDefaultConstructor()
866    * @return
867    *    <jk>true</jk> if a Java class must implement a default no-arg constructor to be considered a bean.
868    *    <br>Otherwise, the bean will be serialized as a string using the {@link Object#toString()} method.
869    */
870   public final boolean isBeansRequireDefaultConstructor() { return ctx.isBeansRequireDefaultConstructor(); }
871
872   /**
873    * Beans require Serializable interface.
874    *
875    * @see MarshallingContext.Builder#beansRequireSerializable()
876    * @return
877    *    <jk>true</jk> if a Java class must implement the {@link Serializable} interface to be considered a bean.
878    *    <br>Otherwise, the bean will be serialized as a string using the {@link Object#toString()} method.
879    */
880   public final boolean isBeansRequireSerializable() { return ctx.isBeansRequireSerializable(); }
881
882   /**
883    * Beans require setters for getters.
884    *
885    * @see MarshallingContext.Builder#beansRequireSettersForGetters()
886    * @return
887    *    <jk>true</jk> if only getters that have equivalent setters will be considered as properties on a bean.
888    *    <br>Otherwise, they are ignored.
889    */
890   public final boolean isBeansRequireSettersForGetters() { return ctx.isBeansRequireSettersForGetters(); }
891
892   /**
893    * Beans require at least one property.
894    *
895    * @see MarshallingContext.Builder#disableBeansRequireSomeProperties()
896    * @return
897    *    <jk>true</jk> if a Java class doesn't need to contain at least 1 property to be considered a bean.
898    *    <br>Otherwise, the bean is serialized as a string using the {@link Object#toString()} method.
899    */
900   public final boolean isBeansRequireSomeProperties() { return ctx.isBeansRequireSomeProperties(); }
901
902   /**
903    * Find fluent setters.
904    *
905    * <h5 class='section'>Description:</h5>
906    * <p>
907    *
908    * @see MarshallingContext.Builder#findFluentSetters()
909    * @return
910    *    <jk>true</jk> if fluent setters are detected on beans.
911    */
912   public final boolean isFindFluentSetters() { return ctx.isFindFluentSetters(); }
913
914   /**
915    * Ignore invocation errors on getters.
916    *
917    * @see MarshallingContext.Builder#ignoreInvocationExceptionsOnGetters()
918    * @return
919    *    <jk>true</jk> if errors thrown when calling bean getter methods are silently ignored.
920    */
921   public final boolean isIgnoreInvocationExceptionsOnGetters() { return ctx.isIgnoreInvocationExceptionsOnGetters(); }
922
923   /**
924    * Ignore invocation errors on setters.
925    *
926    * @see MarshallingContext.Builder#ignoreInvocationExceptionsOnSetters()
927    * @return
928    *    <jk>true</jk> if errors thrown when calling bean setter methods are silently ignored.
929    */
930   public final boolean isIgnoreInvocationExceptionsOnSetters() { return ctx.isIgnoreInvocationExceptionsOnSetters(); }
931
932   /**
933    * Silently ignore missing setters.
934    *
935    * @see MarshallingContext.Builder#disableIgnoreMissingSetters()
936    * @return
937    *    <jk>true</jk> if trying to set a value on a bean property without a setter should throw a {@link BeanRuntimeException}.
938    */
939   public final boolean isIgnoreMissingSetters() { return ctx.isIgnoreMissingSetters(); }
940
941   /**
942    * Ignore unknown properties.
943    *
944    * @see MarshallingContext.Builder#ignoreUnknownBeanProperties()
945    * @return
946    *    <jk>true</jk> if trying to set a value on a non-existent bean property is silently ignored.
947    *    <br>Otherwise, a {@code RuntimeException} is thrown.
948    */
949   public final boolean isIgnoreUnknownBeanProperties() { return ctx.isIgnoreUnknownBeanProperties(); }
950
951   /**
952    * Schema validation mode.
953    *
954    * @see MarshallingContext.Builder#validateSchema()
955    * @return
956    *    <jk>true</jk> if bean property values should be validated against their {@code @Schema}-declared constraints
957    *    during parsing and serialization.
958    * @since 10.0.0
959    */
960   public final boolean isValidateSchema() { return ctx.isValidateSchema(); }
961
962   /**
963    * Ignore unknown properties with null values.
964    *
965    * @see MarshallingContext.Builder#disableIgnoreUnknownNullBeanProperties()
966    * @return
967    *    <jk>true</jk> if trying to set a <jk>null</jk> value on a non-existent bean property should not throw a {@link BeanRuntimeException}.
968    */
969   public final boolean isIgnoreUnknownNullBeanProperties() { return ctx.isIgnoreUnknownNullBeanProperties(); }
970
971   /**
972    * Unsorted properties.
973    *
974    * @see MarshallingContext.Builder#unsortedProperties()
975    * @return
976    *    <jk>true</jk> if bean properties are serialized in declaration order instead of alphabetically.
977    */
978   public final boolean isUnsortedProperties() { return ctx.isUnsortedProperties(); }
979
980   /**
981    * Record component order.
982    *
983    * @see MarshallingContext.Builder#recordComponentOrder()
984    * @return <jk>true</jk> if {@link Record} bean properties use component order.
985    */
986   public final boolean isRecordComponentOrder() { return ctx.isRecordComponentOrder(); }
987
988   /**
989    * Use interface proxies.
990    *
991    * @see MarshallingContext.Builder#disableInterfaceProxies()
992    * @return
993    *    <jk>true</jk> if interfaces will be instantiated as proxy classes through the use of an
994    *    {@link InvocationHandler} if there is no other way of instantiating them.
995    */
996   public final boolean isUseInterfaceProxies() { return ctx.isUseInterfaceProxies(); }
997
998   /**
999    * Use Java Introspector.
1000    *
1001    * @see MarshallingContext.Builder#useJavaBeanIntrospector()
1002    * @return
1003    *    <jk>true</jk> if the built-in Java bean introspector should be used for bean introspection.
1004    */
1005   public final boolean isUseJavaBeanIntrospector() { return ctx.isUseJavaBeanIntrospector(); }
1006
1007   /**
1008    * Creates a new empty bean of the specified type, except used for instantiating inner member classes that must
1009    * be instantiated within another class instance.
1010    *
1011    * <h5 class='section'>Example:</h5>
1012    * <p class='bjava'>
1013    *    <jc>// Construct a new instance of the specified bean class</jc>
1014    *    Person <jv>person</jv> = MarshallingContext.<jsf>DEFAULT</jsf>.newBean(Person.<jk>class</jk>);
1015    * </p>
1016    *
1017    * @param <T> The class type of the bean being created.
1018    * @param c The class type of the bean being created.
1019    * @return A new bean object, or <jk>null</jk> if the class is not a bean.
1020    * @throws BeanRuntimeException If the specified class is not a valid bean.
1021    */
1022   public final <T> T newBean(Class<T> c) throws BeanRuntimeException {
1023      return newBean(null, c);
1024   }
1025
1026   /**
1027    * Same as {@link #newBean(Class)}, except used for instantiating inner member classes that must be instantiated
1028    * within another class instance.
1029    *
1030    * @param <T> The class type of the bean being created.
1031    * @param c The class type of the bean being created.
1032    * @param outer
1033    *    If class is a member class, this is the instance of the containing class.
1034    *    Should be <jk>null</jk> if not a member class.
1035    * @return A new bean object, or <jk>null</jk> if the class is not a bean.
1036    * @throws BeanRuntimeException If the specified class is not a valid bean.
1037    */
1038   public final <T> T newBean(Object outer, Class<T> c) throws BeanRuntimeException {
1039      var cm = getClassMeta(c);
1040      var m = cm.getBeanMeta();
1041      if (m == null)
1042         return null;
1043      try {
1044         var o = m.newBean(outer);
1045         if (o == null)
1046            throw brex(c, "Class does not have a no-arg constructor.");
1047         return o;
1048      } catch (BeanRuntimeException e) {
1049         throw e;
1050      } catch (Exception e) {
1051         throw brex(e);
1052      }
1053   }
1054
1055   /**
1056    * Creates a new {@link BeanMap} object (a modifiable {@link Map}) of the given class with uninitialized
1057    * property values.
1058    *
1059    * <p>
1060    * If object is not a true bean, then throws a {@link BeanRuntimeException} with an explanation of why it's not a
1061    * bean.
1062    *
1063    * <h5 class='section'>Example:</h5>
1064    * <p class='bjava'>
1065    *    <jc>// Construct a new bean map wrapped around a new Person object</jc>
1066    *    BeanMap&lt;Person&gt; <jv>beanMap</jv> = MarshallingContext.<jsf>DEFAULT</jsf>.newBeanMap(Person.<jk>class</jk>);
1067    * </p>
1068    *
1069    * @param <T> The class of the object being wrapped.
1070    * @param c The name of the class to create a new instance of.
1071    * @return A new instance of the class, or <jk>null</jk> if the class is not a bean.
1072    */
1073   public final <T> BeanMap<T> newBeanMap(Class<T> c) {
1074      return newBeanMap(null, c);
1075   }
1076
1077   /**
1078    * Same as {@link #newBeanMap(Class)}, except used for instantiating inner member classes that must be instantiated
1079    * within another class instance.
1080    *
1081    * @param <T> The class of the object being wrapped.
1082    * @param c The name of the class to create a new instance of.
1083    * @param outer
1084    *    If class is a member class, this is the instance of the containing class.
1085    *    Should be <jk>null</jk> if not a member class.
1086    * @return A new instance of the class, or <jk>null</jk> if the class is not a bean.
1087    */
1088   @SuppressWarnings({
1089      "java:S1135", // Deferred design consideration.
1090      "java:S1168" // null when BeanMeta not found. Consider empty BeanMap.
1091   })
1092   public final <T> BeanMap<T> newBeanMap(Object outer, Class<T> c) {
1093      var m = getBeanMeta(c);
1094      if (m == null)
1095         return null;
1096      T bean = null;
1097      if (ie(m.getConstructorArgs()))
1098         bean = newBean(outer, c);
1099      var bm = new BeanMap<>(bean, m);
1100      bm.setBeanSession(this);
1101      return bm;
1102   }
1103
1104   /**
1105    * Returns a reusable {@link ClassMeta} representation for the class <c>Object</c>.
1106    *
1107    * <p>
1108    * This <c>ClassMeta</c> is often used to represent "any object type" when an object type is not known.
1109    *
1110    * <p>
1111    * This method is identical to calling <code>getClassMeta(Object.<jk>class</jk>)</code> but uses a cached copy to
1112    * avoid a hashmap lookup.
1113    *
1114    * @return The {@link ClassMeta} object associated with the <c>Object</c> class.
1115    */
1116   public final ClassMeta<Object> object() {
1117      return ctx.object();
1118   }
1119
1120   /**
1121    * Returns a reusable {@link ClassMeta} representation for the class <c>String</c>.
1122    *
1123    * <p>
1124    * This <c>ClassMeta</c> is often used to represent key types in maps.
1125    *
1126    * <p>
1127    * This method is identical to calling <code>getClassMeta(String.<jk>class</jk>)</code> but uses a cached copy to
1128    * avoid a hashmap lookup.
1129    *
1130    * @return The {@link ClassMeta} object associated with the <c>String</c> class.
1131    */
1132   public final ClassMeta<String> string() {
1133      return ctx.string();
1134   }
1135
1136   /**
1137    * Wraps an object inside a {@link BeanMap} object (a modifiable {@link Map}).
1138    *
1139    * <p>
1140    * If object is not a true bean, then throws a {@link BeanRuntimeException} with an explanation of why it's not a
1141    * bean.
1142    *
1143    * <p>
1144    * If object is already a {@link BeanMap}, simply returns the same object.
1145    *
1146    * <h5 class='section'>Example:</h5>
1147    * <p class='bjava'>
1148    *    <jc>// Construct a bean map around a bean instance</jc>
1149    *    BeanMap&lt;Person&gt; <jv>beanMap</jv> = MarshallingContext.<jsf>DEFAULT</jsf>.toBeanMap(<jk>new</jk> Person());
1150    * </p>
1151    *
1152    * @param <T> The class of the object being wrapped.
1153    * @param o The object to wrap in a map interface.  Must not be null.
1154    * @return The wrapped object.
1155    */
1156   @Override
1157   public final <T> BeanMap<T> toBeanMap(T o) {
1158      reqnn("o", o);
1159      if (o instanceof BeanMap o2)
1160         return o2;
1161      // Unwrap recognized proxies (e.g. Hibernate $HibernateProxy$) so we enumerate the entity's properties, not the proxy's.
1162      var unwrapped = getProxyFor(o);
1163      return this.toBeanMap(o, (Class<T>)(unwrapped != null ? unwrapped : o.getClass()));
1164   }
1165
1166   /**
1167    * Wraps an object inside a {@link BeanMap} object (i.e.: a modifiable {@link Map}) defined as a bean for one of its
1168    * class, a super class, or an implemented interface.
1169    *
1170    * <p>
1171    * If object is not a true bean, throws a {@link BeanRuntimeException} with an explanation of why it's not a bean.
1172    *
1173    * <h5 class='section'>Example:</h5>
1174    * <p class='bjava'>
1175    *    <jc>// Construct a bean map for new bean using only properties defined in a superclass</jc>
1176    *    BeanMap&lt;MySubBean&gt; <jv>beanMap</jv> = MarshallingContext.<jsf>DEFAULT</jsf>.toBeanMap(<jk>new</jk> MySubBean(), MySuperBean.<jk>class</jk>);
1177    *
1178    *    <jc>// Construct a bean map for new bean using only properties defined in an interface</jc>
1179    *    BeanMap&lt;MySubBean&gt; <jv>beanMap</jv> = MarshallingContext.<jsf>DEFAULT</jsf>.toBeanMap(<jk>new</jk> MySubBean(), MySuperInterface.<jk>class</jk>);
1180    * </p>
1181    *
1182    * @param <T> The class of the object being wrapped.
1183    * @param o The object to wrap in a bean interface.  Must not be null.
1184    * @param c The superclass to narrow the bean properties to.  Must not be null.
1185    * @return The bean representation.
1186    * @throws IllegalArgumentException
1187    *    If either parameter is <jk>null</jk>, or if the specified object is not an instance of the specified class.
1188    * @throws
1189    *    BeanRuntimeException If specified object is not a bean according to the bean rules specified in this context
1190    * class.
1191    */
1192   public final <T> BeanMap<T> toBeanMap(T o, Class<? super T> c) throws BeanRuntimeException {
1193      reqnn("o", o);
1194      reqnn("c", c);
1195      req(c.isInstance(o), "The specified object is not an instance of the specified class.  class='%s', objectClass='%s', object='%s'", cn(c), cn(o), 0);
1196
1197      var cm = getClassMeta(c);
1198
1199      BeanMeta m = cm.getBeanMeta();
1200      if (m == null)
1201         throw brex(c, "Class is not a bean.  Reason='%s'", cm.getNotABeanReason());
1202      var bm = new BeanMap<>(o, m);
1203      bm.setBeanSession(this);
1204      return bm;
1205   }
1206
1207   /**
1208    * Wraps an object inside a {@link BeanMap} object (a modifiable {@link Map}).
1209    *
1210    * <p>
1211    * Same as {@link #toBeanMap(Object)} but allows you to specify a property namer instance.
1212    *
1213    * <h5 class='section'>Example:</h5>
1214    * <p class='bjava'>
1215    *    <jc>// Construct a bean map around a bean instance</jc>
1216    *    BeanMap&lt;Person&gt; <jv>beanMap</jv> = MarshallingContext.<jsf>DEFAULT</jsf>.toBeanMap(<jk>new</jk> Person(), PropertyNamerDLC.<jsf>INSTANCE</jsf>);
1217    * </p>
1218    *
1219    * <p>
1220    * The supplied {@code propertyNamer} controls the names of the properties exposed by the returned
1221    * {@link BeanMap}.  For example, passing {@link PropertyNamerDLC#INSTANCE} renames a <c>fooBar</c> property to
1222    * <c>foo-bar</c>.
1223    *
1224    * <p>
1225    * When {@code propertyNamer} is <jk>null</jk> or equal to this session's {@link #getPropertyNamer() default
1226    * namer}, the shared, {@code Class}-keyed {@link BeanMeta} cache is used exactly as by {@link #toBeanMap(Object)}.
1227    * Otherwise a fresh, non-cached {@link BeanMeta} is built with the supplied namer so the default cache is never
1228    * polluted with alternate-namer property keys.
1229    *
1230    * @param <T> The class of the object being wrapped.
1231    * @param o The object to wrap in a map interface.  Must not be null.
1232    * @param propertyNamer The property namer to use.  Can be <jk>null</jk> to use the session's default namer.
1233    * @return The wrapped object.
1234    */
1235   public final <T> BeanMap<T> toBeanMap(T o, PropertyNamer propertyNamer) {
1236      reqnn("o", o);
1237      if (o instanceof BeanMap o2)
1238         return o2;
1239
1240      // Unwrap recognized proxies (e.g. Hibernate $HibernateProxy$) so we enumerate the entity's properties, not the proxy's.
1241      var unwrapped = getProxyFor(o);
1242      var beanClass = unwrapped != null ? unwrapped : o.getClass();
1243
1244      // Preserve the cached default-namer path when no override (or the override matches the default) is supplied.
1245      if (propertyNamer == null || propertyNamer.equals(getPropertyNamer()))
1246         return this.toBeanMap(o, (Class<T>)beanClass);
1247
1248      var c = (Class<T>)beanClass;
1249      var cm = getClassMeta(c);
1250      var m = cm.getBeanMeta(propertyNamer);
1251      if (m == null)
1252         throw brex(c, "Class is not a bean.  Reason='%s'", cm.getNotABeanReason());
1253      var bm = new BeanMap<>(o, m);
1254      bm.setBeanSession(this);
1255      return bm;
1256   }
1257
1258   /**
1259    * Same as {@link #convertToType(Object, ClassMeta)}, except used for instantiating inner member classes that must
1260    * be instantiated within another class instance.
1261    *
1262    * @param <T> The class type to convert the value to.
1263    * @param outer
1264    *    If class is a member class, this is the instance of the containing class.
1265    *    Should be <jk>null</jk> if not a member class.
1266    * @param value The value to convert.  Can be <jk>null</jk> (returns <jk>null</jk>).
1267    * @param to The class type to convert the value to.  Can be <jk>null</jk> (treated as the {@code Object} type).
1268    * @throws InvalidDataConversionException If the specified value cannot be converted to the specified type.
1269    * @return The converted value.
1270    */
1271   protected final <T> T convertToMemberType(Object outer, Object value, ClassMeta<T> to) throws InvalidDataConversionException {
1272      if (to == null)
1273         to = (ClassMeta<T>)object();
1274      try {
1275         // If the value is already an instance of the target type and no element/value conversion is needed, return as-is.
1276         // Skip this shortcut for typed maps/collections whose elements may need conversion.
1277         if (value != null && to.inner().isInstance(value)
1278               && !((to.isMap() && !to.getValueType().is(Object.class)) || ((to.isCollection() || to.isOptional()) && !to.getElementType().isObject())))
1279            return (T) value;
1280         return ctx.getConverter().to(value, outer, this, to.innerType(), to.getParameters());
1281      } catch (InvalidDataConversionException | MissingRequiredPropertyException e) {
1282         throw e;
1283      } catch (Exception e) {
1284         throw new InvalidDataConversionException(value, to, e);
1285      }
1286   }
1287
1288   /**
1289    * Given an array of {@link Type} objects, returns a {@link ClassMeta} representing those arguments.
1290    *
1291    * <p>
1292    * Constructs a new meta on each call.
1293    *
1294    * @param classes The array of classes to get class metas for.  Must not be <jk>null</jk>.
1295    * @return The args {@link ClassMeta} object corresponding to the classes.  Never <jk>null</jk>.
1296    */
1297   protected final ClassMeta<Object[]> getArgsClassMeta(Type[] classes) {
1298      reqnn("classes", classes);
1299      return new ClassMeta(Arrays.stream(classes).map(this::getClassMeta).toList());
1300   }
1301
1302   /**
1303    * Returns the {@link ClassMeta} for the object's class, unwrapping recognized proxies first.
1304    *
1305    * <p>
1306    * If {@link org.apache.juneau.commons.utils.ClassUtils#getProxyFor(Object)} returns a class,
1307    * that class is used; otherwise {@code o.getClass()}. JDK dynamic proxies (including
1308    * annotation instances) resolve to the first interface. Subclass proxies (CGLIB,
1309    * Javassist, ByteBuddy, Hibernate {@code $HibernateProxy$}) resolve to the immediate
1310    * superclass. Spring CGLIB objects may have {@code getTargetClass()} invoked on the live
1311    * instance. Names matching {@code $$SpringCGLIB$$} only (Spring 6) are not recognized.
1312    *
1313    * @param o The object to find the class type for.  Can be <jk>null</jk> (returns {@code def}).
1314    * @param def The default {@link ClassMeta} if the object is null.  Can be <jk>null</jk> (returned as-is if
1315    *    <c>o</c> is <jk>null</jk>).
1316    * @return The ClassMeta object, or the default value if {@code o} is <jk>null</jk>.
1317    */
1318   protected final ClassMeta<?> getClassMetaForObject(Object o, ClassMeta<?> def) {
1319      if (o == null)
1320         return def;
1321      var unwrapped = getProxyFor(o);
1322      Class<?> k = unwrapped != null ? unwrapped : o.getClass();
1323      return getClassMeta(k);
1324   }
1325
1326   /**
1327    * Creates a generic {@link Map} for parser-driven map population, choosing the map type based on the key type.
1328    *
1329    * <p>
1330    * Returns the flavored {@link MarshalledMap} subclass when the key type is String (via {@link #newGenericMap()}),
1331    * otherwise returns a plain {@link LinkedHashMap} (since {@link MarshalledMap} is keyed by String).
1332    *
1333    * <p>
1334    * Per-marshaller parser sessions override {@link #newGenericMap()} (not this method) to return their flavored
1335    * {@code XMap} variant.
1336    *
1337    * @param mapMeta The metadata of the map to create.  Must not be <jk>null</jk>.
1338    * @return A new map.
1339    */
1340   protected Map newGenericMap(ClassMeta mapMeta) {
1341      var k = mapMeta.getKeyType();
1342      return (k == null || k.isString()) ? newGenericMap() : map();
1343   }
1344
1345   /**
1346    * Creates a string-keyed generic map for parser-driven map population.
1347    *
1348    * <p>
1349    * This is the main factory hook overridden by per-marshaller parser sessions to return their flavored
1350    * {@code XMap} variant (for example, {@link JsonParserSession} returns
1351    * {@link JsonMap}; {@link Json5ParserSession} returns
1352    * {@link Json5Map}).
1353    *
1354    * @return A new map.
1355    */
1356   protected MarshalledMap newGenericMap() {
1357      return new MarshalledMap(this);
1358   }
1359
1360   /**
1361    * Creates a generic list for parser-driven list population.
1362    *
1363    * <p>
1364    * Per-marshaller parser sessions override this hook to return their flavored {@code XList} variant
1365    * (for example, {@link JsonParserSession} returns {@link JsonList};
1366    * {@link Json5ParserSession} returns
1367    * {@link Json5List}).
1368    *
1369    * @return A new list.
1370    */
1371   protected MarshalledList newGenericList() {
1372      return new MarshalledList(this);
1373   }
1374
1375   @Override /* Overridden from ContextSession */
1376   protected FluentMap<String,Object> properties() {
1377      return super.properties()
1378         .a("locale", locale)
1379         .a("mediaType", mediaType)
1380         .a("timeZone", timeZone)
1381         .a("activeView", activeView);
1382   }
1383
1384   /**
1385    * Converts the contents of the specified list into an array.
1386    *
1387    * <p>
1388    * Works on both object and primitive arrays.
1389    *
1390    * <p>
1391    * In the case of multi-dimensional arrays, the incoming list must contain elements of type n-1 dimension.
1392    * i.e. if {@code type} is <code><jk>int</jk>[][]</code> then {@code list} must have entries of type
1393    * <code><jk>int</jk>[]</code>.
1394    *
1395    * @param type The type to convert to.  Must be an array type.  Must not be <jk>null</jk>.
1396    * @param list The contents to populate the array with.  Can be <jk>null</jk> (returns <jk>null</jk>).
1397    * @return A new object or primitive array, or <jk>null</jk> if the list was <jk>null</jk>.
1398    */
1399   protected final Object toArray(ClassMeta<?> type, Collection<?> list) {
1400      if (list == null)
1401         return null;
1402      var componentType = type.isArgs() ? object() : type.getElementType();
1403      var array = Array.newInstance(componentType.inner(), list.size());
1404      var i = IntegerHolder.create();
1405      list.forEach(x -> {
1406         var x2 = x;
1407         if (! type.isInstance(x)) {
1408            if (componentType.isArray() && x instanceof Collection<?> x3)
1409               x2 = toArray(componentType, x3);
1410            else if (x == null && componentType.isPrimitive())
1411               x2 = componentType.getPrimitiveDefault();
1412            else
1413               x2 = convertToType(x, componentType);
1414         }
1415         Array.set(array, i.getAndIncrement(), x2);
1416      });
1417      return array;
1418   }
1419
1420   //-----------------------------------------------------------------------------------------------------------------
1421   // BeanSession bridge methods — SPI seam to commons.bean.
1422   //-----------------------------------------------------------------------------------------------------------------
1423
1424   /**
1425    * Bridge implementation of {@link BeanSession#convertToType(Object, Object)} that dispatches to the
1426    * {@link ClassMeta}-typed overload when the supplied {@code targetType} is a {@link ClassMeta}, or to the
1427    * {@link Class}-typed overload when it is a {@link Class}.
1428    *
1429    * <p>
1430    * The bean-modeling layer calls this method through the {@link BeanSession} interface so it can request type
1431    * conversion without referencing the marshalling-side {@link ClassMeta} concrete type.
1432    *
1433    * @param value The value to convert.  May be <jk>null</jk>.
1434    * @param targetType A {@link ClassMeta} or {@link Class} describing the target type.  Can be <jk>null</jk> (treated as the {@code Object} type).
1435    * @return The converted value.
1436    * @throws IllegalArgumentException If {@code targetType} is neither a {@link ClassMeta} nor a {@link Class}.
1437    */
1438   @Override /* BeanSession */
1439   public final Object convertToType(Object value, Object targetType) {
1440      if (targetType == null)
1441         return convertToType(value, (ClassMeta<?>) null);
1442      if (targetType instanceof ClassMeta<?> targetType2)
1443         return convertToType(value, targetType2);
1444      if (targetType instanceof Class<?> targetType2)
1445         return convertToType(value, targetType2);
1446      throw iaex("Unsupported targetType for convertToType: %s", cn(targetType));
1447   }
1448
1449   /**
1450    * Bridge implementation of {@link BeanSession#convertToMemberType(Object, Object, Object)} that dispatches to the
1451    * {@link ClassMeta}-typed overload when the supplied {@code targetType} is a {@link ClassMeta}, or to the
1452    * {@link Class}-typed overload when it is a {@link Class}.
1453    *
1454    * @param outer The outer-class instance for non-static inner classes.  May be <jk>null</jk>.
1455    * @param value The value to convert.  May be <jk>null</jk>.
1456    * @param targetType A {@link ClassMeta} or {@link Class} describing the target type.  Can be <jk>null</jk> (treated as the {@code Object} type).
1457    * @return The converted value.
1458    * @throws IllegalArgumentException If {@code targetType} is neither a {@link ClassMeta} nor a {@link Class}.
1459    */
1460   @Override /* BeanSession */
1461   public final Object convertToMemberType(Object outer, Object value, Object targetType) {
1462      if (targetType == null)
1463         return convertToMemberType(outer, value, (ClassMeta<?>) null);
1464      if (targetType instanceof ClassMeta<?> targetType2)
1465         return convertToMemberType(outer, value, targetType2);
1466      if (targetType instanceof Class<?> targetType2)
1467         return convertToMemberType(outer, value, targetType2);
1468      throw iaex("Unsupported targetType for convertToMemberType: %s", cn(targetType));
1469   }
1470
1471   /**
1472    * Bridge implementation of {@link BeanSession#parseToMap(CharSequence)} that delegates to
1473    * {@link Json5Map#ofString(CharSequence)} paired with this session.
1474    *
1475    * <p>
1476    * Used by {@link BeanPropertyMeta#setPropertyValue} to parse a {@link CharSequence} into a {@link Map} when
1477    * the property is map-typed.  Lifted out of {@link BeanPropertyMeta} so the bean-modeling layer no longer
1478    * references the marshalling-side JSON parser.
1479    *
1480    * <p>
1481    * Uses {@link Json5Map} so that historic JSON5-form inputs (e.g. annotation default
1482    * values written as <c>{a:'b'}</c>) continue to parse — the strict-JSON {@link JsonMap} retargeting in v10.0
1483    * would otherwise break those call sites.
1484    *
1485    * @param value The JSON-formatted character sequence to parse.  Can be <jk>null</jk> (returns an empty map).
1486    * @return The parsed {@link Json5Map} (empty if {@code value} is <jk>null</jk>), never <jk>null</jk>.
1487    */
1488   @Override /* BeanSession */
1489   public final Map<?,?> parseToMap(CharSequence value) {
1490      return Json5Map.ofString(value).session(this);
1491   }
1492
1493   /**
1494    * Bridge implementation of {@link BeanSession#parseToList(CharSequence)} that delegates to
1495    * {@link Json5List#Json5List(CharSequence)} paired with this session.
1496    *
1497    * <p>
1498    * Used by {@link BeanPropertyMeta#setPropertyValue} to parse a {@link CharSequence} into a {@link Collection}
1499    * when the property is collection-typed.  Lifted out of {@link BeanPropertyMeta} so the bean-modeling layer
1500    * no longer references the marshalling-side JSON parser.
1501    *
1502    * <p>
1503    * Uses {@link Json5List} for the same back-compat reasons as
1504    * {@link #parseToMap(CharSequence)}.
1505    *
1506    * @param value The JSON-formatted character sequence to parse.  Must not be <jk>null</jk>.
1507    * @return The parsed {@link Json5List}.
1508    */
1509   @Override /* BeanSession */
1510   public final Collection<?> parseToList(CharSequence value) {
1511      reqnn("value", value);
1512      return new Json5List(value).setBeanSession(this);
1513   }
1514
1515}