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