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