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