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.BeanContext.*;
016import static org.apache.juneau.internal.ClassUtils.*;
017import static org.apache.juneau.internal.StringUtils.*;
018import static org.apache.juneau.internal.ThrowableUtils.*;
019
020import java.lang.reflect.*;
021import java.util.*;
022import java.util.concurrent.atomic.*;
023
024import org.apache.juneau.http.*;
025import org.apache.juneau.internal.*;
026import org.apache.juneau.json.*;
027import org.apache.juneau.parser.*;
028import org.apache.juneau.serializer.*;
029import org.apache.juneau.transform.*;
030
031/**
032 * Session object that lives for the duration of a single use of {@link Serializer} or {@link Parser}.
033 * 
034 * <p>
035 * This class is NOT thread safe.  It is meant to be discarded after one-time use.
036 */
037@SuppressWarnings({"unchecked","rawtypes"})
038public class BeanSession extends Session {
039
040   private final BeanContext ctx;
041   private final Locale locale;
042   private final TimeZone timeZone;
043   private final MediaType mediaType;
044   private final boolean debug;
045   private Stack<StringBuilder> sbStack = new Stack<>();
046
047   /**
048    * Create a new session using properties specified in the context.
049    * 
050    * @param ctx
051    *    The context creating this session object.
052    *    The context contains all the configuration settings for this object.
053    * @param args
054    *    Runtime session arguments.
055    */
056   protected BeanSession(BeanContext ctx, BeanSessionArgs args) {
057      super(args);
058      this.ctx = ctx;
059      locale = getProperty(BEAN_locale, Locale.class, args.locale, ctx.locale, Locale.getDefault());
060      timeZone = getProperty(BEAN_timeZone, TimeZone.class, args.timeZone, ctx.timeZone);
061      debug = getProperty(BEAN_debug, boolean.class, ctx.debug);
062      mediaType = getProperty(BEAN_mediaType, MediaType.class, args.mediaType, ctx.mediaType);
063   }
064
065   @Override /* Session */
066   public ObjectMap asMap() {
067      return super.asMap()
068         .appendAll(ctx.asMap())
069         .append("BeanSession", new ObjectMap()
070            .append("debug", debug)
071            .append("locale", locale)
072            .append("mediaType", mediaType)
073            .append("timeZone", timeZone)
074         );
075   }
076
077   /**
078    * Returns the locale defined on this session.
079    * 
080    * <p>
081    * The locale is determined in the following order:
082    * <ol>
083    *    <li><code>locale</code> parameter passed in through constructor.
084    *    <li>{@link BeanContext#BEAN_locale} entry in parameter passed in through constructor.
085    *    <li>{@link BeanContext#BEAN_locale} setting on bean context.
086    *    <li>Locale returned by {@link Locale#getDefault()}.
087    * </ol>
088    * 
089    * @return The session locale.
090    */
091   public final Locale getLocale() {
092      return locale;
093   }
094
095   /**
096    * Returns the timezone defined on this session.
097    * 
098    * <p>
099    * The timezone is determined in the following order:
100    * <ol>
101    *    <li><code>timeZone</code> parameter passed in through constructor.
102    *    <li>{@link BeanContext#BEAN_timeZone} entry in parameter passed in through constructor.
103    *    <li>{@link BeanContext#BEAN_timeZone} setting on bean context.
104    * </ol>
105    * 
106    * @return The session timezone, or <jk>null</jk> if timezone not specified.
107    */
108   public final TimeZone getTimeZone() {
109      return timeZone;
110   }
111
112   /**
113    * Returns the {@link BeanContext#BEAN_debug} setting value for this session.
114    * 
115    * @return The {@link BeanContext#BEAN_debug} setting value for this session.
116    */
117   public final boolean isDebug() {
118      return debug;
119   }
120
121   /**
122    * Bean property getter:  <property>ignoreUnknownBeanProperties</property>.
123    * 
124    * <p>
125    * See {@link BeanContext#BEAN_ignoreUnknownBeanProperties}.
126    * 
127    * @return The value of the <property>ignoreUnknownBeanProperties</property> property on this bean.
128    */
129   public final boolean isIgnoreUnknownBeanProperties() {
130      return ctx.ignoreUnknownBeanProperties;
131   }
132
133   /**
134    * Converts the specified value to the specified class type.
135    * 
136    * <p>
137    * See {@link #convertToType(Object, ClassMeta)} for the list of valid conversions.
138    * 
139    * @param <T> The class type to convert the value to.
140    * @param value The value to convert.
141    * @param type The class type to convert the value to.
142    * @throws InvalidDataConversionException If the specified value cannot be converted to the specified type.
143    * @return The converted value.
144    */
145   public final <T> T convertToType(Object value, Class<T> type) throws InvalidDataConversionException {
146      // Shortcut for most common case.
147      if (value != null && value.getClass() == type)
148         return (T)value;
149      return convertToMemberType(null, value, ctx.getClassMeta(type));
150   }
151
152   /**
153    * Same as {@link #convertToType(Object, Class)}, except used for instantiating inner member classes that must
154    * be instantiated within another class instance.
155    * 
156    * @param <T> The class type to convert the value to.
157    * @param outer
158    *    If class is a member class, this is the instance of the containing class.
159    *    Should be <jk>null</jk> if not a member class.
160    * @param value The value to convert.
161    * @param type The class type to convert the value to.
162    * @throws InvalidDataConversionException If the specified value cannot be converted to the specified type.
163    * @return The converted value.
164    */
165   public final <T> T convertToMemberType(Object outer, Object value, Class<T> type) throws InvalidDataConversionException {
166      return convertToMemberType(outer, value, ctx.getClassMeta(type));
167   }
168
169   /**
170    * Casts the specified value into the specified type.
171    * 
172    * <p>
173    * If the value isn't an instance of the specified type, then converts the value if possible.
174    * 
175    * <p>
176    * The following conversions are valid:
177    * <table class='styled'>
178    *    <tr><th>Convert to type</th><th>Valid input value types</th><th>Notes</th></tr>
179    *    <tr>
180    *       <td>
181    *          A class that is the normal type of a registered {@link PojoSwap}.
182    *       </td>
183    *       <td>
184    *          A value whose class matches the transformed type of that registered {@link PojoSwap}.
185    *       </td>
186    *       <td>&nbsp;</td>
187    *    </tr>
188    *    <tr>
189    *       <td>
190    *          A class that is the transformed type of a registered {@link PojoSwap}.
191    *       </td>
192    *       <td>
193    *          A value whose class matches the normal type of that registered {@link PojoSwap}.
194    *       </td>
195    *       <td>&nbsp;</td>
196    *    </tr>
197    *    <tr>
198    *       <td>
199    *          {@code Number} (e.g. {@code Integer}, {@code Short}, {@code Float},...)
200    *          <br><code>Number.<jsf>TYPE</jsf></code> (e.g. <code>Integer.<jsf>TYPE</jsf></code>,
201    *          <code>Short.<jsf>TYPE</jsf></code>, <code>Float.<jsf>TYPE</jsf></code>,...)
202    *       </td>
203    *       <td>
204    *          {@code Number}, {@code String}, <jk>null</jk>
205    *       </td>
206    *       <td>
207    *          For primitive {@code TYPES}, <jk>null</jk> returns the JVM default value for that type.
208    *       </td>
209    *    </tr>
210    *    <tr>
211    *       <td>
212    *          {@code Map} (e.g. {@code Map}, {@code HashMap}, {@code TreeMap}, {@code ObjectMap})
213    *       </td>
214    *       <td>
215    *          {@code Map}
216    *       </td>
217    *       <td>
218    *          If {@code Map} is not constructible, a {@code ObjectMap} is created.
219    *       </td>
220    *    </tr>
221    *    <tr>
222    *       <td>
223    *       {@code Collection} (e.g. {@code List}, {@code LinkedList}, {@code HashSet}, {@code ObjectList})
224    *       </td>
225    *       <td>
226    *          {@code Collection<Object>}
227    *          <br>{@code Object[]}
228    *       </td>
229    *       <td>
230    *          If {@code Collection} is not constructible, a {@code ObjectList} is created.
231    *       </td>
232    *    </tr>
233    *    <tr>
234    *       <td>
235    *          {@code X[]} (array of any type X)
236    *       </td>
237    *       <td>
238    *          {@code List<X>}
239    *       </td>
240    *       <td>&nbsp;</td>
241    *    </tr>
242    *    <tr>
243    *       <td>
244    *          {@code X[][]} (multi-dimensional arrays)
245    *       </td>
246    *       <td>
247    *          {@code List<List<X>>}
248    *          <br>{@code List<X[]>}
249    *          <br>{@code List[]<X>}
250    *       </td>
251    *       <td>&nbsp;</td>
252    *    </tr>
253    *    <tr>
254    *       <td>
255    *          {@code Enum}
256    *       </td>
257    *       <td>
258    *          {@code String}
259    *       </td>
260    *       <td>&nbsp;</td>
261    *    </tr>
262    *    <tr>
263    *       <td>
264    *          Bean
265    *       </td>
266    *       <td>
267    *          {@code Map}
268    *       </td>
269    *       <td>&nbsp;</td>
270    *    </tr>
271    *    <tr>
272    *       <td>
273    *          {@code String}
274    *       </td>
275    *       <td>
276    *          Anything
277    *       </td>
278    *       <td>
279    *          Arrays are converted to JSON arrays
280    *       </td>
281    *    </tr>
282    *    <tr>
283    *       <td>
284    *          Anything with one of the following methods:
285    *          <br><code><jk>public static</jk> T fromString(String)</code>
286    *          <br><code><jk>public static</jk> T valueOf(String)</code>
287    *          <br><code><jk>public</jk> T(String)</code>
288    *       </td>
289    *       <td>
290    *          <code>String</code>
291    *       </td>
292    *       <td>
293    *          <br>
294    *       </td>
295    *    </tr>
296    * </table>
297    * 
298    * @param <T> The class type to convert the value to.
299    * @param value The value to be converted.
300    * @param type The target object type.
301    * @return The converted type.
302    * @throws InvalidDataConversionException If the specified value cannot be converted to the specified type.
303    */
304   public final <T> T convertToType(Object value, ClassMeta<T> type) throws InvalidDataConversionException {
305      return convertToMemberType(null, value, type);
306   }
307
308   /**
309    * Same as {@link #convertToType(Object, Class)}, but allows for complex data types consisting of collections or maps.
310    * 
311    * @param <T> The class type to convert the value to.
312    * @param value The value to be converted.
313    * @param type The target object type.
314    * @param args The target object parameter types.
315    * @return The converted type.
316    * @throws InvalidDataConversionException If the specified value cannot be converted to the specified type.
317    */
318   public final <T> T convertToType(Object value, Type type, Type...args) throws InvalidDataConversionException {
319      return (T)convertToMemberType(null, value, getClassMeta(type, args));
320   }
321
322   /**
323    * Same as {@link #convertToType(Object, ClassMeta)}, except used for instantiating inner member classes that must
324    * be instantiated within another class instance.
325    * 
326    * @param <T> The class type to convert the value to.
327    * @param outer
328    *    If class is a member class, this is the instance of the containing class.
329    *    Should be <jk>null</jk> if not a member class.
330    * @param value The value to convert.
331    * @param type The class type to convert the value to.
332    * @throws InvalidDataConversionException If the specified value cannot be converted to the specified type.
333    * @return The converted value.
334    */
335   public final <T> T convertToMemberType(Object outer, Object value, ClassMeta<T> type) throws InvalidDataConversionException {
336      if (type == null)
337         type = (ClassMeta<T>)ctx.object();
338
339      try {
340         // Handle the case of a null value.
341         if (value == null) {
342
343            // If it's a primitive, then use the converters to get the default value for the primitive type.
344            if (type.isPrimitive())
345               return type.getPrimitiveDefault();
346
347            // Otherwise, just return null.
348            return null;
349         }
350
351         Class<T> tc = type.getInnerClass();
352
353         // If no conversion needed, then just return the value.
354         // Don't include maps or collections, because child elements may need conversion.
355         if (tc.isInstance(value))
356            if (! ((type.isMap() && type.getValueType().isNotObject()) || (type.isCollection() && type.getElementType().isNotObject())))
357               return (T)value;
358
359         PojoSwap swap = type.getPojoSwap(this);
360         if (swap != null) {
361            Class<?> nc = swap.getNormalClass(), fc = swap.getSwapClass();
362            if (isParentClass(nc, tc) && isParentClass(fc, value.getClass()))
363               return (T)swap.unswap(this, value, type);
364         }
365
366         ClassMeta<?> vt = ctx.getClassMetaForObject(value);
367         swap = vt.getPojoSwap(this);
368         if (swap != null) {
369            Class<?> nc = swap.getNormalClass(), fc = swap.getSwapClass();
370            if (isParentClass(nc, vt.getInnerClass()) && isParentClass(fc, tc))
371               return (T)swap.swap(this, value);
372         }
373
374         if (type.isPrimitive()) {
375            if (value.toString().isEmpty())
376               return type.getPrimitiveDefault();
377
378            if (type.isNumber()) {
379               if (value instanceof Number) {
380                  Number n = (Number)value;
381                  if (tc == Integer.TYPE)
382                     return (T)Integer.valueOf(n.intValue());
383                  if (tc == Short.TYPE)
384                     return (T)Short.valueOf(n.shortValue());
385                  if (tc == Long.TYPE)
386                     return (T)Long.valueOf(n.longValue());
387                  if (tc == Float.TYPE)
388                     return (T)Float.valueOf(n.floatValue());
389                  if (tc == Double.TYPE)
390                     return (T)Double.valueOf(n.doubleValue());
391                  if (tc == Byte.TYPE)
392                     return (T)Byte.valueOf(n.byteValue());
393               } else {
394                  String n = null;
395                  if (value instanceof Boolean)
396                     n = ((Boolean)value).booleanValue() ? "1" : "0";
397                  else
398                     n = value.toString();
399
400                  int multiplier = (tc == Integer.TYPE || tc == Short.TYPE || tc == Long.TYPE) ? getMultiplier(n) : 1;
401                  if (multiplier != 1) {
402                     n = n.substring(0, n.length()-1).trim();
403                     Long l = Long.valueOf(n) * multiplier;
404                     if (tc == Integer.TYPE)
405                        return (T)Integer.valueOf(l.intValue());
406                     if (tc == Short.TYPE)
407                        return (T)Short.valueOf(l.shortValue());
408                     if (tc == Long.TYPE)
409                        return (T)Long.valueOf(l.longValue());
410                  } else {
411                     if (tc == Integer.TYPE)
412                        return (T)Integer.valueOf(n);
413                     if (tc == Short.TYPE)
414                        return (T)Short.valueOf(n);
415                     if (tc == Long.TYPE)
416                        return (T)Long.valueOf(n);
417                     if (tc == Float.TYPE)
418                        return (T)new Float(n);
419                     if (tc == Double.TYPE)
420                        return (T)new Double(n);
421                     if (tc == Byte.TYPE)
422                        return (T)Byte.valueOf(n);
423                  }
424               }
425            } else if (type.isChar()) {
426               String s = value.toString();
427               return (T)Character.valueOf(s.length() == 0 ? 0 : s.charAt(0));
428            } else if (type.isBoolean()) {
429               if (value instanceof Number) {
430                  int i = ((Number)value).intValue();
431                  return (T)(i == 0 ? Boolean.FALSE : Boolean.TRUE);
432               }
433               return (T)Boolean.valueOf(value.toString());
434            }
435         }
436
437         if (type.isNumber()) {
438            if (value instanceof Number) {
439               Number n = (Number)value;
440               if (tc == Integer.class)
441                  return (T)Integer.valueOf(n.intValue());
442               if (tc == Short.class)
443                  return (T)Short.valueOf(n.shortValue());
444               if (tc == Long.class)
445                  return (T)Long.valueOf(n.longValue());
446               if (tc == Float.class)
447                  return (T)Float.valueOf(n.floatValue());
448               if (tc == Double.class)
449                  return (T)Double.valueOf(n.doubleValue());
450               if (tc == Byte.class)
451                  return (T)Byte.valueOf(n.byteValue());
452               if (tc == Byte.class)
453                  return (T)Byte.valueOf(n.byteValue());
454               if (tc == AtomicInteger.class)
455                  return (T)new AtomicInteger(n.intValue());
456               if (tc == AtomicLong.class)
457                  return (T)new AtomicLong(n.intValue());
458            } else {
459               if (value.toString().isEmpty())
460                  return null;
461               String n = null;
462               if (value instanceof Boolean)
463                  n = ((Boolean)value).booleanValue() ? "1" : "0";
464               else
465                  n = value.toString();
466
467               int multiplier = (tc == Integer.class || tc == Short.class || tc == Long.class) ? getMultiplier(n) : 1;
468               if (multiplier != 1) {
469                  n = n.substring(0, n.length()-1).trim();
470                  Long l = Long.valueOf(n) * multiplier;
471                  if (tc == Integer.TYPE)
472                     return (T)Integer.valueOf(l.intValue());
473                  if (tc == Short.TYPE)
474                     return (T)Short.valueOf(l.shortValue());
475                  if (tc == Long.TYPE)
476                     return (T)Long.valueOf(l.longValue());
477               } else {
478                  if (tc == Integer.class)
479                     return (T)Integer.valueOf(n);
480                  if (tc == Short.class)
481                     return (T)Short.valueOf(n);
482                  if (tc == Long.class)
483                     return (T)Long.valueOf(n);
484                  if (tc == Float.class)
485                     return (T)new Float(n);
486                  if (tc == Double.class)
487                     return (T)new Double(n);
488                  if (tc == Byte.class)
489                     return (T)Byte.valueOf(n);
490                  if (tc == AtomicInteger.class)
491                     return (T)new AtomicInteger(Integer.valueOf(n));
492                  if (tc == AtomicLong.class)
493                     return (T)new AtomicLong(Long.valueOf(n));
494               }
495            }
496         }
497
498         if (type.isChar()) {
499            String s = value.toString();
500            return (T)Character.valueOf(s.length() == 0 ? 0 : s.charAt(0));
501         }
502
503         // Handle setting of array properties
504         if (type.isArray()) {
505            if (vt.isCollection())
506               return (T)toArray(type, (Collection)value);
507            else if (vt.isArray())
508               return (T)toArray(type, Arrays.asList((Object[])value));
509            else if (startsWith(value.toString(), '['))
510               return (T)toArray(type, new ObjectList(value.toString()).setBeanSession(this));
511            else
512               return (T)toArray(type, new ObjectList((Object[])StringUtils.split(value.toString())).setBeanSession(this));
513         }
514
515         // Target type is some sort of Map that needs to be converted.
516         if (type.isMap()) {
517            try {
518               if (value instanceof Map) {
519                  Map m = type.canCreateNewInstance(outer) ? (Map)type.newInstance(outer) : new ObjectMap(this);
520                  ClassMeta keyType = type.getKeyType(), valueType = type.getValueType();
521                  for (Map.Entry e : (Set<Map.Entry>)((Map)value).entrySet()) {
522                     Object k = e.getKey();
523                     if (keyType.isNotObject()) {
524                        if (keyType.isString() && k.getClass() != Class.class)
525                           k = k.toString();
526                        else
527                           k = convertToMemberType(m, k, keyType);
528                     }
529                     Object v = e.getValue();
530                     if (valueType.isNotObject())
531                        v = convertToMemberType(m, v, valueType);
532                     m.put(k, v);
533                  }
534                  return (T)m;
535               } else if (!type.canCreateNewInstanceFromString(outer)) {
536                  ObjectMap m = new ObjectMap(value.toString());
537                  return convertToMemberType(outer, m, type);
538               }
539            } catch (Exception e) {
540               throw new InvalidDataConversionException(value.getClass(), type, e);
541            }
542         }
543
544         // Target type is some sort of Collection
545         if (type.isCollection()) {
546            try {
547               Collection l = type.canCreateNewInstance(outer) ? (Collection)type.newInstance(outer) : new ObjectList(this);
548               ClassMeta elementType = type.getElementType();
549
550               if (value.getClass().isArray())
551                  for (Object o : (Object[])value)
552                     l.add(elementType.isObject() ? o : convertToMemberType(l, o, elementType));
553               else if (value instanceof Collection)
554                  for (Object o : (Collection)value)
555                     l.add(elementType.isObject() ? o : convertToMemberType(l, o, elementType));
556               else if (value instanceof Map)
557                  l.add(elementType.isObject() ? value : convertToMemberType(l, value, elementType));
558               else if (! value.toString().isEmpty())
559                  throw new InvalidDataConversionException(value.getClass(), type, null);
560               return (T)l;
561            } catch (InvalidDataConversionException e) {
562               throw e;
563            } catch (Exception e) {
564               throw new InvalidDataConversionException(value.getClass(), type, e);
565            }
566         }
567
568         if (type.isEnum()) {
569            if (type.canCreateNewInstanceFromString(outer))
570               return type.newInstanceFromString(outer, value.toString());
571            return (T)Enum.valueOf((Class<? extends Enum>)tc, value.toString());
572         }
573
574         if (type.isString()) {
575            if (vt.isMapOrBean() || vt.isCollectionOrArray()) {
576               if (JsonSerializer.DEFAULT_LAX != null)
577                  return (T)JsonSerializer.DEFAULT_LAX.serialize(value);
578            } else if (vt.isClass()) {
579               return (T)((Class<?>)value).getName();
580            }
581            return (T)value.toString();
582         }
583
584         if (type.isCharSequence()) {
585            Class<?> c = value.getClass();
586            if (c.isArray()) {
587               if (c.getComponentType().isPrimitive()) {
588                  ObjectList l = new ObjectList(this);
589                  int size = Array.getLength(value);
590                  for (int i = 0; i < size; i++)
591                     l.add(Array.get(value, i));
592                  value = l;
593               }
594               value = new ObjectList((Object[])value).setBeanSession(this);
595            }
596
597            return type.newInstanceFromString(outer, value.toString());
598         }
599
600         if (type.isBoolean()) {
601            if (value instanceof Number)
602               return (T)(Boolean.valueOf(((Number)value).intValue() != 0));
603            return (T)Boolean.valueOf(value.toString());
604         }
605
606         // It's a bean being initialized with a Map
607         if (type.isBean() && value instanceof Map) {
608            if (value instanceof ObjectMap) {
609               ObjectMap m2 = (ObjectMap)value;
610               String typeName = m2.getString(getBeanTypePropertyName(type));
611               if (typeName != null) {
612                  ClassMeta cm = type.getBeanRegistry().getClassMeta(typeName);
613                  if (cm != null && isParentClass(type.innerClass, cm.innerClass))
614                     return (T)m2.cast(cm);
615               }
616            }
617            return newBeanMap(tc).load((Map<?,?>) value).getBean();
618         }
619
620         if (type.canCreateNewInstanceFromNumber(outer) && value instanceof Number)
621            return type.newInstanceFromNumber(this, outer, (Number)value);
622
623         if (type.canCreateNewInstanceFromString(outer))
624            return type.newInstanceFromString(outer, value.toString());
625
626         if (type.isBean())
627            return newBeanMap(type.getInnerClass()).load(value.toString()).getBean();
628
629      } catch (Exception e) {
630         throw new InvalidDataConversionException(value, type, e);
631      }
632
633      throw new InvalidDataConversionException(value, type, null);
634   }
635
636   private static int getMultiplier(String s) {
637      if (s.endsWith("G"))
638         return 1024*1024*1024;
639      if (s.endsWith("M"))
640         return 1024*1024;
641      if (s.endsWith("K"))
642         return 1024;
643      return 1;
644   }
645
646   /**
647    * Converts the contents of the specified list into an array.
648    * 
649    * <p>
650    * Works on both object and primitive arrays.
651    * 
652    * <p>
653    * In the case of multi-dimensional arrays, the incoming list must contain elements of type n-1 dimension.
654    * i.e. if {@code type} is <code><jk>int</jk>[][]</code> then {@code list} must have entries of type
655    * <code><jk>int</jk>[]</code>.
656    * 
657    * @param type The type to convert to.  Must be an array type.
658    * @param list The contents to populate the array with.
659    * @return A new object or primitive array.
660    */
661   public final Object toArray(ClassMeta<?> type, Collection<?> list) {
662      if (list == null)
663         return null;
664      ClassMeta<?> componentType = type.isArgs() ? object() : type.getElementType();
665      Object array = Array.newInstance(componentType.getInnerClass(), list.size());
666      int i = 0;
667      for (Object o : list) {
668         if (! type.getInnerClass().isInstance(o)) {
669            if (componentType.isArray() && o instanceof Collection)
670               o = toArray(componentType, (Collection<?>)o);
671            else if (o == null && componentType.isPrimitive())
672               o = componentType.getPrimitiveDefault();
673            else
674               o = convertToType(o, componentType);
675         }
676         try {
677            Array.set(array, i++, o);
678         } catch (IllegalArgumentException e) {
679            e.printStackTrace();
680            throw e;
681         }
682      }
683      return array;
684   }
685
686   /**
687    * Wraps an object inside a {@link BeanMap} object (i.e. a modifiable {@link Map}).
688    * 
689    * <p>
690    * If object is not a true bean, then throws a {@link BeanRuntimeException} with an explanation of why it's not a
691    * bean.
692    * 
693    * <h5 class='section'>Example:</h5>
694    * <p class='bcode'>
695    *    <jc>// Construct a bean map around a bean instance</jc>
696    *    BeanMap&lt;Person&gt; bm = BeanContext.<jsf>DEFAULT</jsf>.forBean(<jk>new</jk> Person());
697    * </p>
698    * 
699    * @param <T> The class of the object being wrapped.
700    * @param o The object to wrap in a map interface.  Must not be null.
701    * @return The wrapped object.
702    */
703   public final <T> BeanMap<T> toBeanMap(T o) {
704      return this.toBeanMap(o, (Class<T>)o.getClass());
705   }
706
707   /**
708    * Determines whether the specified object matches the requirements on this context of being a bean.
709    * 
710    * @param o The object being tested.
711    * @return <jk>true</jk> if the specified object is considered a bean.
712    */
713   public final boolean isBean(Object o) {
714      if (o == null)
715         return false;
716      return isBean(o.getClass());
717   }
718
719   /**
720    * Determines whether the specified class matches the requirements on this context of being a bean.
721    * 
722    * @param c The class being tested.
723    * @return <jk>true</jk> if the specified class is considered a bean.
724    */
725   public final boolean isBean(Class<?> c) {
726      return getBeanMeta(c) != null;
727   }
728
729   /**
730    * Wraps an object inside a {@link BeanMap} object (i.e.: a modifiable {@link Map}) defined as a bean for one of its
731    * class, a super class, or an implemented interface.
732    * 
733    * <p>
734    * If object is not a true bean, throws a {@link BeanRuntimeException} with an explanation of why it's not a bean.
735    * 
736    * <h5 class='section'>Example:</h5>
737    * <p class='bcode'>
738    *    <jc>// Construct a bean map for new bean using only properties defined in a superclass</jc>
739    *    BeanMap&lt;MySubBean&gt; bm = BeanContext.<jsf>DEFAULT</jsf>.forBean(<jk>new</jk> MySubBean(), MySuperBean.<jk>class</jk>);
740    * 
741    *    <jc>// Construct a bean map for new bean using only properties defined in an interface</jc>
742    *    BeanMap&lt;MySubBean&gt; bm = BeanContext.<jsf>DEFAULT</jsf>.forBean(<jk>new</jk> MySubBean(), MySuperInterface.<jk>class</jk>);
743    * </p>
744    * 
745    * @param <T> The class of the object being wrapped.
746    * @param o The object to wrap in a bean interface.  Must not be null.
747    * @param c The superclass to narrow the bean properties to.  Must not be null.
748    * @return The bean representation, or <jk>null</jk> if the object is not a true bean.
749    * @throws NullPointerException If either parameter is null.
750    * @throws IllegalArgumentException If the specified object is not an an instance of the specified class.
751    * @throws
752    *    BeanRuntimeException If specified object is not a bean according to the bean rules specified in this context
753    * class.
754    */
755   public final <T> BeanMap<T> toBeanMap(T o, Class<? super T> c) throws BeanRuntimeException {
756      assertFieldNotNull(o, "o");
757      assertFieldNotNull(c, "c");
758
759      if (! c.isInstance(o))
760         illegalArg("The specified object is not an instance of the specified class.  class=''{0}'', objectClass=''{1}'', object=''{2}''", c.getName(), o.getClass().getName(), 0);
761
762      ClassMeta cm = getClassMeta(c);
763
764      BeanMeta m = cm.getBeanMeta();
765      if (m == null)
766         throw new BeanRuntimeException(c, "Class is not a bean.  Reason=''{0}''", cm.getNotABeanReason());
767      return new BeanMap<>(this, o, m);
768   }
769
770   /**
771    * Creates a new {@link BeanMap} object (i.e. a modifiable {@link Map}) of the given class with uninitialized
772    * property values.
773    * 
774    * <p>
775    * If object is not a true bean, then throws a {@link BeanRuntimeException} with an explanation of why it's not a
776    * bean.
777    * 
778    * <h5 class='section'>Example:</h5>
779    * <p class='bcode'>
780    *    <jc>// Construct a new bean map wrapped around a new Person object</jc>
781    *    BeanMap&lt;Person&gt; bm = BeanContext.<jsf>DEFAULT</jsf>.newBeanMap(Person.<jk>class</jk>);
782    * </p>
783    * 
784    * @param <T> The class of the object being wrapped.
785    * @param c The name of the class to create a new instance of.
786    * @return A new instance of the class.
787    */
788   public final <T> BeanMap<T> newBeanMap(Class<T> c) {
789      return newBeanMap(null, c);
790   }
791
792   /**
793    * Same as {@link #newBeanMap(Class)}, except used for instantiating inner member classes that must be instantiated
794    * within another class instance.
795    * 
796    * @param <T> The class of the object being wrapped.
797    * @param c The name of the class to create a new instance of.
798    * @param outer
799    *    If class is a member class, this is the instance of the containing class.
800    *    Should be <jk>null</jk> if not a member class.
801    * @return A new instance of the class.
802    */
803   public final <T> BeanMap<T> newBeanMap(Object outer, Class<T> c) {
804      BeanMeta m = getBeanMeta(c);
805      if (m == null)
806         return null;
807      T bean = null;
808      if (m.constructorArgs.length == 0)
809         bean = newBean(outer, c);
810      return new BeanMap<>(this, bean, m);
811   }
812
813   /**
814    * Creates a new empty bean of the specified type, except used for instantiating inner member classes that must
815    * be instantiated within another class instance.
816    * 
817    * <h5 class='section'>Example:</h5>
818    * <p class='bcode'>
819    *    <jc>// Construct a new instance of the specified bean class</jc>
820    *    Person p = BeanContext.<jsf>DEFAULT</jsf>.newBean(Person.<jk>class</jk>);
821    * </p>
822    * 
823    * @param <T> The class type of the bean being created.
824    * @param c The class type of the bean being created.
825    * @return A new bean object.
826    * @throws BeanRuntimeException If the specified class is not a valid bean.
827    */
828   public final <T> T newBean(Class<T> c) throws BeanRuntimeException {
829      return newBean(null, c);
830   }
831
832   /**
833    * Same as {@link #newBean(Class)}, except used for instantiating inner member classes that must be instantiated
834    * within another class instance.
835    * 
836    * @param <T> The class type of the bean being created.
837    * @param c The class type of the bean being created.
838    * @param outer
839    *    If class is a member class, this is the instance of the containing class.
840    *    Should be <jk>null</jk> if not a member class.
841    * @return A new bean object.
842    * @throws BeanRuntimeException If the specified class is not a valid bean.
843    */
844   public final <T> T newBean(Object outer, Class<T> c) throws BeanRuntimeException {
845      ClassMeta<T> cm = getClassMeta(c);
846      BeanMeta m = cm.getBeanMeta();
847      if (m == null)
848         return null;
849      try {
850         T o = (T)m.newBean(outer);
851         if (o == null)
852            throw new BeanRuntimeException(c, "Class does not have a no-arg constructor.");
853         return o;
854      } catch (BeanRuntimeException e) {
855         throw e;
856      } catch (Exception e) {
857         throw new BeanRuntimeException(e);
858      }
859   }
860
861   /**
862    * Returns the {@link BeanMeta} class for the specified class.
863    * 
864    * @param <T> The class type to get the meta-data on.
865    * @param c The class to get the meta-data on.
866    * @return
867    *    The {@link BeanMeta} for the specified class, or <jk>null</jk> if the class
868    *    is not a bean per the settings on this context.
869    */
870   public final <T> BeanMeta<T> getBeanMeta(Class<T> c) {
871      if (c == null)
872         return null;
873      return getClassMeta(c).getBeanMeta();
874   }
875
876   /**
877    * Returns a {@code ClassMeta} wrapper around a {@link Class} object.
878    * 
879    * @param <T> The class type being wrapped.
880    * @param c The class being wrapped.
881    * @return The class meta object containing information about the class.
882    */
883   public final <T> ClassMeta<T> getClassMeta(Class<T> c) {
884      return ctx.getClassMeta(c);
885   }
886
887   /**
888    * Used to resolve <code>ClassMetas</code> of type <code>Collection</code> and <code>Map</code> that have
889    * <code>ClassMeta</code> values that themselves could be collections or maps.
890    * 
891    * <p>
892    * <code>Collection</code> meta objects are assumed to be followed by zero or one meta objects indicating the
893    * element type.
894    * 
895    * <p>
896    * <code>Map</code> meta objects are assumed to be followed by zero or two meta objects indicating the key and value
897    * types.
898    * 
899    * <p>
900    * The array can be arbitrarily long to indicate arbitrarily complex data structures.
901    * 
902    * <h5 class='section'>Examples:</h5>
903    * <ul>
904    *    <li><code>getClassMeta(String.<jk>class</jk>);</code> - A normal type.
905    *    <li><code>getClassMeta(List.<jk>class</jk>);</code> - A list containing objects.
906    *    <li><code>getClassMeta(List.<jk>class</jk>, String.<jk>class</jk>);</code> - A list containing strings.
907    *    <li><code>getClassMeta(LinkedList.<jk>class</jk>, String.<jk>class</jk>);</code> - A linked-list containing
908    *       strings.
909    *    <li><code>getClassMeta(LinkedList.<jk>class</jk>, LinkedList.<jk>class</jk>, String.<jk>class</jk>);</code> -
910    *       A linked-list containing linked-lists of strings.
911    *    <li><code>getClassMeta(Map.<jk>class</jk>);</code> - A map containing object keys/values.
912    *    <li><code>getClassMeta(Map.<jk>class</jk>, String.<jk>class</jk>, String.<jk>class</jk>);</code> - A map
913    *       containing string keys/values.
914    *    <li><code>getClassMeta(Map.<jk>class</jk>, String.<jk>class</jk>, List.<jk>class</jk>, MyBean.<jk>class</jk>);</code> -
915    *       A map containing string keys and values of lists containing beans.
916    * </ul>
917    * 
918    * @param type
919    *    The class to resolve.
920    *    <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
921    * @param args
922    *    The type arguments of the class if it's a collection or map.
923    *    <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
924    *    <br>Ignored if the main type is not a map or collection.
925    * @return The class meta.
926    */
927   public final <T> ClassMeta<T> getClassMeta(Type type, Type...args) {
928      return ctx.getClassMeta(type, args);
929   }
930
931   /**
932    * Given an array of {@link Type} objects, returns a {@link ClassMeta} representing those arguments.
933    * 
934    * <p>
935    * Constructs a new meta on each call.
936    * 
937    * @param classes The array of classes to get class metas for.
938    * @return The args {@link ClassMeta} object corresponding to the classes.  Never <jk>null</jk>.
939    */
940   public final ClassMeta<Object[]> getArgsClassMeta(Type[] classes) {
941      assertFieldNotNull(classes, "classes");
942      ClassMeta[] cm = new ClassMeta<?>[classes.length];
943      for (int i = 0; i < classes.length; i++)
944         cm[i] = getClassMeta(classes[i]);
945      return new ClassMeta(cm);
946   }
947
948   /**
949    * Shortcut for calling {@code getClassMeta(o.getClass())}.
950    * 
951    * @param <T> The class of the object being passed in.
952    * @param o The class to find the class type for.
953    * @return The ClassMeta object, or <jk>null</jk> if {@code o} is <jk>null</jk>.
954    */
955   public final <T> ClassMeta<T> getClassMetaForObject(T o) {
956      if (o == null)
957         return null;
958      return (ClassMeta<T>)getClassMeta(o.getClass());
959   }
960
961   /**
962    * Returns the type property name as defined by {@link BeanContext#BEAN_beanTypePropertyName}.
963    * 
964    * @param cm
965    *    The class meta of the type we're trying to resolve the type name for.
966    *    Can be <jk>null</jk>.
967    * @return The type property name.  Never <jk>null</jk>.
968    */
969   public final String getBeanTypePropertyName(ClassMeta cm) {
970      String s = cm == null ? null : cm.getBeanTypePropertyName();
971      return s == null ? ctx.beanTypePropertyName : s;
972   }
973
974   /**
975    * Returns the bean registry defined in this bean context defined by {@link BeanContext#BEAN_beanDictionary}.
976    * 
977    * @return The bean registry defined in this bean context.  Never <jk>null</jk>.
978    */
979   public final BeanRegistry getBeanRegistry() {
980      return ctx.beanRegistry;
981   }
982   
983   /**
984    * Creates an instance of the specified class.
985    * 
986    * @param c 
987    *    The class to cast to.
988    * @param c2
989    *    The class to instantiate.
990    *    Can also be an instance of the class.
991    * @return 
992    *    The new class instance, or <jk>null</jk> if the class was <jk>null</jk> or is abstract or an interface.
993    * @throws 
994    *    RuntimeException if constructor could not be found or called.
995    */
996   public <T> T newInstance(Class<T> c, Object c2) {
997      return ctx.newInstance(c, c2);
998   }
999
1000   /**
1001    * Creates an instance of the specified class.
1002    * 
1003    * @param c 
1004    *    The class to cast to.
1005    * @param c2
1006    *    The class to instantiate.
1007    *    Can also be an instance of the class.
1008    * @param fuzzyArgs 
1009    *    Use fuzzy constructor arg matching.  
1010    *    <br>When <jk>true</jk>, constructor args can be in any order and extra args are ignored.
1011    *    <br>No-arg constructors are also used if no other constructors are found.
1012    * @param args 
1013    *    The arguments to pass to the constructor.
1014    * @return 
1015    *    The new class instance, or <jk>null</jk> if the class was <jk>null</jk> or is abstract or an interface.
1016    * @throws 
1017    *    RuntimeException if constructor could not be found or called.
1018    */
1019   public <T> T newInstance(Class<T> c, Object c2, boolean fuzzyArgs, Object...args) {
1020      return ctx.newInstance(c, c2, fuzzyArgs, args);
1021   }
1022
1023   /**
1024    * Creates an instance of the specified class from within the context of another object.
1025    * 
1026    * @param outer
1027    *    The outer object.
1028    *    Can be <jk>null</jk>.
1029    * @param c 
1030    *    The class to cast to.
1031    * @param c2
1032    *    The class to instantiate.
1033    *    Can also be an instance of the class.
1034    * @param fuzzyArgs 
1035    *    Use fuzzy constructor arg matching.  
1036    *    <br>When <jk>true</jk>, constructor args can be in any order and extra args are ignored.
1037    *    <br>No-arg constructors are also used if no other constructors are found.
1038    * @param args 
1039    *    The arguments to pass to the constructor.
1040    * @return 
1041    *    The new class instance, or <jk>null</jk> if the class was <jk>null</jk> or is abstract or an interface.
1042    * @throws 
1043    *    RuntimeException if constructor could not be found or called.
1044    */
1045   public <T> T newInstanceFromOuter(Object outer, Class<T> c, Object c2, boolean fuzzyArgs, Object...args) {
1046      return ctx.newInstanceFromOuter(outer, c, c2, fuzzyArgs, args);
1047   }
1048   
1049   /**
1050    * Creates a reusable {@link StringBuilder} object from an internal pool.
1051    * 
1052    * <p>
1053    * String builders are returned to the pool by calling {@link #returnStringBuilder(StringBuilder)}.
1054    * 
1055    * @return A new or previously returned string builder.
1056    */
1057   public final StringBuilder getStringBuilder() {
1058      if (sbStack.isEmpty())
1059         return new StringBuilder();
1060      return sbStack.pop();
1061   }
1062
1063   /**
1064    * Returns a {@link StringBuilder} object back into the internal reuse pool.
1065    * 
1066    * @param sb The string builder to return to the pool.  No-op if <jk>null</jk>.
1067    */
1068   public final void returnStringBuilder(StringBuilder sb) {
1069      if (sb == null)
1070         return;
1071      sb.setLength(0);
1072      sbStack.push(sb);
1073   }
1074
1075   /**
1076    * Returns a reusable {@link ClassMeta} representation for the class <code>Object</code>.
1077    * 
1078    * <p>
1079    * This <code>ClassMeta</code> is often used to represent "any object type" when an object type is not known.
1080    * 
1081    * <p>
1082    * This method is identical to calling <code>getClassMeta(Object.<jk>class</jk>)</code> but uses a cached copy to
1083    * avoid a hashmap lookup.
1084    * 
1085    * @return The {@link ClassMeta} object associated with the <code>Object</code> class.
1086    */
1087   public final ClassMeta<Object> object() {
1088      return ctx.cmObject;
1089   }
1090
1091   /**
1092    * Returns a reusable {@link ClassMeta} representation for the class <code>String</code>.
1093    * 
1094    * <p>
1095    * This <code>ClassMeta</code> is often used to represent key types in maps.
1096    * 
1097    * <p>
1098    * This method is identical to calling <code>getClassMeta(String.<jk>class</jk>)</code> but uses a cached copy to
1099    * avoid a hashmap lookup.
1100    * 
1101    * @return The {@link ClassMeta} object associated with the <code>String</code> class.
1102    */
1103   public final ClassMeta<String> string() {
1104      return ctx.cmString;
1105   }
1106
1107   /**
1108    * Returns a reusable {@link ClassMeta} representation for the class <code>Class</code>.
1109    * 
1110    * <p>
1111    * This <code>ClassMeta</code> is often used to represent key types in maps.
1112    * 
1113    * <p>
1114    * This method is identical to calling <code>getClassMeta(Class.<jk>class</jk>)</code> but uses a cached copy to
1115    * avoid a hashmap lookup.
1116    * 
1117    * @return The {@link ClassMeta} object associated with the <code>String</code> class.
1118    */
1119   public final ClassMeta<Class> _class() {
1120      return ctx.cmClass;
1121   }
1122
1123   /**
1124    * Returns the media type specified for this session.
1125    * 
1126    * <p>
1127    * For example, <js>"application/json"</js>.
1128    * 
1129    * @return The media type for this session, or <jk>null</jk> if not specified.
1130    */
1131   public final MediaType getMediaType() {
1132      return mediaType;
1133   }
1134
1135   @Override /* Session */
1136   public void checkForWarnings() {
1137      if (debug)
1138         super.checkForWarnings();
1139   }
1140}