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