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