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> </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> </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> </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> </td> 252 * </tr> 253 * <tr> 254 * <td> 255 * {@code Enum} 256 * </td> 257 * <td> 258 * {@code String} 259 * </td> 260 * <td> </td> 261 * </tr> 262 * <tr> 263 * <td> 264 * Bean 265 * </td> 266 * <td> 267 * {@code Map} 268 * </td> 269 * <td> </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<Person> 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<MySubBean> 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<MySubBean> 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<Person> 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}