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