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 <[email protected]>
Authored: Sat Feb 4 15:44:34 2017 -0500
Committer: JamesBognar <[email protected]>
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;

Reply via email to