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