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