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