You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@juneau.apache.org by ja...@apache.org on 2017/02/04 22:53:23 UTC

[1/5] incubator-juneau git commit: Improvements to ClassMeta/BeanContext.

Repository: incubator-juneau
Updated Branches:
  refs/heads/master c8fa4ed45 -> 4bc66a6a9


Improvements to ClassMeta/BeanContext.

Project: http://git-wip-us.apache.org/repos/asf/incubator-juneau/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-juneau/commit/61894c85
Tree: http://git-wip-us.apache.org/repos/asf/incubator-juneau/tree/61894c85
Diff: http://git-wip-us.apache.org/repos/asf/incubator-juneau/diff/61894c85

Branch: refs/heads/master
Commit: 61894c857be9a9d0b87a08ac1ce1b1cf9e939184
Parents: bdeb4f0
Author: JamesBognar <ja...@apache.org>
Authored: Sat Feb 4 15:44:34 2017 -0500
Committer: JamesBognar <ja...@apache.org>
Committed: Sat Feb 4 17:34:35 2017 -0500

----------------------------------------------------------------------
 .../java/org/apache/juneau/BeanContext.java     |  62 +++--
 .../org/apache/juneau/BeanPropertyMeta.java     |   8 +-
 .../main/java/org/apache/juneau/ClassMeta.java  | 257 +++++++++++++------
 .../org/apache/juneau/transform/PojoSwap.java   |   6 +
 4 files changed, 230 insertions(+), 103 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/61894c85/juneau-core/src/main/java/org/apache/juneau/BeanContext.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/BeanContext.java b/juneau-core/src/main/java/org/apache/juneau/BeanContext.java
index 7690729..1cb9180 100644
--- a/juneau-core/src/main/java/org/apache/juneau/BeanContext.java
+++ b/juneau-core/src/main/java/org/apache/juneau/BeanContext.java
@@ -1155,8 +1155,8 @@ public class BeanContext extends Context {
 
 		if (! cmCacheCache.containsKey(hashCode)) {
 			ConcurrentHashMap<Class,ClassMeta> cm = new ConcurrentHashMap<Class,ClassMeta>();
-			cm.put(String.class, new ClassMeta(String.class, this));
-			cm.put(Object.class, new ClassMeta(Object.class, this));
+			cm.put(String.class, new ClassMeta(String.class, this, null, null, findPojoSwap(String.class), findChildPojoSwaps(String.class)));
+			cm.put(Object.class, new ClassMeta(Object.class, this, null, null, findPojoSwap(Object.class), findChildPojoSwaps(Object.class)));
 			cmCacheCache.putIfAbsent(hashCode, cm);
 		}
 		this.cmCache = cmCacheCache.get(hashCode);
@@ -1346,10 +1346,11 @@ public class BeanContext extends Context {
 			if (oc instanceof Class) {
 				Class c = (Class)oc;
 				if (Collection.class.isAssignableFrom(c)) {
+					ClassMeta<?> rawType = getClassMeta(c);
 					ClassMeta<?> ce = getClassMeta(Array.get(o, 1));
 					if (ce.isObject())
-						return getClassMeta(c);
-					return new ClassMeta(c, this).setElementType(ce);
+						return (ClassMeta<T>)rawType;
+					return new ClassMeta(rawType, null, null, ce);
 				}
 			}
 		} else if (len == 3) {
@@ -1357,11 +1358,12 @@ public class BeanContext extends Context {
 			if (oc instanceof Class) {
 				Class c = (Class)oc;
 				if (Map.class.isAssignableFrom(c)) {
+					ClassMeta<?> rawType = getClassMeta(c);
 					ClassMeta<?> ck = getClassMeta(Array.get(o, 1));
 					ClassMeta<?> cv = getClassMeta(Array.get(o, 2));
 					if (ck.isObject() && cv.isObject())
-						return getClassMeta(c);
-					return new ClassMeta(c, this).setKeyType(ck).setValueType(cv);
+						return (ClassMeta<T>)rawType;
+					return new ClassMeta(rawType, ck, cv, null);
 				}
 			}
 		}
@@ -1383,7 +1385,7 @@ public class BeanContext extends Context {
 		// Note that if it has a pojo swap, we still want to cache it so that
 		// we can cache something like byte[] with ByteArrayBase64Swap.
 		if (c.isArray() && findPojoSwap(c) == null)
-			return new ClassMeta(c, this);
+			return new ClassMeta(c, this, findImplClass(c), findBeanFilter(c), findPojoSwap(c), findChildPojoSwaps(c));
 
 		// This can happen if we have transforms defined against String or Object.
 		if (cmCache == null)
@@ -1405,7 +1407,7 @@ public class BeanContext extends Context {
 						if (pcm.innerClass == c)
 							return pcm;
 
-					cm = new ClassMeta<T>(c, this, true);
+					cm = new ClassMeta<T>(c, this, findImplClass(c), findBeanFilter(c), findPojoSwap(c), findChildPojoSwaps(c), true);
 					pendingClassMetas.addLast(cm);
 					try {
 						cm.init();
@@ -1601,7 +1603,7 @@ public class BeanContext extends Context {
 				ClassMeta<?> valueType = resolveType(pParams[1], cm2.getValueType(), cm.getValueType());
 				if (keyType.isObject() && valueType.isObject())
 					return cm2;
-				return new ClassMeta<T>(cm2.innerClass, this).setKeyType(keyType).setValueType(valueType);
+				return new ClassMeta<T>(cm2, keyType, valueType, null);
 			}
 
 			if (cm2.isCollection()) {
@@ -1611,7 +1613,7 @@ public class BeanContext extends Context {
 				ClassMeta<?> elementType = resolveType(pParams[0], cm2.getElementType(), cm.getElementType());
 				if (elementType.isObject())
 					return cm2;
-				return new ClassMeta<T>(cm2.innerClass, this).setElementType(elementType);
+				return new ClassMeta<T>(cm2, null, null, elementType);
 			}
 
 			return cm2;
@@ -1749,7 +1751,7 @@ public class BeanContext extends Context {
 	 * @param c The class associated with the swap.
 	 * @return The swap associated with the class, or null if there is no association.
 	 */
-	protected final <T> PojoSwap findPojoSwap(Class<T> c) {
+	private final <T> PojoSwap findPojoSwap(Class<T> c) {
 		// Note:  On first
 		if (c != null)
 			for (PojoSwap f : pojoSwaps)
@@ -1763,12 +1765,18 @@ public class BeanContext extends Context {
 	 * @param c The class to check.
 	 * @return <jk>true</jk> if the specified class or one of its subclasses has a {@link PojoSwap} associated with it.
 	 */
-	protected final boolean hasChildPojoSwaps(Class<?> c) {
-		if (c != null)
-			for (PojoSwap f : pojoSwaps)
-				if (isParentClass(c, f.getNormalClass()))
-					return true;
-		return false;
+	private final PojoSwap[] findChildPojoSwaps(Class<?> c) {
+		if (c == null || pojoSwaps.length == 0)
+			return null;
+		List<PojoSwap> l = null;
+		for (PojoSwap f : pojoSwaps) {
+			if (isParentClass(c, f.getNormalClass())) {
+				if (l == null)
+					l = new ArrayList<PojoSwap>();
+				l.add(f);
+			}
+		}
+		return l == null ? null : l.toArray(new PojoSwap[l.size()]);
 	}
 
 	/**
@@ -1779,7 +1787,7 @@ public class BeanContext extends Context {
 	 * @param c The class associated with the bean filter.
 	 * @return The bean filter associated with the class, or null if there is no association.
 	 */
-	protected final <T> BeanFilter findBeanFilter(Class<T> c) {
+	private final <T> BeanFilter findBeanFilter(Class<T> c) {
 		if (c != null)
 			for (BeanFilter f : beanFilters)
 				if (isParentClass(f.getBeanClass(), c))
@@ -1831,6 +1839,24 @@ public class BeanContext extends Context {
 		return null;
 	}
 
+	private final <T> Class<? extends T> findImplClass(Class<T> c) {
+		if (implClasses.isEmpty())
+			return null;
+		Class cc = c;
+		while (cc != null) {
+			Class implClass = implClasses.get(cc);
+			if (implClass != null)
+				return implClass;
+			for (Class ic : cc.getInterfaces()) {
+				implClass = implClasses.get(ic);
+				if (implClass != null)
+					return implClass;
+			}
+			cc = cc.getSuperclass();
+		}
+		return null;
+	}
+
 	/**
 	 * Returns a reusable {@link ClassMeta} representation for the class <code>Object</code>.
 	 * <p>

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/61894c85/juneau-core/src/main/java/org/apache/juneau/BeanPropertyMeta.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/BeanPropertyMeta.java b/juneau-core/src/main/java/org/apache/juneau/BeanPropertyMeta.java
index ce7fdb5..a9e52f0 100644
--- a/juneau-core/src/main/java/org/apache/juneau/BeanPropertyMeta.java
+++ b/juneau-core/src/main/java/org/apache/juneau/BeanPropertyMeta.java
@@ -848,9 +848,7 @@ public class BeanPropertyMeta {
 			return null;
 		// Otherwise, look it up via bean context.
 		if (rawTypeMeta.hasChildPojoSwaps()) {
-			Class c = o.getClass();
-			ClassMeta<?> cm = rawTypeMeta.innerClass == c ? rawTypeMeta : beanContext.getClassMeta(c);
-			PojoSwap f = cm.getPojoSwap();
+			PojoSwap f = rawTypeMeta.getChildPojoSwapForSwap(o.getClass());
 			if (f != null)
 				return f.swap(session, o);
 		}
@@ -863,9 +861,7 @@ public class BeanPropertyMeta {
 		if (o == null)
 			return null;
 		if (rawTypeMeta.hasChildPojoSwaps()) {
-			Class c = o.getClass();
-			ClassMeta<?> cm = rawTypeMeta.innerClass == c ? rawTypeMeta : beanContext.getClassMeta(c);
-			PojoSwap f = cm.getPojoSwap();
+			PojoSwap f = rawTypeMeta.getChildPojoSwapForUnswap(o.getClass());
 			if (f != null)
 				return f.unswap(session, o, rawTypeMeta);
 		}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/61894c85/juneau-core/src/main/java/org/apache/juneau/ClassMeta.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/ClassMeta.java b/juneau-core/src/main/java/org/apache/juneau/ClassMeta.java
index c36ffd8..f103b2a 100644
--- a/juneau-core/src/main/java/org/apache/juneau/ClassMeta.java
+++ b/juneau-core/src/main/java/org/apache/juneau/ClassMeta.java
@@ -21,6 +21,7 @@ import java.lang.reflect.Proxy;
 import java.net.*;
 import java.net.URI;
 import java.util.*;
+import java.util.concurrent.*;
 
 import org.apache.juneau.annotation.*;
 import org.apache.juneau.internal.*;
@@ -57,9 +58,10 @@ public final class ClassMeta<T> implements Type {
 	}
 
 	final Class<T> innerClass;                              // The class being wrapped.
+	final Class<? extends T> implClass;                     // The implementation class to use if this is an interface.
 	final ClassCategory cc;                                 // The class category.
 	final Method fromStringMethod;                          // The static valueOf(String) or fromString(String) or forString(String) method (if it has one).
-	Constructor<? extends T>
+	final Constructor<? extends T>
 		noArgConstructor;                                    // The no-arg constructor for this class (if it has one).
 	final Constructor<T>
 		stringConstructor,                                   // The X(String) constructor (if it has one).
@@ -82,7 +84,10 @@ public final class ClassMeta<T> implements Type {
 	final Map<String,Method>
 		remoteableMethods,                                   // Methods annotated with @Remoteable.  Contains all public methods if class is annotated with @Remotable.
 		publicMethods;                                       // All public methods, including static methods.
-
+	final PojoSwap<?,?>[] childPojoSwaps;                   // Any PojoSwaps where the normal type is a subclass of this class.
+	final ConcurrentHashMap<Class<?>,PojoSwap<?,?>> 
+		childSwapMap,                                        // Maps normal subclasses to PojoSwaps.
+		childUnswapMap;                                      // Maps swap subclasses to PojoSwaps.
 
 	final BeanContext beanContext;                    // The bean context that created this object.
 	ClassMeta<?>
@@ -99,7 +104,6 @@ public final class ClassMeta<T> implements Type {
 
 	private MetadataMap extMeta = new MetadataMap();  // Extended metadata
 	private Throwable initException;                  // Any exceptions thrown in the init() method.
-	private boolean hasChildPojoSwaps;                // True if this class or any subclass of this class has a PojoSwap associated with it.
 
 	private static final Boolean BOOLEAN_DEFAULT = false;
 	private static final Character CHARACTER_DEFAULT = (char)0;
@@ -113,8 +117,8 @@ public final class ClassMeta<T> implements Type {
 	/**
 	 * Shortcut for calling <code>ClassMeta(innerClass, beanContext, <jk>false</jk>)</code>.
 	 */
-	ClassMeta(Class<T> innerClass, BeanContext beanContext) {
-		this(innerClass, beanContext, false);
+	ClassMeta(Class<T> innerClass, BeanContext beanContext, Class<? extends T> implClass, BeanFilter beanFilter, PojoSwap<T,?> pojoSwap, PojoSwap<?,?>[] childPojoSwaps) {
+		this(innerClass, beanContext, implClass, beanFilter, pojoSwap, childPojoSwaps, false);
 	}
 
 	/**
@@ -122,13 +126,26 @@ public final class ClassMeta<T> implements Type {
 	 *
 	 * @param innerClass The class being wrapped.
 	 * @param beanContext The bean context that created this object.
+	 * @param implClass For interfaces and abstract classes, this represents the "real" class to instantiate.
+	 * 	Can be <jk>null</jk>.
+	 * @param beanFilter The {@link BeanFilter} programmatically associated with this class.
+	 * 	Can be <jk>null</jk>.
+	 * @param pojoSwap The {@link PojoSwap} programmatically associated with this class.
+	 * 	Can be <jk>null</jk>.
+	 * @param childPojoSwap The child {@link PojoSwap PojoSwaps} programmatically associated with this class.
+	 * 	These are the <code>PojoSwaps</code> that have normal classes that are subclasses of this class.
+	 * 	Can be <jk>null</jk>.
 	 * @param delayedInit Don't call init() in constructor.
 	 * 	Used for delayed initialization when the possibility of class reference loops exist.
 	 */
 	@SuppressWarnings({ "rawtypes", "unchecked" })
-	ClassMeta(Class<T> innerClass, BeanContext beanContext, boolean delayedInit) {
+	ClassMeta(Class<T> innerClass, BeanContext beanContext, Class<? extends T> implClass, BeanFilter beanFilter, PojoSwap<T,?> pojoSwap, PojoSwap<?,?>[] childPojoSwaps, boolean delayedInit) {
 		this.innerClass = innerClass;
 		this.beanContext = beanContext;
+		this.implClass = implClass;
+		this.childPojoSwaps = childPojoSwaps;
+		this.childSwapMap = childPojoSwaps == null ? null : new ConcurrentHashMap<Class<?>,PojoSwap<?,?>>();
+		this.childUnswapMap = childPojoSwaps == null ? null : new ConcurrentHashMap<Class<?>,PojoSwap<?,?>>();
 
 		Class<T> c = innerClass;
 		ClassCategory _cc = ClassCategory.OTHER;
@@ -351,6 +368,41 @@ public final class ClassMeta<T> implements Type {
 			}
 		}
 
+		if (innerClass != Object.class) {
+			_noArgConstructor = (Constructor<T>)findNoArgConstructor(implClass == null ? innerClass : implClass, Visibility.PUBLIC);
+		}
+
+		if (beanFilter == null)
+			beanFilter = findBeanFilter();
+
+		PojoSwap ps = null;
+		if (_swapMethod != null) {
+			ps = new PojoSwap<T,Object>(c, _swapMethod.getReturnType()) {
+				@Override
+				public Object swap(BeanSession session, Object o) throws SerializeException {
+					try {
+						return swapMethod.invoke(o, session);
+					} catch (Exception e) {
+						throw new SerializeException(e);
+					}
+				}
+				@Override
+				public T unswap(BeanSession session, Object f, ClassMeta<?> hint) throws ParseException {
+					try {
+						if (swapConstructor != null)
+							return swapConstructor.newInstance(f);
+						return super.unswap(session, f, hint);
+					} catch (Exception e) {
+						throw new ParseException(e);
+					}
+				}
+			};
+		}
+		if (ps == null)
+			ps = findPojoSwap();
+		if (ps == null)
+			ps = pojoSwap;
+
 		this.cc = _cc;
 		this.isDelegate = _isDelegate;
 		this.fromStringMethod = _fromStringMethod;
@@ -368,6 +420,8 @@ public final class ClassMeta<T> implements Type {
 		this.primitiveDefault = _primitiveDefault;
 		this.publicMethods = _publicMethods;
 		this.remoteableMethods = _remoteableMethods;
+		this.beanFilter = beanFilter;
+		this.pojoSwap = ps;
 
 		if (! delayedInit)
 			init();
@@ -379,6 +433,10 @@ public final class ClassMeta<T> implements Type {
 	 */
 	ClassMeta(ClassMeta<T> mainType, ClassMeta<?> keyType, ClassMeta<?> valueType, ClassMeta<?> elementType) {
 		this.innerClass = mainType.innerClass;
+		this.implClass = mainType.implClass;
+		this.childPojoSwaps = mainType.childPojoSwaps;
+		this.childSwapMap = mainType.childSwapMap;
+		this.childUnswapMap = mainType.childUnswapMap;
 		this.cc = mainType.cc;
 		this.fromStringMethod = mainType.fromStringMethod;
 		this.noArgConstructor = mainType.noArgConstructor;
@@ -412,76 +470,40 @@ public final class ClassMeta<T> implements Type {
 		this.beanFilter = mainType.beanFilter;
 		this.extMeta = mainType.extMeta;
 		this.initException = mainType.initException;
-		this.hasChildPojoSwaps = mainType.hasChildPojoSwaps;
 	}
 
 	@SuppressWarnings({ "unchecked", "rawtypes" })
 	ClassMeta init() {
 
 		try {
-			beanFilter = findBeanFilter(beanContext);
-			pojoSwap = findPojoSwap(beanContext);
-
-			if (innerClass != Object.class) {
-				this.noArgConstructor = beanContext.getImplClassConstructor(innerClass, Visibility.PUBLIC);
-				if (noArgConstructor == null)
-					noArgConstructor = findNoArgConstructor(innerClass, Visibility.PUBLIC);
-			}
-
-			this.hasChildPojoSwaps = beanContext.hasChildPojoSwaps(innerClass);
-
-			Class c = innerClass;
-
-			if (swapMethod != null) {
-				this.pojoSwap = new PojoSwap<T,Object>(c, swapMethod.getReturnType()) {
-					@Override
-					public Object swap(BeanSession session, Object o) throws SerializeException {
-						try {
-							return swapMethod.invoke(o, session);
-						} catch (Exception e) {
-							throw new SerializeException(e);
-						}
-					}
-					@Override
-					public T unswap(BeanSession session, Object f, ClassMeta<?> hint) throws ParseException {
-						try {
-							if (swapConstructor != null)
-								return swapConstructor.newInstance(f);
-							return super.unswap(session, f, hint);
-						} catch (Exception e) {
-							throw new ParseException(e);
-						}
-					}
-				};
-			}
 
-			serializedClassMeta = (pojoSwap == null ? this : beanContext.getClassMeta(pojoSwap.getSwapClass()));
+			serializedClassMeta = (pojoSwap == null ? this : findClassMeta(pojoSwap.getSwapClass()));
 			if (serializedClassMeta == null)
 				serializedClassMeta = this;
 
 			// If this is an array, get the element type.
 			if (cc == ARRAY)
-				elementType = beanContext.getClassMeta(innerClass.getComponentType());
+				elementType = findClassMeta(innerClass.getComponentType());
 
 			// If this is a MAP, see if it's parameterized (e.g. AddressBook extends HashMap<String,Person>)
 			else if (cc == MAP) {
-				ClassMeta[] parameters = beanContext.findParameters(innerClass, innerClass);
+				ClassMeta[] parameters = findParameters();
 				if (parameters != null && parameters.length == 2) {
 					keyType = parameters[0];
 					valueType = parameters[1];
 				} else {
-					keyType = beanContext.getClassMeta(Object.class);
-					valueType = beanContext.getClassMeta(Object.class);
+					keyType = findClassMeta(Object.class);
+					valueType = findClassMeta(Object.class);
 				}
 			}
 
 			// If this is a COLLECTION, see if it's parameterized (e.g. AddressBook extends LinkedList<Person>)
 			else if (cc == COLLECTION) {
-				ClassMeta[] parameters = beanContext.findParameters(innerClass, innerClass);
+				ClassMeta[] parameters = findParameters();
 				if (parameters != null && parameters.length == 1) {
 					elementType = parameters[0];
 				} else {
-					elementType = beanContext.getClassMeta(Object.class);
+					elementType = findClassMeta(Object.class);
 				}
 			}
 
@@ -520,6 +542,43 @@ public final class ClassMeta<T> implements Type {
 		return this;
 	}
 
+	private ClassMeta<?> findClassMeta(Class<?> c) {
+		return beanContext.getClassMeta(c);
+	}
+
+	private ClassMeta<?>[] findParameters() {
+		return beanContext.findParameters(innerClass, innerClass);
+	}
+
+	private BeanFilter findBeanFilter() {
+		try {
+			List<Bean> ba = ReflectionUtils.findAnnotations(Bean.class, innerClass);
+			if (! ba.isEmpty())
+				return new AnnotationBeanFilterBuilder(innerClass, ba).build();
+		} catch (Exception e) {
+			throw new RuntimeException(e);
+		}
+		return null;
+	}
+
+	@SuppressWarnings("unchecked")
+	private PojoSwap<T,?> findPojoSwap() {
+		try {
+			Pojo p = innerClass.getAnnotation(Pojo.class);
+			if (p != null) {
+				Class<?> c = p.swap();
+				if (c != Null.class) {
+					if (ClassUtils.isParentClass(PojoSwap.class, c))
+						return (PojoSwap<T,?>)c.newInstance();
+					throw new RuntimeException("TODO - Surrogate classes not yet supported.");
+				}
+			}
+			return null;
+		} catch (Exception e) {
+			throw new RuntimeException(e);
+		}
+	}
+
 	/**
 	 * Returns the bean dictionary name associated with this class.
 	 * <p>
@@ -589,45 +648,58 @@ public final class ClassMeta<T> implements Type {
 	 *
 	 * @return <jk>true</jk> if this class or any child classes has a {@link PojoSwap} associated with it.
 	 */
-	public boolean hasChildPojoSwaps() {
-		return hasChildPojoSwaps;
+	protected boolean hasChildPojoSwaps() {
+		return childPojoSwaps != null;
 	}
 
-	private BeanFilter findBeanFilter(BeanContext context) {
-		try {
-			if (context == null)
+	/**
+	 * Returns the {@link PojoSwap} where the specified class is the same/subclass of the normal class of
+	 * one of the child pojo swaps associated with this class.
+	 *
+	 * @param normalClass The normal class being resolved.
+	 * @return The resolved {@link PojoSwap} or <jk>null</jk> if none were found.
+	 */
+	protected PojoSwap<?,?> getChildPojoSwapForSwap(Class<?> normalClass) {
+		if (childSwapMap != null) {
+			PojoSwap<?,?> s = childSwapMap.get(normalClass);
+			if (s == null) {
+				for (PojoSwap<?,?> f : childPojoSwaps)
+					if (s == null && isParentClass(f.getNormalClass(), normalClass))
+						s = f;
+				if (s == null)
+					 s = PojoSwap.NULL;
+				childSwapMap.putIfAbsent(normalClass, s);
+			}
+			if (s == PojoSwap.NULL)
 				return null;
-			BeanFilter f = context.findBeanFilter(innerClass);
-			if (f != null)
-				return f;
-			List<Bean> ba = ReflectionUtils.findAnnotations(Bean.class, innerClass);
-			if (! ba.isEmpty())
-				f = new AnnotationBeanFilterBuilder(innerClass, ba).build();
-			return f;
-		} catch (Exception e) {
-			throw new RuntimeException(e);
+			return s;
 		}
+		return null;
 	}
 
-	@SuppressWarnings("unchecked")
-	private PojoSwap<T,?> findPojoSwap(BeanContext context) {
-		try {
-			Pojo p = innerClass.getAnnotation(Pojo.class);
-			if (p != null) {
-				Class<?> c = p.swap();
-				if (c != Null.class) {
-					if (ClassUtils.isParentClass(PojoSwap.class, c))
-						return (PojoSwap<T,?>)c.newInstance();
-					throw new RuntimeException("TODO - Surrogate classes not yet supported.");
-				}
+	/**
+	 * Returns the {@link PojoSwap} where the specified class is the same/subclass of the swap class of
+	 * one of the child pojo swaps associated with this class.
+	 *
+	 * @param swapClass The swap class being resolved.
+	 * @return The resolved {@link PojoSwap} or <jk>null</jk> if none were found.
+	 */
+	protected PojoSwap<?,?> getChildPojoSwapForUnswap(Class<?> swapClass) {
+		if (childUnswapMap != null) {
+			PojoSwap<?,?> s = childUnswapMap.get(swapClass);
+			if (s == null) {
+				for (PojoSwap<?,?> f : childPojoSwaps)
+					if (s == null && isParentClass(f.getSwapClass(), swapClass))
+						s = f;
+				if (s == null)
+					 s = PojoSwap.NULL;
+				childUnswapMap.putIfAbsent(swapClass, s);
 			}
-			if (context == null)
+			if (s == PojoSwap.NULL)
 				return null;
-			PojoSwap<T,?> f = context.findPojoSwap(innerClass);
-			return f;
-		} catch (Exception e) {
-			throw new RuntimeException(e);
+			return s;
 		}
+		return null;
 	}
 
 	/**
@@ -1504,4 +1576,31 @@ public final class ClassMeta<T> implements Type {
 	public int hashCode() {
 		return super.hashCode();
 	}
+//
+//	public abstract static class CreateSession {
+//		LinkedList<ClassMeta<?>> stack;
+//
+//		public CreateSession push(ClassMeta<?> cm) {
+//			if (stack == null)
+//				stack = new LinkedList<ClassMeta<?>>();
+//			stack.add(cm);
+//			return this;
+//		}
+//
+//		public CreateSession pop(ClassMeta<?> expected) {
+//			if (stack == null || stack.removeLast() != expected)
+//				throw new BeanRuntimeException("ClassMetaSession creation stack corruption!");
+//			return this;
+//		}
+//
+//		public <T> ClassMeta<T> getClassMeta(Class<T> c) {
+//			if (stack != null)
+//				for (ClassMeta<?> cm : stack)
+//					if (cm.innerClass == c)
+//						return (ClassMeta<T>)cm;
+//			return createClassMeta(c);
+//		}
+//
+//		public abstract <T> ClassMeta<T> createClassMeta(Class<T> c);
+//	}
 }

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/61894c85/juneau-core/src/main/java/org/apache/juneau/transform/PojoSwap.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/transform/PojoSwap.java b/juneau-core/src/main/java/org/apache/juneau/transform/PojoSwap.java
index ec97dd8..5a1d104 100644
--- a/juneau-core/src/main/java/org/apache/juneau/transform/PojoSwap.java
+++ b/juneau-core/src/main/java/org/apache/juneau/transform/PojoSwap.java
@@ -98,6 +98,12 @@ import org.apache.juneau.serializer.*;
  */
 public abstract class PojoSwap<T,S> {
 
+	/**
+	 * Represents a non-existent pojo swap.
+	 */
+	@SuppressWarnings({ "unchecked", "rawtypes" })
+	public final static PojoSwap NULL = new PojoSwap(null, null) {};
+
 	private final Class<T> normalClass;
 	private final Class<?> swapClass;
 	private ClassMeta<?> swapClassMeta;


[3/5] incubator-juneau git commit: Improvements to ClassMeta class.

Posted by ja...@apache.org.
Improvements to ClassMeta class.

Project: http://git-wip-us.apache.org/repos/asf/incubator-juneau/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-juneau/commit/96cf56b4
Tree: http://git-wip-us.apache.org/repos/asf/incubator-juneau/tree/96cf56b4
Diff: http://git-wip-us.apache.org/repos/asf/incubator-juneau/diff/96cf56b4

Branch: refs/heads/master
Commit: 96cf56b4aa448d34b86aa96631d65886db241b2a
Parents: 062d7dd
Author: JamesBognar <ja...@apache.org>
Authored: Sat Feb 4 17:49:42 2017 -0500
Committer: JamesBognar <ja...@apache.org>
Committed: Sat Feb 4 17:49:42 2017 -0500

----------------------------------------------------------------------
 .../main/java/org/apache/juneau/ClassMeta.java  | 35 ++++----------------
 1 file changed, 6 insertions(+), 29 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/96cf56b4/juneau-core/src/main/java/org/apache/juneau/ClassMeta.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/ClassMeta.java b/juneau-core/src/main/java/org/apache/juneau/ClassMeta.java
index 5e079c4..586d0b5 100644
--- a/juneau-core/src/main/java/org/apache/juneau/ClassMeta.java
+++ b/juneau-core/src/main/java/org/apache/juneau/ClassMeta.java
@@ -88,6 +88,11 @@ public final class ClassMeta<T> implements Type {
 	final ConcurrentHashMap<Class<?>,PojoSwap<?,?>>
 		childSwapMap,                                        // Maps normal subclasses to PojoSwaps.
 		childUnswapMap;                                      // Maps swap subclasses to PojoSwaps.
+	final PojoSwap<T,?> pojoSwap;                           // The object POJO swap associated with this bean (if it has one).
+	final BeanFilter beanFilter;                            // The bean filter associated with this bean (if it has one).
+
+	private final MetadataMap extMeta;                      // Extended metadata
+
 
 	final BeanContext beanContext;                    // The bean context that created this object.
 	ClassMeta<?>
@@ -99,10 +104,6 @@ public final class ClassMeta<T> implements Type {
 	BeanMeta<T> beanMeta;                             // The bean meta for this bean class (if it's a bean).
 	String dictionaryName, resolvedDictionaryName;    // The dictionary name of this class if it has one.
 	String notABeanReason;                            // If this isn't a bean, the reason why.
-	PojoSwap<T,?> pojoSwap;                           // The object POJO swap associated with this bean (if it has one).
-	BeanFilter beanFilter;                            // The bean filter associated with this bean (if it has one).
-
-	private MetadataMap extMeta = new MetadataMap();  // Extended metadata
 	private Throwable initException;                  // Any exceptions thrown in the init() method.
 
 	private static final Boolean BOOLEAN_DEFAULT = false;
@@ -422,6 +423,7 @@ public final class ClassMeta<T> implements Type {
 		this.remoteableMethods = _remoteableMethods;
 		this.beanFilter = beanFilter;
 		this.pojoSwap = ps;
+		this.extMeta = new MetadataMap();
 
 		if (! delayedInit)
 			init();
@@ -477,31 +479,6 @@ public final class ClassMeta<T> implements Type {
 
 		try {
 
-			Class c = innerClass;
-
-			if (swapMethod != null) {
-				this.pojoSwap = new PojoSwap<T,Object>(c, swapMethod.getReturnType()) {
-					@Override
-					public Object swap(BeanSession session, Object o) throws SerializeException {
-						try {
-							return swapMethod.invoke(o, session);
-						} catch (Exception e) {
-							throw new SerializeException(e);
-						}
-					}
-					@Override
-					public T unswap(BeanSession session, Object f, ClassMeta<?> hint) throws ParseException {
-						try {
-							if (swapConstructor != null)
-								return swapConstructor.newInstance(f);
-							return super.unswap(session, f, hint);
-						} catch (Exception e) {
-							throw new ParseException(e);
-						}
-					}
-				};
-			}
-
 			serializedClassMeta = (pojoSwap == null ? this : findClassMeta(pojoSwap.getSwapClass()));
 			if (serializedClassMeta == null)
 				serializedClassMeta = this;


[5/5] incubator-juneau git commit: Fix merge issue.

Posted by ja...@apache.org.
Fix merge issue.

Project: http://git-wip-us.apache.org/repos/asf/incubator-juneau/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-juneau/commit/4bc66a6a
Tree: http://git-wip-us.apache.org/repos/asf/incubator-juneau/tree/4bc66a6a
Diff: http://git-wip-us.apache.org/repos/asf/incubator-juneau/diff/4bc66a6a

Branch: refs/heads/master
Commit: 4bc66a6a9ec549fc00ff2581d7ff68dfa9997adc
Parents: 23dc784
Author: JamesBognar <ja...@apache.org>
Authored: Sat Feb 4 17:52:58 2017 -0500
Committer: JamesBognar <ja...@apache.org>
Committed: Sat Feb 4 17:52:58 2017 -0500

----------------------------------------------------------------------
 .../src/main/java/org/apache/juneau/ClassMeta.java        | 10 ----------
 1 file changed, 10 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/4bc66a6a/juneau-core/src/main/java/org/apache/juneau/ClassMeta.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/ClassMeta.java b/juneau-core/src/main/java/org/apache/juneau/ClassMeta.java
index 47e3ca5..90cdd49 100644
--- a/juneau-core/src/main/java/org/apache/juneau/ClassMeta.java
+++ b/juneau-core/src/main/java/org/apache/juneau/ClassMeta.java
@@ -85,7 +85,6 @@ public final class ClassMeta<T> implements Type {
 		remoteableMethods,                                   // Methods annotated with @Remoteable.  Contains all public methods if class is annotated with @Remotable.
 		publicMethods;                                       // All public methods, including static methods.
 	final PojoSwap<?,?>[] childPojoSwaps;                   // Any PojoSwaps where the normal type is a subclass of this class.
-<<<<<<< HEAD
 	final ConcurrentHashMap<Class<?>,PojoSwap<?,?>>
 		childSwapMap,                                        // Maps normal subclasses to PojoSwaps.
 		childUnswapMap;                                      // Maps swap subclasses to PojoSwaps.
@@ -94,12 +93,6 @@ public final class ClassMeta<T> implements Type {
 
 	private final MetadataMap extMeta;                      // Extended metadata
 
-=======
-	final ConcurrentHashMap<Class<?>,PojoSwap<?,?>> 
-		childSwapMap,                                        // Maps normal subclasses to PojoSwaps.
-		childUnswapMap;                                      // Maps swap subclasses to PojoSwaps.
->>>>>>> master
-
 	final BeanContext beanContext;                    // The bean context that created this object.
 	ClassMeta<?>
 		serializedClassMeta,                           // The transformed class type (if class has swap associated with it).
@@ -429,10 +422,7 @@ public final class ClassMeta<T> implements Type {
 		this.remoteableMethods = _remoteableMethods;
 		this.beanFilter = beanFilter;
 		this.pojoSwap = ps;
-<<<<<<< HEAD
 		this.extMeta = new MetadataMap();
-=======
->>>>>>> master
 
 		if (! delayedInit)
 			init();


[4/5] incubator-juneau git commit: Merge branch 'master' into HEAD

Posted by ja...@apache.org.
Merge branch 'master' into HEAD

# Conflicts:
#	juneau-core/src/main/java/org/apache/juneau/ClassMeta.java


Project: http://git-wip-us.apache.org/repos/asf/incubator-juneau/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-juneau/commit/23dc784a
Tree: http://git-wip-us.apache.org/repos/asf/incubator-juneau/tree/23dc784a
Diff: http://git-wip-us.apache.org/repos/asf/incubator-juneau/diff/23dc784a

Branch: refs/heads/master
Commit: 23dc784adcf80ad00b39332495bbedf2a344f875
Parents: 96cf56b 61894c8
Author: JamesBognar <ja...@apache.org>
Authored: Sat Feb 4 17:51:41 2017 -0500
Committer: JamesBognar <ja...@apache.org>
Committed: Sat Feb 4 17:51:41 2017 -0500

----------------------------------------------------------------------
 .../main/java/org/apache/juneau/ClassMeta.java  |  9 ++++++
 .../org/apache/juneau/utils/ObjectUtils.java    | 32 ++++++++++++++++++++
 2 files changed, 41 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/23dc784a/juneau-core/src/main/java/org/apache/juneau/ClassMeta.java
----------------------------------------------------------------------
diff --cc juneau-core/src/main/java/org/apache/juneau/ClassMeta.java
index 586d0b5,f103b2a..47e3ca5
--- a/juneau-core/src/main/java/org/apache/juneau/ClassMeta.java
+++ b/juneau-core/src/main/java/org/apache/juneau/ClassMeta.java
@@@ -85,14 -85,9 +85,20 @@@ public final class ClassMeta<T> impleme
  		remoteableMethods,                                   // Methods annotated with @Remoteable.  Contains all public methods if class is annotated with @Remotable.
  		publicMethods;                                       // All public methods, including static methods.
  	final PojoSwap<?,?>[] childPojoSwaps;                   // Any PojoSwaps where the normal type is a subclass of this class.
++<<<<<<< HEAD
 +	final ConcurrentHashMap<Class<?>,PojoSwap<?,?>>
 +		childSwapMap,                                        // Maps normal subclasses to PojoSwaps.
 +		childUnswapMap;                                      // Maps swap subclasses to PojoSwaps.
 +	final PojoSwap<T,?> pojoSwap;                           // The object POJO swap associated with this bean (if it has one).
 +	final BeanFilter beanFilter;                            // The bean filter associated with this bean (if it has one).
 +
 +	private final MetadataMap extMeta;                      // Extended metadata
 +
++=======
+ 	final ConcurrentHashMap<Class<?>,PojoSwap<?,?>> 
+ 		childSwapMap,                                        // Maps normal subclasses to PojoSwaps.
+ 		childUnswapMap;                                      // Maps swap subclasses to PojoSwaps.
++>>>>>>> master
  
  	final BeanContext beanContext;                    // The bean context that created this object.
  	ClassMeta<?>
@@@ -423,7 -422,6 +429,10 @@@
  		this.remoteableMethods = _remoteableMethods;
  		this.beanFilter = beanFilter;
  		this.pojoSwap = ps;
++<<<<<<< HEAD
 +		this.extMeta = new MetadataMap();
++=======
++>>>>>>> master
  
  		if (! delayedInit)
  			init();

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/23dc784a/juneau-core/src/main/java/org/apache/juneau/utils/ObjectUtils.java
----------------------------------------------------------------------
diff --cc juneau-core/src/main/java/org/apache/juneau/utils/ObjectUtils.java
index 0000000,0000000..7cd68fe
new file mode 100644
--- /dev/null
+++ b/juneau-core/src/main/java/org/apache/juneau/utils/ObjectUtils.java
@@@ -1,0 -1,0 +1,32 @@@
++// ***************************************************************************************************************************
++// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
++// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
++// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
++// * with the License.  You may obtain a copy of the License at                                                              *
++// *                                                                                                                         *
++// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
++// *                                                                                                                         *
++// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
++// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
++// * specific language governing permissions and limitations under the License.                                              *
++// ***************************************************************************************************************************
++package org.apache.juneau.utils;
++
++/**
++ * TODO
++ */
++public class ObjectUtils {
++//
++//	private static final ConcurrentHashMap<Class<?>,ClassMetaSimple> metaCache = new ConcurrentHashMap<Class<?>,ClassMetaSimple>();
++//
++//	public static <T> T convertToType(Class<T> c, Object value, Object outer) {
++//		return null;
++//
++//		ClassMetaSimple<T> type = metaCache.get(c);
++//		if (type == null) {
++//			metaCache.putIfAbsent(c, new ClassMetaSimple<T>(c));
++//			type = metaCache.get(c);
++//		}
++//
++//	}
++}


[2/5] incubator-juneau git commit: Improvements to ClassMeta/BeanContext (2).

Posted by ja...@apache.org.
Improvements to ClassMeta/BeanContext (2).

Project: http://git-wip-us.apache.org/repos/asf/incubator-juneau/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-juneau/commit/062d7ddc
Tree: http://git-wip-us.apache.org/repos/asf/incubator-juneau/tree/062d7ddc
Diff: http://git-wip-us.apache.org/repos/asf/incubator-juneau/diff/062d7ddc

Branch: refs/heads/master
Commit: 062d7ddc65b462128c43b9673c20104dcfd58e80
Parents: c8fa4ed
Author: JamesBognar <ja...@apache.org>
Authored: Sat Feb 4 17:44:09 2017 -0500
Committer: JamesBognar <ja...@apache.org>
Committed: Sat Feb 4 17:44:09 2017 -0500

----------------------------------------------------------------------
 .../java/org/apache/juneau/BeanContext.java     |  48 +++-
 .../org/apache/juneau/BeanPropertyMeta.java     |   8 +-
 .../main/java/org/apache/juneau/ClassMeta.java  | 237 +++++++++++++------
 .../org/apache/juneau/transform/PojoSwap.java   |   6 +
 4 files changed, 207 insertions(+), 92 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/062d7ddc/juneau-core/src/main/java/org/apache/juneau/BeanContext.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/BeanContext.java b/juneau-core/src/main/java/org/apache/juneau/BeanContext.java
index 05006f3..1cb9180 100644
--- a/juneau-core/src/main/java/org/apache/juneau/BeanContext.java
+++ b/juneau-core/src/main/java/org/apache/juneau/BeanContext.java
@@ -1155,8 +1155,8 @@ public class BeanContext extends Context {
 
 		if (! cmCacheCache.containsKey(hashCode)) {
 			ConcurrentHashMap<Class,ClassMeta> cm = new ConcurrentHashMap<Class,ClassMeta>();
-			cm.put(String.class, new ClassMeta(String.class, this));
-			cm.put(Object.class, new ClassMeta(Object.class, this));
+			cm.put(String.class, new ClassMeta(String.class, this, null, null, findPojoSwap(String.class), findChildPojoSwaps(String.class)));
+			cm.put(Object.class, new ClassMeta(Object.class, this, null, null, findPojoSwap(Object.class), findChildPojoSwaps(Object.class)));
 			cmCacheCache.putIfAbsent(hashCode, cm);
 		}
 		this.cmCache = cmCacheCache.get(hashCode);
@@ -1385,7 +1385,7 @@ public class BeanContext extends Context {
 		// Note that if it has a pojo swap, we still want to cache it so that
 		// we can cache something like byte[] with ByteArrayBase64Swap.
 		if (c.isArray() && findPojoSwap(c) == null)
-			return new ClassMeta(c, this);
+			return new ClassMeta(c, this, findImplClass(c), findBeanFilter(c), findPojoSwap(c), findChildPojoSwaps(c));
 
 		// This can happen if we have transforms defined against String or Object.
 		if (cmCache == null)
@@ -1407,7 +1407,7 @@ public class BeanContext extends Context {
 						if (pcm.innerClass == c)
 							return pcm;
 
-					cm = new ClassMeta<T>(c, this, true);
+					cm = new ClassMeta<T>(c, this, findImplClass(c), findBeanFilter(c), findPojoSwap(c), findChildPojoSwaps(c), true);
 					pendingClassMetas.addLast(cm);
 					try {
 						cm.init();
@@ -1751,7 +1751,7 @@ public class BeanContext extends Context {
 	 * @param c The class associated with the swap.
 	 * @return The swap associated with the class, or null if there is no association.
 	 */
-	protected final <T> PojoSwap findPojoSwap(Class<T> c) {
+	private final <T> PojoSwap findPojoSwap(Class<T> c) {
 		// Note:  On first
 		if (c != null)
 			for (PojoSwap f : pojoSwaps)
@@ -1765,12 +1765,18 @@ public class BeanContext extends Context {
 	 * @param c The class to check.
 	 * @return <jk>true</jk> if the specified class or one of its subclasses has a {@link PojoSwap} associated with it.
 	 */
-	protected final boolean hasChildPojoSwaps(Class<?> c) {
-		if (c != null)
-			for (PojoSwap f : pojoSwaps)
-				if (isParentClass(c, f.getNormalClass()))
-					return true;
-		return false;
+	private final PojoSwap[] findChildPojoSwaps(Class<?> c) {
+		if (c == null || pojoSwaps.length == 0)
+			return null;
+		List<PojoSwap> l = null;
+		for (PojoSwap f : pojoSwaps) {
+			if (isParentClass(c, f.getNormalClass())) {
+				if (l == null)
+					l = new ArrayList<PojoSwap>();
+				l.add(f);
+			}
+		}
+		return l == null ? null : l.toArray(new PojoSwap[l.size()]);
 	}
 
 	/**
@@ -1781,7 +1787,7 @@ public class BeanContext extends Context {
 	 * @param c The class associated with the bean filter.
 	 * @return The bean filter associated with the class, or null if there is no association.
 	 */
-	protected final <T> BeanFilter findBeanFilter(Class<T> c) {
+	private final <T> BeanFilter findBeanFilter(Class<T> c) {
 		if (c != null)
 			for (BeanFilter f : beanFilters)
 				if (isParentClass(f.getBeanClass(), c))
@@ -1833,6 +1839,24 @@ public class BeanContext extends Context {
 		return null;
 	}
 
+	private final <T> Class<? extends T> findImplClass(Class<T> c) {
+		if (implClasses.isEmpty())
+			return null;
+		Class cc = c;
+		while (cc != null) {
+			Class implClass = implClasses.get(cc);
+			if (implClass != null)
+				return implClass;
+			for (Class ic : cc.getInterfaces()) {
+				implClass = implClasses.get(ic);
+				if (implClass != null)
+					return implClass;
+			}
+			cc = cc.getSuperclass();
+		}
+		return null;
+	}
+
 	/**
 	 * Returns a reusable {@link ClassMeta} representation for the class <code>Object</code>.
 	 * <p>

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/062d7ddc/juneau-core/src/main/java/org/apache/juneau/BeanPropertyMeta.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/BeanPropertyMeta.java b/juneau-core/src/main/java/org/apache/juneau/BeanPropertyMeta.java
index ce7fdb5..a9e52f0 100644
--- a/juneau-core/src/main/java/org/apache/juneau/BeanPropertyMeta.java
+++ b/juneau-core/src/main/java/org/apache/juneau/BeanPropertyMeta.java
@@ -848,9 +848,7 @@ public class BeanPropertyMeta {
 			return null;
 		// Otherwise, look it up via bean context.
 		if (rawTypeMeta.hasChildPojoSwaps()) {
-			Class c = o.getClass();
-			ClassMeta<?> cm = rawTypeMeta.innerClass == c ? rawTypeMeta : beanContext.getClassMeta(c);
-			PojoSwap f = cm.getPojoSwap();
+			PojoSwap f = rawTypeMeta.getChildPojoSwapForSwap(o.getClass());
 			if (f != null)
 				return f.swap(session, o);
 		}
@@ -863,9 +861,7 @@ public class BeanPropertyMeta {
 		if (o == null)
 			return null;
 		if (rawTypeMeta.hasChildPojoSwaps()) {
-			Class c = o.getClass();
-			ClassMeta<?> cm = rawTypeMeta.innerClass == c ? rawTypeMeta : beanContext.getClassMeta(c);
-			PojoSwap f = cm.getPojoSwap();
+			PojoSwap f = rawTypeMeta.getChildPojoSwapForUnswap(o.getClass());
 			if (f != null)
 				return f.unswap(session, o, rawTypeMeta);
 		}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/062d7ddc/juneau-core/src/main/java/org/apache/juneau/ClassMeta.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/ClassMeta.java b/juneau-core/src/main/java/org/apache/juneau/ClassMeta.java
index e98f595..5e079c4 100644
--- a/juneau-core/src/main/java/org/apache/juneau/ClassMeta.java
+++ b/juneau-core/src/main/java/org/apache/juneau/ClassMeta.java
@@ -21,6 +21,7 @@ import java.lang.reflect.Proxy;
 import java.net.*;
 import java.net.URI;
 import java.util.*;
+import java.util.concurrent.*;
 
 import org.apache.juneau.annotation.*;
 import org.apache.juneau.internal.*;
@@ -57,9 +58,10 @@ public final class ClassMeta<T> implements Type {
 	}
 
 	final Class<T> innerClass;                              // The class being wrapped.
+	final Class<? extends T> implClass;                     // The implementation class to use if this is an interface.
 	final ClassCategory cc;                                 // The class category.
 	final Method fromStringMethod;                          // The static valueOf(String) or fromString(String) or forString(String) method (if it has one).
-	Constructor<? extends T>
+	final Constructor<? extends T>
 		noArgConstructor;                                    // The no-arg constructor for this class (if it has one).
 	final Constructor<T>
 		stringConstructor,                                   // The X(String) constructor (if it has one).
@@ -82,7 +84,10 @@ public final class ClassMeta<T> implements Type {
 	final Map<String,Method>
 		remoteableMethods,                                   // Methods annotated with @Remoteable.  Contains all public methods if class is annotated with @Remotable.
 		publicMethods;                                       // All public methods, including static methods.
-
+	final PojoSwap<?,?>[] childPojoSwaps;                   // Any PojoSwaps where the normal type is a subclass of this class.
+	final ConcurrentHashMap<Class<?>,PojoSwap<?,?>>
+		childSwapMap,                                        // Maps normal subclasses to PojoSwaps.
+		childUnswapMap;                                      // Maps swap subclasses to PojoSwaps.
 
 	final BeanContext beanContext;                    // The bean context that created this object.
 	ClassMeta<?>
@@ -99,7 +104,6 @@ public final class ClassMeta<T> implements Type {
 
 	private MetadataMap extMeta = new MetadataMap();  // Extended metadata
 	private Throwable initException;                  // Any exceptions thrown in the init() method.
-	private boolean hasChildPojoSwaps;                // True if this class or any subclass of this class has a PojoSwap associated with it.
 
 	private static final Boolean BOOLEAN_DEFAULT = false;
 	private static final Character CHARACTER_DEFAULT = (char)0;
@@ -113,8 +117,8 @@ public final class ClassMeta<T> implements Type {
 	/**
 	 * Shortcut for calling <code>ClassMeta(innerClass, beanContext, <jk>false</jk>)</code>.
 	 */
-	ClassMeta(Class<T> innerClass, BeanContext beanContext) {
-		this(innerClass, beanContext, false);
+	ClassMeta(Class<T> innerClass, BeanContext beanContext, Class<? extends T> implClass, BeanFilter beanFilter, PojoSwap<T,?> pojoSwap, PojoSwap<?,?>[] childPojoSwaps) {
+		this(innerClass, beanContext, implClass, beanFilter, pojoSwap, childPojoSwaps, false);
 	}
 
 	/**
@@ -122,13 +126,26 @@ public final class ClassMeta<T> implements Type {
 	 *
 	 * @param innerClass The class being wrapped.
 	 * @param beanContext The bean context that created this object.
+	 * @param implClass For interfaces and abstract classes, this represents the "real" class to instantiate.
+	 * 	Can be <jk>null</jk>.
+	 * @param beanFilter The {@link BeanFilter} programmatically associated with this class.
+	 * 	Can be <jk>null</jk>.
+	 * @param pojoSwap The {@link PojoSwap} programmatically associated with this class.
+	 * 	Can be <jk>null</jk>.
+	 * @param childPojoSwap The child {@link PojoSwap PojoSwaps} programmatically associated with this class.
+	 * 	These are the <code>PojoSwaps</code> that have normal classes that are subclasses of this class.
+	 * 	Can be <jk>null</jk>.
 	 * @param delayedInit Don't call init() in constructor.
 	 * 	Used for delayed initialization when the possibility of class reference loops exist.
 	 */
 	@SuppressWarnings({ "rawtypes", "unchecked" })
-	ClassMeta(Class<T> innerClass, BeanContext beanContext, boolean delayedInit) {
+	ClassMeta(Class<T> innerClass, BeanContext beanContext, Class<? extends T> implClass, BeanFilter beanFilter, PojoSwap<T,?> pojoSwap, PojoSwap<?,?>[] childPojoSwaps, boolean delayedInit) {
 		this.innerClass = innerClass;
 		this.beanContext = beanContext;
+		this.implClass = implClass;
+		this.childPojoSwaps = childPojoSwaps;
+		this.childSwapMap = childPojoSwaps == null ? null : new ConcurrentHashMap<Class<?>,PojoSwap<?,?>>();
+		this.childUnswapMap = childPojoSwaps == null ? null : new ConcurrentHashMap<Class<?>,PojoSwap<?,?>>();
 
 		Class<T> c = innerClass;
 		ClassCategory _cc = ClassCategory.OTHER;
@@ -351,6 +368,41 @@ public final class ClassMeta<T> implements Type {
 			}
 		}
 
+		if (innerClass != Object.class) {
+			_noArgConstructor = (Constructor<T>)findNoArgConstructor(implClass == null ? innerClass : implClass, Visibility.PUBLIC);
+		}
+
+		if (beanFilter == null)
+			beanFilter = findBeanFilter();
+
+		PojoSwap ps = null;
+		if (_swapMethod != null) {
+			ps = new PojoSwap<T,Object>(c, _swapMethod.getReturnType()) {
+				@Override
+				public Object swap(BeanSession session, Object o) throws SerializeException {
+					try {
+						return swapMethod.invoke(o, session);
+					} catch (Exception e) {
+						throw new SerializeException(e);
+					}
+				}
+				@Override
+				public T unswap(BeanSession session, Object f, ClassMeta<?> hint) throws ParseException {
+					try {
+						if (swapConstructor != null)
+							return swapConstructor.newInstance(f);
+						return super.unswap(session, f, hint);
+					} catch (Exception e) {
+						throw new ParseException(e);
+					}
+				}
+			};
+		}
+		if (ps == null)
+			ps = findPojoSwap();
+		if (ps == null)
+			ps = pojoSwap;
+
 		this.cc = _cc;
 		this.isDelegate = _isDelegate;
 		this.fromStringMethod = _fromStringMethod;
@@ -368,6 +420,8 @@ public final class ClassMeta<T> implements Type {
 		this.primitiveDefault = _primitiveDefault;
 		this.publicMethods = _publicMethods;
 		this.remoteableMethods = _remoteableMethods;
+		this.beanFilter = beanFilter;
+		this.pojoSwap = ps;
 
 		if (! delayedInit)
 			init();
@@ -379,6 +433,10 @@ public final class ClassMeta<T> implements Type {
 	 */
 	ClassMeta(ClassMeta<T> mainType, ClassMeta<?> keyType, ClassMeta<?> valueType, ClassMeta<?> elementType) {
 		this.innerClass = mainType.innerClass;
+		this.implClass = mainType.implClass;
+		this.childPojoSwaps = mainType.childPojoSwaps;
+		this.childSwapMap = mainType.childSwapMap;
+		this.childUnswapMap = mainType.childUnswapMap;
 		this.cc = mainType.cc;
 		this.fromStringMethod = mainType.fromStringMethod;
 		this.noArgConstructor = mainType.noArgConstructor;
@@ -412,23 +470,12 @@ public final class ClassMeta<T> implements Type {
 		this.beanFilter = mainType.beanFilter;
 		this.extMeta = mainType.extMeta;
 		this.initException = mainType.initException;
-		this.hasChildPojoSwaps = mainType.hasChildPojoSwaps;
 	}
 
 	@SuppressWarnings({ "unchecked", "rawtypes" })
 	ClassMeta init() {
 
 		try {
-			beanFilter = findBeanFilter(beanContext);
-			pojoSwap = findPojoSwap(beanContext);
-
-			if (innerClass != Object.class) {
-				this.noArgConstructor = beanContext.getImplClassConstructor(innerClass, Visibility.PUBLIC);
-				if (noArgConstructor == null)
-					noArgConstructor = findNoArgConstructor(innerClass, Visibility.PUBLIC);
-			}
-
-			this.hasChildPojoSwaps = beanContext.hasChildPojoSwaps(innerClass);
 
 			Class c = innerClass;
 
@@ -528,6 +575,35 @@ public final class ClassMeta<T> implements Type {
 		return beanContext.findParameters(innerClass, innerClass);
 	}
 
+	private BeanFilter findBeanFilter() {
+		try {
+			List<Bean> ba = ReflectionUtils.findAnnotations(Bean.class, innerClass);
+			if (! ba.isEmpty())
+				return new AnnotationBeanFilterBuilder(innerClass, ba).build();
+		} catch (Exception e) {
+			throw new RuntimeException(e);
+		}
+		return null;
+	}
+
+	@SuppressWarnings("unchecked")
+	private PojoSwap<T,?> findPojoSwap() {
+		try {
+			Pojo p = innerClass.getAnnotation(Pojo.class);
+			if (p != null) {
+				Class<?> c = p.swap();
+				if (c != Null.class) {
+					if (ClassUtils.isParentClass(PojoSwap.class, c))
+						return (PojoSwap<T,?>)c.newInstance();
+					throw new RuntimeException("TODO - Surrogate classes not yet supported.");
+				}
+			}
+			return null;
+		} catch (Exception e) {
+			throw new RuntimeException(e);
+		}
+	}
+
 	/**
 	 * Returns the bean dictionary name associated with this class.
 	 * <p>
@@ -597,45 +673,58 @@ public final class ClassMeta<T> implements Type {
 	 *
 	 * @return <jk>true</jk> if this class or any child classes has a {@link PojoSwap} associated with it.
 	 */
-	public boolean hasChildPojoSwaps() {
-		return hasChildPojoSwaps;
+	protected boolean hasChildPojoSwaps() {
+		return childPojoSwaps != null;
 	}
 
-	private BeanFilter findBeanFilter(BeanContext context) {
-		try {
-			if (context == null)
+	/**
+	 * Returns the {@link PojoSwap} where the specified class is the same/subclass of the normal class of
+	 * one of the child pojo swaps associated with this class.
+	 *
+	 * @param normalClass The normal class being resolved.
+	 * @return The resolved {@link PojoSwap} or <jk>null</jk> if none were found.
+	 */
+	protected PojoSwap<?,?> getChildPojoSwapForSwap(Class<?> normalClass) {
+		if (childSwapMap != null) {
+			PojoSwap<?,?> s = childSwapMap.get(normalClass);
+			if (s == null) {
+				for (PojoSwap<?,?> f : childPojoSwaps)
+					if (s == null && isParentClass(f.getNormalClass(), normalClass))
+						s = f;
+				if (s == null)
+					 s = PojoSwap.NULL;
+				childSwapMap.putIfAbsent(normalClass, s);
+			}
+			if (s == PojoSwap.NULL)
 				return null;
-			BeanFilter f = context.findBeanFilter(innerClass);
-			if (f != null)
-				return f;
-			List<Bean> ba = ReflectionUtils.findAnnotations(Bean.class, innerClass);
-			if (! ba.isEmpty())
-				f = new AnnotationBeanFilterBuilder(innerClass, ba).build();
-			return f;
-		} catch (Exception e) {
-			throw new RuntimeException(e);
+			return s;
 		}
+		return null;
 	}
 
-	@SuppressWarnings("unchecked")
-	private PojoSwap<T,?> findPojoSwap(BeanContext context) {
-		try {
-			Pojo p = innerClass.getAnnotation(Pojo.class);
-			if (p != null) {
-				Class<?> c = p.swap();
-				if (c != Null.class) {
-					if (ClassUtils.isParentClass(PojoSwap.class, c))
-						return (PojoSwap<T,?>)c.newInstance();
-					throw new RuntimeException("TODO - Surrogate classes not yet supported.");
-				}
+	/**
+	 * Returns the {@link PojoSwap} where the specified class is the same/subclass of the swap class of
+	 * one of the child pojo swaps associated with this class.
+	 *
+	 * @param swapClass The swap class being resolved.
+	 * @return The resolved {@link PojoSwap} or <jk>null</jk> if none were found.
+	 */
+	protected PojoSwap<?,?> getChildPojoSwapForUnswap(Class<?> swapClass) {
+		if (childUnswapMap != null) {
+			PojoSwap<?,?> s = childUnswapMap.get(swapClass);
+			if (s == null) {
+				for (PojoSwap<?,?> f : childPojoSwaps)
+					if (s == null && isParentClass(f.getSwapClass(), swapClass))
+						s = f;
+				if (s == null)
+					 s = PojoSwap.NULL;
+				childUnswapMap.putIfAbsent(swapClass, s);
 			}
-			if (context == null)
+			if (s == PojoSwap.NULL)
 				return null;
-			PojoSwap<T,?> f = context.findPojoSwap(innerClass);
-			return f;
-		} catch (Exception e) {
-			throw new RuntimeException(e);
+			return s;
 		}
+		return null;
 	}
 
 	/**
@@ -1512,31 +1601,31 @@ public final class ClassMeta<T> implements Type {
 	public int hashCode() {
 		return super.hashCode();
 	}
-
-	public abstract static class CreateSession {
-		LinkedList<ClassMeta<?>> stack;
-
-		public CreateSession push(ClassMeta<?> cm) {
-			if (stack == null)
-				stack = new LinkedList<ClassMeta<?>>();
-			stack.add(cm);
-			return this;
-		}
-
-		public CreateSession pop(ClassMeta<?> expected) {
-			if (stack == null || stack.removeLast() != expected)
-				throw new BeanRuntimeException("ClassMetaSession creation stack corruption!");
-			return this;
-		}
-
-		public <T> ClassMeta<T> getClassMeta(Class<T> c) {
-			if (stack != null)
-				for (ClassMeta<?> cm : stack)
-					if (cm.innerClass == c)
-						return (ClassMeta<T>)cm;
-			return createClassMeta(c);
-		}
-
-		public abstract <T> ClassMeta<T> createClassMeta(Class<T> c);
-	}
+//
+//	public abstract static class CreateSession {
+//		LinkedList<ClassMeta<?>> stack;
+//
+//		public CreateSession push(ClassMeta<?> cm) {
+//			if (stack == null)
+//				stack = new LinkedList<ClassMeta<?>>();
+//			stack.add(cm);
+//			return this;
+//		}
+//
+//		public CreateSession pop(ClassMeta<?> expected) {
+//			if (stack == null || stack.removeLast() != expected)
+//				throw new BeanRuntimeException("ClassMetaSession creation stack corruption!");
+//			return this;
+//		}
+//
+//		public <T> ClassMeta<T> getClassMeta(Class<T> c) {
+//			if (stack != null)
+//				for (ClassMeta<?> cm : stack)
+//					if (cm.innerClass == c)
+//						return (ClassMeta<T>)cm;
+//			return createClassMeta(c);
+//		}
+//
+//		public abstract <T> ClassMeta<T> createClassMeta(Class<T> c);
+//	}
 }

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/062d7ddc/juneau-core/src/main/java/org/apache/juneau/transform/PojoSwap.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/transform/PojoSwap.java b/juneau-core/src/main/java/org/apache/juneau/transform/PojoSwap.java
index ec97dd8..5a1d104 100644
--- a/juneau-core/src/main/java/org/apache/juneau/transform/PojoSwap.java
+++ b/juneau-core/src/main/java/org/apache/juneau/transform/PojoSwap.java
@@ -98,6 +98,12 @@ import org.apache.juneau.serializer.*;
  */
 public abstract class PojoSwap<T,S> {
 
+	/**
+	 * Represents a non-existent pojo swap.
+	 */
+	@SuppressWarnings({ "unchecked", "rawtypes" })
+	public final static PojoSwap NULL = new PojoSwap(null, null) {};
+
 	private final Class<T> normalClass;
 	private final Class<?> swapClass;
 	private ClassMeta<?> swapClassMeta;