You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by bi...@apache.org on 2009/09/04 02:03:14 UTC

svn commit: r811180 - in /cxf/trunk/rt/databinding/aegis/src/main/java/org/apache/cxf/aegis/type: ./ java5/

Author: bimargulies
Date: Fri Sep  4 00:03:14 2009
New Revision: 811180

URL: http://svn.apache.org/viewvc?rev=811180&view=rev
Log:
Lots of changes in the 'Class->Type' campaign. Still fails two tests.

Added:
    cxf/trunk/rt/databinding/aegis/src/main/java/org/apache/cxf/aegis/type/ParameterizedTypeFactory.java   (with props)
    cxf/trunk/rt/databinding/aegis/src/main/java/org/apache/cxf/aegis/type/SimpleParameterizedType.java   (with props)
Modified:
    cxf/trunk/rt/databinding/aegis/src/main/java/org/apache/cxf/aegis/type/AbstractTypeCreator.java
    cxf/trunk/rt/databinding/aegis/src/main/java/org/apache/cxf/aegis/type/AegisType.java
    cxf/trunk/rt/databinding/aegis/src/main/java/org/apache/cxf/aegis/type/DefaultTypeCreator.java
    cxf/trunk/rt/databinding/aegis/src/main/java/org/apache/cxf/aegis/type/TypeClassInfo.java
    cxf/trunk/rt/databinding/aegis/src/main/java/org/apache/cxf/aegis/type/TypeCreator.java
    cxf/trunk/rt/databinding/aegis/src/main/java/org/apache/cxf/aegis/type/TypeUtil.java
    cxf/trunk/rt/databinding/aegis/src/main/java/org/apache/cxf/aegis/type/XMLTypeCreator.java
    cxf/trunk/rt/databinding/aegis/src/main/java/org/apache/cxf/aegis/type/java5/Java5TypeCreator.java

Modified: cxf/trunk/rt/databinding/aegis/src/main/java/org/apache/cxf/aegis/type/AbstractTypeCreator.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/databinding/aegis/src/main/java/org/apache/cxf/aegis/type/AbstractTypeCreator.java?rev=811180&r1=811179&r2=811180&view=diff
==============================================================================
--- cxf/trunk/rt/databinding/aegis/src/main/java/org/apache/cxf/aegis/type/AbstractTypeCreator.java (original)
+++ cxf/trunk/rt/databinding/aegis/src/main/java/org/apache/cxf/aegis/type/AbstractTypeCreator.java Fri Sep  4 00:03:14 2009
@@ -21,7 +21,7 @@
 import java.beans.PropertyDescriptor;
 import java.lang.reflect.Field;
 import java.lang.reflect.Method;
-import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
 import java.util.Collection;
 import java.util.Map;
 
@@ -37,9 +37,6 @@
 import org.apache.cxf.common.WSDLConstants;
 import org.apache.cxf.common.util.XMLSchemaQNames;
 
-/**
- * @author Hani Suleiman Date: Jun 14, 2005 Time: 11:59:57 PM
- */
 public abstract class AbstractTypeCreator implements TypeCreator {
     public static final String HTTP_CXF_APACHE_ORG_ARRAYS = "http://cxf.apache.org/arrays";
 
@@ -92,33 +89,39 @@
         return info;
     }
     
-    public TypeClassInfo createBasicClassInfo(Class typeClass) {
+    public TypeClassInfo createBasicClassInfo(Type type) {
         TypeClassInfo info = new TypeClassInfo();
-        info.setDescription("class '" + typeClass.getName() + '\'');
-        info.setTypeClass(typeClass);
+        Class typeClass = TypeUtil.getTypeClass(type, false);
+        if (typeClass != null) {
+            info.setDescription("class '" + typeClass.getName() + "'");
+        } else {
+            info.setDescription("type '" + type + "'");
+        }
+        info.setType(type);
 
         return info;
     }
 
     public AegisType createTypeForClass(TypeClassInfo info) {
-        Class javaType = info.getTypeClass();
+
+        Class javaClass = TypeUtil.getTypeRelatedClass(info.getType());
         AegisType result = null;
         boolean newType = true;
 
         if (info.getAegisTypeClass() != null) {
             result = createUserType(info);
-        } else if (isArray(javaType)) {
+        } else if (isArray(javaClass)) {
             result = createArrayType(info);
-        } else if (isMap(javaType)) {
+        } else if (isMap(javaClass)) {
             result = createMapType(info);
-        }  else if (isHolder(javaType)) {
+        }  else if (isHolder(javaClass)) {
             result = createHolderType(info);
-        } else if (isCollection(javaType)) {
+        } else if (isCollection(javaClass)) {
             result = createCollectionType(info);
-        } else if (isEnum(javaType)) {
+        } else if (isEnum(javaClass)) {
             result = createEnumType(info);
         } else {
-            AegisType type = getTypeMapping().getType(javaType);
+            AegisType type = getTypeMapping().getType(info.getType());
             if (type == null) {
                 if (info.getTypeName() != null) {
                     type = getTypeMapping().getType(info.getTypeName());
@@ -149,15 +152,14 @@
     }
 
     protected AegisType createHolderType(TypeClassInfo info) {
-        if (info.getGenericType() == null) {
-            throw new UnsupportedOperationException("To use holder types "
-                    + "you must have an XML descriptor declaring the component type.");
-        }
 
-        Class heldCls = (Class) info.getGenericType();
-        info.setTypeClass(heldCls);
+        Type heldType = TypeUtil.getSingleTypeParameter(info.getType());
+        if (heldType == null) {
+            throw new UnsupportedOperationException("Invalid holder type " + info.getType());
+        }
 
-        return createType(heldCls);
+        info.setType(heldType);
+        return createType(heldType);
     }
 
 
@@ -175,18 +177,19 @@
                 // If the @ annotation or XML file didn't specify a schema type,
                 // but the natural type has a schema type mapping, we use that rather
                 // than create nonsense.
-                if (info.getTypeClass().getPackage().getName().startsWith("java")) {
-                    name = tm.getTypeQName(info.getTypeClass());
+                Class<?> typeClass = TypeUtil.getTypeRelatedClass(info.getType());
+                if (typeClass.getPackage().getName().startsWith("java")) {
+                    name = tm.getTypeQName(typeClass);
                 }
-                // if it's still null, we'll take our lumps, but probably end up wih
+                // if it's still null, we'll take our lumps, but probably end up with
                 // an invalid schema.
                 if (name == null) {
-                    name = createQName(info.getTypeClass());
+                    name = createQName(typeClass);
                 }
             }
 
             type.setSchemaType(name);
-            type.setTypeClass(info.getTypeClass());
+            type.setTypeClass(info.getType());
             type.setTypeMapping(getTypeMapping());
 
             return type;
@@ -202,7 +205,7 @@
     protected AegisType createArrayType(TypeClassInfo info) {
         ArrayType type = new ArrayType();
         type.setTypeMapping(getTypeMapping());
-        type.setTypeClass(info.getTypeClass());
+        type.setTypeClass(info.getType());
         type.setSchemaType(createCollectionQName(info, type.getComponentType()));
 
         if (info.getMinOccurs() != -1) {
@@ -246,7 +249,7 @@
 
         type.setSchemaType(name);
 
-        type.setTypeClass(info.getTypeClass());
+        type.setTypeClass(info.getType());
 
         if (info.getMinOccurs() != -1) {
             type.setMinOccurs(info.getMinOccurs());
@@ -284,7 +287,7 @@
         QName schemaType = createMapQName(info, keyType, valueType);
         MapType type = new MapType(schemaType, keyType, valueType);
         type.setTypeMapping(getTypeMapping());
-        type.setTypeClass(info.getTypeClass());
+        type.setTypeClass(info.getType());
 
         return type;
     }
@@ -405,19 +408,9 @@
      * @param t the reflected type.
      * @return the type
      */
-    public AegisType createType(java.lang.reflect.Type t) {
+    public AegisType createType(Type t) {
         TypeClassInfo info = new TypeClassInfo();
-        info.setGenericType(t);
-        if (t instanceof ParameterizedType) {
-            ParameterizedType pt = (ParameterizedType) t;
-            java.lang.reflect.Type rawType = pt.getRawType();
-            if (rawType instanceof Class) {
-                info.setTypeClass((Class)rawType);
-            } 
-        } else if (t instanceof Class) {
-            info.setTypeClass((Class)t);
-        }
-        
+        info.setType(t);
         info.setDescription("reflected type " + t.toString());
         return createTypeForClass(info);
         

Modified: cxf/trunk/rt/databinding/aegis/src/main/java/org/apache/cxf/aegis/type/AegisType.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/databinding/aegis/src/main/java/org/apache/cxf/aegis/type/AegisType.java?rev=811180&r1=811179&r2=811180&view=diff
==============================================================================
--- cxf/trunk/rt/databinding/aegis/src/main/java/org/apache/cxf/aegis/type/AegisType.java (original)
+++ cxf/trunk/rt/databinding/aegis/src/main/java/org/apache/cxf/aegis/type/AegisType.java Fri Sep  4 00:03:14 2009
@@ -100,15 +100,12 @@
     }
 
     /**
-     * @return Returns the java type as a Class. If the type is not a 
-     * plain class, return null.
+     * @return Returns the java type as a Class. 
+     * For a generic, return the raw type. For something
+     * truly exotic, return null.
      */
     public Class getTypeClass() {
-        if (typeClass instanceof Class) {
-            return (Class)typeClass;
-        } else {
-            return null;
-        }
+        return TypeUtil.getTypeRelatedClass(typeClass);
     }
     
     /**

Modified: cxf/trunk/rt/databinding/aegis/src/main/java/org/apache/cxf/aegis/type/DefaultTypeCreator.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/databinding/aegis/src/main/java/org/apache/cxf/aegis/type/DefaultTypeCreator.java?rev=811180&r1=811179&r2=811180&view=diff
==============================================================================
--- cxf/trunk/rt/databinding/aegis/src/main/java/org/apache/cxf/aegis/type/DefaultTypeCreator.java (original)
+++ cxf/trunk/rt/databinding/aegis/src/main/java/org/apache/cxf/aegis/type/DefaultTypeCreator.java Fri Sep  4 00:03:14 2009
@@ -20,6 +20,7 @@
 
 import java.beans.PropertyDescriptor;
 import java.lang.reflect.Method;
+import java.lang.reflect.ParameterizedType;
 
 import org.apache.cxf.aegis.DatabindingException;
 import org.apache.cxf.aegis.type.basic.BeanType;
@@ -39,9 +40,9 @@
         info.setDescription("method " + m.getName() + " parameter " + index);
 
         if (index >= 0) {
-            info.setTypeClass(m.getParameterTypes()[index]);
+            info.setType(m.getParameterTypes()[index]);
         } else {
-            info.setTypeClass(m.getReturnType());
+            info.setType(m.getReturnType());
         }
 
         return info;
@@ -54,8 +55,8 @@
 
     @Override
     public AegisType createCollectionType(TypeClassInfo info) {
-        if (info.getGenericType() == null) {
-            throw new DatabindingException("Cannot create mapping for " + info.getTypeClass().getName()
+        if (!(info.getType() instanceof ParameterizedType)) {
+            throw new DatabindingException("Cannot create mapping for " + info.getType() 
                                            + ", unspecified component type for " + info.getDescription());
         }
 
@@ -65,8 +66,16 @@
     @Override
     public AegisType createDefaultType(TypeClassInfo info) {
         BeanType type = new BeanType();
-        type.setSchemaType(createQName(info.getTypeClass()));
-        type.setTypeClass(info.getTypeClass());
+        /*
+         * As of this point, we refuse to do this for generics in general.
+         * This might be revisited ... it might turn out to 'just work'.
+         */
+        Class<?> typeClass = TypeUtil.getTypeClass(info.getType(), false);
+        if (typeClass == null) {
+            throw new DatabindingException("Unable to map generic type " + info.getType());
+        }
+        type.setSchemaType(createQName(typeClass));
+        type.setTypeClass(typeClass);
         type.setTypeMapping(getTypeMapping());
 
         BeanTypeInfo typeInfo = type.getTypeInfo();

Added: cxf/trunk/rt/databinding/aegis/src/main/java/org/apache/cxf/aegis/type/ParameterizedTypeFactory.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/databinding/aegis/src/main/java/org/apache/cxf/aegis/type/ParameterizedTypeFactory.java?rev=811180&view=auto
==============================================================================
--- cxf/trunk/rt/databinding/aegis/src/main/java/org/apache/cxf/aegis/type/ParameterizedTypeFactory.java (added)
+++ cxf/trunk/rt/databinding/aegis/src/main/java/org/apache/cxf/aegis/type/ParameterizedTypeFactory.java Fri Sep  4 00:03:14 2009
@@ -0,0 +1,35 @@
+/**
+ * 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.cxf.aegis.type;
+
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+
+/**
+ * Create ParameterizedType objects for some limited cases.
+ */
+public final class ParameterizedTypeFactory {
+    private ParameterizedTypeFactory() {
+    }
+    
+    public static ParameterizedType createParameterizedType(Class<?> rawType, Type[] parameters) {
+        return new SimpleParameterizedType(rawType, parameters);
+    }
+}

Propchange: cxf/trunk/rt/databinding/aegis/src/main/java/org/apache/cxf/aegis/type/ParameterizedTypeFactory.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: cxf/trunk/rt/databinding/aegis/src/main/java/org/apache/cxf/aegis/type/SimpleParameterizedType.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/databinding/aegis/src/main/java/org/apache/cxf/aegis/type/SimpleParameterizedType.java?rev=811180&view=auto
==============================================================================
--- cxf/trunk/rt/databinding/aegis/src/main/java/org/apache/cxf/aegis/type/SimpleParameterizedType.java (added)
+++ cxf/trunk/rt/databinding/aegis/src/main/java/org/apache/cxf/aegis/type/SimpleParameterizedType.java Fri Sep  4 00:03:14 2009
@@ -0,0 +1,90 @@
+/**
+ * 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.cxf.aegis.type;
+
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.Arrays;
+
+/**
+ * When an XML file tells is that it wants a List to be a List<x> or a Map to be
+ * a Map<x, y>, we create one of these. We do not tolerate nesting. If we really
+ * wanted the entire apparatus, asm would be more appropriate. This is good enough
+ * to allow us to probe a hash table hashed on Type objects where List<x> might
+ * be in there.
+ */
+class SimpleParameterizedType implements ParameterizedType {
+    private Class<?> rawType;
+    private Type[] parameters;
+    
+    SimpleParameterizedType(Class<?> rawType, Type[] parameters) {
+        this.rawType = rawType;
+        this.parameters = parameters;
+    }
+
+    public Type[] getActualTypeArguments() {
+        return parameters;
+    }
+
+    public Type getOwnerType() {
+        // no nested types.
+        return null;
+    }
+
+    public Type getRawType() {
+        return rawType;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + Arrays.hashCode(parameters);
+        result = prime * result + ((rawType == null) ? 0 : rawType.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        
+        ParameterizedType opt = null;
+        try {
+            opt = (ParameterizedType) obj;
+        } catch (ClassCastException cce) {
+            return false;
+        }
+        
+        if (opt.getOwnerType() != null) {
+            return false;
+        }
+        
+        if (rawType != opt.getRawType()) {
+            return false;
+        }
+        
+        return Arrays.equals(parameters, opt.getActualTypeArguments());
+    }
+}

Propchange: cxf/trunk/rt/databinding/aegis/src/main/java/org/apache/cxf/aegis/type/SimpleParameterizedType.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: cxf/trunk/rt/databinding/aegis/src/main/java/org/apache/cxf/aegis/type/TypeClassInfo.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/databinding/aegis/src/main/java/org/apache/cxf/aegis/type/TypeClassInfo.java?rev=811180&r1=811179&r2=811180&view=diff
==============================================================================
--- cxf/trunk/rt/databinding/aegis/src/main/java/org/apache/cxf/aegis/type/TypeClassInfo.java (original)
+++ cxf/trunk/rt/databinding/aegis/src/main/java/org/apache/cxf/aegis/type/TypeClassInfo.java Fri Sep  4 00:03:14 2009
@@ -19,16 +19,29 @@
 
 package org.apache.cxf.aegis.type;
 
+import java.lang.reflect.Type;
+
 import javax.xml.namespace.QName;
 
 /**
- * Object to carry information for a aegisTypeClass, such as that from an XML mapping file.
+ * Object to carry information for an Aegis type, 
+ * such as that from an XML mapping file.
  * 
  * Note that this class has a misleading name. It is used both for 
- * aegisTypeClass information that corresponds to a aegisTypeClass, and also for parameters 
- * of methods and elements of beans. When describing a top-level aegisTypeClass,
- * minOccurs and maxOccurs are not meaningful. Nillable is only used for
- * parameters. It might be that the code could be deconfused by
+ * type information that corresponds to a type, and also for parameters 
+ * of methods and elements of beans. When describing a top-level type,
+ * minOccurs and maxOccurs are not meaningful. Aegis does not have a
+ * very clear model of a 'type', in the sense of an AegisType object
+ * corresponding to some particular XML Schema type, in isolation
+ * from the mapping system. 
+ * 
+ * Historically, Aegis talked about Java types as Class. However, 
+ * we want to be able to keep track, distinctly, of un-erased
+ * generics. That requires java.lang.reflect.Type.
+ * 
+ *  Nillable is only used for parameters.
+ * 
+ *  It might be that the code could be deconfused by
  * using the nillable property in here for the non-parameters cases
  * that look at minOccurs and maxOccurs.
  * 
@@ -38,24 +51,27 @@
  * of a plain boolean.
  */
 public class TypeClassInfo {
-    private Class typeClass;
+    // The general reflection Type.
+    private Type type;
     private Object[] annotations;
-    // Object because it can be either a TypeClassInfo or a
-    // java.lang.reflect.Type
-    private Object genericType;
-    // ditto
-    private Object keyType;
-    // ditto
-    private Object valueType;
+
+    // for collection types we pull out the parameters for convenience.
+    private Type keyType;
+    private Type valueType;
+
+    // Preferred element name.
     private QName mappedName;
+    // XML schema name for the type.
     private QName typeName;
+    
     // a Class reference to the aegis aegisTypeClass, if the app has specified it
     // via XML or via an annotation.
     private Class<? extends AegisType> aegisTypeClass;
+
     private String description;
     private long minOccurs = -1;
     private long maxOccurs = -1;
-    // not yet implemented
+    // Flat array.
     private boolean flat;
     private Boolean nillable;
     
@@ -79,28 +95,20 @@
         this.annotations = annotations;
     }
 
-    public Object getGenericType() {
-        return genericType;
-    }
-
-    public void setGenericType(Object genericType) {
-        this.genericType = genericType;
-    }
-
-    public Object getKeyType() {
+    public Type getKeyType() {
         return keyType;
     }
 
-    public void setKeyType(Object keyType) {
+    public void setKeyType(Type keyType) {
         this.keyType = keyType;
     }
 
-    public Class getTypeClass() {
-        return typeClass;
+    public Type getType() {
+        return type;
     }
 
-    public void setTypeClass(Class typeClass) {
-        this.typeClass = typeClass;
+    public void setType(Type type) {
+        this.type = type;
     }
 
     public QName getTypeName() {
@@ -156,11 +164,11 @@
         return "TypeClassInfo " + getDescription();
     }
 
-    public Object getValueType() {
+    public Type getValueType() {
         return valueType;
     }
 
-    public void setValueType(Object valueType) {
+    public void setValueType(Type valueType) {
         this.valueType = valueType;
     }
 

Modified: cxf/trunk/rt/databinding/aegis/src/main/java/org/apache/cxf/aegis/type/TypeCreator.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/databinding/aegis/src/main/java/org/apache/cxf/aegis/type/TypeCreator.java?rev=811180&r1=811179&r2=811180&view=diff
==============================================================================
--- cxf/trunk/rt/databinding/aegis/src/main/java/org/apache/cxf/aegis/type/TypeCreator.java (original)
+++ cxf/trunk/rt/databinding/aegis/src/main/java/org/apache/cxf/aegis/type/TypeCreator.java Fri Sep  4 00:03:14 2009
@@ -21,13 +21,10 @@
 import java.beans.PropertyDescriptor;
 import java.lang.reflect.Field;
 import java.lang.reflect.Method;
+import java.lang.reflect.Type;
 
 import javax.xml.namespace.QName;
 
-
-/**
- * @author <a href="mailto:dan@envoisolutions.com">Dan Diephouse</a>
- */
 public interface TypeCreator {
     /**
      * Get the mapped name of a method parameter.
@@ -42,17 +39,16 @@
 
     AegisType createType(PropertyDescriptor pd);
     
-    AegisType createType(java.lang.reflect.Type type);
+    AegisType createType(Type type);
 
     AegisType createType(Field f);
 
-    AegisType createType(Class clazz);
-
     TypeCreator getParent();
     
     void setParent(TypeCreator creator);
         
     void setTypeMapping(TypeMapping typeMapping);
+
     /** Retrieve the classInfo for a method. Needed to get parameters right. 
      * 
      * @param m Method object
@@ -60,12 +56,13 @@
      * @return info
      */
     TypeClassInfo createClassInfo(Method m, int index); 
+
     /**
-     * Retrieve the class info for a class. Needed to get parameters right.
-     * @param itemClass
+     * Create class info for a Type.
+     * @param itemType
      * @return info
      */
-    TypeClassInfo createBasicClassInfo(Class<?> itemClass);
+    TypeClassInfo createBasicClassInfo(Type itemType);
     
     /**
      * Turn a TypeClassInfo into a type.

Modified: cxf/trunk/rt/databinding/aegis/src/main/java/org/apache/cxf/aegis/type/TypeUtil.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/databinding/aegis/src/main/java/org/apache/cxf/aegis/type/TypeUtil.java?rev=811180&r1=811179&r2=811180&view=diff
==============================================================================
--- cxf/trunk/rt/databinding/aegis/src/main/java/org/apache/cxf/aegis/type/TypeUtil.java (original)
+++ cxf/trunk/rt/databinding/aegis/src/main/java/org/apache/cxf/aegis/type/TypeUtil.java Fri Sep  4 00:03:14 2009
@@ -18,6 +18,8 @@
  */
 package org.apache.cxf.aegis.type;
 
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
 import java.util.logging.Logger;
 
 import javax.xml.namespace.QName;
@@ -178,9 +180,64 @@
         
     }
     
-    
     public static void setAttributeAttributes(QName name, AegisType type, XmlSchema root) {
         String ns = type.getSchemaType().getNamespaceURI();
         XmlSchemaUtils.addImportIfNeeded(root, ns);
     }
+
+    /**
+     * Utility function to cast a Type to a Class. This throws an unchecked exception if the Type is
+     * not a Class. The idea here is that these Type references should have been checked for 
+     * reasonableness before the point of calls to this function.
+     * @param type Reflection type.
+     * @param throwForNonClass whether to throw (true) or return null (false) if the Type
+     * is not a class.
+     * @return the Class
+     */
+    public static Class<?> getTypeClass(Type type, boolean throwForNonClass) {
+        if (type instanceof Class) {
+            return (Class) type;
+        } else if (throwForNonClass) {
+            throw new RuntimeException("Attempt to derive Class from reflection Type " + type);
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Insist that a Type is a parameterized type of one parameter.
+     * This is used to decompose Holders, for example.
+     * @param type the type
+     * @return the parameter, or null if the type is not what we want.
+     */
+    public static Type getSingleTypeParameter(Type type) {
+        if (type instanceof ParameterizedType) {
+            ParameterizedType pType = (ParameterizedType) type;
+            Type[] params = pType.getActualTypeArguments();
+            if (params.length == 1) {
+                return params[0];
+            }
+        }
+        return null;
+    }
+
+    /**
+     * If a Type is a class, return it as a class.
+     * If it is a ParameterizedType, return the raw type as a class.
+     * Otherwise return null.
+     * @param type
+     * @return
+     */
+    public static Class<?> getTypeRelatedClass(Type type) {
+        Class<?> directClass = getTypeClass(type, false);
+        if (directClass != null) {
+            return directClass;
+        }
+        
+        if (type instanceof ParameterizedType) {
+            ParameterizedType pType = (ParameterizedType) type;
+            return getTypeRelatedClass(pType.getRawType());
+        }
+        return null;
+    }
 }

Modified: cxf/trunk/rt/databinding/aegis/src/main/java/org/apache/cxf/aegis/type/XMLTypeCreator.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/databinding/aegis/src/main/java/org/apache/cxf/aegis/type/XMLTypeCreator.java?rev=811180&r1=811179&r2=811180&view=diff
==============================================================================
--- cxf/trunk/rt/databinding/aegis/src/main/java/org/apache/cxf/aegis/type/XMLTypeCreator.java (original)
+++ cxf/trunk/rt/databinding/aegis/src/main/java/org/apache/cxf/aegis/type/XMLTypeCreator.java Fri Sep  4 00:03:14 2009
@@ -22,8 +22,11 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.lang.reflect.Method;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
 import java.text.MessageFormat;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
@@ -230,7 +233,7 @@
 
     @Override
     public AegisType createEnumType(TypeClassInfo info) {
-        Element mapping = findMapping(info.getTypeClass());
+        Element mapping = findMapping(info.getType());
         if (mapping != null) {
             return super.createEnumType(info);
         } else {
@@ -240,7 +243,10 @@
 
     @Override
     public AegisType createCollectionType(TypeClassInfo info) {
-        if (info.getGenericType() instanceof Class || info.getGenericType() instanceof TypeClassInfo) {
+        /* If it is a parameterized type, then we already know
+         * the parameter(s) and we don't need to fish them out of the XML.
+         */
+        if (info.getType() instanceof Class) {
             return createCollectionTypeFromGeneric(info);
         }
 
@@ -260,14 +266,22 @@
         }
 
         TypeClassInfo info = new TypeClassInfo();
-        info.setTypeClass(pd.getReadMethod().getReturnType());
+        Type returnType = pd.getReadMethod().getGenericReturnType();
+        info.setType(returnType);
         info.setDescription("property " + pd.getDisplayName());
         readMetadata(info, mapping, propertyEl);
 
         return info;
     }
 
-    protected Element findMapping(Class clazz) {
+    protected Element findMapping(Type type) {
+        // We are not prepared to find .aegis.xml files for Parameterized types.
+        
+        Class<?> clazz = TypeUtil.getTypeClass(type, false);
+        
+        if (clazz == null) {
+            return null;
+        }
         Document doc = getDocument(clazz);
         if (doc == null) {
             return null;
@@ -283,8 +297,12 @@
         return mapping;
     }
 
-    protected List<Element> findMappings(Class clazz) {
+    protected List<Element> findMappings(Type type) {
+        Class clazz = TypeUtil.getTypeClass(type, false);
         List<Element> mappings = new ArrayList<Element>();
+        if (clazz == null) {
+            return mappings;
+        }
 
         Element top = findMapping(clazz);
         if (top != null) {
@@ -321,8 +339,9 @@
 
     @Override
     public AegisType createDefaultType(TypeClassInfo info) {
-        Element mapping = findMapping(info.getTypeClass());
-        List mappings = findMappings(info.getTypeClass());
+        Element mapping = findMapping(info.getType());
+        List<Element> mappings = findMappings(info.getType());
+        Class<?> relatedClass = TypeUtil.getTypeRelatedClass(info.getType());
 
         if (mapping != null || mappings.size() > 0) {
             String typeNameAtt = null;
@@ -340,8 +359,7 @@
                 extensibleAttributes = mapping.getAttribute("extensibleAttributes");
             }
 
-            String defaultNS = NamespaceHelper.makeNamespaceFromClassName(info.getTypeClass().getName(),
-                                                                          "http");
+            String defaultNS = NamespaceHelper.makeNamespaceFromClassName(relatedClass.getName(), "http");
             QName name = null;
             if (typeNameAtt != null) {
                 name = NamespaceHelper.createQName(mapping, typeNameAtt, defaultNS);
@@ -349,7 +367,8 @@
                 defaultNS = name.getNamespaceURI();
             }
 
-            XMLBeanTypeInfo btinfo = new XMLBeanTypeInfo(info.getTypeClass(), mappings, defaultNS);
+            // We do not deal with Generic beans at this point.
+            XMLBeanTypeInfo btinfo = new XMLBeanTypeInfo(relatedClass, mappings, defaultNS);
             btinfo.setTypeMapping(getTypeMapping());
             btinfo.setDefaultMinOccurs(getConfiguration().getDefaultMinOccurs());
             btinfo.setDefaultNillable(getConfiguration().isDefaultNillable());
@@ -371,12 +390,12 @@
             BeanType type = new BeanType(btinfo);
 
             if (name == null) {
-                name = createQName(info.getTypeClass());
+                name = createQName(relatedClass);
             }
 
             type.setSchemaType(name);
 
-            type.setTypeClass(info.getTypeClass());
+            type.setTypeClass(info.getType());
             type.setTypeMapping(getTypeMapping());
 
             return type;
@@ -425,7 +444,7 @@
                 // no mapping for this method
                 return info;
             }
-            info.setTypeClass(m.getParameterTypes()[index]);
+            info.setType(m.getGenericParameterTypes()[index]);
             // info.setAnnotations(m.getParameterAnnotations()[index]);
             Element parameter = getMatch(bestMatch, "parameter[@index='" + index + "']");
             readMetadata(info, mapping, parameter);
@@ -440,7 +459,7 @@
                 // no mapping for this method
                 return info;
             }
-            info.setTypeClass(m.getReturnType());
+            info.setType(m.getGenericReturnType());
             // info.setAnnotations(m.getAnnotations());
             Element rtElement = DOMUtils.getFirstChildWithName(bestMatch, "", "return-type");
             readMetadata(info, mapping, rtElement);
@@ -453,9 +472,23 @@
         info.setTypeName(createQName(parameter, DOMUtils.getAttributeValueEmptyNull(parameter, "typeName")));
         info.setMappedName(createQName(parameter, 
                                        DOMUtils.getAttributeValueEmptyNull(parameter, "mappedName")));
-        setComponentType(info, mapping, parameter);
-        setKeyType(info, mapping, parameter);
-        setValueType(info, mapping, parameter);
+        Class<?> relatedClass = TypeUtil.getTypeRelatedClass(info.getType());
+        // we only mess with the generic issues for list and map
+        if (Collection.class.isAssignableFrom(relatedClass)) {
+            Type componentType = getComponentType(mapping, parameter);
+            Type fullType = ParameterizedTypeFactory.createParameterizedType(relatedClass,
+                                                                             new Type[] {componentType});
+            info.setType(fullType);
+        } else if (Map.class.isAssignableFrom(relatedClass)) {
+            Type keyType = getKeyType(mapping, parameter);
+            info.setKeyType(keyType);
+            Type valueType = getValueType(mapping, parameter);
+            info.setValueType(valueType);
+            Type fullType = ParameterizedTypeFactory.createParameterizedType(relatedClass,
+                                                                             new Type[] {keyType, valueType});
+            info.setType(fullType);
+
+        }
         setType(info, parameter);
 
         String min = DOMUtils.getAttributeValueEmptyNull(parameter, "minOccurs");
@@ -482,8 +515,8 @@
     @Override
     protected AegisType getOrCreateGenericType(TypeClassInfo info) {
         AegisType type = null;
-        if (info.getGenericType() != null) {
-            type = createTypeFromGeneric(info.getGenericType());
+        if (info.getType() instanceof ParameterizedType) { 
+            type = createTypeFromGeneric(info.getType());
         }
 
         if (type == null) {
@@ -520,7 +553,8 @@
     @Override
     protected AegisType getOrCreateMapValueType(TypeClassInfo info) {
         AegisType type = null;
-        if (info.getGenericType() != null) {
+        if (info.getType() instanceof ParameterizedType) {
+            // well, let's hope that someone has filled in the value type.
             type = createTypeFromGeneric(info.getValueType());
         }
 
@@ -531,14 +565,32 @@
         return type;
     }
 
-    protected void setComponentType(TypeClassInfo info, Element mapping, Element parameter) {
-        String componentType = DOMUtils.getAttributeValueEmptyNull(parameter, "componentType");
-        if (componentType != null) {
-            info.setGenericType(loadGeneric(info, mapping, componentType));
+    private Type getComponentType(Element mapping, Element parameter) {
+        String componentSpec = DOMUtils.getAttributeValueEmptyNull(parameter, "componentType");
+        if (componentSpec == null) {
+            return null;
         }
+        return getGenericParameterFromSpec(mapping, componentSpec);
+    }
+    
+    private Type getKeyType(Element mapping, Element parameter) {
+        String spec = DOMUtils.getAttributeValueEmptyNull(parameter, "keyType");
+        if (spec == null) {
+            return null;
+        }
+        return getGenericParameterFromSpec(mapping, spec);
+    }
+
+    private Type getValueType(Element mapping, Element parameter) {
+        String spec = DOMUtils.getAttributeValueEmptyNull(parameter, "valueType");
+        if (spec == null) {
+            return null;
+        }
+        return getGenericParameterFromSpec(mapping, spec);
     }
 
-    private Object loadGeneric(TypeClassInfo info, Element mapping, String componentType) {
+    // This cannot do List<List<x>>.
+    private Type getGenericParameterFromSpec(Element mapping, String componentType) {
         if (componentType.startsWith("#")) {
             String name = componentType.substring(1);
             Element propertyEl = getMatch(mapping, "./component[@name='" + name + "']");
@@ -547,18 +599,13 @@
                                                + "'");
             }
 
-            TypeClassInfo componentInfo = new TypeClassInfo();
-            componentInfo.setDescription("generic component " + componentInfo.getDescription());
-            readMetadata(componentInfo, mapping, propertyEl);
             String className = DOMUtils.getAttributeValueEmptyNull(propertyEl, "class");
             if (className == null) {
                 throw new DatabindingException("A 'class' attribute must be specified for <component> "
                                                + name);
             }
-
-            componentInfo.setTypeClass(loadComponentClass(className));
-
-            return componentInfo;
+            
+            return loadComponentClass(className);
         } else {
             return loadComponentClass(componentType);
         }
@@ -584,19 +631,7 @@
         }
     }
 
-    protected void setKeyType(TypeClassInfo info, Element mapping, Element parameter) {
-        String componentType = DOMUtils.getAttributeValueEmptyNull(parameter, "keyType");
-        if (componentType != null) {
-            info.setKeyType(loadGeneric(info, mapping, componentType));
-        }
-    }
 
-    private void setValueType(TypeClassInfo info, Element mapping, Element parameter) {
-        String componentType = DOMUtils.getAttributeValueEmptyNull(parameter, "valueType");
-        if (componentType != null) {
-            info.setValueType(loadGeneric(info, mapping, componentType));
-        }
-    }
 
     private Element getBestMatch(Element mapping, Method method, List<Element> availableNodes) {
         // first find all the matching method names

Modified: cxf/trunk/rt/databinding/aegis/src/main/java/org/apache/cxf/aegis/type/java5/Java5TypeCreator.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/databinding/aegis/src/main/java/org/apache/cxf/aegis/type/java5/Java5TypeCreator.java?rev=811180&r1=811179&r2=811180&view=diff
==============================================================================
--- cxf/trunk/rt/databinding/aegis/src/main/java/org/apache/cxf/aegis/type/java5/Java5TypeCreator.java (original)
+++ cxf/trunk/rt/databinding/aegis/src/main/java/org/apache/cxf/aegis/type/java5/Java5TypeCreator.java Fri Sep  4 00:03:14 2009
@@ -21,6 +21,7 @@
 import java.beans.PropertyDescriptor;
 import java.lang.reflect.Method;
 import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
 import java.lang.reflect.WildcardType;
 import java.util.Collection;
 import java.util.Map;
@@ -31,6 +32,7 @@
 import org.apache.cxf.aegis.type.AbstractTypeCreator;
 import org.apache.cxf.aegis.type.AegisType;
 import org.apache.cxf.aegis.type.TypeClassInfo;
+import org.apache.cxf.aegis.type.TypeUtil;
 import org.apache.cxf.aegis.type.basic.BeanType;
 import org.apache.cxf.aegis.util.NamespaceHelper;
 import org.apache.cxf.aegis.util.ServiceUtils;
@@ -61,18 +63,16 @@
     public TypeClassInfo createClassInfo(Method m, int index) {
         if (index >= 0) {
             TypeClassInfo info;
-            java.lang.reflect.Type genericType = m.getGenericParameterTypes()[index];
+            Type genericType = m.getGenericParameterTypes()[index];
             if (genericType instanceof Class) {
                 info = nextCreator.createClassInfo(m, index);
             } else {
                 info = new TypeClassInfo();
                 info.setDescription("method " + m.getName() + " parameter " + index);
-                info.setGenericType(genericType);
+                info.setType(genericType);
             }
-            info.setTypeClass(m.getParameterTypes()[index]);
 
             Class paramTypeClass = annotationReader.getParamType(m, index);
-
             info.setAegisTypeClass(castToAegisTypeClass(paramTypeClass));
 
             String paramName = annotationReader.getParamName(m, index);
@@ -84,18 +84,16 @@
 
             return info;
         } else {
-            java.lang.reflect.Type genericReturnType = m.getGenericReturnType();
+            Type genericReturnType = m.getGenericReturnType();
             TypeClassInfo info;
             if (genericReturnType instanceof Class) {
                 info = nextCreator.createClassInfo(m, index);
             } else {
                 info = new TypeClassInfo();
                 info.setDescription("method " + m.getName() + " parameter " + index);
-                info.setGenericType(genericReturnType);
+                info.setType(genericReturnType);
             }
 
-            info.setTypeClass(m.getReturnType());
-
             if (m.getParameterAnnotations() != null && m.getAnnotations().length > 0) {
                 info.setAnnotations(m.getAnnotations());
             }
@@ -113,10 +111,14 @@
         }
     }
 
+    /*
+     * Apparently, this callers must notice collection types and not call this.
+     */
     @Override
     public TypeClassInfo createClassInfo(PropertyDescriptor pd) {
+        Type genericType = pd.getReadMethod().getGenericReturnType();
         TypeClassInfo info = createBasicClassInfo(pd.getPropertyType());
-        info.setGenericType(pd.getReadMethod().getGenericReturnType());
+        info.setType(genericType); // override basicClassInfo's of the type.
         info.setAnnotations(pd.getReadMethod().getAnnotations());
         info.setAegisTypeClass(castToAegisTypeClass(annotationReader.getType(pd.getReadMethod())));
 
@@ -125,109 +127,95 @@
 
     @Override
     public AegisType createCollectionType(TypeClassInfo info) {
-        Object genericType = info.getGenericType();
-        Class paramClass = getComponentType(genericType, 0);
+        Type type = info.getType();
+
+        Type componentType = getComponentType(type, 0);
 
-        if (paramClass != null) {
+        if (componentType != null) {
             return createCollectionTypeFromGeneric(info);
         } else {
             return nextCreator.createCollectionType(info);
         }
     }
 
+    // should be called 'collection'
     protected AegisType getOrCreateGenericType(TypeClassInfo info) {
-        return getOrCreateParameterizedType(info.getGenericType(), 0);
+        return getOrCreateParameterizedType(info.getType(), 0);
     }
 
     protected AegisType getOrCreateMapKeyType(TypeClassInfo info) {
-        return getOrCreateParameterizedType(info.getGenericType(), 0);
+        return getOrCreateParameterizedType(info.getType(), 0);
     }
 
     protected AegisType getOrCreateMapValueType(TypeClassInfo info) {
-        return getOrCreateParameterizedType(info.getGenericType(), 1);
+        return getOrCreateParameterizedType(info.getType(), 1);
     }
 
-    protected AegisType getOrCreateParameterizedType(Object generic, int index) {
-        Class clazz = getComponentType(generic, index);
+    protected AegisType getOrCreateParameterizedType(Type generic, int index) {
+        Type paramType = getComponentType(generic, index);
 
+        if (paramType == null) {
+            return createObjectType();
+        }
+        
+        /* null arises when the index-th parameter to generic is something list List<T> */
+        Class clazz = TypeUtil.getTypeRelatedClass(paramType);
         if (clazz == null) {
             return createObjectType();
         }
         
-        if (!Collection.class.isAssignableFrom(clazz) && !Map.class.isAssignableFrom(clazz)) {
+        // here is where we insist that we only deal with collection types.
+
+        if (!Collection.class.isAssignableFrom(clazz) 
+            && !Map.class.isAssignableFrom(clazz)) {
             return getTopCreator().createType(clazz);
         }
         
-        Object component = getGenericComponent(generic, index);
-        
         TypeClassInfo info = createBasicClassInfo(clazz);
         info.setDescription(clazz.toString());
-        info.setGenericType(component);
+        info.setType(paramType); 
 
         AegisType type = createTypeForClass(info);
 
         return type;
     }
 
-    private Object getGenericComponent(Object genericType, int index) {
-        if (genericType instanceof ParameterizedType) {
-            ParameterizedType type = (ParameterizedType)genericType;
-
-            if (type.getActualTypeArguments()[index] instanceof WildcardType) {
-                WildcardType wildcardType = (WildcardType)type.getActualTypeArguments()[index];
-
-                return wildcardType;
-            } else if (type.getActualTypeArguments()[index] instanceof ParameterizedType) {
-                ParameterizedType ptype = (ParameterizedType)type.getActualTypeArguments()[index];
-
-                return ptype;
-            }
-        }
-
-        return null;
-    }
-
-    protected Class getComponentType(Object genericType, int index) {
-        Class paramClass = null;
-
+    protected Type getComponentType(Type genericType, int index) {
         if (genericType instanceof ParameterizedType) {
             ParameterizedType type = (ParameterizedType)genericType;
-
-            if (type.getActualTypeArguments()[index] instanceof Class) {
-                paramClass = (Class)type.getActualTypeArguments()[index];
-            } else if (type.getActualTypeArguments()[index] instanceof WildcardType) {
-                WildcardType wildcardType = (WildcardType)type.getActualTypeArguments()[index];
+            Type paramType = type.getActualTypeArguments()[index]; 
+            if (paramType instanceof WildcardType) {
+                WildcardType wildcardType = (WildcardType)paramType;
                 // we really aren't prepared to deal with multiple upper bounds,
                 // so we just look at the first one.
-                if (wildcardType.getUpperBounds()[0] instanceof Class) {
-                    paramClass = (Class)wildcardType.getUpperBounds()[0];
-                }
-            } else if (type.getActualTypeArguments()[index] instanceof ParameterizedType) {
-                ParameterizedType ptype = (ParameterizedType)type.getActualTypeArguments()[index];
-                paramClass = (Class)ptype.getRawType();
+                return wildcardType.getUpperBounds()[0];
+            } else {
+                return paramType; // take our chances.
             }
+        } else {
+            throw new DatabindingException("Type " + genericType + " is not a generic.");
         }
-        return paramClass;
     }
 
     @Override
     public AegisType createDefaultType(TypeClassInfo info) {
         QName typeName = info.getTypeName();
+        Class<?> relatedClass = TypeUtil.getTypeRelatedClass(info.getType());
         if (typeName == null) {
-            typeName = createQName(info.getTypeClass());
+            typeName = createQName(relatedClass);
         }
 
         AnnotatedTypeInfo typeInfo = new AnnotatedTypeInfo(
                 getTypeMapping(),
-                info.getTypeClass(),
+                relatedClass,
                 typeName.getNamespaceURI(),
                 getConfiguration());
 
         typeInfo.setExtensibleElements(annotationReader.isExtensibleElements(
-                info.getTypeClass(),
+                relatedClass,
                 getConfiguration().isDefaultExtensibleElements()));
         typeInfo.setExtensibleAttributes(annotationReader.isExtensibleAttributes(
-                info.getTypeClass(),
+                relatedClass,
                 getConfiguration().isDefaultExtensibleAttributes()));
 
         typeInfo.setDefaultMinOccurs(getConfiguration().getDefaultMinOccurs());
@@ -244,8 +232,8 @@
     public AegisType createEnumType(TypeClassInfo info) {
         EnumType type = new EnumType();
 
-        type.setSchemaType(createQName(info.getTypeClass()));
-        type.setTypeClass(info.getTypeClass());
+        type.setSchemaType(createQName(TypeUtil.getTypeRelatedClass(info.getType())));
+        type.setTypeClass(info.getType());
         type.setTypeMapping(getTypeMapping());
 
         return type;