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