001// *************************************************************************************************************************** 002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * 003// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * 004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * 005// * with the License. You may obtain a copy of the License at * 006// * * 007// * http://www.apache.org/licenses/LICENSE-2.0 * 008// * * 009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * 010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * 011// * specific language governing permissions and limitations under the License. * 012// *************************************************************************************************************************** 013package org.apache.juneau; 014 015import static org.apache.juneau.ClassMeta.ClassCategory.*; 016import static org.apache.juneau.internal.ClassUtils.*; 017import static org.apache.juneau.internal.ReflectionUtils.*; 018 019import java.io.*; 020import java.lang.reflect.*; 021import java.lang.reflect.Proxy; 022import java.net.*; 023import java.net.URI; 024import java.util.*; 025import java.util.Date; 026import java.util.concurrent.*; 027import java.util.concurrent.locks.*; 028 029import org.apache.juneau.annotation.*; 030import org.apache.juneau.http.*; 031import org.apache.juneau.internal.*; 032import org.apache.juneau.parser.*; 033import org.apache.juneau.remoteable.*; 034import org.apache.juneau.serializer.*; 035import org.apache.juneau.transform.*; 036import org.apache.juneau.utils.*; 037 038/** 039 * A wrapper class around the {@link Class} object that provides cached information about that class. 040 * 041 * <p> 042 * Instances of this class can be created through the {@link BeanContext#getClassMeta(Class)} method. 043 * 044 * <p> 045 * The {@link BeanContext} class will cache and reuse instances of this class except for the following class types: 046 * <ul> 047 * <li>Arrays 048 * <li>Maps with non-Object key/values. 049 * <li>Collections with non-Object key/values. 050 * </ul> 051 * 052 * <p> 053 * This class is tied to the {@link BeanContext} class because it's that class that makes the determination of what is 054 * a bean. 055 * 056 * @param <T> The class type of the wrapped class. 057 */ 058@Bean(properties="innerClass,classCategory,elementType,keyType,valueType,notABeanReason,initException,beanMeta") 059public final class ClassMeta<T> implements Type { 060 061 /** Class categories. */ 062 enum ClassCategory { 063 MAP, COLLECTION, CLASS, METHOD, NUMBER, DECIMAL, BOOLEAN, CHAR, DATE, ARRAY, ENUM, OTHER, CHARSEQ, STR, OBJ, URI, BEANMAP, READER, INPUTSTREAM, VOID, ARGS 064 } 065 066 final Class<T> innerClass; // The class being wrapped. 067 068 private final Class<? extends T> implClass; // The implementation class to use if this is an interface. 069 private final ClassCategory cc; // The class category. 070 private final Method fromStringMethod; // The static valueOf(String) or fromString(String) or forString(String) method (if it has one). 071 private final Constructor<? extends T> 072 noArgConstructor; // The no-arg constructor for this class (if it has one). 073 private final Constructor<T> 074 stringConstructor, // The X(String) constructor (if it has one). 075 numberConstructor, // The X(Number) constructor (if it has one). 076 swapConstructor; // The X(Swappable) constructor (if it has one). 077 private final Class<?> 078 swapMethodType, // The class type of the object in the number constructor. 079 numberConstructorType; 080 private final Method 081 swapMethod, // The swap() method (if it has one). 082 unswapMethod; // The unswap() method (if it has one). 083 private final Setter 084 namePropertyMethod, // The method to set the name on an object (if it has one). 085 parentPropertyMethod; // The method to set the parent on an object (if it has one). 086 private final boolean 087 isDelegate, // True if this class extends Delegate. 088 isAbstract, // True if this class is abstract. 089 isMemberClass; // True if this is a non-static member class. 090 private final Object primitiveDefault; // Default value for primitive type classes. 091 private final Map<String,Method> 092 remoteableMethods, // Methods annotated with @RemoteMethod. 093 publicMethods; // All public methods, including static methods. 094 private final PojoSwap<?,?>[] childPojoSwaps; // Any PojoSwaps where the normal type is a subclass of this class. 095 private final ConcurrentHashMap<Class<?>,PojoSwap<?,?>> 096 childSwapMap, // Maps normal subclasses to PojoSwaps. 097 childUnswapMap; // Maps swap subclasses to PojoSwaps. 098 private final PojoSwap<T,?>[] pojoSwaps; // The object POJO swaps associated with this bean (if it has any). 099 private final BeanFilter beanFilter; // The bean filter associated with this bean (if it has one). 100 private final BuilderSwap<T,?> builderSwap; // The builder swap associated with this bean (if it has one). 101 private final MetadataMap extMeta; // Extended metadata 102 private final BeanContext beanContext; // The bean context that created this object. 103 private final ClassMeta<?> 104 elementType, // If ARRAY or COLLECTION, the element class type. 105 keyType, // If MAP, the key class type. 106 valueType; // If MAP, the value class type. 107 private final BeanMeta<T> beanMeta; // The bean meta for this bean class (if it's a bean). 108 private final String 109 typePropertyName, // The property name of the _type property for this class and subclasses. 110 notABeanReason, // If this isn't a bean, the reason why. 111 dictionaryName; // The dictionary name of this class if it has one. 112 private final Throwable initException; // Any exceptions thrown in the init() method. 113 private final InvocationHandler invocationHandler; // The invocation handler for this class (if it has one). 114 private final BeanRegistry beanRegistry; // The bean registry of this class meta (if it has one). 115 private final ClassMeta<?>[] args; // Arg types if this is an array of args. 116 117 private ReadWriteLock lock = new ReentrantReadWriteLock(false); 118 private Lock rLock = lock.readLock(), wLock = lock.writeLock(); 119 120 /** 121 * Construct a new {@code ClassMeta} based on the specified {@link Class}. 122 * 123 * @param innerClass The class being wrapped. 124 * @param beanContext The bean context that created this object. 125 * @param implClass 126 * For interfaces and abstract classes, this represents the "real" class to instantiate. 127 * Can be <jk>null</jk>. 128 * @param beanFilter 129 * The {@link BeanFilter} programmatically associated with this class. 130 * Can be <jk>null</jk>. 131 * @param pojoSwap 132 * The {@link PojoSwap} programmatically associated with this class. 133 * Can be <jk>null</jk>. 134 * @param childPojoSwap 135 * The child {@link PojoSwap PojoSwaps} programmatically associated with this class. 136 * These are the <code>PojoSwaps</code> that have normal classes that are subclasses of this class. 137 * Can be <jk>null</jk>. 138 * @param delayedInit 139 * Don't call init() in constructor. 140 * Used for delayed initialization when the possibility of class reference loops exist. 141 */ 142 @SuppressWarnings({ "rawtypes", "unchecked" }) 143 ClassMeta(Class<T> innerClass, BeanContext beanContext, Class<? extends T> implClass, BeanFilter beanFilter, PojoSwap<T,?>[] pojoSwaps, PojoSwap<?,?>[] childPojoSwaps) { 144 this.innerClass = innerClass; 145 this.beanContext = beanContext; 146 147 wLock.lock(); 148 try { 149 // We always immediately add this class meta to the bean context cache so that we can resolve recursive references. 150 if (beanContext != null && beanContext.cmCache != null) 151 beanContext.cmCache.put(innerClass, this); 152 153 ClassMetaBuilder<T> builder = new ClassMetaBuilder(innerClass, beanContext, implClass, beanFilter, pojoSwaps, childPojoSwaps); 154 155 this.cc = builder.cc; 156 this.isDelegate = builder.isDelegate; 157 this.fromStringMethod = builder.fromStringMethod; 158 this.swapMethod = builder.swapMethod; 159 this.unswapMethod = builder.unswapMethod; 160 this.swapMethodType = builder.swapMethodType; 161 this.parentPropertyMethod = builder.parentPropertyMethod; 162 this.namePropertyMethod = builder.namePropertyMethod; 163 this.noArgConstructor = builder.noArgConstructor; 164 this.stringConstructor = builder.stringConstructor; 165 this.swapConstructor = builder.swapConstructor; 166 this.numberConstructor = builder.numberConstructor; 167 this.numberConstructorType = builder.numberConstructorType; 168 this.primitiveDefault = builder.primitiveDefault; 169 this.publicMethods = builder.publicMethods; 170 this.remoteableMethods = builder.remoteableMethods; 171 this.beanFilter = beanFilter; 172 this.pojoSwaps = builder.pojoSwaps.isEmpty() ? null : builder.pojoSwaps.toArray(new PojoSwap[builder.pojoSwaps.size()]); 173 this.builderSwap = builder.builderSwap; 174 this.extMeta = new MetadataMap(); 175 this.keyType = builder.keyType; 176 this.valueType = builder.valueType; 177 this.elementType = builder.elementType; 178 this.notABeanReason = builder.notABeanReason; 179 this.beanMeta = builder.beanMeta; 180 this.initException = builder.initException; 181 this.typePropertyName = builder.typePropertyName; 182 this.dictionaryName = builder.dictionaryName; 183 this.invocationHandler = builder.invocationHandler; 184 this.beanRegistry = builder.beanRegistry; 185 this.isMemberClass = builder.isMemberClass; 186 this.isAbstract = builder.isAbstract; 187 this.implClass = builder.implClass; 188 this.childUnswapMap = builder.childUnswapMap; 189 this.childSwapMap = builder.childSwapMap; 190 this.childPojoSwaps = builder.childPojoSwaps; 191 this.args = null; 192 } finally { 193 wLock.unlock(); 194 } 195 } 196 197 /** 198 * Causes thread to wait until constructor has exited. 199 */ 200 final void waitForInit() { 201 rLock.lock(); 202 rLock.unlock(); 203 } 204 205 /** 206 * Copy constructor. 207 * 208 * <p> 209 * Used for creating Map and Collection class metas that shouldn't be cached. 210 */ 211 ClassMeta(ClassMeta<T> mainType, ClassMeta<?> keyType, ClassMeta<?> valueType, ClassMeta<?> elementType) { 212 this.innerClass = mainType.innerClass; 213 this.implClass = mainType.implClass; 214 this.childPojoSwaps = mainType.childPojoSwaps; 215 this.childSwapMap = mainType.childSwapMap; 216 this.childUnswapMap = mainType.childUnswapMap; 217 this.cc = mainType.cc; 218 this.fromStringMethod = mainType.fromStringMethod; 219 this.noArgConstructor = mainType.noArgConstructor; 220 this.stringConstructor = mainType.stringConstructor; 221 this.numberConstructor = mainType.numberConstructor; 222 this.swapConstructor = mainType.swapConstructor; 223 this.swapMethodType = mainType.swapMethodType; 224 this.numberConstructorType = mainType.numberConstructorType; 225 this.swapMethod = mainType.swapMethod; 226 this.unswapMethod = mainType.unswapMethod; 227 this.namePropertyMethod = mainType.namePropertyMethod; 228 this.parentPropertyMethod = mainType.parentPropertyMethod; 229 this.isDelegate = mainType.isDelegate; 230 this.isAbstract = mainType.isAbstract; 231 this.isMemberClass = mainType.isMemberClass; 232 this.primitiveDefault = mainType.primitiveDefault; 233 this.remoteableMethods = mainType.remoteableMethods; 234 this.publicMethods = mainType.publicMethods; 235 this.beanContext = mainType.beanContext; 236 this.elementType = elementType; 237 this.keyType = keyType; 238 this.valueType = valueType; 239 this.invocationHandler = mainType.invocationHandler; 240 this.beanMeta = mainType.beanMeta; 241 this.typePropertyName = mainType.typePropertyName; 242 this.dictionaryName = mainType.dictionaryName; 243 this.notABeanReason = mainType.notABeanReason; 244 this.pojoSwaps = mainType.pojoSwaps; 245 this.builderSwap = mainType.builderSwap; 246 this.beanFilter = mainType.beanFilter; 247 this.extMeta = mainType.extMeta; 248 this.initException = mainType.initException; 249 this.beanRegistry = mainType.beanRegistry; 250 this.args = null; 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.args = args; 260 this.implClass = null; 261 this.childPojoSwaps = null; 262 this.childSwapMap = null; 263 this.childUnswapMap = null; 264 this.cc = ARGS; 265 this.fromStringMethod = null; 266 this.noArgConstructor = null; 267 this.stringConstructor = null; 268 this.numberConstructor = null; 269 this.swapConstructor = null; 270 this.swapMethodType = null; 271 this.numberConstructorType = null; 272 this.swapMethod = null; 273 this.unswapMethod = null; 274 this.namePropertyMethod = null; 275 this.parentPropertyMethod = null; 276 this.isDelegate = false; 277 this.isAbstract = false; 278 this.isMemberClass = false; 279 this.primitiveDefault = null; 280 this.remoteableMethods = null; 281 this.publicMethods = null; 282 this.beanContext = null; 283 this.elementType = null; 284 this.keyType = null; 285 this.valueType = null; 286 this.invocationHandler = null; 287 this.beanMeta = null; 288 this.typePropertyName = null; 289 this.dictionaryName = null; 290 this.notABeanReason = null; 291 this.pojoSwaps = null; 292 this.builderSwap = null; 293 this.beanFilter = null; 294 this.extMeta = new MetadataMap(); 295 this.initException = null; 296 this.beanRegistry = null; 297 } 298 299 @SuppressWarnings({"unchecked","rawtypes","hiding"}) 300 private final class ClassMetaBuilder<T> { 301 Class<T> innerClass; 302 Class<? extends T> implClass; 303 BeanContext beanContext; 304 ClassCategory cc = ClassCategory.OTHER; 305 boolean 306 isDelegate = false, 307 isMemberClass = false, 308 isAbstract = false; 309 Method 310 fromStringMethod = null, 311 swapMethod = null, 312 unswapMethod = null; 313 Setter 314 parentPropertyMethod = null, 315 namePropertyMethod = null; 316 Constructor<T> 317 noArgConstructor = null, 318 stringConstructor = null, 319 swapConstructor = null, 320 numberConstructor = null; 321 Class<?> 322 swapMethodType = null, 323 numberConstructorType = null; 324 Object primitiveDefault = null; 325 Map<String,Method> 326 publicMethods = new LinkedHashMap<>(), 327 remoteableMethods = new LinkedHashMap<>(); 328 ClassMeta<?> 329 keyType = null, 330 valueType = null, 331 elementType = null; 332 String 333 typePropertyName = null, 334 notABeanReason = null, 335 dictionaryName = null; 336 Throwable initException = null; 337 BeanMeta beanMeta = null; 338 List<PojoSwap> pojoSwaps = new ArrayList<>(); 339 BuilderSwap builderSwap; 340 InvocationHandler invocationHandler = null; 341 BeanRegistry beanRegistry = null; 342 PojoSwap<?,?>[] childPojoSwaps; 343 ConcurrentHashMap<Class<?>,PojoSwap<?,?>> 344 childSwapMap, 345 childUnswapMap; 346 347 ClassMetaBuilder(Class<T> innerClass, BeanContext beanContext, Class<? extends T> implClass, BeanFilter beanFilter, PojoSwap<T,?>[] pojoSwaps, PojoSwap<?,?>[] childPojoSwaps) { 348 this.innerClass = innerClass; 349 this.beanContext = beanContext; 350 351 this.implClass = implClass; 352 this.childPojoSwaps = childPojoSwaps; 353 this.childSwapMap = childPojoSwaps == null ? null : new ConcurrentHashMap<Class<?>,PojoSwap<?,?>>(); 354 this.childUnswapMap = childPojoSwaps == null ? null : new ConcurrentHashMap<Class<?>,PojoSwap<?,?>>(); 355 356 Class<T> c = innerClass; 357 if (c.isPrimitive()) { 358 if (c == Boolean.TYPE) 359 cc = BOOLEAN; 360 else if (c == Byte.TYPE || c == Short.TYPE || c == Integer.TYPE || c == Long.TYPE || c == Float.TYPE || c == Double.TYPE) { 361 if (c == Float.TYPE || c == Double.TYPE) 362 cc = DECIMAL; 363 else 364 cc = NUMBER; 365 } 366 else if (c == Character.TYPE) 367 cc = CHAR; 368 else if (c == void.class || c == Void.class) 369 cc = VOID; 370 } else { 371 if (isParentClass(Delegate.class, c)) 372 isDelegate = true; 373 374 if (c == Object.class) 375 cc = OBJ; 376 else if (c.isEnum()) 377 cc = ENUM; 378 else if (c.equals(Class.class)) 379 cc = CLASS; 380 else if (isParentClass(Method.class, c)) 381 cc = METHOD; 382 else if (isParentClass(CharSequence.class, c)) { 383 if (c.equals(String.class)) 384 cc = STR; 385 else 386 cc = CHARSEQ; 387 } 388 else if (isParentClass(Number.class, c)) { 389 if (isParentClass(Float.class, c) || isParentClass(Double.class, c)) 390 cc = DECIMAL; 391 else 392 cc = NUMBER; 393 } 394 else if (isParentClass(Collection.class, c)) 395 cc = COLLECTION; 396 else if (isParentClass(Map.class, c)) { 397 if (isParentClass(BeanMap.class, c)) 398 cc = BEANMAP; 399 else 400 cc = MAP; 401 } 402 else if (c == Character.class) 403 cc = CHAR; 404 else if (c == Boolean.class) 405 cc = BOOLEAN; 406 else if (isParentClass(Date.class, c) || isParentClass(Calendar.class, c)) 407 cc = DATE; 408 else if (c.isArray()) 409 cc = ARRAY; 410 else if (isParentClass(URL.class, c) || isParentClass(URI.class, c) || c.isAnnotationPresent(org.apache.juneau.annotation.URI.class)) 411 cc = URI; 412 else if (isParentClass(Reader.class, c)) 413 cc = READER; 414 else if (isParentClass(InputStream.class, c)) 415 cc = INPUTSTREAM; 416 } 417 418 isMemberClass = c.isMemberClass() && ! isStatic(c); 419 420 // Find static fromString(String) or equivalent method. 421 // fromString() must be checked before valueOf() so that Enum classes can create their own 422 // specialized fromString() methods to override the behavior of Enum.valueOf(String). 423 // valueOf() is used by enums. 424 // parse() is used by the java logging Level class. 425 // forName() is used by Class and Charset 426 for (String methodName : new String[]{"fromString","fromValue","valueOf","parse","parseString","forName","forString"}) { 427 if (fromStringMethod == null) { 428 for (Method m : c.getMethods()) { 429 if (isStatic(m) && isPublic(m) && isNotDeprecated(m)) { 430 String mName = m.getName(); 431 if (mName.equals(methodName) && m.getReturnType() == c) { 432 Class<?>[] args = m.getParameterTypes(); 433 if (args.length == 1 && args[0] == String.class) { 434 fromStringMethod = m; 435 break; 436 } 437 } 438 } 439 } 440 } 441 } 442 443 // Special cases 444 try { 445 if (c == TimeZone.class) 446 fromStringMethod = c.getMethod("getTimeZone", String.class); 447 else if (c == Locale.class) 448 fromStringMethod = LocaleAsString.class.getMethod("fromString", String.class); 449 } catch (NoSuchMethodException e1) {} 450 451 // Find swap() method if present. 452 for (Method m : c.getMethods()) { 453 if (isPublic(m) && isNotDeprecated(m) && ! isStatic(m)) { 454 String mName = m.getName(); 455 if (mName.equals("swap")) { 456 Class<?>[] pt = m.getParameterTypes(); 457 if (pt.length == 1 && pt[0] == BeanSession.class) { 458 swapMethod = m; 459 swapMethodType = m.getReturnType(); 460 break; 461 } 462 } 463 } 464 } 465 // Find unswap() method if present. 466 if (swapMethod != null) { 467 for (Method m : c.getMethods()) { 468 if (isPublic(m) && isNotDeprecated(m) && isStatic(m)) { 469 String mName = m.getName(); 470 if (mName.equals("unswap")) { 471 Class<?>[] pt = m.getParameterTypes(); 472 if (pt.length == 2 && pt[0] == BeanSession.class && pt[1] == swapMethodType) { 473 unswapMethod = m; 474 break; 475 } 476 } 477 } 478 } 479 } 480 481 for (Field f : getAllFields(c, true)) { 482 if (f.isAnnotationPresent(ParentProperty.class)) { 483 f.setAccessible(true); 484 parentPropertyMethod = new Setter.FieldSetter(f); 485 } 486 if (f.isAnnotationPresent(NameProperty.class)) { 487 f.setAccessible(true); 488 namePropertyMethod = new Setter.FieldSetter(f); 489 } 490 } 491 492 // Find @NameProperty and @ParentProperty methods if present. 493 for (Method m : getAllMethods(c, true)) { 494 if (m.isAnnotationPresent(ParentProperty.class) && m.getParameterTypes().length == 1) { 495 m.setAccessible(true); 496 parentPropertyMethod = new Setter.MethodSetter(m); 497 } 498 if (m.isAnnotationPresent(NameProperty.class) && m.getParameterTypes().length == 1) { 499 m.setAccessible(true); 500 namePropertyMethod = new Setter.MethodSetter(m); 501 } 502 } 503 504 // Note: Primitive types are normally abstract. 505 isAbstract = Modifier.isAbstract(c.getModifiers()) && ! c.isPrimitive(); 506 507 // Find constructor(String) method if present. 508 for (Constructor cs : c.getConstructors()) { 509 if (isPublic(cs) && isNotDeprecated(cs)) { 510 Class<?>[] args = cs.getParameterTypes(); 511 if (args.length == (isMemberClass ? 1 : 0) && c != Object.class && ! isAbstract) { 512 noArgConstructor = cs; 513 } else if (args.length == (isMemberClass ? 2 : 1)) { 514 Class<?> arg = args[(isMemberClass ? 1 : 0)]; 515 if (arg == String.class) 516 stringConstructor = cs; 517 else if (swapMethodType != null && swapMethodType.isAssignableFrom(arg)) 518 swapConstructor = cs; 519 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)))) { 520 numberConstructor = cs; 521 numberConstructorType = getWrapperIfPrimitive(arg); 522 } 523 } 524 } 525 } 526 527 primitiveDefault = ClassUtils.getPrimitiveDefault(c); 528 529 for (Method m : c.getMethods()) 530 if (isPublic(m) && isNotDeprecated(m)) 531 publicMethods.put(getMethodSignature(m), m); 532 533 Map<Class<?>,Remoteable> remoteableMap = findAnnotationsMap(Remoteable.class, c); 534 if (! remoteableMap.isEmpty()) { 535 Map.Entry<Class<?>,Remoteable> e = remoteableMap.entrySet().iterator().next(); // Grab the first one. 536 Class<?> ic = e.getKey(); 537 Remoteable r = e.getValue(); 538 String methodPaths = r.methodPaths(); 539 String expose = r.expose(); 540 for (Method m : "DECLARED".equals(expose) ? ic.getDeclaredMethods() : ic.getMethods()) { 541 if (isPublic(m)) { 542 RemoteMethod rm = m.getAnnotation(RemoteMethod.class); 543 if (rm != null || ! "ANNOTATED".equals(expose)) { 544 String path = "NAME".equals(methodPaths) ? m.getName() : getMethodSignature(m); 545 remoteableMethods.put(path, m); 546 } 547 } 548 } 549 } 550 551 if (innerClass != Object.class) { 552 noArgConstructor = (Constructor<T>)findNoArgConstructor(implClass == null ? innerClass : implClass, Visibility.PUBLIC); 553 } 554 555 if (beanFilter == null) 556 beanFilter = findBeanFilter(); 557 558 if (swapMethod != null) { 559 final Method fSwapMethod = swapMethod; 560 final Method fUnswapMethod = unswapMethod; 561 final Constructor<T> fSwapConstructor = swapConstructor; 562 this.pojoSwaps.add( 563 new PojoSwap<T,Object>(c, swapMethod.getReturnType()) { 564 @Override 565 public Object swap(BeanSession session, Object o) throws SerializeException { 566 try { 567 return fSwapMethod.invoke(o, session); 568 } catch (Exception e) { 569 throw new SerializeException(e); 570 } 571 } 572 @Override 573 public T unswap(BeanSession session, Object f, ClassMeta<?> hint) throws ParseException { 574 try { 575 if (fUnswapMethod != null) 576 return (T)fUnswapMethod.invoke(null, session, f); 577 if (fSwapConstructor != null) 578 return fSwapConstructor.newInstance(f); 579 return super.unswap(session, f, hint); 580 } catch (Exception e) { 581 throw new ParseException(e); 582 } 583 } 584 } 585 ); 586 } 587 588 if (pojoSwaps != null) 589 this.pojoSwaps.addAll(Arrays.asList(pojoSwaps)); 590 591 if (beanContext != null) 592 this.builderSwap = BuilderSwap.findSwapFromPojoClass(c, beanContext.beanConstructorVisibility, beanContext.beanMethodVisibility); 593 594 findPojoSwaps(this.pojoSwaps); 595 596 try { 597 598 // If this is an array, get the element type. 599 if (cc == ARRAY) 600 elementType = findClassMeta(innerClass.getComponentType()); 601 602 // If this is a MAP, see if it's parameterized (e.g. AddressBook extends HashMap<String,Person>) 603 else if (cc == MAP) { 604 ClassMeta[] parameters = findParameters(); 605 if (parameters != null && parameters.length == 2) { 606 keyType = parameters[0]; 607 valueType = parameters[1]; 608 } else { 609 keyType = findClassMeta(Object.class); 610 valueType = findClassMeta(Object.class); 611 } 612 } 613 614 // If this is a COLLECTION, see if it's parameterized (e.g. AddressBook extends LinkedList<Person>) 615 else if (cc == COLLECTION) { 616 ClassMeta[] parameters = findParameters(); 617 if (parameters != null && parameters.length == 1) { 618 elementType = parameters[0]; 619 } else { 620 elementType = findClassMeta(Object.class); 621 } 622 } 623 624 // If the category is unknown, see if it's a bean. 625 // Note that this needs to be done after all other initialization has been done. 626 else if (cc == OTHER) { 627 628 BeanMeta newMeta = null; 629 try { 630 newMeta = new BeanMeta(ClassMeta.this, beanContext, beanFilter, null); 631 notABeanReason = newMeta.notABeanReason; 632 633 // Always get these even if it's not a bean: 634 beanRegistry = newMeta.beanRegistry; 635 typePropertyName = newMeta.typePropertyName; 636 637 } catch (RuntimeException e) { 638 notABeanReason = e.getMessage(); 639 throw e; 640 } 641 if (notABeanReason == null) 642 beanMeta = newMeta; 643 } 644 645 } catch (NoClassDefFoundError e) { 646 initException = e; 647 } catch (RuntimeException e) { 648 initException = e; 649 throw e; 650 } 651 652 if (beanMeta != null) 653 dictionaryName = beanMeta.getDictionaryName(); 654 655 if (beanMeta != null && beanContext != null && beanContext.useInterfaceProxies && innerClass.isInterface()) 656 invocationHandler = new BeanProxyInvocationHandler<T>(beanMeta); 657 658 Bean b = c.getAnnotation(Bean.class); 659 if (b != null) { 660 if (b.beanDictionary().length != 0) 661 beanRegistry = new BeanRegistry(beanContext, null, b.beanDictionary()); 662 663 // This could be a non-bean POJO with a type name. 664 if (dictionaryName == null && ! b.typeName().isEmpty()) 665 dictionaryName = b.typeName(); 666 } 667 } 668 669 private BeanFilter findBeanFilter() { 670 try { 671 Map<Class<?>,Bean> ba = findAnnotationsMap(Bean.class, innerClass); 672 if (! ba.isEmpty()) 673 return new AnnotationBeanFilterBuilder(innerClass, ba).build(); 674 } catch (Exception e) { 675 throw new RuntimeException(e); 676 } 677 return null; 678 } 679 680 private void findPojoSwaps(List<PojoSwap> l) { 681 Swap swap = innerClass.getAnnotation(Swap.class); 682 if (swap != null) 683 l.add(createPojoSwap(swap)); 684 Swaps swaps = innerClass.getAnnotation(Swaps.class); 685 if (swaps != null) 686 for (Swap s : swaps.value()) 687 l.add(createPojoSwap(s)); 688 } 689 690 private PojoSwap<T,?> createPojoSwap(Swap s) { 691 Class<?> c = s.value(); 692 if (c == Null.class) 693 c = s.impl(); 694 695 if (isParentClass(PojoSwap.class, c)) { 696 PojoSwap ps = beanContext.newInstance(PojoSwap.class, c); 697 if (s.mediaTypes().length > 0) 698 ps.forMediaTypes(MediaType.forStrings(s.mediaTypes())); 699 if (! s.template().isEmpty()) 700 ps.withTemplate(s.template()); 701 return ps; 702 } 703 704 if (isParentClass(Surrogate.class, c)) { 705 List<SurrogateSwap<?,?>> l = SurrogateSwap.findPojoSwaps(c); 706 if (! l.isEmpty()) 707 return (PojoSwap<T,?>)l.iterator().next(); 708 } 709 710 throw new FormattedRuntimeException("Invalid swap class ''{0}'' specified. Must extend from PojoSwap or Surrogate.", c); 711 } 712 713 private ClassMeta<?> findClassMeta(Class<?> c) { 714 return beanContext.getClassMeta(c, false); 715 } 716 717 private ClassMeta<?>[] findParameters() { 718 return beanContext.findParameters(innerClass, innerClass); 719 } 720 } 721 722 723 /** 724 * Returns the type property name associated with this class and subclasses. 725 * 726 * <p> 727 * If <jk>null</jk>, <js>"_type"</js> should be assumed. 728 * 729 * @return 730 * The type property name associated with this bean class, or <jk>null</jk> if there is no explicit type 731 * property name defined or this isn't a bean. 732 */ 733 public String getBeanTypePropertyName() { 734 return typePropertyName; 735 } 736 737 /** 738 * Returns the bean dictionary name associated with this class. 739 * 740 * <p> 741 * The lexical name is defined by {@link Bean#typeName() @Bean.typeName()}. 742 * 743 * @return 744 * The type name associated with this bean class, or <jk>null</jk> if there is no type name defined or this 745 * isn't a bean. 746 */ 747 public String getDictionaryName() { 748 return dictionaryName; 749 } 750 751 /** 752 * Returns the bean registry for this class. 753 * 754 * <p> 755 * This bean registry contains names specified in the {@link Bean#beanDictionary() @Bean.beanDictionary()} annotation 756 * defined on the class, regardless of whether the class is an actual bean. 757 * This allows interfaces to define subclasses with type names. 758 * 759 * @return The bean registry for this class, or <jk>null</jk> if no bean registry is associated with it. 760 */ 761 public BeanRegistry getBeanRegistry() { 762 return beanRegistry; 763 } 764 765 /** 766 * Returns the category of this class. 767 * 768 * @return The category of this class. 769 */ 770 public ClassCategory getClassCategory() { 771 return cc; 772 } 773 774 /** 775 * Returns <jk>true</jk> if this class is a superclass of or the same as the specified class. 776 * 777 * @param c The comparison class. 778 * @return <jk>true</jk> if this class is a superclass of or the same as the specified class. 779 */ 780 public boolean isAssignableFrom(Class<?> c) { 781 return isParentClass(innerClass, c); 782 } 783 784 /** 785 * Returns <jk>true</jk> if this class is a subclass of or the same as the specified class. 786 * 787 * @param c The comparison class. 788 * @return <jk>true</jk> if this class is a subclass of or the same as the specified class. 789 */ 790 public boolean isInstanceOf(Class<?> c) { 791 return isParentClass(c, innerClass); 792 } 793 794 /** 795 * Returns <jk>true</jk> if this class or any child classes has a {@link PojoSwap} associated with it. 796 * 797 * <p> 798 * Used when transforming bean properties to prevent having to look up transforms if we know for certain that no 799 * transforms are associated with a bean property. 800 * 801 * @return <jk>true</jk> if this class or any child classes has a {@link PojoSwap} associated with it. 802 */ 803 protected boolean hasChildPojoSwaps() { 804 return childPojoSwaps != null; 805 } 806 807 /** 808 * Returns the {@link PojoSwap} where the specified class is the same/subclass of the normal class of one of the 809 * child POJO swaps associated with this class. 810 * 811 * @param normalClass The normal class being resolved. 812 * @return The resolved {@link PojoSwap} or <jk>null</jk> if none were found. 813 */ 814 protected PojoSwap<?,?> getChildPojoSwapForSwap(Class<?> normalClass) { 815 if (childSwapMap != null) { 816 PojoSwap<?,?> s = childSwapMap.get(normalClass); 817 if (s == null) { 818 for (PojoSwap<?,?> f : childPojoSwaps) 819 if (s == null && isParentClass(f.getNormalClass(), normalClass)) 820 s = f; 821 if (s == null) 822 s = PojoSwap.NULL; 823 PojoSwap<?,?> s2 = childSwapMap.putIfAbsent(normalClass, s); 824 if (s2 != null) 825 s = s2; 826 } 827 if (s == PojoSwap.NULL) 828 return null; 829 return s; 830 } 831 return null; 832 } 833 834 /** 835 * Returns the {@link PojoSwap} where the specified class is the same/subclass of the swap class of one of the child 836 * POJO swaps associated with this class. 837 * 838 * @param swapClass The swap class being resolved. 839 * @return The resolved {@link PojoSwap} or <jk>null</jk> if none were found. 840 */ 841 protected PojoSwap<?,?> getChildPojoSwapForUnswap(Class<?> swapClass) { 842 if (childUnswapMap != null) { 843 PojoSwap<?,?> s = childUnswapMap.get(swapClass); 844 if (s == null) { 845 for (PojoSwap<?,?> f : childPojoSwaps) 846 if (s == null && isParentClass(f.getSwapClass(), swapClass)) 847 s = f; 848 if (s == null) 849 s = PojoSwap.NULL; 850 PojoSwap<?,?> s2 = childUnswapMap.putIfAbsent(swapClass, s); 851 if (s2 != null) 852 s = s2; 853 } 854 if (s == PojoSwap.NULL) 855 return null; 856 return s; 857 } 858 return null; 859 } 860 861 /** 862 * Locates the no-arg constructor for the specified class. 863 * 864 * <p> 865 * Constructor must match the visibility requirements specified by parameter 'v'. 866 * If class is abstract, always returns <jk>null</jk>. 867 * Note that this also returns the 1-arg constructor for non-static member classes. 868 * 869 * @param c The class from which to locate the no-arg constructor. 870 * @param v The minimum visibility. 871 * @return The constructor, or <jk>null</jk> if no no-arg constructor exists with the required visibility. 872 */ 873 @SuppressWarnings({"rawtypes","unchecked"}) 874 protected static <T> Constructor<? extends T> findNoArgConstructor(Class<?> c, Visibility v) { 875 int mod = c.getModifiers(); 876 if (Modifier.isAbstract(mod)) 877 return null; 878 boolean isMemberClass = c.isMemberClass() && ! isStatic(c); 879 for (Constructor cc : c.getConstructors()) { 880 mod = cc.getModifiers(); 881 if (cc.getParameterTypes().length == (isMemberClass ? 1 : 0) && v.isVisible(mod) && isNotDeprecated(cc)) 882 return v.transform(cc); 883 } 884 return null; 885 } 886 887 /** 888 * Returns the {@link Class} object that this class type wraps. 889 * 890 * @return The wrapped class object. 891 */ 892 public Class<T> getInnerClass() { 893 return innerClass; 894 } 895 896 /** 897 * Returns the serialized (swapped) form of this class if there is an {@link PojoSwap} associated with it. 898 * 899 * @param session 900 * The bean session. 901 * <br>Required because the swap used may depend on the media type being serialized or parsed. 902 * @return The serialized class type, or this object if no swap is associated with the class. 903 */ 904 @BeanIgnore 905 public ClassMeta<?> getSerializedClassMeta(BeanSession session) { 906 PojoSwap<T,?> ps = getPojoSwap(session); 907 return (ps == null ? this : ps.getSwapClassMeta(session)); 908 } 909 910 /** 911 * For array and {@code Collection} types, returns the class type of the components of the array or 912 * {@code Collection}. 913 * 914 * @return The element class type, or <jk>null</jk> if this class is not an array or Collection. 915 */ 916 public ClassMeta<?> getElementType() { 917 return elementType; 918 } 919 920 /** 921 * For {@code Map} types, returns the class type of the keys of the {@code Map}. 922 * 923 * @return The key class type, or <jk>null</jk> if this class is not a Map. 924 */ 925 public ClassMeta<?> getKeyType() { 926 return keyType; 927 } 928 929 /** 930 * For {@code Map} types, returns the class type of the values of the {@code Map}. 931 * 932 * @return The value class type, or <jk>null</jk> if this class is not a Map. 933 */ 934 public ClassMeta<?> getValueType() { 935 return valueType; 936 } 937 938 /** 939 * Returns <jk>true</jk> if this class implements {@link Delegate}, meaning it's a representation of some other 940 * object. 941 * 942 * @return <jk>true</jk> if this class implements {@link Delegate}. 943 */ 944 public boolean isDelegate() { 945 return isDelegate; 946 } 947 948 /** 949 * Returns <jk>true</jk> if this class is a subclass of {@link Map}. 950 * 951 * @return <jk>true</jk> if this class is a subclass of {@link Map}. 952 */ 953 public boolean isMap() { 954 return cc == MAP || cc == BEANMAP; 955 } 956 957 /** 958 * Returns <jk>true</jk> if this class is a subclass of {@link Map} or it's a bean. 959 * 960 * @return <jk>true</jk> if this class is a subclass of {@link Map} or it's a bean. 961 */ 962 public boolean isMapOrBean() { 963 return cc == MAP || cc == BEANMAP || beanMeta != null; 964 } 965 966 /** 967 * Returns <jk>true</jk> if this class is a subclass of {@link BeanMap}. 968 * 969 * @return <jk>true</jk> if this class is a subclass of {@link BeanMap}. 970 */ 971 public boolean isBeanMap() { 972 return cc == BEANMAP; 973 } 974 975 /** 976 * Returns <jk>true</jk> if this class is a subclass of {@link Collection}. 977 * 978 * @return <jk>true</jk> if this class is a subclass of {@link Collection}. 979 */ 980 public boolean isCollection() { 981 return cc == COLLECTION; 982 } 983 984 /** 985 * Returns <jk>true</jk> if this class is a subclass of {@link Collection} or is an array. 986 * 987 * @return <jk>true</jk> if this class is a subclass of {@link Collection} or is an array. 988 */ 989 public boolean isCollectionOrArray() { 990 return cc == COLLECTION || cc == ARRAY; 991 } 992 993 /** 994 * Returns <jk>true</jk> if this class is {@link Class}. 995 * 996 * @return <jk>true</jk> if this class is {@link Class}. 997 */ 998 public boolean isClass() { 999 return cc == CLASS; 1000 } 1001 1002 /** 1003 * Returns <jk>true</jk> if this class is {@link Method}. 1004 * 1005 * @return <jk>true</jk> if this class is {@link Method}. 1006 */ 1007 public boolean isMethod() { 1008 return cc == METHOD; 1009 } 1010 1011 /** 1012 * Returns <jk>true</jk> if this class is an {@link Enum}. 1013 * 1014 * @return <jk>true</jk> if this class is an {@link Enum}. 1015 */ 1016 public boolean isEnum() { 1017 return cc == ENUM; 1018 } 1019 1020 /** 1021 * Returns <jk>true</jk> if this class is an array. 1022 * 1023 * @return <jk>true</jk> if this class is an array. 1024 */ 1025 public boolean isArray() { 1026 return cc == ARRAY; 1027 } 1028 1029 /** 1030 * Returns <jk>true</jk> if this class is a bean. 1031 * 1032 * @return <jk>true</jk> if this class is a bean. 1033 */ 1034 public boolean isBean() { 1035 return beanMeta != null; 1036 } 1037 1038 /** 1039 * Returns <jk>true</jk> if this class is {@link Object}. 1040 * 1041 * @return <jk>true</jk> if this class is {@link Object}. 1042 */ 1043 public boolean isObject() { 1044 return cc == OBJ; 1045 } 1046 1047 /** 1048 * Returns <jk>true</jk> if this class is not {@link Object}. 1049 * 1050 * @return <jk>true</jk> if this class is not {@link Object}. 1051 */ 1052 public boolean isNotObject() { 1053 return cc != OBJ; 1054 } 1055 1056 /** 1057 * Returns <jk>true</jk> if this class is a subclass of {@link Number}. 1058 * 1059 * @return <jk>true</jk> if this class is a subclass of {@link Number}. 1060 */ 1061 public boolean isNumber() { 1062 return cc == NUMBER || cc == DECIMAL; 1063 } 1064 1065 /** 1066 * Returns <jk>true</jk> if this class is a subclass of {@link Float} or {@link Double}. 1067 * 1068 * @return <jk>true</jk> if this class is a subclass of {@link Float} or {@link Double}. 1069 */ 1070 public boolean isDecimal() { 1071 return cc == DECIMAL; 1072 } 1073 1074 /** 1075 * Returns <jk>true</jk> if this class is a {@link Boolean}. 1076 * 1077 * @return <jk>true</jk> if this class is a {@link Boolean}. 1078 */ 1079 public boolean isBoolean() { 1080 return cc == BOOLEAN; 1081 } 1082 1083 /** 1084 * Returns <jk>true</jk> if this class is a subclass of {@link CharSequence}. 1085 * 1086 * @return <jk>true</jk> if this class is a subclass of {@link CharSequence}. 1087 */ 1088 public boolean isCharSequence() { 1089 return cc == STR || cc == CHARSEQ; 1090 } 1091 1092 /** 1093 * Returns <jk>true</jk> if this class is a {@link String}. 1094 * 1095 * @return <jk>true</jk> if this class is a {@link String}. 1096 */ 1097 public boolean isString() { 1098 return cc == STR; 1099 } 1100 1101 /** 1102 * Returns <jk>true</jk> if this class is a {@link Character}. 1103 * 1104 * @return <jk>true</jk> if this class is a {@link Character}. 1105 */ 1106 public boolean isChar() { 1107 return cc == CHAR; 1108 } 1109 1110 /** 1111 * Returns <jk>true</jk> if this class is a primitive. 1112 * 1113 * @return <jk>true</jk> if this class is a primitive. 1114 */ 1115 public boolean isPrimitive() { 1116 return innerClass.isPrimitive(); 1117 } 1118 1119 /** 1120 * Returns <jk>true</jk> if this class is a {@link Date} or {@link Calendar}. 1121 * 1122 * @return <jk>true</jk> if this class is a {@link Date} or {@link Calendar}. 1123 */ 1124 public boolean isDate() { 1125 return cc == DATE; 1126 } 1127 1128 /** 1129 * Returns <jk>true</jk> if this class is a {@link URI} or {@link URL}. 1130 * 1131 * @return <jk>true</jk> if this class is a {@link URI} or {@link URL}. 1132 */ 1133 public boolean isUri() { 1134 return cc == URI; 1135 } 1136 1137 /** 1138 * Returns <jk>true</jk> if this class is a {@link Reader}. 1139 * 1140 * @return <jk>true</jk> if this class is a {@link Reader}. 1141 */ 1142 public boolean isReader() { 1143 return cc == READER; 1144 } 1145 1146 /** 1147 * Returns <jk>true</jk> if this class is an {@link InputStream}. 1148 * 1149 * @return <jk>true</jk> if this class is an {@link InputStream}. 1150 */ 1151 public boolean isInputStream() { 1152 return cc == INPUTSTREAM; 1153 } 1154 1155 /** 1156 * Returns <jk>true</jk> if this class is {@link Void} or <jk>void</jk>. 1157 * 1158 * @return <jk>true</jk> if this class is {@link Void} or <jk>void</jk>. 1159 */ 1160 public boolean isVoid() { 1161 return cc == VOID; 1162 } 1163 1164 /** 1165 * Returns <jk>true</jk> if this metadata represents an array of argument types. 1166 * 1167 * @return <jk>true</jk> if this metadata represents an array of argument types. 1168 */ 1169 public boolean isArgs() { 1170 return cc == ARGS; 1171 } 1172 1173 /** 1174 * Returns the argument types of this meta. 1175 * 1176 * @return The argument types of this meta, or <jk>null</jk> if this isn't an array of argument types. 1177 */ 1178 public ClassMeta<?>[] getArgs() { 1179 return args; 1180 } 1181 1182 /** 1183 * Returns the argument metadata at the specified index if this is an args metadata object. 1184 * 1185 * @param index The argument index. 1186 * @return The The argument metadata. Never <jk>null</jk>. 1187 * @throws BeanRuntimeException If this metadata object is not a list of arguments, or the index is out of range. 1188 */ 1189 public ClassMeta<?> getArg(int index) { 1190 if (args != null && index >= 0 && index < args.length) 1191 return args[index]; 1192 throw new BeanRuntimeException("Invalid argument index specified: {0}. Only {1} arguments are defined.", index, args == null ? 0 : args.length); 1193 } 1194 1195 /** 1196 * Returns <jk>true</jk> if instance of this object can be <jk>null</jk>. 1197 * 1198 * <p> 1199 * Objects can be <jk>null</jk>, but primitives cannot, except for chars which can be represented by 1200 * <code>(<jk>char</jk>)0</code>. 1201 * 1202 * @return <jk>true</jk> if instance of this class can be null. 1203 */ 1204 public boolean isNullable() { 1205 if (innerClass.isPrimitive()) 1206 return cc == CHAR; 1207 return true; 1208 } 1209 1210 /** 1211 * Returns <jk>true</jk> if this class or one of it's methods are annotated with {@link Remoteable @Remotable}. 1212 * 1213 * @return <jk>true</jk> if this class is remoteable. 1214 */ 1215 public boolean isRemoteable() { 1216 return remoteableMethods != null; 1217 } 1218 1219 /** 1220 * Returns <jk>true</jk> if this class is abstract. 1221 * 1222 * @return <jk>true</jk> if this class is abstract. 1223 */ 1224 public boolean isAbstract() { 1225 return isAbstract; 1226 } 1227 1228 /** 1229 * Returns <jk>true</jk> if this class is an inner class. 1230 * 1231 * @return <jk>true</jk> if this class is an inner class. 1232 */ 1233 public boolean isMemberClass() { 1234 return isMemberClass; 1235 } 1236 1237 /** 1238 * All methods on this class annotated with {@link Remoteable @Remotable}, or all public methods if class is 1239 * annotated. 1240 * 1241 * <p> 1242 * Keys are method signatures. 1243 * 1244 * @return All remoteable methods on this class. 1245 */ 1246 public Map<String,Method> getRemoteableMethods() { 1247 return remoteableMethods; 1248 } 1249 1250 /** 1251 * All public methods on this class including static methods. 1252 * 1253 * <p> 1254 * Keys are method signatures. 1255 * 1256 * @return The public methods on this class. 1257 */ 1258 public Map<String,Method> getPublicMethods() { 1259 return publicMethods; 1260 } 1261 1262 /** 1263 * Returns the {@link PojoSwap} associated with this class that's the best match for the specified session. 1264 * 1265 * @param session 1266 * The current bean session. 1267 * <br>If multiple swaps are associated with a class, only the first one with a matching media type will 1268 * be returned. 1269 * @return 1270 * The {@link PojoSwap} associated with this class, or <jk>null</jk> if there are no POJO swaps associated with 1271 * this class. 1272 */ 1273 public PojoSwap<T,?> getPojoSwap(BeanSession session) { 1274 if (pojoSwaps != null) { 1275 int matchQuant = 0, matchIndex = -1; 1276 1277 for (int i = 0; i < pojoSwaps.length; i++) { 1278 int q = pojoSwaps[i].match(session); 1279 if (q > matchQuant) { 1280 matchQuant = q; 1281 matchIndex = i; 1282 } 1283 } 1284 1285 if (matchIndex > -1) 1286 return pojoSwaps[matchIndex]; 1287 } 1288 return null; 1289 } 1290 1291 /** 1292 * Returns the builder swap associated with this class. 1293 * 1294 * @param session The current bean session. 1295 * @return The builder swap associated with this class, or <jk>null</jk> if it doesn't exist. 1296 */ 1297 public BuilderSwap<T,?> getBuilderSwap(BeanSession session) { 1298 return builderSwap; 1299 } 1300 1301 /** 1302 * Returns the {@link BeanMeta} associated with this class. 1303 * 1304 * @return 1305 * The {@link BeanMeta} associated with this class, or <jk>null</jk> if there is no bean meta associated with 1306 * this class. 1307 */ 1308 public BeanMeta<T> getBeanMeta() { 1309 return beanMeta; 1310 } 1311 1312 /** 1313 * Returns the no-arg constructor for this class. 1314 * 1315 * @return The no-arg constructor for this class, or <jk>null</jk> if it does not exist. 1316 */ 1317 public Constructor<? extends T> getConstructor() { 1318 return noArgConstructor; 1319 } 1320 1321 /** 1322 * Returns the language-specified extended metadata on this class. 1323 * 1324 * @param c The name of the metadata class to create. 1325 * @return Extended metadata on this class. Never <jk>null</jk>. 1326 */ 1327 public <M extends ClassMetaExtended> M getExtendedMeta(Class<M> c) { 1328 return extMeta.get(c, this); 1329 } 1330 1331 /** 1332 * Returns the interface proxy invocation handler for this class. 1333 * 1334 * @return The interface proxy invocation handler, or <jk>null</jk> if it does not exist. 1335 */ 1336 public InvocationHandler getProxyInvocationHandler() { 1337 return invocationHandler; 1338 } 1339 1340 /** 1341 * Returns <jk>true</jk> if this class has a no-arg constructor or invocation handler. 1342 * 1343 * @return <jk>true</jk> if a new instance of this class can be constructed. 1344 */ 1345 public boolean canCreateNewInstance() { 1346 if (isMemberClass) 1347 return false; 1348 if (noArgConstructor != null) 1349 return true; 1350 if (getProxyInvocationHandler() != null) 1351 return true; 1352 if (isArray() && elementType.canCreateNewInstance()) 1353 return true; 1354 return false; 1355 } 1356 1357 /** 1358 * Returns <jk>true</jk> if this class has a no-arg constructor or invocation handler. 1359 * Returns <jk>false</jk> if this is a non-static member class and the outer object does not match the class type of 1360 * the defining class. 1361 * 1362 * @param outer 1363 * The outer class object for non-static member classes. Can be <jk>null</jk> for non-member or static classes. 1364 * @return 1365 * <jk>true</jk> if a new instance of this class can be created within the context of the specified outer object. 1366 */ 1367 public boolean canCreateNewInstance(Object outer) { 1368 if (isMemberClass) 1369 return outer != null && noArgConstructor != null && noArgConstructor.getParameterTypes()[0] == outer.getClass(); 1370 return canCreateNewInstance(); 1371 } 1372 1373 /** 1374 * Returns <jk>true</jk> if this class can be instantiated as a bean. 1375 * Returns <jk>false</jk> if this is a non-static member class and the outer object does not match the class type of 1376 * the defining class. 1377 * 1378 * @param outer 1379 * The outer class object for non-static member classes. Can be <jk>null</jk> for non-member or static classes. 1380 * @return 1381 * <jk>true</jk> if a new instance of this bean can be created within the context of the specified outer object. 1382 */ 1383 public boolean canCreateNewBean(Object outer) { 1384 if (beanMeta == null) 1385 return false; 1386 if (beanMeta.constructor == null) 1387 return false; 1388 if (isMemberClass) 1389 return outer != null && beanMeta.constructor.getParameterTypes()[0] == outer.getClass(); 1390 return true; 1391 } 1392 1393 /** 1394 * Returns <jk>true</jk> if this class can call the {@link #newInstanceFromString(Object, String)} method. 1395 * 1396 * @param outer 1397 * The outer class object for non-static member classes. 1398 * Can be <jk>null</jk> for non-member or static classes. 1399 * @return <jk>true</jk> if this class has a no-arg constructor or invocation handler. 1400 */ 1401 public boolean canCreateNewInstanceFromString(Object outer) { 1402 if (fromStringMethod != null) 1403 return true; 1404 if (stringConstructor != null) { 1405 if (isMemberClass) 1406 return outer != null && stringConstructor.getParameterTypes()[0] == outer.getClass(); 1407 return true; 1408 } 1409 return false; 1410 } 1411 1412 /** 1413 * Returns <jk>true</jk> if this class can call the {@link #newInstanceFromString(Object, String)} method. 1414 * 1415 * @param outer 1416 * The outer class object for non-static member classes. 1417 * Can be <jk>null</jk> for non-member or static classes. 1418 * @return <jk>true</jk> if this class has a no-arg constructor or invocation handler. 1419 */ 1420 public boolean canCreateNewInstanceFromNumber(Object outer) { 1421 if (numberConstructor != null) { 1422 if (isMemberClass) 1423 return outer != null && numberConstructor.getParameterTypes()[0] == outer.getClass(); 1424 return true; 1425 } 1426 return false; 1427 } 1428 1429 /** 1430 * Returns the class type of the parameter of the numeric constructor. 1431 * 1432 * @return The class type of the numeric constructor, or <jk>null</jk> if no such constructor exists. 1433 */ 1434 @SuppressWarnings("unchecked") 1435 public Class<? extends Number> getNewInstanceFromNumberClass() { 1436 return (Class<? extends Number>) numberConstructorType; 1437 } 1438 1439 /** 1440 * Returns the method or field annotated with {@link NameProperty @NameProperty}. 1441 * 1442 * @return 1443 * The method or field annotated with {@link NameProperty @NameProperty} or <jk>null</jk> if method does not 1444 * exist. 1445 */ 1446 public Setter getNameProperty() { 1447 return namePropertyMethod; 1448 } 1449 1450 /** 1451 * Returns the method or field annotated with {@link ParentProperty @ParentProperty}. 1452 * 1453 * @return 1454 * The method or field annotated with {@link ParentProperty @ParentProperty} or <jk>null</jk> if method does not 1455 * exist. 1456 */ 1457 public Setter getParentProperty() { 1458 return parentPropertyMethod; 1459 } 1460 1461 /** 1462 * Returns the reason why this class is not a bean, or <jk>null</jk> if it is a bean. 1463 * 1464 * @return The reason why this class is not a bean, or <jk>null</jk> if it is a bean. 1465 */ 1466 public synchronized String getNotABeanReason() { 1467 return notABeanReason; 1468 } 1469 1470 /** 1471 * Returns any exception that was throw in the <code>init()</code> method. 1472 * 1473 * @return The cached exception. 1474 */ 1475 public Throwable getInitException() { 1476 return initException; 1477 } 1478 1479 /** 1480 * Returns the {@link BeanContext} that created this object. 1481 * 1482 * @return The bean context. 1483 */ 1484 public BeanContext getBeanContext() { 1485 return beanContext; 1486 } 1487 1488 /** 1489 * Returns the default value for primitives such as <jk>int</jk> or <jk>Integer</jk>. 1490 * 1491 * @return The default value, or <jk>null</jk> if this class type is not a primitive. 1492 */ 1493 @SuppressWarnings("unchecked") 1494 public T getPrimitiveDefault() { 1495 return (T)primitiveDefault; 1496 } 1497 1498 /** 1499 * Create a new instance of the main class of this declared type from a <code>String</code> input. 1500 * 1501 * <p> 1502 * In order to use this method, the class must have one of the following methods: 1503 * <ul> 1504 * <li><code><jk>public static</jk> T valueOf(String in);</code> 1505 * <li><code><jk>public static</jk> T fromString(String in);</code> 1506 * <li><code><jk>public</jk> T(String in);</code> 1507 * </ul> 1508 * 1509 * @param outer 1510 * The outer class object for non-static member classes. Can be <jk>null</jk> for non-member or static classes. 1511 * @param arg The input argument value. 1512 * @return A new instance of the object, or <jk>null</jk> if there is no string constructor on the object. 1513 * @throws IllegalAccessException 1514 * If the <code>Constructor</code> object enforces Java language access control and the underlying constructor is 1515 * inaccessible. 1516 * @throws IllegalArgumentException If the parameter type on the method was invalid. 1517 * @throws InstantiationException 1518 * If the class that declares the underlying constructor represents an abstract class, or does not have one of 1519 * the methods described above. 1520 * @throws InvocationTargetException If the underlying constructor throws an exception. 1521 */ 1522 @SuppressWarnings("unchecked") 1523 public T newInstanceFromString(Object outer, String arg) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException, InstantiationException { 1524 Method m = fromStringMethod; 1525 if (m != null) 1526 return (T)m.invoke(null, arg); 1527 Constructor<T> c = stringConstructor; 1528 if (c != null) { 1529 if (isMemberClass) 1530 return c.newInstance(outer, arg); 1531 return c.newInstance(arg); 1532 } 1533 throw new InstantiationError("No string constructor or valueOf(String) method found for class '"+getInnerClass().getName()+"'"); 1534 } 1535 1536 /** 1537 * Create a new instance of the main class of this declared type from a <code>Number</code> input. 1538 * 1539 * <p> 1540 * In order to use this method, the class must have one of the following methods: 1541 * <ul> 1542 * <li><code><jk>public</jk> T(Number in);</code> 1543 * </ul> 1544 * 1545 * @param session The current bean session. 1546 * @param outer 1547 * The outer class object for non-static member classes. 1548 * Can be <jk>null</jk> for non-member or static classes. 1549 * @param arg The input argument value. 1550 * @return A new instance of the object, or <jk>null</jk> if there is no numeric constructor on the object. 1551 * @throws IllegalAccessException 1552 * If the <code>Constructor</code> object enforces Java language access control and the underlying constructor is 1553 * inaccessible. 1554 * @throws IllegalArgumentException If the parameter type on the method was invalid. 1555 * @throws InstantiationException 1556 * If the class that declares the underlying constructor represents an abstract class, or does not have one of 1557 * the methods described above. 1558 * @throws InvocationTargetException If the underlying constructor throws an exception. 1559 */ 1560 public T newInstanceFromNumber(BeanSession session, Object outer, Number arg) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException, InstantiationException { 1561 Constructor<T> c = numberConstructor; 1562 if (c != null) { 1563 Object arg2 = session.convertToType(arg, numberConstructor.getParameterTypes()[0]); 1564 if (isMemberClass) 1565 return c.newInstance(outer, arg2); 1566 return c.newInstance(arg2); 1567 } 1568 throw new InstantiationError("No string constructor or valueOf(Number) method found for class '"+getInnerClass().getName()+"'"); 1569 } 1570 1571 /** 1572 * Create a new instance of the main class of this declared type. 1573 * 1574 * @return A new instance of the object, or <jk>null</jk> if there is no no-arg constructor on the object. 1575 * @throws IllegalAccessException 1576 * If the <code>Constructor</code> object enforces Java language access control and the underlying constructor is 1577 * inaccessible. 1578 * @throws IllegalArgumentException 1579 * If one of the following occurs: 1580 * <ul class='spaced-list'> 1581 * <li> 1582 * The number of actual and formal parameters differ. 1583 * <li> 1584 * An unwrapping conversion for primitive arguments fails. 1585 * <li> 1586 * A parameter value cannot be converted to the corresponding formal parameter type by a method invocation 1587 * conversion. 1588 * <li> 1589 * The constructor pertains to an enum type. 1590 * </ul> 1591 * @throws InstantiationException If the class that declares the underlying constructor represents an abstract class. 1592 * @throws InvocationTargetException If the underlying constructor throws an exception. 1593 */ 1594 @SuppressWarnings("unchecked") 1595 public T newInstance() throws IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException { 1596 if (isArray()) 1597 return (T)Array.newInstance(getInnerClass().getComponentType(), 0); 1598 Constructor<? extends T> c = getConstructor(); 1599 if (c != null) 1600 return c.newInstance((Object[])null); 1601 InvocationHandler h = getProxyInvocationHandler(); 1602 if (h != null) 1603 return (T)Proxy.newProxyInstance(this.getClass().getClassLoader(), new Class[] { getInnerClass(), java.io.Serializable.class }, h); 1604 if (isArray()) 1605 return (T)Array.newInstance(this.elementType.innerClass,0); 1606 return null; 1607 } 1608 1609 /** 1610 * Same as {@link #newInstance()} except for instantiating non-static member classes. 1611 * 1612 * @param outer 1613 * The instance of the owning object of the member class instance. 1614 * Can be <jk>null</jk> if instantiating a non-member or static class. 1615 * @return A new instance of the object, or <jk>null</jk> if there is no no-arg constructor on the object. 1616 * @throws IllegalAccessException 1617 * If the <code>Constructor</code> object enforces Java language access control and the underlying constructor is 1618 * inaccessible. 1619 * @throws IllegalArgumentException 1620 * If one of the following occurs: 1621 * <ul class='spaced-list'> 1622 * <li> 1623 * The number of actual and formal parameters differ. 1624 * <li> 1625 * An unwrapping conversion for primitive arguments fails. 1626 * <li> 1627 * A parameter value cannot be converted to the corresponding formal parameter type by a method invocation 1628 * conversion. 1629 * <li> 1630 * The constructor pertains to an enum type. 1631 * </ul> 1632 * @throws InstantiationException If the class that declares the underlying constructor represents an abstract class. 1633 * @throws InvocationTargetException If the underlying constructor throws an exception. 1634 */ 1635 public T newInstance(Object outer) throws IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException { 1636 if (isMemberClass) 1637 return noArgConstructor.newInstance(outer); 1638 return newInstance(); 1639 } 1640 1641 /** 1642 * Checks to see if the specified class type is the same as this one. 1643 * 1644 * @param t The specified class type. 1645 * @return <jk>true</jk> if the specified class type is the same as the class for this type. 1646 */ 1647 @Override /* Object */ 1648 public boolean equals(Object t) { 1649 if (t == null || ! (t instanceof ClassMeta)) 1650 return false; 1651 ClassMeta<?> t2 = (ClassMeta<?>)t; 1652 return t2.getInnerClass() == this.getInnerClass(); 1653 } 1654 1655 /** 1656 * Similar to {@link #equals(Object)} except primitive and Object types that are similar are considered the same. 1657 * (e.g. <jk>boolean</jk> == <code>Boolean</code>). 1658 * 1659 * @param cm The class meta to compare to. 1660 * @return <jk>true</jk> if the specified class-meta is equivalent to this one. 1661 */ 1662 public boolean same(ClassMeta<?> cm) { 1663 if (equals(cm)) 1664 return true; 1665 return (isPrimitive() && cc == cm.cc); 1666 } 1667 1668 @Override /* Object */ 1669 public String toString() { 1670 return toString(false); 1671 } 1672 1673 /** 1674 * Same as {@link #toString()} except use simple class names. 1675 * 1676 * @param simple Print simple class names only (no package). 1677 * @return A new string. 1678 */ 1679 public String toString(boolean simple) { 1680 return toString(new StringBuilder(), simple).toString(); 1681 } 1682 1683 /** 1684 * Appends this object as a readable string to the specified string builder. 1685 * 1686 * @param sb The string builder to append this object to. 1687 * @param simple Print simple class names only (no package). 1688 * @return The same string builder passed in (for method chaining). 1689 */ 1690 protected StringBuilder toString(StringBuilder sb, boolean simple) { 1691 String n = innerClass.getName(); 1692 if (simple) { 1693 int i = n.lastIndexOf('.'); 1694 n = n.substring(i == -1 ? 0 : i+1).replace('$', '.'); 1695 } 1696 if (cc == ARRAY) 1697 return elementType.toString(sb, simple).append('[').append(']'); 1698 if (cc == MAP) 1699 return sb.append(n).append(keyType.isObject() && valueType.isObject() ? "" : "<"+keyType.toString(simple)+","+valueType.toString(simple)+">"); 1700 if (cc == BEANMAP) 1701 return sb.append(BeanMap.class.getName()).append('<').append(n).append('>'); 1702 if (cc == COLLECTION) 1703 return sb.append(n).append(elementType.isObject() ? "" : "<"+elementType.toString(simple)+">"); 1704 if (cc == OTHER && beanMeta == null) { 1705 if (simple) 1706 return sb.append(n); 1707 sb.append("OTHER-").append(n).append(",notABeanReason=").append(notABeanReason); 1708 if (initException != null) 1709 sb.append(",initException=").append(initException); 1710 return sb; 1711 } 1712 return sb.append(n); 1713 } 1714 1715 /** 1716 * Returns <jk>true</jk> if the specified object is an instance of this class. 1717 * 1718 * <p> 1719 * This is a simple comparison on the base class itself and not on any generic parameters. 1720 * 1721 * @param o The object to check. 1722 * @return <jk>true</jk> if the specified object is an instance of this class. 1723 */ 1724 public boolean isInstance(Object o) { 1725 if (o != null) 1726 return isParentClass(this.innerClass, o.getClass()); 1727 return false; 1728 } 1729 1730 /** 1731 * Returns a readable name for this class (e.g. <js>"java.lang.String"</js>, <js>"boolean[]"</js>). 1732 * 1733 * @return The readable name for this class. 1734 */ 1735 public String getReadableName() { 1736 return getReadableClassName(this.innerClass); 1737 } 1738 1739 private static class LocaleAsString { 1740 private static Method forLanguageTagMethod; 1741 static { 1742 try { 1743 forLanguageTagMethod = Locale.class.getMethod("forLanguageTag", String.class); 1744 } catch (NoSuchMethodException e) {} 1745 } 1746 1747 @SuppressWarnings("unused") 1748 public static final Locale fromString(String localeString) { 1749 if (forLanguageTagMethod != null) { 1750 if (localeString.indexOf('_') != -1) 1751 localeString = localeString.replace('_', '-'); 1752 try { 1753 return (Locale)forLanguageTagMethod.invoke(null, localeString); 1754 } catch (Exception e) { 1755 throw new BeanRuntimeException(e); 1756 } 1757 } 1758 String[] v = localeString.toString().split("[\\-\\_]"); 1759 if (v.length == 1) 1760 return new Locale(v[0]); 1761 else if (v.length == 2) 1762 return new Locale(v[0], v[1]); 1763 else if (v.length == 3) 1764 return new Locale(v[0], v[1], v[2]); 1765 throw new BeanRuntimeException("Could not convert string ''{0}'' to a Locale.", localeString); 1766 } 1767 } 1768 1769 @Override /* Object */ 1770 public int hashCode() { 1771 return super.hashCode(); 1772 } 1773}