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