001// ***************************************************************************************************************************
002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
003// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
005// * with the License.  You may obtain a copy of the License at                                                              *
006// *                                                                                                                         *
007// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
008// *                                                                                                                         *
009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
011// * specific language governing permissions and limitations under the License.                                              *
012// ***************************************************************************************************************************
013package org.apache.juneau;
014
015import static org.apache.juneau.internal.StringUtils.*;
016import static org.apache.juneau.internal.ThrowableUtils.*;
017import static org.apache.juneau.BeanContext.*;
018
019import java.io.*;
020import java.lang.reflect.*;
021import java.time.*;
022import java.util.*;
023import java.util.Date;
024import java.util.concurrent.atomic.*;
025
026import org.apache.juneau.http.*;
027import org.apache.juneau.httppart.*;
028import org.apache.juneau.internal.*;
029import org.apache.juneau.json.*;
030import org.apache.juneau.parser.*;
031import org.apache.juneau.reflect.*;
032import org.apache.juneau.serializer.*;
033import org.apache.juneau.transform.*;
034
035/**
036 * Session object that lives for the duration of a single use of {@link Serializer} or {@link Parser}.
037 *
038 * <p>
039 * This class is NOT thread safe.  It is meant to be discarded after one-time use.
040 */
041@SuppressWarnings({"unchecked","rawtypes"})
042public class BeanSession extends Session {
043
044   private final BeanContext ctx;
045   private final Locale locale;
046   private final TimeZone timeZone;
047   private final MediaType mediaType;
048   private final boolean debug;
049   private final HttpPartSchema schema;
050   private Stack<StringBuilder> sbStack = new Stack<>();
051
052   /**
053    * Create a new session using properties specified in the context.
054    *
055    * @param ctx
056    *    The context creating this session object.
057    *    The context contains all the configuration settings for this object.
058    * @param args
059    *    Runtime session arguments.
060    */
061   protected BeanSession(BeanContext ctx, BeanSessionArgs args) {
062      super(args);
063      this.ctx = ctx;
064      locale = getProperty(BEAN_locale, Locale.class, ctx.getLocale());
065      timeZone = getProperty(BEAN_timeZone, TimeZone.class, ctx.getTimeZone());
066      debug = getProperty(BEAN_debug, Boolean.class, ctx.isDebug());
067      mediaType = getProperty(BEAN_mediaType, MediaType.class, ctx.getMediaType());
068      schema = args.schema;
069   }
070
071   /**
072    * Converts the specified value to the specified class type.
073    *
074    * <p>
075    * See {@link #convertToType(Object, ClassMeta)} for the list of valid conversions.
076    *
077    * @param <T> The class type to convert the value to.
078    * @param value The value to convert.
079    * @param type The class type to convert the value to.
080    * @throws InvalidDataConversionException If the specified value cannot be converted to the specified type.
081    * @return The converted value.
082    */
083   public final <T> T convertToType(Object value, Class<T> type) throws InvalidDataConversionException {
084      // Shortcut for most common case.
085      if (value != null && value.getClass() == type)
086         return (T)value;
087      return convertToMemberType(null, value, getClassMeta(type));
088   }
089
090   /**
091    * Same as {@link #convertToType(Object, Class)}, except used for instantiating inner member classes that must
092    * be instantiated within another class instance.
093    *
094    * @param <T> The class type to convert the value to.
095    * @param outer
096    *    If class is a member class, this is the instance of the containing class.
097    *    Should be <jk>null</jk> if not a member class.
098    * @param value The value to convert.
099    * @param type The class type to convert the value to.
100    * @throws InvalidDataConversionException If the specified value cannot be converted to the specified type.
101    * @return The converted value.
102    */
103   public final <T> T convertToMemberType(Object outer, Object value, Class<T> type) throws InvalidDataConversionException {
104      return convertToMemberType(outer, value, getClassMeta(type));
105   }
106
107   /**
108    * Casts the specified value into the specified type.
109    *
110    * <p>
111    * If the value isn't an instance of the specified type, then converts the value if possible.
112    *
113    * <p>
114    * The following conversions are valid:
115    * <table class='styled'>
116    *    <tr><th>Convert to type</th><th>Valid input value types</th><th>Notes</th></tr>
117    *    <tr>
118    *       <td>
119    *          A class that is the normal type of a registered {@link PojoSwap}.
120    *       </td>
121    *       <td>
122    *          A value whose class matches the transformed type of that registered {@link PojoSwap}.
123    *       </td>
124    *       <td>&nbsp;</td>
125    *    </tr>
126    *    <tr>
127    *       <td>
128    *          A class that is the transformed type of a registered {@link PojoSwap}.
129    *       </td>
130    *       <td>
131    *          A value whose class matches the normal type of that registered {@link PojoSwap}.
132    *       </td>
133    *       <td>&nbsp;</td>
134    *    </tr>
135    *    <tr>
136    *       <td>
137    *          {@code Number} (e.g. {@code Integer}, {@code Short}, {@code Float},...)
138    *          <br><code>Number.<jsf>TYPE</jsf></code> (e.g. <code>Integer.<jsf>TYPE</jsf></code>,
139    *          <code>Short.<jsf>TYPE</jsf></code>, <code>Float.<jsf>TYPE</jsf></code>,...)
140    *       </td>
141    *       <td>
142    *          {@code Number}, {@code String}, <jk>null</jk>
143    *       </td>
144    *       <td>
145    *          For primitive {@code TYPES}, <jk>null</jk> returns the JVM default value for that type.
146    *       </td>
147    *    </tr>
148    *    <tr>
149    *       <td>
150    *          {@code Map} (e.g. {@code Map}, {@code HashMap}, {@code TreeMap}, {@code ObjectMap})
151    *       </td>
152    *       <td>
153    *          {@code Map}
154    *       </td>
155    *       <td>
156    *          If {@code Map} is not constructible, a {@code ObjectMap} is created.
157    *       </td>
158    *    </tr>
159    *    <tr>
160    *       <td>
161    *       {@code Collection} (e.g. {@code List}, {@code LinkedList}, {@code HashSet}, {@code ObjectList})
162    *       </td>
163    *       <td>
164    *          {@code Collection<Object>}
165    *          <br>{@code Object[]}
166    *       </td>
167    *       <td>
168    *          If {@code Collection} is not constructible, a {@code ObjectList} is created.
169    *       </td>
170    *    </tr>
171    *    <tr>
172    *       <td>
173    *          {@code X[]} (array of any type X)
174    *       </td>
175    *       <td>
176    *          {@code List<X>}
177    *       </td>
178    *       <td>&nbsp;</td>
179    *    </tr>
180    *    <tr>
181    *       <td>
182    *          {@code X[][]} (multi-dimensional arrays)
183    *       </td>
184    *       <td>
185    *          {@code List<List<X>>}
186    *          <br>{@code List<X[]>}
187    *          <br>{@code List[]<X>}
188    *       </td>
189    *       <td>&nbsp;</td>
190    *    </tr>
191    *    <tr>
192    *       <td>
193    *          {@code Enum}
194    *       </td>
195    *       <td>
196    *          {@code String}
197    *       </td>
198    *       <td>&nbsp;</td>
199    *    </tr>
200    *    <tr>
201    *       <td>
202    *          Bean
203    *       </td>
204    *       <td>
205    *          {@code Map}
206    *       </td>
207    *       <td>&nbsp;</td>
208    *    </tr>
209    *    <tr>
210    *       <td>
211    *          {@code String}
212    *       </td>
213    *       <td>
214    *          Anything
215    *       </td>
216    *       <td>
217    *          Arrays are converted to JSON arrays
218    *       </td>
219    *    </tr>
220    *    <tr>
221    *       <td>
222    *          Anything with one of the following methods:
223    *          <br><code><jk>public static</jk> T fromString(String)</code>
224    *          <br><code><jk>public static</jk> T valueOf(String)</code>
225    *          <br><code><jk>public</jk> T(String)</code>
226    *       </td>
227    *       <td>
228    *          <c>String</c>
229    *       </td>
230    *       <td>
231    *          <br>
232    *       </td>
233    *    </tr>
234    * </table>
235    *
236    * @param <T> The class type to convert the value to.
237    * @param value The value to be converted.
238    * @param type The target object type.
239    * @return The converted type.
240    * @throws InvalidDataConversionException If the specified value cannot be converted to the specified type.
241    */
242   public final <T> T convertToType(Object value, ClassMeta<T> type) throws InvalidDataConversionException {
243      return convertToMemberType(null, value, type);
244   }
245
246   /**
247    * Same as {@link #convertToType(Object, Class)}, but allows for complex data types consisting of collections or maps.
248    *
249    * @param <T> The class type to convert the value to.
250    * @param value The value to be converted.
251    * @param type The target object type.
252    * @param args The target object parameter types.
253    * @return The converted type.
254    * @throws InvalidDataConversionException If the specified value cannot be converted to the specified type.
255    */
256   public final <T> T convertToType(Object value, Type type, Type...args) throws InvalidDataConversionException {
257      return (T)convertToMemberType(null, value, getClassMeta(type, args));
258   }
259
260   /**
261    * Same as {@link #convertToType(Object, ClassMeta)}, except used for instantiating inner member classes that must
262    * be instantiated within another class instance.
263    *
264    * @param <T> The class type to convert the value to.
265    * @param outer
266    *    If class is a member class, this is the instance of the containing class.
267    *    Should be <jk>null</jk> if not a member class.
268    * @param value The value to convert.
269    * @param to The class type to convert the value to.
270    * @throws InvalidDataConversionException If the specified value cannot be converted to the specified type.
271    * @return The converted value.
272    */
273   protected final <T> T convertToMemberType(Object outer, Object value, ClassMeta<T> to) throws InvalidDataConversionException {
274      if (to == null)
275         to = (ClassMeta<T>)object();
276
277      try {
278         // Handle the case of a null value.
279         if (value == null) {
280
281            // If it's a primitive, then use the converters to get the default value for the primitive type.
282            if (to.isPrimitive())
283               return to.getPrimitiveDefault();
284
285            // Otherwise, just return null.
286            return to.isOptional() ? (T)to.getOptionalDefault() : null;
287         }
288
289         if (to.isOptional() && (! (value instanceof Optional)))
290            return (T) Optional.ofNullable(convertToMemberType(outer, value, to.getElementType()));
291
292         Class<T> tc = to.getInnerClass();
293
294         // If no conversion needed, then just return the value.
295         // Don't include maps or collections, because child elements may need conversion.
296         if (tc.isInstance(value))
297            if (! ((to.isMap() && to.getValueType().isNotObject()) || ((to.isCollection() || to.isOptional()) && to.getElementType().isNotObject())))
298               return (T)value;
299
300         PojoSwap swap = to.getPojoSwap(this);
301         if (swap != null) {
302            ClassInfo nc = swap.getNormalClass(), fc = swap.getSwapClass();
303            if (nc.isParentOf(tc) && fc.isParentOf(value.getClass()))
304               return (T)swap.unswap(this, value, to);
305            ClassMeta fcm = getClassMeta(fc.inner());
306            if (fcm.isNumber() && value instanceof Number) {
307               value = convertToMemberType(null, value, fc.inner());
308               return (T)swap.unswap(this, value, to);
309            }
310         }
311
312         ClassMeta<?> from = getClassMetaForObject(value);
313         swap = from.getPojoSwap(this);
314         if (swap != null) {
315            ClassInfo nc = swap.getNormalClass(), fc = swap.getSwapClass();
316            if (nc.isParentOf(from.getInnerClass()) && fc.isParentOf(tc))
317               return (T)swap.swap(this, value);
318         }
319
320         if (to.isPrimitive()) {
321            if (to.isNumber()) {
322               if (from.isNumber()) {
323                  Number n = (Number)value;
324                  if (tc == Integer.TYPE)
325                     return (T)Integer.valueOf(n.intValue());
326                  if (tc == Short.TYPE)
327                     return (T)Short.valueOf(n.shortValue());
328                  if (tc == Long.TYPE)
329                     return (T)Long.valueOf(n.longValue());
330                  if (tc == Float.TYPE)
331                     return (T)Float.valueOf(n.floatValue());
332                  if (tc == Double.TYPE)
333                     return (T)Double.valueOf(n.doubleValue());
334                  if (tc == Byte.TYPE)
335                     return (T)Byte.valueOf(n.byteValue());
336               } else if (from.isBoolean()) {
337                  Boolean b = (Boolean)value;
338                  if (tc == Integer.TYPE)
339                     return (T)(Integer.valueOf(b ? 1 : 0));
340                  if (tc == Short.TYPE)
341                     return (T)(Short.valueOf(b ? (short)1 : 0));
342                  if (tc == Long.TYPE)
343                     return (T)(Long.valueOf(b ? 1l : 0));
344                  if (tc == Float.TYPE)
345                     return (T)(Float.valueOf(b ? 1f : 0));
346                  if (tc == Double.TYPE)
347                     return (T)(Double.valueOf(b ? 1d : 0));
348                  if (tc == Byte.TYPE)
349                     return (T)(Byte.valueOf(b ? (byte)1 : 0));
350               } else if (isNullOrEmpty(value)) {
351                  return (T)to.info.getPrimitiveDefault();
352               } else {
353                  String s = value.toString();
354                  int multiplier = (tc == Integer.TYPE || tc == Short.TYPE || tc == Long.TYPE) ? getMultiplier(s) : 1;
355                  if (multiplier != 1) {
356                     s = s.substring(0, s.length()-1).trim();
357                     Long l = Long.valueOf(s) * multiplier;
358                     if (tc == Integer.TYPE)
359                        return (T)Integer.valueOf(l.intValue());
360                     if (tc == Short.TYPE)
361                        return (T)Short.valueOf(l.shortValue());
362                     if (tc == Long.TYPE)
363                        return (T)Long.valueOf(l.longValue());
364                  } else {
365                     if (tc == Integer.TYPE)
366                        return (T)Integer.valueOf(s);
367                     if (tc == Short.TYPE)
368                        return (T)Short.valueOf(s);
369                     if (tc == Long.TYPE)
370                        return (T)Long.valueOf(s);
371                     if (tc == Float.TYPE)
372                        return (T)new Float(s);
373                     if (tc == Double.TYPE)
374                        return (T)new Double(s);
375                     if (tc == Byte.TYPE)
376                        return (T)Byte.valueOf(s);
377                  }
378               }
379            } else if (to.isChar()) {
380               if (isNullOrEmpty(value))
381                  return (T)to.info.getPrimitiveDefault();
382               return (T)parseCharacter(value);
383            } else if (to.isBoolean()) {
384               if (from.isNumber()) {
385                  int i = ((Number)value).intValue();
386                  return (T)(i == 0 ? Boolean.FALSE : Boolean.TRUE);
387               } else if (isNullOrEmpty(value)) {
388                  return (T)to.info.getPrimitiveDefault();
389               } else {
390                  return (T)Boolean.valueOf(value.toString());
391               }
392            }
393         }
394
395         if (to.isNumber()) {
396            if (from.isNumber()) {
397               Number n = (Number)value;
398               if (tc == Integer.class)
399                  return (T)Integer.valueOf(n.intValue());
400               if (tc == Short.class)
401                  return (T)Short.valueOf(n.shortValue());
402               if (tc == Long.class)
403                  return (T)Long.valueOf(n.longValue());
404               if (tc == Float.class)
405                  return (T)Float.valueOf(n.floatValue());
406               if (tc == Double.class)
407                  return (T)Double.valueOf(n.doubleValue());
408               if (tc == Byte.class)
409                  return (T)Byte.valueOf(n.byteValue());
410               if (tc == AtomicInteger.class)
411                  return (T)new AtomicInteger(n.intValue());
412               if (tc == AtomicLong.class)
413                  return (T)new AtomicLong(n.intValue());
414            } else if (from.isBoolean()) {
415               Boolean b = (Boolean)value;
416               if (tc == Integer.class)
417                  return (T)Integer.valueOf(b ? 1 : 0);
418               if (tc == Short.class)
419                  return (T)Short.valueOf(b ? (short)1 : 0);
420               if (tc == Long.class)
421                  return (T)Long.valueOf(b ? 1 : 0);
422               if (tc == Float.class)
423                  return (T)Float.valueOf(b ? 1 : 0);
424               if (tc == Double.class)
425                  return (T)Double.valueOf(b ? 1 : 0);
426               if (tc == Byte.class)
427                  return (T)Byte.valueOf(b ? (byte)1 : 0);
428               if (tc == AtomicInteger.class)
429                  return (T)new AtomicInteger(b ? 1 : 0);
430               if (tc == AtomicLong.class)
431                  return (T)new AtomicLong(b ? 1 : 0);
432            } else if (isNullOrEmpty(value)) {
433               return null;
434            } else if (! hasMutater(from, to)) {
435               String s = value.toString();
436
437               int multiplier = (tc == Integer.class || tc == Short.class || tc == Long.class) ? getMultiplier(s) : 1;
438               if (multiplier != 1) {
439                  s = s.substring(0, s.length()-1).trim();
440                  Long l = Long.valueOf(s) * multiplier;
441                  if (tc == Integer.TYPE)
442                     return (T)Integer.valueOf(l.intValue());
443                  if (tc == Short.TYPE)
444                     return (T)Short.valueOf(l.shortValue());
445                  if (tc == Long.TYPE)
446                     return (T)Long.valueOf(l.longValue());
447               } else {
448                  if (tc == Integer.class)
449                     return (T)Integer.valueOf(s);
450                  if (tc == Short.class)
451                     return (T)Short.valueOf(s);
452                  if (tc == Long.class)
453                     return (T)Long.valueOf(s);
454                  if (tc == Float.class)
455                     return (T)new Float(s);
456                  if (tc == Double.class)
457                     return (T)new Double(s);
458                  if (tc == Byte.class)
459                     return (T)Byte.valueOf(s);
460                  if (tc == AtomicInteger.class)
461                     return (T)new AtomicInteger(Integer.valueOf(s));
462                  if (tc == AtomicLong.class)
463                     return (T)new AtomicLong(Long.valueOf(s));
464                  if (tc == Number.class)
465                     return (T)StringUtils.parseNumber(s, Number.class);
466               }
467            }
468         }
469
470         if (to.isChar()) {
471            if (isNullOrEmpty(value))
472               return null;
473            String s = value.toString();
474            if (s.length() == 1)
475               return (T)Character.valueOf(s.charAt(0));
476         }
477
478         if (to.isByteArray()) {
479            if (from.isInputStream())
480               return (T)IOUtils.readBytes((InputStream)value, 1024);
481            if (from.isReader())
482               return (T)IOUtils.read((Reader)value).getBytes();
483         }
484
485         // Handle setting of array properties
486         if (to.isArray()) {
487            if (from.isCollection())
488               return (T)toArray(to, (Collection)value);
489            else if (from.isArray())
490               return (T)toArray(to, Arrays.asList((Object[])value));
491            else if (startsWith(value.toString(), '['))
492               return (T)toArray(to, new ObjectList(value.toString()).setBeanSession(this));
493            else if (to.hasMutaterFrom(from))
494               return to.mutateFrom(value);
495            else if (from.hasMutaterTo(to))
496               return from.mutateTo(value, to);
497            else
498               return (T)toArray(to, new ObjectList((Object[])StringUtils.split(value.toString())).setBeanSession(this));
499         }
500
501         // Target type is some sort of Map that needs to be converted.
502         if (to.isMap()) {
503            try {
504               if (from.isMap()) {
505                  Map m = to.canCreateNewInstance(outer) ? (Map)to.newInstance(outer) : new ObjectMap(this);
506                  ClassMeta keyType = to.getKeyType(), valueType = to.getValueType();
507                  for (Map.Entry e : (Set<Map.Entry>)((Map)value).entrySet()) {
508                     Object k = e.getKey();
509                     if (keyType.isNotObject()) {
510                        if (keyType.isString() && k.getClass() != Class.class)
511                           k = k.toString();
512                        else
513                           k = convertToMemberType(m, k, keyType);
514                     }
515                     Object v = e.getValue();
516                     if (valueType.isNotObject())
517                        v = convertToMemberType(m, v, valueType);
518                     m.put(k, v);
519                  }
520                  return (T)m;
521               } else if (!to.canCreateNewInstanceFromString(outer)) {
522                  ObjectMap m = new ObjectMap(value.toString());
523                  m.setBeanSession(this);
524                  return convertToMemberType(outer, m, to);
525               }
526            } catch (Exception e) {
527               throw new InvalidDataConversionException(value.getClass(), to, e);
528            }
529         }
530
531         // Target type is some sort of Collection
532         if (to.isCollection()) {
533            try {
534               Collection l = to.canCreateNewInstance(outer) ? (Collection)to.newInstance(outer) : to.isSet() ? new LinkedHashSet<>() : new ObjectList(this);
535               ClassMeta elementType = to.getElementType();
536
537               if (from.isArray())
538                  for (Object o : (Object[])value)
539                     l.add(elementType.isObject() ? o : convertToMemberType(l, o, elementType));
540               else if (from.isCollection())
541                  for (Object o : (Collection)value)
542                     l.add(elementType.isObject() ? o : convertToMemberType(l, o, elementType));
543               else if (from.isMap())
544                  l.add(elementType.isObject() ? value : convertToMemberType(l, value, elementType));
545               else if (isNullOrEmpty(value))
546                  return null;
547               else if (from.isString()) {
548                  String s = value.toString();
549                  if (isObjectList(s, false)) {
550                     ObjectList l2 = new ObjectList(s);
551                     l2.setBeanSession(this);
552                     for (Object o : l2)
553                        l.add(elementType.isObject() ? o : convertToMemberType(l, o, elementType));
554                  } else {
555                     throw new InvalidDataConversionException(value.getClass(), to, null);
556                  }
557               }
558               else
559                  throw new InvalidDataConversionException(value.getClass(), to, null);
560               return (T)l;
561            } catch (InvalidDataConversionException e) {
562               throw e;
563            } catch (Exception e) {
564               throw new InvalidDataConversionException(value.getClass(), to, e);
565            }
566         }
567
568         if (to.isEnum()) {
569            if (to.canCreateNewInstanceFromString(outer))
570               return to.newInstanceFromString(outer, value.toString());
571            if (isNullOrEmpty(value))
572               return null;
573            return (T)Enum.valueOf((Class<? extends Enum>)tc, value.toString());
574         }
575
576         if (to.isString()) {
577            if (from.isByteArray()) {
578               return (T) new String((byte[])value);
579            } else if (from.isMapOrBean() || from.isCollectionOrArrayOrOptional()) {
580               if (SimpleJsonSerializer.DEFAULT != null)
581                  return (T)SimpleJsonSerializer.DEFAULT.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:  Debug mode.
1280    *
1281    * @see BeanContext#BEAN_debug
1282    * @return
1283    *    <jk>true</jk> if debug mode is enabled.
1284    */
1285   protected final boolean isDebug() {
1286      return debug;
1287   }
1288
1289   /**
1290    * Configuration property:  POJO examples.
1291    *
1292    * @see BeanContext#BEAN_examples
1293    * @return
1294    *    A map of POJO examples keyed by class name.
1295    */
1296   protected final Map<String,?> getExamples() {
1297      return ctx.getExamples();
1298   }
1299
1300
1301   /**
1302    * Configuration property:  Bean property excludes.
1303    *
1304    * @see BeanContext#BEAN_excludeProperties
1305    * @return
1306    *    The list of property names to exclude keyed by class name.
1307    */
1308   protected final Map<String,String[]> getExcludeProperties() {
1309      return ctx.getExcludeProperties();
1310   }
1311
1312
1313   /**
1314    * Configuration property:  Find fluent setters.
1315    *
1316    * <h5 class='section'>Description:</h5>
1317    * <p>
1318    *
1319    * @see BeanContext#BEAN_fluentSetters
1320    * @return
1321    *    <jk>true</jk> if fluent setters are detected on beans.
1322    */
1323   protected final boolean isFluentSetters() {
1324      return ctx.isFluentSetters();
1325   }
1326
1327   /**
1328    * Configuration property:  Ignore invocation errors on getters.
1329    *
1330    * @see BeanContext#BEAN_ignoreInvocationExceptionsOnGetters
1331    * @return
1332    *    <jk>true</jk> if errors thrown when calling bean getter methods are silently ignored.
1333    */
1334   protected final boolean isIgnoreInvocationExceptionsOnGetters() {
1335      return ctx.isIgnoreInvocationExceptionsOnGetters();
1336   }
1337
1338   /**
1339    * Configuration property:  Ignore invocation errors on setters.
1340    *
1341    * @see BeanContext#BEAN_ignoreInvocationExceptionsOnSetters
1342    * @return
1343    *    <jk>true</jk> if errors thrown when calling bean setter methods are silently ignored.
1344    */
1345   protected final boolean isIgnoreInvocationExceptionsOnSetters() {
1346      return ctx.isIgnoreInvocationExceptionsOnSetters();
1347   }
1348
1349   /**
1350    * Configuration property:  Ignore properties without setters.
1351    *
1352    * <br>Otherwise, a {@code RuntimeException} is thrown.
1353    *
1354    * @see BeanContext#BEAN_ignorePropertiesWithoutSetters
1355    * @return
1356    *    <jk>true</jk> if trying to set a value on a bean property without a setter is silently ignored.
1357    */
1358   protected final boolean isIgnorePropertiesWithoutSetters() {
1359      return ctx.isIgnorePropertiesWithoutSetters();
1360   }
1361
1362   /**
1363    * Configuration property:  Ignore unknown properties.
1364    *
1365    * @see BeanContext#BEAN_ignoreUnknownBeanProperties
1366    * @return
1367    *    <jk>true</jk> if trying to set a value on a non-existent bean property is silently ignored.
1368    *    <br>Otherwise, a {@code RuntimeException} is thrown.
1369    */
1370   protected final boolean isIgnoreUnknownBeanProperties() {
1371      return ctx.isIgnoreUnknownBeanProperties();
1372   }
1373
1374   /**
1375    * Configuration property:  Ignore unknown properties with null values.
1376    *
1377    * @see BeanContext#BEAN_ignoreUnknownNullBeanProperties
1378    * @return
1379    *    <jk>true</jk> if trying to set a <jk>null</jk> value on a non-existent bean property is silently ignored.
1380    */
1381   protected final boolean isIgnoreUnknownNullBeanProperties() {
1382      return ctx.isIgnoreUnknownNullBeanProperties();
1383   }
1384
1385   /**
1386    * Configuration property:  Implementation classes.
1387    *
1388    * @see BeanContext#BEAN_implClasses
1389    * @return
1390    *    Implementation classes keyed by interface class names.
1391    */
1392   protected final Map<String,ClassInfo> getImplClasses() {
1393      return ctx.getImplClasses();
1394   }
1395
1396   /**
1397    * Configuration property:  Bean property includes.
1398    *
1399    * @see BeanContext#BEAN_includeProperties
1400    * @return
1401    *    Include properties keyed by class name.
1402    */
1403   protected final Map<String,String[]> getIncludeProperties() {
1404      return ctx.getIncludeProperties();
1405   }
1406
1407   /**
1408    * Configuration property:  Locale.
1409    *
1410    * <p>
1411    * The locale is determined in the following order:
1412    * <ol>
1413    *    <li><c>locale</c> parameter passed in through constructor.
1414    *    <li>{@link BeanContext#BEAN_locale} entry in parameter passed in through constructor.
1415    *    <li>{@link BeanContext#BEAN_locale} setting on bean context.
1416    *    <li>Locale returned by {@link Locale#getDefault()}.
1417    * </ol>
1418    *
1419    * @see BeanContext#BEAN_locale
1420    * @return The session locale.
1421    */
1422   public final Locale getLocale() {
1423      return locale;
1424   }
1425
1426   /**
1427    * Configuration property:  Media type.
1428    *
1429    * <p>
1430    * For example, <js>"application/json"</js>.
1431    *
1432    * @see BeanContext#BEAN_mediaType
1433    * @return The media type for this session, or <jk>null</jk> if not specified.
1434    */
1435   public final MediaType getMediaType() {
1436      return mediaType;
1437   }
1438
1439   /**
1440    * Configuration property:  Bean class exclusions.
1441    *
1442    * @see BeanContext#BEAN_notBeanClasses
1443    * @return
1444    *    The list of classes that are explicitly not beans.
1445    */
1446   protected final Class<?>[] getNotBeanClasses() {
1447      return ctx.getNotBeanClasses();
1448   }
1449
1450   /**
1451    * Configuration property:  Bean package exclusions.
1452    *
1453    * @see BeanContext#BEAN_notBeanPackages
1454    * @return
1455    *    The list of fully-qualified package names to exclude from being classified as beans.
1456    */
1457   protected final String[] getNotBeanPackagesNames() {
1458      return ctx.getNotBeanPackagesNames();
1459   }
1460
1461   /**
1462    * Configuration property:  Bean package exclusions.
1463    *
1464    * @see BeanContext#BEAN_notBeanPackages
1465    * @return
1466    *    The list of package name prefixes to exclude from being classified as beans.
1467    */
1468   protected final String[] getNotBeanPackagesPrefixes() {
1469      return ctx.getNotBeanPackagesPrefixes();
1470   }
1471
1472   /**
1473    * Configuration property:  POJO swaps.
1474    *
1475    * @see BeanContext#BEAN_pojoSwaps
1476    * @return
1477    *    The list POJO swaps defined.
1478    */
1479   protected final PojoSwap<?,?>[] getPojoSwaps() {
1480      return ctx.getPojoSwaps();
1481   }
1482   /**
1483    * Configuration property:  Bean property namer.
1484    *
1485    * @see BeanContext#BEAN_propertyNamer
1486    * @return
1487    *    The interface used to calculate bean property names.
1488    */
1489   protected final PropertyNamer getPropertyNamer() {
1490      return ctx.getPropertyNamer();
1491   }
1492
1493   /**
1494    * Configuration property:  Sort bean properties.
1495    *
1496    * @see BeanContext#BEAN_sortProperties
1497    * @return
1498    *    <jk>true</jk> if all bean properties will be serialized and access in alphabetical order.
1499    */
1500   protected final boolean isSortProperties() {
1501      return ctx.isSortProperties();
1502   }
1503
1504   /**
1505    * Configuration property:  Time zone.
1506    *
1507    * <p>
1508    * The timezone is determined in the following order:
1509    * <ol>
1510    *    <li><c>timeZone</c> parameter passed in through constructor.
1511    *    <li>{@link BeanContext#BEAN_timeZone} entry in parameter passed in through constructor.
1512    *    <li>{@link BeanContext#BEAN_timeZone} setting on bean context.
1513    * </ol>
1514    *
1515    * @see BeanContext#BEAN_timeZone
1516    * @return The session timezone, or <jk>null</jk> if timezone not specified.
1517    */
1518   public final TimeZone getTimeZone() {
1519      return timeZone;
1520   }
1521
1522   /**
1523    * Configuration property:  Time zone.
1524    *
1525    * <p>
1526    * The timezone is determined in the following order:
1527    * <ol>
1528    *    <li><c>timeZone</c> parameter passed in through constructor.
1529    *    <li>{@link BeanContext#BEAN_timeZone} entry in parameter passed in through constructor.
1530    *    <li>{@link BeanContext#BEAN_timeZone} setting on bean context.
1531    * </ol>
1532    *
1533    * @see BeanContext#BEAN_timeZone
1534    * @return The session timezone, or the system timezone if not specified.  Never <jk>null</jk>.
1535    */
1536   public final ZoneId getTimeZoneId() {
1537      return timeZone == null ? ZoneId.systemDefault() : timeZone.toZoneId();
1538   }
1539
1540   /**
1541    * Configuration property:  Use enum names.
1542    *
1543    * @see BeanContext#BEAN_useEnumNames
1544    * @return
1545    *    <jk>true</jk> if enums are always serialized by name, not using {@link Object#toString()}.
1546    */
1547   protected final boolean isUseEnumNames() {
1548      return ctx.isUseEnumNames();
1549   }
1550
1551   /**
1552    * Configuration property:  Use interface proxies.
1553    *
1554    * @see BeanContext#BEAN_useInterfaceProxies
1555    * @return
1556    *    <jk>true</jk> if interfaces will be instantiated as proxy classes through the use of an
1557    *    {@link InvocationHandler} if there is no other way of instantiating them.
1558    */
1559   protected final boolean isUseInterfaceProxies() {
1560      return ctx.isUseInterfaceProxies();
1561   }
1562
1563   /**
1564    * Configuration property:  Use Java Introspector.
1565    *
1566    * @see BeanContext#BEAN_useJavaBeanIntrospector
1567    * @return
1568    *    <jk>true</jk> if the built-in Java bean introspector should be used for bean introspection.
1569    */
1570   protected final boolean isUseJavaBeanIntrospector() {
1571      return ctx.isUseJavaBeanIntrospector();
1572   }
1573
1574   //-----------------------------------------------------------------------------------------------------------------
1575   // Other methods
1576   //-----------------------------------------------------------------------------------------------------------------
1577
1578   /**
1579    * HTTP part schema of object being serialized or parsed.
1580    *
1581    * @return HTTP part schema of object being serialized or parsed, or <jk>null</jk> if not specified.
1582    */
1583   public final HttpPartSchema getSchema() {
1584      return schema;
1585   }
1586
1587   @Override /* Session */
1588   public void checkForWarnings() {
1589      if (debug)
1590         super.checkForWarnings();
1591   }
1592
1593   @Override /* Session */
1594   public ObjectMap toMap() {
1595      return super.toMap()
1596         .append("Context", ctx.toMap())
1597         .append("BeanSession", new DefaultFilteringObjectMap()
1598            .append("debug", debug)
1599            .append("locale", locale)
1600            .append("mediaType", mediaType)
1601            .append("schema", schema)
1602            .append("timeZone", timeZone)
1603         );
1604   }
1605}