001// *************************************************************************************************************************** 002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * 003// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * 004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * 005// * with the License. You may obtain a copy of the License at * 006// * * 007// * http://www.apache.org/licenses/LICENSE-2.0 * 008// * * 009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * 010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * 011// * specific language governing permissions and limitations under the License. * 012// *************************************************************************************************************************** 013package org.apache.juneau; 014 015import static org.apache.juneau.ClassMeta.ClassCategory.*; 016import static org.apache.juneau.common.internal.ThrowableUtils.*; 017import static org.apache.juneau.internal.CollectionUtils.*; 018import static org.apache.juneau.internal.ConsumerUtils.*; 019import static org.apache.juneau.internal.ObjectUtils.*; 020import static java.util.Arrays.*; 021 022import java.io.*; 023import java.lang.annotation.*; 024import java.lang.reflect.*; 025import java.lang.reflect.Proxy; 026import java.net.*; 027import java.net.URI; 028import java.time.temporal.*; 029import java.util.*; 030import java.util.Date; 031import java.util.concurrent.*; 032import java.util.function.*; 033 034import org.apache.juneau.annotation.*; 035import org.apache.juneau.cp.*; 036import org.apache.juneau.internal.*; 037import org.apache.juneau.json.*; 038import org.apache.juneau.reflect.*; 039import org.apache.juneau.swap.*; 040 041/** 042 * A wrapper class around the {@link Class} object that provides cached information about that class. 043 * 044 * <p> 045 * Instances of this class can be created through the {@link BeanContext#getClassMeta(Class)} method. 046 * 047 * <p> 048 * The {@link BeanContext} class will cache and reuse instances of this class except for the following class types: 049 * <ul> 050 * <li>Arrays 051 * <li>Maps with non-Object key/values. 052 * <li>Collections with non-Object key/values. 053 * </ul> 054 * 055 * <p> 056 * This class is tied to the {@link BeanContext} class because it's that class that makes the determination of what is 057 * a bean. 058 * 059 * <h5 class='section'>See Also:</h5><ul> 060 061 * </ul> 062 * 063 * @param <T> The class type of the wrapped class. 064 */ 065@Bean(properties="innerClass,classCategory,elementType,keyType,valueType,notABeanReason,initException,beanMeta") 066public final class ClassMeta<T> implements Type { 067 068 /** Class categories. */ 069 enum ClassCategory { 070 MAP, COLLECTION, CLASS, METHOD, NUMBER, DECIMAL, BOOLEAN, CHAR, DATE, ARRAY, ENUM, OTHER, CHARSEQ, STR, OBJ, URI, BEANMAP, READER, INPUTSTREAM, VOID, ARGS, OPTIONAL 071 } 072 073 final Class<T> innerClass; // The class being wrapped. 074 final ClassInfo info; 075 076 private final Class<? extends T> implClass; // The implementation class to use if this is an interface. 077 private final ClassCategory cc; // The class category. 078 private final Method fromStringMethod; // The static valueOf(String) or fromString(String) or forString(String) method (if it has one). 079 private final ConstructorInfo 080 noArgConstructor, // The no-arg constructor for this class (if it has one). 081 stringConstructor; // The X(String) constructor (if it has one). 082 private final Method 083 exampleMethod; // The example() or @Example-annotated method (if it has one). 084 private final Field 085 exampleField; // The @Example-annotated field (if it has one). 086 private final Setter 087 namePropertyMethod, // The method to set the name on an object (if it has one). 088 parentPropertyMethod; // The method to set the parent on an object (if it has one). 089 private final boolean 090 isDelegate, // True if this class extends Delegate. 091 isAbstract, // True if this class is abstract. 092 isMemberClass; // True if this is a non-static member class. 093 private final Object primitiveDefault; // Default value for primitive type classes. 094 private final Map<String,Method> 095 publicMethods; // All public methods, including static methods. 096 private final ObjectSwap<?,?>[] childSwaps; // Any ObjectSwaps where the normal type is a subclass of this class. 097 private final ConcurrentHashMap<Class<?>,ObjectSwap<?,?>> 098 childSwapMap, // Maps normal subclasses to ObjectSwaps. 099 childUnswapMap; // Maps swap subclasses to ObjectSwaps. 100 private final ObjectSwap<T,?>[] swaps; // The object POJO swaps associated with this bean (if it has any). 101 private final BuilderSwap<T,?> builderSwap; // The builder swap associated with this bean (if it has one). 102 private final BeanContext beanContext; // The bean context that created this object. 103 private final ClassMeta<?> 104 elementType, // If ARRAY or COLLECTION, the element class type. 105 keyType, // If MAP, the key class type. 106 valueType; // If MAP, the value class type. 107 private final BeanMeta<T> beanMeta; // The bean meta for this bean class (if it's a bean). 108 private final String 109 typePropertyName, // The property name of the _type property for this class and subclasses. 110 notABeanReason, // If this isn't a bean, the reason why. 111 dictionaryName; // The dictionary name of this class if it has one. 112 private final Throwable initException; // Any exceptions thrown in the init() method. 113 private final InvocationHandler invocationHandler; // The invocation handler for this class (if it has one). 114 private final BeanRegistry beanRegistry; // The bean registry of this class meta (if it has one). 115 private final ClassMeta<?>[] args; // Arg types if this is an array of args. 116 private final String example; // Example JSON. 117 private final Map<Class<?>,Mutater<?,T>> fromMutaters = new ConcurrentHashMap<>(); 118 private final Map<Class<?>,Mutater<T,?>> toMutaters = new ConcurrentHashMap<>(); 119 private final Mutater<String,T> stringMutater; 120 private final Map<Class<?>,Annotation[]> annotationArrayMap = new ConcurrentHashMap<>(); 121 private final Map<Class<?>,Optional<?>> annotationLastMap = new ConcurrentHashMap<>(); 122 private final Map<String,Optional<?>> properties = new ConcurrentHashMap<>(); 123 private final BiMap<Object,String> enumValues; 124 125 private final SimpleReadWriteLock lock = new SimpleReadWriteLock(false); 126 127 /** 128 * Construct a new {@code ClassMeta} based on the specified {@link Class}. 129 * 130 * @param innerClass The class being wrapped. 131 * @param beanContext The bean context that created this object. 132 * @param implClass 133 * For interfaces and abstract classes, this represents the "real" class to instantiate. 134 * Can be <jk>null</jk>. 135 * @param swaps 136 * The {@link ObjectSwap} programmatically associated with this class. 137 * Can be <jk>null</jk>. 138 * @param childSwaps 139 * The child {@link ObjectSwap ObjectSwaps} programmatically associated with this class. 140 * These are the <c>ObjectSwaps</c> that have normal classes that are subclasses of this class. 141 * Can be <jk>null</jk>. 142 * @param delayedInit 143 * Don't call init() in constructor. 144 * Used for delayed initialization when the possibility of class reference loops exist. 145 */ 146 @SuppressWarnings({ "rawtypes", "unchecked" }) 147 ClassMeta(Class<T> innerClass, BeanContext beanContext, ObjectSwap<T,?>[] swaps, ObjectSwap<?,?>[] childSwaps) { 148 this.innerClass = innerClass; 149 this.info = ClassInfo.of(innerClass); 150 this.beanContext = beanContext; 151 String notABeanReason = null; 152 153 try (SimpleLock x = lock.write()) { 154 // We always immediately add this class meta to the bean context cache so that we can resolve recursive references. 155 if (beanContext != null && beanContext.cmCache != null && isCacheable(innerClass)) 156 beanContext.cmCache.put(innerClass, this); 157 158 ClassMetaBuilder<T> builder = new ClassMetaBuilder(innerClass, beanContext, swaps, childSwaps); 159 160 this.cc = builder.cc; 161 this.isDelegate = builder.isDelegate; 162 this.fromStringMethod = builder.fromStringMethod; 163 this.parentPropertyMethod = builder.parentPropertyMethod; 164 this.namePropertyMethod = builder.namePropertyMethod; 165 this.noArgConstructor = builder.noArgConstructor; 166 this.stringConstructor = builder.stringConstructor; 167 this.primitiveDefault = builder.primitiveDefault; 168 this.publicMethods = builder.publicMethods; 169 this.swaps = builder.swaps.isEmpty() ? null : builder.swaps.toArray(new ObjectSwap[builder.swaps.size()]); 170 this.builderSwap = builder.builderSwap; 171 this.keyType = builder.keyType; 172 this.valueType = builder.valueType; 173 this.elementType = builder.elementType; 174 notABeanReason = builder.notABeanReason; 175 this.beanMeta = builder.beanMeta; 176 this.initException = builder.initException; 177 this.typePropertyName = builder.typePropertyName; 178 this.dictionaryName = builder.dictionaryName; 179 this.invocationHandler = builder.invocationHandler; 180 this.beanRegistry = builder.beanRegistry; 181 this.isMemberClass = builder.isMemberClass; 182 this.isAbstract = builder.isAbstract; 183 this.implClass = builder.implClass; 184 this.childUnswapMap = builder.childUnswapMap; 185 this.childSwapMap = builder.childSwapMap; 186 this.childSwaps = builder.childSwaps; 187 this.exampleMethod = builder.exampleMethod; 188 this.exampleField = builder.exampleField; 189 this.example = builder.example; 190 this.args = null; 191 this.stringMutater = builder.stringMutater; 192 this.enumValues = builder.enumValues == null ? null : builder.enumValues.build(); 193 } catch (ClassMetaRuntimeException e) { 194 notABeanReason = e.getMessage(); 195 throw e; 196 } finally { 197 this.notABeanReason = notABeanReason; 198 } 199 } 200 201 /** 202 * Generated classes shouldn't be cacheable to prevent needlessly filling up the cache. 203 */ 204 private static boolean isCacheable(Class<?> c) { 205 String n = c.getName(); 206 char x = n.charAt(n.length()-1); // All generated classes appear to end with digits. 207 if (x >= '0' && x <= '9') { 208 if (n.indexOf("$$") != -1 || n.startsWith("sun") || n.startsWith("com.sun") || n.indexOf("$Proxy") != -1) 209 return false; 210 } 211 return true; 212 } 213 214 /** 215 * Causes thread to wait until constructor has exited. 216 */ 217 void waitForInit() { 218 try (SimpleLock x = lock.read()) {} 219 } 220 221 /** 222 * Copy constructor. 223 * 224 * <p> 225 * Used for creating Map and Collection class metas that shouldn't be cached. 226 */ 227 ClassMeta(ClassMeta<T> mainType, ClassMeta<?> keyType, ClassMeta<?> valueType, ClassMeta<?> elementType) { 228 this.innerClass = mainType.innerClass; 229 this.info = mainType.info; 230 this.implClass = mainType.implClass; 231 this.childSwaps = mainType.childSwaps; 232 this.childSwapMap = mainType.childSwapMap; 233 this.childUnswapMap = mainType.childUnswapMap; 234 this.cc = mainType.cc; 235 this.fromStringMethod = mainType.fromStringMethod; 236 this.noArgConstructor = mainType.noArgConstructor; 237 this.stringConstructor = mainType.stringConstructor; 238 this.namePropertyMethod = mainType.namePropertyMethod; 239 this.parentPropertyMethod = mainType.parentPropertyMethod; 240 this.isDelegate = mainType.isDelegate; 241 this.isAbstract = mainType.isAbstract; 242 this.isMemberClass = mainType.isMemberClass; 243 this.primitiveDefault = mainType.primitiveDefault; 244 this.publicMethods = mainType.publicMethods; 245 this.beanContext = mainType.beanContext; 246 this.elementType = elementType; 247 this.keyType = keyType; 248 this.valueType = valueType; 249 this.invocationHandler = mainType.invocationHandler; 250 this.beanMeta = mainType.beanMeta; 251 this.typePropertyName = mainType.typePropertyName; 252 this.dictionaryName = mainType.dictionaryName; 253 this.notABeanReason = mainType.notABeanReason; 254 this.swaps = mainType.swaps; 255 this.builderSwap = mainType.builderSwap; 256 this.initException = mainType.initException; 257 this.beanRegistry = mainType.beanRegistry; 258 this.exampleMethod = mainType.exampleMethod; 259 this.exampleField = mainType.exampleField; 260 this.example = mainType.example; 261 this.args = null; 262 this.stringMutater = mainType.stringMutater; 263 this.enumValues = mainType.enumValues; 264 } 265 266 /** 267 * Constructor for args-arrays. 268 */ 269 @SuppressWarnings("unchecked") 270 ClassMeta(ClassMeta<?>[] args) { 271 this.innerClass = (Class<T>) Object[].class; 272 this.info = ClassInfo.of(innerClass); 273 this.args = args; 274 this.implClass = null; 275 this.childSwaps = null; 276 this.childSwapMap = null; 277 this.childUnswapMap = null; 278 this.cc = ARGS; 279 this.fromStringMethod = null; 280 this.noArgConstructor = null; 281 this.stringConstructor = null; 282 this.namePropertyMethod = null; 283 this.parentPropertyMethod = null; 284 this.isDelegate = false; 285 this.isAbstract = false; 286 this.isMemberClass = false; 287 this.primitiveDefault = null; 288 this.publicMethods = null; 289 this.beanContext = null; 290 this.elementType = null; 291 this.keyType = null; 292 this.valueType = null; 293 this.invocationHandler = null; 294 this.beanMeta = null; 295 this.typePropertyName = null; 296 this.dictionaryName = null; 297 this.notABeanReason = null; 298 this.swaps = null; 299 this.builderSwap = null; 300 this.initException = null; 301 this.beanRegistry = null; 302 this.exampleMethod = null; 303 this.exampleField = null; 304 this.example = null; 305 this.stringMutater = null; 306 this.enumValues = null; 307 } 308 309 @SuppressWarnings({"unchecked","rawtypes","hiding"}) 310 private final class ClassMetaBuilder<T> { 311 Class<T> innerClass; 312 ClassInfo ci; 313 Class<? extends T> implClass; 314 BeanContext beanContext; 315 ClassCategory cc = ClassCategory.OTHER; 316 boolean 317 isDelegate = false, 318 isMemberClass = false, 319 isAbstract = false; 320 Method 321 fromStringMethod = null; 322 Setter 323 parentPropertyMethod = null, 324 namePropertyMethod = null; 325 ConstructorInfo 326 noArgConstructor = null, 327 stringConstructor = null; 328 Object primitiveDefault = null; 329 Map<String,Method> 330 publicMethods = map(); 331 ClassMeta<?> 332 keyType = null, 333 valueType = null, 334 elementType = null; 335 String 336 typePropertyName = null, 337 notABeanReason = null, 338 dictionaryName = null; 339 Throwable initException = null; 340 BeanMeta beanMeta = null; 341 List<ObjectSwap> swaps = list(); 342 BuilderSwap builderSwap; 343 InvocationHandler invocationHandler = null; 344 BeanRegistry beanRegistry = null; 345 ObjectSwap<?,?>[] childSwaps; 346 ConcurrentHashMap<Class<?>,ObjectSwap<?,?>> 347 childSwapMap, 348 childUnswapMap; 349 Method exampleMethod; 350 Field exampleField; 351 String example; 352 Mutater<String,T> stringMutater; 353 BiMap.Builder<Object,String> enumValues; 354 355 ClassMetaBuilder(Class<T> innerClass, BeanContext beanContext, ObjectSwap<T,?>[] swaps, ObjectSwap<?,?>[] childSwaps) { 356 this.innerClass = innerClass; 357 this.beanContext = beanContext; 358 BeanContext bc = beanContext; 359 360 this.childSwaps = childSwaps; 361 if (childSwaps == null) { 362 this.childSwapMap = null; 363 this.childUnswapMap = null; 364 } else { 365 this.childSwapMap = new ConcurrentHashMap<>(); 366 this.childUnswapMap = new ConcurrentHashMap<>(); 367 } 368 369 Class<T> c = innerClass; 370 ci = ClassInfo.of(c); 371 372 if (c.isPrimitive()) { 373 if (c == Boolean.TYPE) 374 cc = BOOLEAN; 375 else if (c == Byte.TYPE || c == Short.TYPE || c == Integer.TYPE || c == Long.TYPE || c == Float.TYPE || c == Double.TYPE) { 376 if (c == Float.TYPE || c == Double.TYPE) 377 cc = DECIMAL; 378 else 379 cc = NUMBER; 380 } 381 else if (c == Character.TYPE) 382 cc = CHAR; 383 else if (c == void.class || c == Void.class) 384 cc = VOID; 385 } else { 386 if (ci.isChildOf(Delegate.class)) 387 isDelegate = true; 388 389 if (c == Object.class) 390 cc = OBJ; 391 else if (c.isEnum()) 392 cc = ENUM; 393 else if (c.equals(Class.class)) 394 cc = ClassCategory.CLASS; 395 else if (ci.isChildOf(Method.class)) 396 cc = METHOD; 397 else if (ci.isChildOf(CharSequence.class)) { 398 if (c.equals(String.class)) 399 cc = STR; 400 else 401 cc = CHARSEQ; 402 } 403 else if (ci.isChildOf(Number.class)) { 404 if (ci.isChildOfAny(Float.class, Double.class)) 405 cc = DECIMAL; 406 else 407 cc = NUMBER; 408 } 409 else if (ci.isChildOf(Collection.class)) 410 cc = COLLECTION; 411 else if (ci.isChildOf(Map.class)) { 412 if (ci.isChildOf(BeanMap.class)) 413 cc = BEANMAP; 414 else 415 cc = MAP; 416 } 417 else if (c == Character.class) 418 cc = CHAR; 419 else if (c == Boolean.class) 420 cc = BOOLEAN; 421 else if (ci.isChildOfAny(Date.class, Calendar.class)) 422 cc = DATE; 423 else if (c.isArray()) 424 cc = ARRAY; 425 else if (ci.isChildOfAny(URL.class, URI.class) || ci.hasAnnotation(bc, Uri.class)) 426 cc = URI; 427 else if (ci.isChildOf(Reader.class)) 428 cc = READER; 429 else if (ci.isChildOf(InputStream.class)) 430 cc = INPUTSTREAM; 431 else if (ci.is(Optional.class)) 432 cc = OPTIONAL; 433 } 434 435 isMemberClass = ci.isMemberClass() && ci.isNotStatic(); 436 437 // Find static fromString(String) or equivalent method. 438 // fromString() must be checked before valueOf() so that Enum classes can create their own 439 // specialized fromString() methods to override the behavior of Enum.valueOf(String). 440 // valueOf() is used by enums. 441 // parse() is used by the java logging Level class. 442 // forName() is used by Class and Charset 443 String[] fromStringMethodNames = {"fromString","fromValue","valueOf","parse","parseString","forName","forString"}; 444 fromStringMethod = optional( 445 ci.getPublicMethod( 446 x -> x.isStatic() 447 && x.isNotDeprecated() 448 && x.hasReturnType(c) 449 && x.hasParamTypes(String.class) 450 && ArrayUtils.contains(x.getName(), fromStringMethodNames)) 451 ).map(MethodInfo::inner) 452 .orElse(null); 453 454 // Find example() method if present. 455 exampleMethod = optional( 456 ci.getPublicMethod( 457 x -> x.isStatic() 458 && x.isNotDeprecated() 459 && x.hasName("example") 460 && x.hasFuzzyParamTypes(BeanSession.class)) 461 ).map(MethodInfo::inner) 462 .orElse(null); 463 464 ci.forEachAllField(x -> x.hasAnnotation(bc, ParentProperty.class), x -> { 465 if (x.isStatic()) 466 throw new ClassMetaRuntimeException(c, "@ParentProperty used on invalid field ''{0}''. Must be static.", x); 467 parentPropertyMethod = new Setter.FieldSetter(x.accessible().inner()); 468 }); 469 470 ci.forEachAllField(x -> x.hasAnnotation(bc, NameProperty.class), x -> { 471 if (x.isStatic()) 472 throw new ClassMetaRuntimeException(c, "@NameProperty used on invalid field ''{0}''. Must be static.", x); 473 namePropertyMethod = new Setter.FieldSetter(x.accessible().inner()); 474 }); 475 476 ci.forEachDeclaredField(x -> x.hasAnnotation(bc, Example.class), x -> { 477 if (! (x.isStatic() && ci.isParentOf(x.getType().inner()))) 478 throw new ClassMetaRuntimeException(c, "@Example used on invalid field ''{0}''. Must be static and an instance of the type.", x); 479 exampleField = x.accessible().inner(); 480 }); 481 482 // Find @NameProperty and @ParentProperty methods if present. 483 List<MethodInfo> methods = ci.getMethods(); 484 for (int i = methods.size()-1; i >=0; i--) { 485 MethodInfo m = methods.get(i); 486 if (m.hasAnnotation(bc, ParentProperty.class)) { 487 if (m.isStatic() || ! m.hasNumParams(1)) 488 throw new ClassMetaRuntimeException(c, "@ParentProperty used on invalid method ''{0}''. Must not be static and have one argument.", m); 489 m.setAccessible(); 490 parentPropertyMethod = new Setter.MethodSetter(m.inner()); 491 } 492 if (m.hasAnnotation(bc, NameProperty.class)) { 493 if (m.isStatic() || ! m.hasNumParams(1)) 494 throw new ClassMetaRuntimeException(c, "@NameProperty used on invalid method ''{0}''. Must not be static and have one argument.", m); 495 m.setAccessible(); 496 namePropertyMethod = new Setter.MethodSetter(m.inner()); 497 } 498 } 499 500 ci.forEachDeclaredMethod(m -> m.hasAnnotation(bc, Example.class), m -> { 501 if (! (m.isStatic() && m.hasFuzzyParamTypes(BeanSession.class) && ci.isParentOf(m.getReturnType().inner()))) 502 throw new ClassMetaRuntimeException(c, "@Example used on invalid method ''{0}''. Must be static and return an instance of the declaring class.", m.toString()); 503 m.setAccessible(); 504 exampleMethod = m.inner(); 505 }); 506 507 // Note: Primitive types are normally abstract. 508 isAbstract = ci.isAbstract() && ci.isNotPrimitive(); 509 510 // Find constructor(String) method if present. 511 ci.forEachPublicConstructor(cs -> cs.isPublic() && cs.isNotDeprecated(), cs -> { 512 List<ClassInfo> pt = cs.getParamTypes(); 513 if (pt.size() == (isMemberClass ? 1 : 0) && c != Object.class && ! isAbstract) { 514 noArgConstructor = cs; 515 } else if (pt.size() == (isMemberClass ? 2 : 1)) { 516 ClassInfo arg = pt.get(isMemberClass ? 1 : 0); 517 if (arg.is(String.class)) 518 stringConstructor = cs; 519 } 520 }); 521 522 primitiveDefault = ci.getPrimitiveDefault(); 523 524 ci.forEachPublicMethod( 525 MethodInfo::isNotDeprecated, 526 x -> publicMethods.put(x.getSignature(), x.inner()) 527 ); 528 529 BeanFilter beanFilter = findBeanFilter(bc); 530 MarshalledFilter marshalledFilter = findMarshalledFilter(bc); 531 532 addAll(this.swaps, swaps); 533 534 if (bc != null) 535 this.builderSwap = BuilderSwap.findSwapFromObjectClass(bc, c, bc.getBeanConstructorVisibility(), bc.getBeanMethodVisibility()); 536 537 findSwaps(this.swaps, bc); 538 539 if (beanFilter != null) { 540 example = beanFilter.getExample(); 541 implClass = (Class<? extends T>) beanFilter.getImplClass(); 542 } 543 544 if (marshalledFilter != null) { 545 if (example == null) 546 example = marshalledFilter.getExample(); 547 if (implClass == null) 548 implClass = (Class<? extends T>) marshalledFilter.getImplClass(); 549 } 550 551 if (innerClass != Object.class) { 552 ClassInfo x = implClass == null ? ci : ClassInfo.of(implClass); 553 noArgConstructor = x.getPublicConstructor(ConstructorInfo::hasNoParams); 554 } 555 556 try { 557 558 // If this is an array, get the element type. 559 if (cc == ARRAY) 560 elementType = findClassMeta(innerClass.getComponentType()); 561 562 // If this is a MAP, see if it's parameterized (e.g. AddressBook extends HashMap<String,Person>) 563 else if (cc == MAP) { 564 ClassMeta[] parameters = findParameters(); 565 if (parameters != null && parameters.length == 2) { 566 keyType = parameters[0]; 567 valueType = parameters[1]; 568 } else { 569 keyType = findClassMeta(Object.class); 570 valueType = findClassMeta(Object.class); 571 } 572 } 573 574 // If this is a COLLECTION, see if it's parameterized (e.g. AddressBook extends LinkedList<Person>) 575 else if (cc == COLLECTION || cc == OPTIONAL) { 576 ClassMeta[] parameters = findParameters(); 577 if (parameters != null && parameters.length == 1) { 578 elementType = parameters[0]; 579 } else { 580 elementType = findClassMeta(Object.class); 581 } 582 } 583 584 // If the category is unknown, see if it's a bean. 585 // Note that this needs to be done after all other initialization has been done. 586 else if (cc == OTHER) { 587 588 BeanMeta newMeta = null; 589 try { 590 newMeta = new BeanMeta(ClassMeta.this, bc, beanFilter, null, implClass == null ? null : noArgConstructor); 591 notABeanReason = newMeta.notABeanReason; 592 593 // Always get these even if it's not a bean: 594 beanRegistry = newMeta.beanRegistry; 595 typePropertyName = newMeta.typePropertyName; 596 597 } catch (RuntimeException e) { 598 notABeanReason = e.getMessage(); 599 throw e; 600 } 601 if (notABeanReason == null) 602 beanMeta = newMeta; 603 } 604 605 } catch (NoClassDefFoundError e) { 606 initException = e; 607 } catch (RuntimeException e) { 608 initException = e; 609 throw e; 610 } 611 612 if (beanMeta != null) 613 dictionaryName = beanMeta.getDictionaryName(); 614 615 if (beanMeta != null && bc != null && bc.isUseInterfaceProxies() && innerClass.isInterface()) 616 invocationHandler = new BeanProxyInvocationHandler<T>(beanMeta); 617 618 if (bc != null) { 619 bc.forEachAnnotation(Bean.class, c, x -> true, x -> { 620 if (x.dictionary().length != 0) 621 beanRegistry = new BeanRegistry(bc, null, x.dictionary()); 622 // This could be a non-bean POJO with a type name. 623 if (dictionaryName == null && ! x.typeName().isEmpty()) 624 dictionaryName = x.typeName(); 625 }); 626 } 627 628 if (example == null && bc != null) { 629 bc.forEachAnnotation(Example.class, c, x -> ! x.value().isEmpty(), x -> example = x.value()); 630 } 631 632 if (example == null) { 633 switch(cc) { 634 case BOOLEAN: 635 example = "true"; 636 break; 637 case CHAR: 638 example = "a"; 639 break; 640 case CHARSEQ: 641 case STR: 642 example = "foo"; 643 break; 644 case DECIMAL: 645 if (isFloat()) 646 example = "1.0"; 647 else if (isDouble()) 648 example = "1.0"; 649 break; 650 case ENUM: 651 Iterator<? extends Enum> i = EnumSet.allOf((Class<? extends Enum>)c).iterator(); 652 if (i.hasNext()) 653 example = beanContext.isUseEnumNames() ? i.next().name() : i.next().toString(); 654 break; 655 case NUMBER: 656 if (isShort()) 657 example = "1"; 658 else if (isInteger()) 659 example = "1"; 660 else if (isLong()) 661 example = "1"; 662 break; 663 case URI: 664 case ARGS: 665 case ARRAY: 666 case BEANMAP: 667 case CLASS: 668 case COLLECTION: 669 case DATE: 670 case INPUTSTREAM: 671 case MAP: 672 case METHOD: 673 case OBJ: 674 case OTHER: 675 case READER: 676 case OPTIONAL: 677 case VOID: 678 break; 679 } 680 } 681 682 this.stringMutater = Mutaters.get(String.class, c); 683 684 if (cc == ENUM) { 685 Class<? extends Enum> ec = (Class<? extends Enum<?>>)c; 686 boolean useEnumNames = bc != null && bc.isUseEnumNames(); 687 enumValues = BiMap.create(); 688 enumValues.unmodifiable(); 689 stream(ec.getEnumConstants()).forEach(x -> enumValues.add(x, useEnumNames ? x.name() : x.toString())); 690 } 691 } 692 693 private BeanFilter findBeanFilter(BeanContext bc) { 694 try { 695 List<Bean> ba = info.getAnnotations(bc, Bean.class); 696 if (! ba.isEmpty()) 697 return BeanFilter.create(innerClass).applyAnnotations(ba).build(); 698 } catch (Exception e) { 699 throw asRuntimeException(e); 700 } 701 return null; 702 } 703 704 private MarshalledFilter findMarshalledFilter(BeanContext bc) { 705 try { 706 List<Marshalled> ba = info.getAnnotations(bc, Marshalled.class); 707 if (! ba.isEmpty()) 708 return MarshalledFilter.create(innerClass).applyAnnotations(ba).build(); 709 } catch (Exception e) { 710 throw asRuntimeException(e); 711 } 712 return null; 713 } 714 715 private void findSwaps(List<ObjectSwap> l, BeanContext bc) { 716 717 if (bc != null) 718 bc.forEachAnnotation(Swap.class, innerClass, x -> true, x -> l.add(createSwap(x))); 719 720 ObjectSwap defaultSwap = DefaultSwaps.find(ci); 721 if (defaultSwap == null) 722 defaultSwap = AutoObjectSwap.find(bc, ci); 723 if (defaultSwap == null) 724 defaultSwap = AutoNumberSwap.find(bc, ci); 725 if (defaultSwap == null) 726 defaultSwap = AutoMapSwap.find(bc, ci); 727 if (defaultSwap == null) 728 defaultSwap = AutoListSwap.find(bc, ci); 729 if (defaultSwap != null) 730 l.add(defaultSwap); 731 } 732 733 private ObjectSwap<T,?> createSwap(Swap s) { 734 Class<?> c = s.value(); 735 if (ClassUtils.isVoid(c)) 736 c = s.impl(); 737 ClassInfo ci = ClassInfo.of(c); 738 739 if (ci.isChildOf(ObjectSwap.class)) { 740 ObjectSwap ps = BeanCreator.of(ObjectSwap.class).type(c).run(); 741 if (s.mediaTypes().length > 0) 742 ps.forMediaTypes(MediaType.ofAll(s.mediaTypes())); 743 if (! s.template().isEmpty()) 744 ps.withTemplate(s.template()); 745 return ps; 746 } 747 748 if (ci.isChildOf(Surrogate.class)) { 749 List<SurrogateSwap<?,?>> l = SurrogateSwap.findObjectSwaps(c, beanContext); 750 if (! l.isEmpty()) 751 return (ObjectSwap<T,?>)l.iterator().next(); 752 } 753 754 throw new ClassMetaRuntimeException(c, "Invalid swap class ''{0}'' specified. Must extend from ObjectSwap or Surrogate.", c); 755 } 756 757 private ClassMeta<?> findClassMeta(Class<?> c) { 758 return beanContext.getClassMeta(c, false); 759 } 760 761 private ClassMeta<?>[] findParameters() { 762 return beanContext.findParameters(innerClass, innerClass); 763 } 764 } 765 766 /** 767 * Returns the {@link ClassInfo} wrapper for the underlying class. 768 * 769 * @return The {@link ClassInfo} wrapper for the underlying class, never <jk>null</jk>. 770 */ 771 public ClassInfo getInfo() { 772 return info; 773 } 774 775 /** 776 * Returns the type property name associated with this class and subclasses. 777 * 778 * <p> 779 * If <jk>null</jk>, <js>"_type"</js> should be assumed. 780 * 781 * @return 782 * The type property name associated with this bean class, or <jk>null</jk> if there is no explicit type 783 * property name defined or this isn't a bean. 784 */ 785 public String getBeanTypePropertyName() { 786 return typePropertyName; 787 } 788 789 /** 790 * Returns the bean dictionary name associated with this class. 791 * 792 * <p> 793 * The lexical name is defined by {@link Bean#typeName() @Bean(typeName)}. 794 * 795 * @return 796 * The type name associated with this bean class, or <jk>null</jk> if there is no type name defined or this 797 * isn't a bean. 798 */ 799 public String getDictionaryName() { 800 return dictionaryName; 801 } 802 803 /** 804 * Returns the bean registry for this class. 805 * 806 * <p> 807 * This bean registry contains names specified in the {@link Bean#dictionary() @Bean(dictionary)} annotation 808 * defined on the class, regardless of whether the class is an actual bean. 809 * This allows interfaces to define subclasses with type names. 810 * 811 * @return The bean registry for this class, or <jk>null</jk> if no bean registry is associated with it. 812 */ 813 public BeanRegistry getBeanRegistry() { 814 return beanRegistry; 815 } 816 817 /** 818 * Returns the category of this class. 819 * 820 * @return The category of this class. 821 */ 822 public ClassCategory getClassCategory() { 823 return cc; 824 } 825 826 /** 827 * Returns <jk>true</jk> if this class is a superclass of or the same as the specified class. 828 * 829 * @param c The comparison class. 830 * @return <jk>true</jk> if this class is a superclass of or the same as the specified class. 831 */ 832 public boolean isAssignableFrom(Class<?> c) { 833 return info.isChildOf(c); 834 } 835 836 /** 837 * Returns <jk>true</jk> if this class is a subclass of or the same as the specified class. 838 * 839 * @param c The comparison class. 840 * @return <jk>true</jk> if this class is a subclass of or the same as the specified class. 841 */ 842 public boolean isInstanceOf(Class<?> c) { 843 return info.isParentOf(c); 844 } 845 846 /** 847 * Returns <jk>true</jk> if this class or any child classes has a {@link ObjectSwap} associated with it. 848 * 849 * <p> 850 * Used when transforming bean properties to prevent having to look up transforms if we know for certain that no 851 * transforms are associated with a bean property. 852 * 853 * @return <jk>true</jk> if this class or any child classes has a {@link ObjectSwap} associated with it. 854 */ 855 protected boolean hasChildSwaps() { 856 return childSwaps != null; 857 } 858 859 /** 860 * Returns the {@link ObjectSwap} where the specified class is the same/subclass of the normal class of one of the 861 * child POJO swaps associated with this class. 862 * 863 * @param normalClass The normal class being resolved. 864 * @return The resolved {@link ObjectSwap} or <jk>null</jk> if none were found. 865 */ 866 protected ObjectSwap<?,?> getChildObjectSwapForSwap(Class<?> normalClass) { 867 if (childSwapMap != null) { 868 ObjectSwap<?,?> s = childSwapMap.get(normalClass); 869 if (s == null) { 870 for (ObjectSwap<?,?> f : childSwaps) 871 if (s == null && f.getNormalClass().isParentOf(normalClass)) 872 s = f; 873 if (s == null) 874 s = ObjectSwap.NULL; 875 ObjectSwap<?,?> s2 = childSwapMap.putIfAbsent(normalClass, s); 876 if (s2 != null) 877 s = s2; 878 } 879 if (s == ObjectSwap.NULL) 880 return null; 881 return s; 882 } 883 return null; 884 } 885 886 /** 887 * Returns the {@link ObjectSwap} where the specified class is the same/subclass of the swap class of one of the child 888 * POJO swaps associated with this class. 889 * 890 * @param swapClass The swap class being resolved. 891 * @return The resolved {@link ObjectSwap} or <jk>null</jk> if none were found. 892 */ 893 protected ObjectSwap<?,?> getChildObjectSwapForUnswap(Class<?> swapClass) { 894 if (childUnswapMap != null) { 895 ObjectSwap<?,?> s = childUnswapMap.get(swapClass); 896 if (s == null) { 897 for (ObjectSwap<?,?> f : childSwaps) 898 if (s == null && f.getSwapClass().isParentOf(swapClass)) 899 s = f; 900 if (s == null) 901 s = ObjectSwap.NULL; 902 ObjectSwap<?,?> s2 = childUnswapMap.putIfAbsent(swapClass, s); 903 if (s2 != null) 904 s = s2; 905 } 906 if (s == ObjectSwap.NULL) 907 return null; 908 return s; 909 } 910 return null; 911 } 912 913 /** 914 * Locates the no-arg constructor for the specified class. 915 * 916 * <p> 917 * Constructor must match the visibility requirements specified by parameter 'v'. 918 * If class is abstract, always returns <jk>null</jk>. 919 * Note that this also returns the 1-arg constructor for non-static member classes. 920 * 921 * @param <T> The class from which to locate the no-arg constructor. 922 * @param c The class from which to locate the no-arg constructor. 923 * @param v The minimum visibility. 924 * @return The constructor, or <jk>null</jk> if no no-arg constructor exists with the required visibility. 925 */ 926 @SuppressWarnings({"unchecked"}) 927 protected static <T> Constructor<? extends T> findNoArgConstructor(Class<?> c, Visibility v) { 928 ClassInfo ci = ClassInfo.of(c); 929 if (ci.isAbstract()) 930 return null; 931 boolean isMemberClass = ci.isMemberClass() && ci.isNotStatic(); 932 ConstructorInfo cc = ci.getPublicConstructor( 933 x -> x.isVisible(v) 934 && x.isNotDeprecated() 935 && x.hasNumParams(isMemberClass ? 1 : 0) 936 ); 937 if (cc != null) 938 return (Constructor<? extends T>) v.transform(cc.inner()); 939 return null; 940 } 941 942 /** 943 * Returns the {@link Class} object that this class type wraps. 944 * 945 * @return The wrapped class object. 946 */ 947 public Class<T> getInnerClass() { 948 return innerClass; 949 } 950 951 /** 952 * Returns the serialized (swapped) form of this class if there is an {@link ObjectSwap} associated with it. 953 * 954 * @param session 955 * The bean session. 956 * <br>Required because the swap used may depend on the media type being serialized or parsed. 957 * @return The serialized class type, or this object if no swap is associated with the class. 958 */ 959 public ClassMeta<?> getSerializedClassMeta(BeanSession session) { 960 ObjectSwap<T,?> ps = getSwap(session); 961 return (ps == null ? this : ps.getSwapClassMeta(session)); 962 } 963 964 /** 965 * Returns the example of this class. 966 * 967 * @param session 968 * The bean session. 969 * <br>Required because the example method may take it in as a parameter. 970 * @param jpSession The JSON parser for parsing examples into POJOs. 971 * @return The serialized class type, or this object if no swap is associated with the class. 972 */ 973 @SuppressWarnings({"unchecked","rawtypes"}) 974 public T getExample(BeanSession session, JsonParserSession jpSession) { 975 try { 976 if (example != null) 977 return jpSession.parse(example, this); 978 if (exampleMethod != null) 979 return (T)MethodInfo.of(exampleMethod).invokeFuzzy(null, session); 980 if (exampleField != null) 981 return (T)exampleField.get(null); 982 983 if (isCollection()) { 984 Object etExample = getElementType().getExample(session, jpSession); 985 if (etExample != null) { 986 if (canCreateNewInstance()) { 987 Collection c = (Collection)newInstance(); 988 c.add(etExample); 989 return (T)c; 990 } 991 return (T)Collections.singleton(etExample); 992 } 993 } else if (isArray()) { 994 Object etExample = getElementType().getExample(session, jpSession); 995 if (etExample != null) { 996 Object o = Array.newInstance(getElementType().innerClass, 1); 997 Array.set(o, 0, etExample); 998 return (T)o; 999 } 1000 } else if (isMap()) { 1001 Object vtExample = getValueType().getExample(session, jpSession); 1002 Object ktExample = getKeyType().getExample(session, jpSession); 1003 if (ktExample != null && vtExample != null) { 1004 if (canCreateNewInstance()) { 1005 Map m = (Map)newInstance(); 1006 m.put(ktExample, vtExample); 1007 return (T)m; 1008 } 1009 return (T)Collections.singletonMap(ktExample, vtExample); 1010 } 1011 } 1012 1013 return null; 1014 } catch (Exception e) { 1015 throw new ClassMetaRuntimeException(e); 1016 } 1017 } 1018 1019 /** 1020 * For array and {@code Collection} types, returns the class type of the components of the array or 1021 * {@code Collection}. 1022 * 1023 * @return The element class type, or <jk>null</jk> if this class is not an array or Collection. 1024 */ 1025 public ClassMeta<?> getElementType() { 1026 return elementType; 1027 } 1028 1029 /** 1030 * For {@code Map} types, returns the class type of the keys of the {@code Map}. 1031 * 1032 * @return The key class type, or <jk>null</jk> if this class is not a Map. 1033 */ 1034 public ClassMeta<?> getKeyType() { 1035 return keyType; 1036 } 1037 1038 /** 1039 * For {@code Map} types, returns the class type of the values of the {@code Map}. 1040 * 1041 * @return The value class type, or <jk>null</jk> if this class is not a Map. 1042 */ 1043 public ClassMeta<?> getValueType() { 1044 return valueType; 1045 } 1046 1047 /** 1048 * Returns <jk>true</jk> if this class implements {@link Delegate}, meaning it's a representation of some other 1049 * object. 1050 * 1051 * @return <jk>true</jk> if this class implements {@link Delegate}. 1052 */ 1053 public boolean isDelegate() { 1054 return isDelegate; 1055 } 1056 1057 /** 1058 * Returns <jk>true</jk> if the specified class is an exact match for this metadata. 1059 * 1060 * @param value The value to check against. 1061 * @return <jk>true</jk> if the specified class is an exact match for this metadata. 1062 */ 1063 public boolean is(Class<?> value) { 1064 return eq(innerClass, value); 1065 } 1066 1067 /** 1068 * Returns <jk>true</jk> if this metadata represents the specified type. 1069 * 1070 * @param c The class to test against. 1071 * @return <jk>true</jk> if this metadata represents the specified type. 1072 */ 1073 public boolean isChildOf(Class<?> c) { 1074 return info.isChildOf(c); 1075 } 1076 1077 /** 1078 * Returns <jk>true</jk> if this class is a subclass of {@link Map}. 1079 * 1080 * @return <jk>true</jk> if this class is a subclass of {@link Map}. 1081 */ 1082 public boolean isMap() { 1083 return cc == MAP || cc == BEANMAP; 1084 } 1085 1086 /** 1087 * Returns <jk>true</jk> if this class is a subclass of {@link Map} or it's a bean. 1088 * 1089 * @return <jk>true</jk> if this class is a subclass of {@link Map} or it's a bean. 1090 */ 1091 public boolean isMapOrBean() { 1092 return cc == MAP || cc == BEANMAP || beanMeta != null; 1093 } 1094 1095 /** 1096 * Returns <jk>true</jk> if this class is a subclass of {@link BeanMap}. 1097 * 1098 * @return <jk>true</jk> if this class is a subclass of {@link BeanMap}. 1099 */ 1100 public boolean isBeanMap() { 1101 return cc == BEANMAP; 1102 } 1103 1104 /** 1105 * Returns <jk>true</jk> if this class is a subclass of {@link Collection}. 1106 * 1107 * @return <jk>true</jk> if this class is a subclass of {@link Collection}. 1108 */ 1109 public boolean isCollection() { 1110 return cc == COLLECTION; 1111 } 1112 1113 /** 1114 * Returns <jk>true</jk> if this class is a subclass of {@link Optional}. 1115 * 1116 * @return <jk>true</jk> if this class is a subclass of {@link Optional}. 1117 */ 1118 public boolean isOptional() { 1119 return cc == OPTIONAL; 1120 } 1121 1122 /** 1123 * Returns <jk>true</jk> if this class is a subclass of {@link Collection} or is an array. 1124 * 1125 * @return <jk>true</jk> if this class is a subclass of {@link Collection} or is an array. 1126 */ 1127 public boolean isCollectionOrArray() { 1128 return cc == COLLECTION || cc == ARRAY; 1129 } 1130 1131 /** 1132 * Returns <jk>true</jk> if this class is a subclass of {@link Collection} or is an array or {@link Optional}. 1133 * 1134 * @return <jk>true</jk> if this class is a subclass of {@link Collection} or is an array or {@link Optional}. 1135 */ 1136 public boolean isCollectionOrArrayOrOptional() { 1137 return cc == COLLECTION || cc == ARRAY || cc == OPTIONAL; 1138 } 1139 1140 /** 1141 * Returns <jk>true</jk> if this class extends from {@link Set}. 1142 * 1143 * @return <jk>true</jk> if this class extends from {@link Set}. 1144 */ 1145 public boolean isSet() { 1146 return cc == COLLECTION && info.isChildOf(Set.class); 1147 } 1148 1149 /** 1150 * Returns <jk>true</jk> if this class extends from {@link List}. 1151 * 1152 * @return <jk>true</jk> if this class extends from {@link List}. 1153 */ 1154 public boolean isList() { 1155 return cc == COLLECTION && info.isChildOf(List.class); 1156 } 1157 1158 /** 1159 * Returns <jk>true</jk> if this class is <code><jk>byte</jk>[]</code>. 1160 * 1161 * @return <jk>true</jk> if this class is <code><jk>byte</jk>[]</code>. 1162 */ 1163 public boolean isByteArray() { 1164 return cc == ARRAY && this.innerClass == byte[].class; 1165 } 1166 1167 /** 1168 * Returns <jk>true</jk> if this class is {@link Class}. 1169 * 1170 * @return <jk>true</jk> if this class is {@link Class}. 1171 */ 1172 public boolean isClass() { 1173 return cc == ClassCategory.CLASS; 1174 } 1175 1176 /** 1177 * Returns <jk>true</jk> if this class is {@link Method}. 1178 * 1179 * @return <jk>true</jk> if this class is {@link Method}. 1180 */ 1181 public boolean isMethod() { 1182 return cc == METHOD; 1183 } 1184 1185 /** 1186 * Returns <jk>true</jk> if this class is an {@link Enum}. 1187 * 1188 * @return <jk>true</jk> if this class is an {@link Enum}. 1189 */ 1190 public boolean isEnum() { 1191 return cc == ENUM; 1192 } 1193 1194 /** 1195 * Returns <jk>true</jk> if this class is an array. 1196 * 1197 * @return <jk>true</jk> if this class is an array. 1198 */ 1199 public boolean isArray() { 1200 return cc == ARRAY; 1201 } 1202 1203 /** 1204 * Returns <jk>true</jk> if this class is a bean. 1205 * 1206 * @return <jk>true</jk> if this class is a bean. 1207 */ 1208 public boolean isBean() { 1209 return beanMeta != null; 1210 } 1211 1212 /** 1213 * Returns <jk>true</jk> if this class is {@link Object}. 1214 * 1215 * @return <jk>true</jk> if this class is {@link Object}. 1216 */ 1217 public boolean isObject() { 1218 return cc == OBJ; 1219 } 1220 1221 /** 1222 * Returns <jk>true</jk> if this class is not {@link Object}. 1223 * 1224 * @return <jk>true</jk> if this class is not {@link Object}. 1225 */ 1226 public boolean isNotObject() { 1227 return cc != OBJ; 1228 } 1229 1230 /** 1231 * Returns <jk>true</jk> if this class is a subclass of {@link Number}. 1232 * 1233 * @return <jk>true</jk> if this class is a subclass of {@link Number}. 1234 */ 1235 public boolean isNumber() { 1236 return cc == NUMBER || cc == DECIMAL; 1237 } 1238 1239 /** 1240 * Returns <jk>true</jk> if this class is a subclass of {@link Float} or {@link Double}. 1241 * 1242 * @return <jk>true</jk> if this class is a subclass of {@link Float} or {@link Double}. 1243 */ 1244 public boolean isDecimal() { 1245 return cc == DECIMAL; 1246 } 1247 1248 /** 1249 * Returns <jk>true</jk> if this class is either {@link Float} or <jk>float</jk>. 1250 * 1251 * @return <jk>true</jk> if this class is either {@link Float} or <jk>float</jk>. 1252 */ 1253 public boolean isFloat() { 1254 return innerClass == Float.class || innerClass == float.class; 1255 } 1256 1257 /** 1258 * Returns <jk>true</jk> if this class is either {@link Double} or <jk>double</jk>. 1259 * 1260 * @return <jk>true</jk> if this class is either {@link Double} or <jk>double</jk>. 1261 */ 1262 public boolean isDouble() { 1263 return innerClass == Double.class || innerClass == double.class; 1264 } 1265 1266 /** 1267 * Returns <jk>true</jk> if this class is either {@link Short} or <jk>short</jk>. 1268 * 1269 * @return <jk>true</jk> if this class is either {@link Short} or <jk>short</jk>. 1270 */ 1271 public boolean isShort() { 1272 return innerClass == Short.class || innerClass == short.class; 1273 } 1274 1275 /** 1276 * Returns <jk>true</jk> if this class is either {@link Integer} or <jk>int</jk>. 1277 * 1278 * @return <jk>true</jk> if this class is either {@link Integer} or <jk>int</jk>. 1279 */ 1280 public boolean isInteger() { 1281 return innerClass == Integer.class || innerClass == int.class; 1282 } 1283 1284 /** 1285 * Returns <jk>true</jk> if this class is either {@link Long} or <jk>long</jk>. 1286 * 1287 * @return <jk>true</jk> if this class is either {@link Long} or <jk>long</jk>. 1288 */ 1289 public boolean isLong() { 1290 return innerClass == Long.class || innerClass == long.class; 1291 } 1292 1293 /** 1294 * Returns <jk>true</jk> if this class is a {@link Boolean}. 1295 * 1296 * @return <jk>true</jk> if this class is a {@link Boolean}. 1297 */ 1298 public boolean isBoolean() { 1299 return cc == BOOLEAN; 1300 } 1301 1302 /** 1303 * Returns <jk>true</jk> if this class is a subclass of {@link CharSequence}. 1304 * 1305 * @return <jk>true</jk> if this class is a subclass of {@link CharSequence}. 1306 */ 1307 public boolean isCharSequence() { 1308 return cc == STR || cc == CHARSEQ; 1309 } 1310 1311 /** 1312 * Returns <jk>true</jk> if this class is a {@link String}. 1313 * 1314 * @return <jk>true</jk> if this class is a {@link String}. 1315 */ 1316 public boolean isString() { 1317 return cc == STR; 1318 } 1319 1320 /** 1321 * Returns <jk>true</jk> if this class is a {@link Character}. 1322 * 1323 * @return <jk>true</jk> if this class is a {@link Character}. 1324 */ 1325 public boolean isChar() { 1326 return cc == CHAR; 1327 } 1328 1329 /** 1330 * Returns <jk>true</jk> if this class is a primitive. 1331 * 1332 * @return <jk>true</jk> if this class is a primitive. 1333 */ 1334 public boolean isPrimitive() { 1335 return innerClass.isPrimitive(); 1336 } 1337 1338 /** 1339 * Returns <jk>true</jk> if this class is a {@link Date} or {@link Calendar}. 1340 * 1341 * @return <jk>true</jk> if this class is a {@link Date} or {@link Calendar}. 1342 */ 1343 public boolean isDateOrCalendar() { 1344 return cc == DATE; 1345 } 1346 1347 /** 1348 * Returns <jk>true</jk> if this class is a {@link Date} or {@link Calendar} or {@link Temporal}. 1349 * 1350 * @return <jk>true</jk> if this class is a {@link Date} or {@link Calendar} or {@link Temporal}. 1351 */ 1352 public boolean isDateOrCalendarOrTemporal() { 1353 return cc == DATE || info.isChildOf(Temporal.class); 1354 } 1355 1356 /** 1357 * Returns <jk>true</jk> if this class is a {@link Date}. 1358 * 1359 * @return <jk>true</jk> if this class is a {@link Date}. 1360 */ 1361 public boolean isDate() { 1362 return cc == DATE && info.isChildOf(Date.class); 1363 } 1364 1365 /** 1366 * Returns <jk>true</jk> if this class is a {@link Temporal}. 1367 * 1368 * @return <jk>true</jk> if this class is a {@link Temporal}. 1369 */ 1370 public boolean isTemporal() { 1371 return info.isChildOf(Temporal.class); 1372 } 1373 1374 /** 1375 * Returns <jk>true</jk> if this class is a {@link Calendar}. 1376 * 1377 * @return <jk>true</jk> if this class is a {@link Calendar}. 1378 */ 1379 public boolean isCalendar() { 1380 return cc == DATE && info.isChildOf(Calendar.class); 1381 } 1382 1383 /** 1384 * Returns <jk>true</jk> if this class is a {@link URI} or {@link URL}. 1385 * 1386 * @return <jk>true</jk> if this class is a {@link URI} or {@link URL}. 1387 */ 1388 public boolean isUri() { 1389 return cc == URI; 1390 } 1391 1392 /** 1393 * Returns <jk>true</jk> if this class is a {@link Reader}. 1394 * 1395 * @return <jk>true</jk> if this class is a {@link Reader}. 1396 */ 1397 public boolean isReader() { 1398 return cc == READER; 1399 } 1400 1401 /** 1402 * Returns <jk>true</jk> if this class is an {@link InputStream}. 1403 * 1404 * @return <jk>true</jk> if this class is an {@link InputStream}. 1405 */ 1406 public boolean isInputStream() { 1407 return cc == INPUTSTREAM; 1408 } 1409 1410 /** 1411 * Returns <jk>true</jk> if this class is {@link Void} or <jk>void</jk>. 1412 * 1413 * @return <jk>true</jk> if this class is {@link Void} or <jk>void</jk>. 1414 */ 1415 public boolean isVoid() { 1416 return cc == VOID; 1417 } 1418 1419 /** 1420 * Returns <jk>true</jk> if this metadata represents an array of argument types. 1421 * 1422 * @return <jk>true</jk> if this metadata represents an array of argument types. 1423 */ 1424 public boolean isArgs() { 1425 return cc == ARGS; 1426 } 1427 1428 /** 1429 * Returns the argument types of this meta. 1430 * 1431 * @return The argument types of this meta, or <jk>null</jk> if this isn't an array of argument types. 1432 */ 1433 public ClassMeta<?>[] getArgs() { 1434 return args; 1435 } 1436 1437 /** 1438 * Returns the argument metadata at the specified index if this is an args metadata object. 1439 * 1440 * @param index The argument index. 1441 * @return The The argument metadata. Never <jk>null</jk>. 1442 * @throws BeanRuntimeException If this metadata object is not a list of arguments, or the index is out of range. 1443 */ 1444 public ClassMeta<?> getArg(int index) { 1445 if (args != null && index >= 0 && index < args.length) 1446 return args[index]; 1447 throw new BeanRuntimeException("Invalid argument index specified: {0}. Only {1} arguments are defined.", index, args == null ? 0 : args.length); 1448 } 1449 1450 /** 1451 * Returns <jk>true</jk> if instance of this object can be <jk>null</jk>. 1452 * 1453 * <p> 1454 * Objects can be <jk>null</jk>, but primitives cannot, except for chars which can be represented by 1455 * <code>(<jk>char</jk>)0</code>. 1456 * 1457 * @return <jk>true</jk> if instance of this class can be null. 1458 */ 1459 public boolean isNullable() { 1460 if (innerClass.isPrimitive()) 1461 return cc == CHAR; 1462 return true; 1463 } 1464 1465 /** 1466 * Returns <jk>true</jk> if this class is abstract. 1467 * 1468 * @return <jk>true</jk> if this class is abstract. 1469 */ 1470 public boolean isAbstract() { 1471 return isAbstract; 1472 } 1473 1474 /** 1475 * Returns <jk>true</jk> if this class is an inner class. 1476 * 1477 * @return <jk>true</jk> if this class is an inner class. 1478 */ 1479 public boolean isMemberClass() { 1480 return isMemberClass; 1481 } 1482 1483 /** 1484 * All public methods on this class including static methods. 1485 * 1486 * <p> 1487 * Keys are method signatures. 1488 * 1489 * @return The public methods on this class. 1490 */ 1491 public Map<String,Method> getPublicMethods() { 1492 return publicMethods; 1493 } 1494 1495 /** 1496 * Returns the {@link ObjectSwap} associated with this class that's the best match for the specified session. 1497 * 1498 * @param session 1499 * The current bean session. 1500 * <br>If multiple swaps are associated with a class, only the first one with a matching media type will 1501 * be returned. 1502 * @return 1503 * The {@link ObjectSwap} associated with this class, or <jk>null</jk> if there are no POJO swaps associated with 1504 * this class. 1505 */ 1506 public ObjectSwap<T,?> getSwap(BeanSession session) { 1507 if (swaps != null) { 1508 int matchQuant = 0, matchIndex = -1; 1509 1510 for (int i = 0; i < swaps.length; i++) { 1511 int q = swaps[i].match(session); 1512 if (q > matchQuant) { 1513 matchQuant = q; 1514 matchIndex = i; 1515 } 1516 } 1517 1518 if (matchIndex > -1) 1519 return swaps[matchIndex]; 1520 } 1521 return null; 1522 } 1523 1524 /** 1525 * Returns the builder swap associated with this class. 1526 * 1527 * @param session The current bean session. 1528 * @return The builder swap associated with this class, or <jk>null</jk> if it doesn't exist. 1529 */ 1530 public BuilderSwap<T,?> getBuilderSwap(BeanSession session) { 1531 return builderSwap; 1532 } 1533 1534 /** 1535 * Returns the {@link BeanMeta} associated with this class. 1536 * 1537 * @return 1538 * The {@link BeanMeta} associated with this class, or <jk>null</jk> if there is no bean meta associated with 1539 * this class. 1540 */ 1541 public BeanMeta<T> getBeanMeta() { 1542 return beanMeta; 1543 } 1544 1545 /** 1546 * Returns the no-arg constructor for this class. 1547 * 1548 * @return The no-arg constructor for this class, or <jk>null</jk> if it does not exist. 1549 */ 1550 public ConstructorInfo getConstructor() { 1551 return noArgConstructor; 1552 } 1553 1554 /** 1555 * Returns the no-arg constructor for this class based on the {@link Marshalled#implClass()} value. 1556 * 1557 * @param conVis The constructor visibility. 1558 * @return The no-arg constructor for this class, or <jk>null</jk> if it does not exist. 1559 */ 1560 public ConstructorInfo getImplClassConstructor(Visibility conVis) { 1561 if (implClass != null) 1562 return ClassInfo.of(implClass).getNoArgConstructor(conVis); 1563 return null; 1564 } 1565 1566 /** 1567 * Returns the interface proxy invocation handler for this class. 1568 * 1569 * @return The interface proxy invocation handler, or <jk>null</jk> if it does not exist. 1570 */ 1571 public InvocationHandler getProxyInvocationHandler() { 1572 return invocationHandler; 1573 } 1574 1575 /** 1576 * Returns <jk>true</jk> if this class has a no-arg constructor or invocation handler. 1577 * 1578 * @return <jk>true</jk> if a new instance of this class can be constructed. 1579 */ 1580 public boolean canCreateNewInstance() { 1581 if (isMemberClass) 1582 return false; 1583 if (noArgConstructor != null || getProxyInvocationHandler() != null || (isArray() && elementType.canCreateNewInstance())) 1584 return true; 1585 return false; 1586 } 1587 1588 /** 1589 * Returns <jk>true</jk> if this class has a no-arg constructor or invocation handler. 1590 * Returns <jk>false</jk> if this is a non-static member class and the outer object does not match the class type of 1591 * the defining class. 1592 * 1593 * @param outer 1594 * The outer class object for non-static member classes. Can be <jk>null</jk> for non-member or static classes. 1595 * @return 1596 * <jk>true</jk> if a new instance of this class can be created within the context of the specified outer object. 1597 */ 1598 public boolean canCreateNewInstance(Object outer) { 1599 if (isMemberClass) 1600 return outer != null && noArgConstructor != null && noArgConstructor.hasParamTypes(outer.getClass()); 1601 return canCreateNewInstance(); 1602 } 1603 1604 /** 1605 * Returns <jk>true</jk> if this class can be instantiated as a bean. 1606 * Returns <jk>false</jk> if this is a non-static member class and the outer object does not match the class type of 1607 * the defining class. 1608 * 1609 * @param outer 1610 * The outer class object for non-static member classes. Can be <jk>null</jk> for non-member or static classes. 1611 * @return 1612 * <jk>true</jk> if a new instance of this bean can be created within the context of the specified outer object. 1613 */ 1614 public boolean canCreateNewBean(Object outer) { 1615 if (beanMeta == null || beanMeta.constructor == null) 1616 return false; 1617 if (isMemberClass) 1618 return outer != null && beanMeta.constructor.hasParamTypes(outer.getClass()); 1619 return true; 1620 } 1621 1622 /** 1623 * Returns <jk>true</jk> if this class can call the {@link #newInstanceFromString(Object, String)} method. 1624 * 1625 * @param outer 1626 * The outer class object for non-static member classes. 1627 * Can be <jk>null</jk> for non-member or static classes. 1628 * @return <jk>true</jk> if this class has a no-arg constructor or invocation handler. 1629 */ 1630 public boolean canCreateNewInstanceFromString(Object outer) { 1631 if (fromStringMethod != null) 1632 return true; 1633 if (stringConstructor != null) { 1634 if (isMemberClass) 1635 return outer != null && stringConstructor.hasParamTypes(outer.getClass(), String.class); 1636 return true; 1637 } 1638 return false; 1639 } 1640 1641 /** 1642 * Returns the method or field annotated with {@link NameProperty @NameProperty}. 1643 * 1644 * @return 1645 * The method or field annotated with {@link NameProperty @NameProperty} or <jk>null</jk> if method does not 1646 * exist. 1647 */ 1648 public Setter getNameProperty() { 1649 return namePropertyMethod; 1650 } 1651 1652 /** 1653 * Returns the method or field annotated with {@link ParentProperty @ParentProperty}. 1654 * 1655 * @return 1656 * The method or field annotated with {@link ParentProperty @ParentProperty} or <jk>null</jk> if method does not 1657 * exist. 1658 */ 1659 public Setter getParentProperty() { 1660 return parentPropertyMethod; 1661 } 1662 1663 /** 1664 * Returns the reason why this class is not a bean, or <jk>null</jk> if it is a bean. 1665 * 1666 * @return The reason why this class is not a bean, or <jk>null</jk> if it is a bean. 1667 */ 1668 public synchronized String getNotABeanReason() { 1669 return notABeanReason; 1670 } 1671 1672 /** 1673 * Returns any exception that was throw in the <c>init()</c> method. 1674 * 1675 * @return The cached exception. 1676 */ 1677 public Throwable getInitException() { 1678 return initException; 1679 } 1680 1681 /** 1682 * Returns the {@link BeanContext} that created this object. 1683 * 1684 * @return The bean context. 1685 */ 1686 public BeanContext getBeanContext() { 1687 return beanContext; 1688 } 1689 1690 /** 1691 * Returns the default value for primitives such as <jk>int</jk> or <jk>Integer</jk>. 1692 * 1693 * @return The default value, or <jk>null</jk> if this class type is not a primitive. 1694 */ 1695 @SuppressWarnings("unchecked") 1696 public T getPrimitiveDefault() { 1697 return (T)primitiveDefault; 1698 } 1699 1700 /** 1701 * If this is an {@link Optional}, returns an empty optional. 1702 * 1703 * <p> 1704 * Note that if this is a nested optional, will recursively create empty optionals. 1705 * 1706 * @return An empty optional, or <jk>null</jk> if this isn't an optional. 1707 */ 1708 public Optional<?> getOptionalDefault() { 1709 if (isOptional()) 1710 return optional(getElementType().getOptionalDefault()); 1711 return null; 1712 } 1713 1714 /** 1715 * Converts the specified object to a string. 1716 * 1717 * @param t The object to convert. 1718 * @return The object converted to a string, or <jk>null</jk> if the object was null. 1719 */ 1720 public String toString(Object t) { 1721 if (t == null) 1722 return null; 1723 if (isEnum() && beanContext.isUseEnumNames()) 1724 return ((Enum<?>)t).name(); 1725 return t.toString(); 1726 } 1727 1728 /** 1729 * Create a new instance of the main class of this declared type from a <c>String</c> input. 1730 * 1731 * <p> 1732 * In order to use this method, the class must have one of the following methods: 1733 * <ul> 1734 * <li><code><jk>public static</jk> T valueOf(String in);</code> 1735 * <li><code><jk>public static</jk> T fromString(String in);</code> 1736 * <li><code><jk>public</jk> T(String in);</code> 1737 * </ul> 1738 * 1739 * @param outer 1740 * The outer class object for non-static member classes. Can be <jk>null</jk> for non-member or static classes. 1741 * @param arg The input argument value. 1742 * @return A new instance of the object, or <jk>null</jk> if there is no string constructor on the object. 1743 * @throws ExecutableException Exception occurred on invoked constructor/method/field. 1744 */ 1745 @SuppressWarnings({ "unchecked" }) 1746 public T newInstanceFromString(Object outer, String arg) throws ExecutableException { 1747 1748 if (isEnum()) { 1749 T t = (T)enumValues.getKey(arg); 1750 if (t == null && ! beanContext.isIgnoreUnknownEnumValues()) 1751 throw new ExecutableException("Could not resolve enum value '"+arg+"' on class '"+getInnerClass().getName()+"'"); 1752 return t; 1753 } 1754 1755 Method m = fromStringMethod; 1756 if (m != null) { 1757 try { 1758 return (T)m.invoke(null, arg); 1759 } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { 1760 throw new ExecutableException(e); 1761 } 1762 } 1763 ConstructorInfo c = stringConstructor; 1764 if (c != null) { 1765 if (isMemberClass) 1766 return c.<T>invoke(outer, arg); 1767 return c.<T>invoke(arg); 1768 } 1769 throw new ExecutableException("No string constructor or valueOf(String) method found for class '"+getInnerClass().getName()+"'"); 1770 } 1771 1772 /** 1773 * Create a new instance of the main class of this declared type. 1774 * 1775 * @return A new instance of the object, or <jk>null</jk> if there is no no-arg constructor on the object. 1776 * @throws ExecutableException Exception occurred on invoked constructor/method/field. 1777 */ 1778 @SuppressWarnings("unchecked") 1779 public T newInstance() throws ExecutableException { 1780 if (isArray()) 1781 return (T)Array.newInstance(getInnerClass().getComponentType(), 0); 1782 ConstructorInfo c = getConstructor(); 1783 if (c != null) 1784 return c.<T>invoke(); 1785 InvocationHandler h = getProxyInvocationHandler(); 1786 if (h != null) 1787 return (T)Proxy.newProxyInstance(this.getClass().getClassLoader(), new Class[] { getInnerClass(), java.io.Serializable.class }, h); 1788 if (isArray()) 1789 return (T)Array.newInstance(this.elementType.innerClass,0); 1790 return null; 1791 } 1792 1793 /** 1794 * Same as {@link #newInstance()} except for instantiating non-static member classes. 1795 * 1796 * @param outer 1797 * The instance of the owning object of the member class instance. 1798 * Can be <jk>null</jk> if instantiating a non-member or static class. 1799 * @return A new instance of the object, or <jk>null</jk> if there is no no-arg constructor on the object. 1800 * @throws ExecutableException Exception occurred on invoked constructor/method/field. 1801 */ 1802 public T newInstance(Object outer) throws ExecutableException { 1803 if (isMemberClass) 1804 return noArgConstructor.<T>invoke(outer); 1805 return newInstance(); 1806 } 1807 1808 /** 1809 * Similar to {@link #equals(Object)} except primitive and Object types that are similar are considered the same. 1810 * (e.g. <jk>boolean</jk> == <c>Boolean</c>). 1811 * 1812 * @param cm The class meta to compare to. 1813 * @return <jk>true</jk> if the specified class-meta is equivalent to this one. 1814 */ 1815 public boolean same(ClassMeta<?> cm) { 1816 if (equals(cm)) 1817 return true; 1818 return (isPrimitive() && cc == cm.cc); 1819 } 1820 1821 @Override /* Object */ 1822 public String toString() { 1823 return toString(false); 1824 } 1825 1826 /** 1827 * Same as {@link #toString()} except use simple class names. 1828 * 1829 * @param simple Print simple class names only (no package). 1830 * @return A new string. 1831 */ 1832 public String toString(boolean simple) { 1833 return toString(new StringBuilder(), simple).toString(); 1834 } 1835 1836 /** 1837 * Appends this object as a readable string to the specified string builder. 1838 * 1839 * @param sb The string builder to append this object to. 1840 * @param simple Print simple class names only (no package). 1841 * @return The passed-in string builder. 1842 */ 1843 protected StringBuilder toString(StringBuilder sb, boolean simple) { 1844 String n = innerClass.getName(); 1845 if (simple) { 1846 int i = n.lastIndexOf('.'); 1847 n = n.substring(i == -1 ? 0 : i+1).replace('$', '.'); 1848 } 1849 if (cc == ARRAY) 1850 return elementType.toString(sb, simple).append('[').append(']'); 1851 if (cc == MAP) 1852 return sb.append(n).append(keyType.isObject() && valueType.isObject() ? "" : "<"+keyType.toString(simple)+","+valueType.toString(simple)+">"); 1853 if (cc == BEANMAP) 1854 return sb.append(BeanMap.class.getName()).append('<').append(n).append('>'); 1855 if (cc == COLLECTION || cc == OPTIONAL) 1856 return sb.append(n).append(elementType.isObject() ? "" : "<"+elementType.toString(simple)+">"); 1857 return sb.append(n); 1858 } 1859 1860 /** 1861 * Returns <jk>true</jk> if the specified object is an instance of this class. 1862 * 1863 * <p> 1864 * This is a simple comparison on the base class itself and not on any generic parameters. 1865 * 1866 * @param o The object to check. 1867 * @return <jk>true</jk> if the specified object is an instance of this class. 1868 */ 1869 public boolean isInstance(Object o) { 1870 if (o != null) 1871 return info.isParentOf(o.getClass()) || (isPrimitive() && info.getPrimitiveWrapper() == o.getClass()); 1872 return false; 1873 } 1874 1875 /** 1876 * Returns a readable name for this class (e.g. <js>"java.lang.String"</js>, <js>"boolean[]"</js>). 1877 * 1878 * @return The readable name for this class. 1879 */ 1880 public String getFullName() { 1881 return info.getFullName(); 1882 } 1883 1884 /** 1885 * Shortcut for calling {@link Class#getName()} on the inner class of this metadata. 1886 * 1887 * @return The name of the inner class. 1888 */ 1889 public String getName() { 1890 return innerClass.getName(); 1891 } 1892 1893 /** 1894 * Shortcut for calling {@link Class#getSimpleName()} on the inner class of this metadata. 1895 * 1896 * @return The simple name of the inner class. 1897 */ 1898 public String getSimpleName() { 1899 return innerClass.getSimpleName(); 1900 } 1901 1902 /** 1903 * Returns <jk>true</jk> if this class has a transform associated with it that allows it to be created from a Reader. 1904 * 1905 * @return <jk>true</jk> if this class has a transform associated with it that allows it to be created from a Reader. 1906 */ 1907 public boolean hasReaderMutater() { 1908 return hasMutaterFrom(Reader.class); 1909 } 1910 1911 /** 1912 * Returns the transform for this class for creating instances from a Reader. 1913 * 1914 * @return The transform, or <jk>null</jk> if no such transform exists. 1915 */ 1916 public Mutater<Reader,T> getReaderMutater() { 1917 return getFromMutater(Reader.class); 1918 } 1919 1920 /** 1921 * Returns <jk>true</jk> if this class has a transform associated with it that allows it to be created from an InputStream. 1922 * 1923 * @return <jk>true</jk> if this class has a transform associated with it that allows it to be created from an InputStream. 1924 */ 1925 public boolean hasInputStreamMutater() { 1926 return hasMutaterFrom(InputStream.class); 1927 } 1928 1929 /** 1930 * Returns the transform for this class for creating instances from an InputStream. 1931 * 1932 * @return The transform, or <jk>null</jk> if no such transform exists. 1933 */ 1934 public Mutater<InputStream,T> getInputStreamMutater() { 1935 return getFromMutater(InputStream.class); 1936 } 1937 1938 /** 1939 * Returns <jk>true</jk> if this class has a transform associated with it that allows it to be created from a String. 1940 * 1941 * @return <jk>true</jk> if this class has a transform associated with it that allows it to be created from a String. 1942 */ 1943 public boolean hasStringMutater() { 1944 return stringMutater != null; 1945 } 1946 1947 /** 1948 * Returns the transform for this class for creating instances from a String. 1949 * 1950 * @return The transform, or <jk>null</jk> if no such transform exists. 1951 */ 1952 public Mutater<String,T> getStringMutater() { 1953 return stringMutater; 1954 } 1955 1956 /** 1957 * Returns <jk>true</jk> if this class can be instantiated from the specified type. 1958 * 1959 * @param c The class type to convert from. 1960 * @return <jk>true</jk> if this class can be instantiated from the specified type. 1961 */ 1962 public boolean hasMutaterFrom(Class<?> c) { 1963 return getFromMutater(c) != null; 1964 } 1965 1966 /** 1967 * Returns <jk>true</jk> if this class can be instantiated from the specified type. 1968 * 1969 * @param c The class type to convert from. 1970 * @return <jk>true</jk> if this class can be instantiated from the specified type. 1971 */ 1972 public boolean hasMutaterFrom(ClassMeta<?> c) { 1973 return getFromMutater(c.getInnerClass()) != null; 1974 } 1975 1976 /** 1977 * Returns <jk>true</jk> if this class can be transformed to the specified type. 1978 * 1979 * @param c The class type to convert from. 1980 * @return <jk>true</jk> if this class can be transformed to the specified type. 1981 */ 1982 public boolean hasMutaterTo(Class<?> c) { 1983 return getToMutater(c) != null; 1984 } 1985 1986 /** 1987 * Returns <jk>true</jk> if this class can be transformed to the specified type. 1988 * 1989 * @param c The class type to convert from. 1990 * @return <jk>true</jk> if this class can be transformed to the specified type. 1991 */ 1992 public boolean hasMutaterTo(ClassMeta<?> c) { 1993 return getToMutater(c.getInnerClass()) != null; 1994 } 1995 1996 /** 1997 * Transforms the specified object into an instance of this class. 1998 * 1999 * @param o The object to transform. 2000 * @return The transformed object. 2001 */ 2002 @SuppressWarnings({"unchecked","rawtypes"}) 2003 public T mutateFrom(Object o) { 2004 Mutater t = getFromMutater(o.getClass()); 2005 return (T)(t == null ? null : t.mutate(o)); 2006 } 2007 2008 /** 2009 * Transforms the specified object into an instance of this class. 2010 * 2011 * @param <O> The transform-to class. 2012 * @param o The object to transform. 2013 * @param c The class 2014 * @return The transformed object. 2015 */ 2016 @SuppressWarnings({"unchecked","rawtypes"}) 2017 public <O> O mutateTo(Object o, Class<O> c) { 2018 Mutater t = getToMutater(c); 2019 return (O)(t == null ? null : t.mutate(o)); 2020 } 2021 2022 /** 2023 * Transforms the specified object into an instance of this class. 2024 * 2025 * @param <O> The transform-to class. 2026 * @param o The object to transform. 2027 * @param c The class 2028 * @return The transformed object. 2029 */ 2030 public <O> O mutateTo(Object o, ClassMeta<O> c) { 2031 return mutateTo(o, c.getInnerClass()); 2032 } 2033 2034 /** 2035 * Returns the transform for this class for creating instances from other object types. 2036 * 2037 * @param <I> The transform-from class. 2038 * @param c The transform-from class. 2039 * @return The transform, or <jk>null</jk> if no such transform exists. 2040 */ 2041 @SuppressWarnings({ "rawtypes", "unchecked" }) 2042 public <I> Mutater<I,T> getFromMutater(Class<I> c) { 2043 Mutater t = fromMutaters.get(c); 2044 if (t == Mutaters.NULL) 2045 return null; 2046 if (t == null) { 2047 t = Mutaters.get(c, innerClass); 2048 if (t == null) 2049 t = Mutaters.NULL; 2050 fromMutaters.put(c, t); 2051 } 2052 return t == Mutaters.NULL ? null : t; 2053 } 2054 2055 /** 2056 * Returns the transform for this class for creating instances from other object types. 2057 * 2058 * @param <O> The transform-to class. 2059 * @param c The transform-from class. 2060 * @return The transform, or <jk>null</jk> if no such transform exists. 2061 */ 2062 @SuppressWarnings({ "rawtypes", "unchecked" }) 2063 public <O> Mutater<T,O> getToMutater(Class<O> c) { 2064 Mutater t = toMutaters.get(c); 2065 if (t == Mutaters.NULL) 2066 return null; 2067 if (t == null) { 2068 t = Mutaters.get(innerClass, c); 2069 if (t == null) 2070 t = Mutaters.NULL; 2071 toMutaters.put(c, t); 2072 } 2073 return t == Mutaters.NULL ? null : t; 2074 } 2075 2076 /** 2077 * Shortcut for calling <code>getInnerClass().getAnnotation(a) != <jk>null</jk></code>. 2078 * 2079 * @param a The annotation to check for. 2080 * @return <jk>true</jk> if the inner class has the annotation. 2081 */ 2082 public boolean hasAnnotation(Class<? extends Annotation> a) { 2083 return getLastAnnotation(a) != null; 2084 } 2085 2086 /** 2087 * Shortcut for calling <c>getInnerClass().getAnnotation(a)</c>. 2088 * 2089 * @param <A> The annotation type to look for. 2090 * @param a The annotation to retrieve. 2091 * @return The specified annotation, or <jk>null</jk> if the class does not have the specified annotation. 2092 */ 2093 @SuppressWarnings("unchecked") 2094 public <A extends Annotation> A getLastAnnotation(Class<A> a) { 2095 Optional<A> o = (Optional<A>)annotationLastMap.get(a); 2096 if (o == null) { 2097 if (beanContext == null) 2098 return info.getAnnotation(BeanContext.DEFAULT, a); 2099 o = optional(info.getAnnotation(beanContext, a)); 2100 annotationLastMap.put(a, o); 2101 } 2102 return o.orElse(null); 2103 } 2104 2105 /** 2106 * Performs an action on all matching annotations of the specified type defined on this class or parent classes/interfaces in parent-to-child order. 2107 * 2108 * @param <A> The annotation type to look for. 2109 * @param type The annotation to search for. 2110 * @param filter A predicate to apply to the entries to determine if action should be performed. Can be <jk>null</jk>. 2111 * @param action An action to perform on the entry. 2112 * @return This object. 2113 */ 2114 public <A extends Annotation> ClassMeta<T> forEachAnnotation(Class<A> type, Predicate<A> filter, Consumer<A> action) { 2115 A[] array = annotationArray(type); 2116 if (array == null) { 2117 if (beanContext == null) 2118 info.forEachAnnotation(BeanContext.DEFAULT, type, filter, action); 2119 return this; 2120 } 2121 for (A a : array) 2122 consume(filter, action, a); 2123 return this; 2124 } 2125 2126 /** 2127 * Returns the first matching annotation on this class or parent classes/interfaces in parent-to-child order. 2128 * 2129 * @param <A> The annotation type to look for. 2130 * @param type The annotation to search for. 2131 * @param filter A predicate to apply to the entries to determine if annotation should be used. Can be <jk>null</jk>. 2132 * @return This object. 2133 */ 2134 public <A extends Annotation> Optional<A> firstAnnotation(Class<A> type, Predicate<A> filter) { 2135 A[] array = annotationArray(type); 2136 if (array == null) { 2137 if (beanContext == null) 2138 return Optional.ofNullable(info.firstAnnotation(BeanContext.DEFAULT, type, filter)); 2139 return Optional.empty(); 2140 } 2141 for (A a : array) 2142 if (test(filter, a)) 2143 return Optional.of(a); 2144 return Optional.empty(); 2145 } 2146 2147 /** 2148 * Returns the last matching annotation on this class or parent classes/interfaces in parent-to-child order. 2149 * 2150 * @param <A> The annotation type to look for. 2151 * @param type The annotation to search for. 2152 * @param filter A predicate to apply to the entries to determine if annotation should be used. Can be <jk>null</jk>. 2153 * @return This object. 2154 */ 2155 public <A extends Annotation> Optional<A> lastAnnotation(Class<A> type, Predicate<A> filter) { 2156 A[] array = annotationArray(type); 2157 if (array == null) { 2158 if (beanContext == null) 2159 return Optional.ofNullable(info.lastAnnotation(BeanContext.DEFAULT, type, filter)); 2160 return Optional.empty(); 2161 } 2162 for (int i = array.length-1; i >= 0; i--) 2163 if (test(filter, array[i])) 2164 return Optional.of(array[i]); 2165 return Optional.empty(); 2166 } 2167 2168 @SuppressWarnings("unchecked") 2169 private <A extends Annotation> A[] annotationArray(Class<A> type) { 2170 A[] array = (A[])annotationArrayMap.get(type); 2171 if (array == null && beanContext != null) { 2172 List<A> l = list(); 2173 info.forEachAnnotation(beanContext, type, x-> true, x -> l.add(x)); 2174 array = (A[])Array.newInstance(type, l.size()); 2175 for (int i = 0; i < l.size(); i++) 2176 Array.set(array, i, l.get(i)); 2177 annotationArrayMap.put(type, array); 2178 } 2179 return array; 2180 } 2181 2182 /** 2183 * Returns a calculated property on this context. 2184 * 2185 * @param <T2> The type to convert the property to. 2186 * @param name The name of the property. 2187 * @param function The function used to create this property. 2188 * @return The property value. Never <jk>null</jk>. 2189 */ 2190 @SuppressWarnings("unchecked") 2191 public <T2> Optional<T2> getProperty(String name, Function<ClassMeta<?>,T2> function) { 2192 Optional<T2> t = (Optional<T2>) properties.get(name); 2193 if (t == null) { 2194 t = optional(function.apply(this)); 2195 properties.put(name, t); 2196 } 2197 return t; 2198 } 2199 2200 @Override /* Object */ 2201 public int hashCode() { 2202 return innerClass.hashCode(); 2203 } 2204 2205 @Override /* Object */ 2206 public boolean equals(Object o) { 2207 return (o instanceof ClassMeta) && eq(this, (ClassMeta<?>)o, (x,y)->eq(x.innerClass, y.innerClass)); 2208 } 2209}