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