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