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