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