Title: [726] trunk/qdox/src/test/com/thoughtworks/qdox: QDOX-207: resolve generic Type

Diff

Modified: trunk/qdox/src/java/com/thoughtworks/qdox/model/JavaClass.java (725 => 726)

--- trunk/qdox/src/java/com/thoughtworks/qdox/model/JavaClass.java	2010-03-30 16:04:01 UTC (rev 725)
+++ trunk/qdox/src/java/com/thoughtworks/qdox/model/JavaClass.java	2010-04-19 12:57:29 UTC (rev 726)
@@ -466,7 +466,7 @@
 
                 // todo: ideally we should check on package privacy too. oh well.
                 if ((method != null) && !method.isPrivate()) {
-                    result.add(method);
+                    result.add( new JavaMethodDelegate( this, method ) );
                 }
             }
 
@@ -477,7 +477,7 @@
                         parameterTypes, true, varArg );
 
                 if (method != null) {
-                    result.add(method);
+                    result.add( new JavaMethodDelegate( this, method ) );
                 }
             }
         }

Modified: trunk/qdox/src/java/com/thoughtworks/qdox/model/JavaMethod.java (725 => 726)

--- trunk/qdox/src/java/com/thoughtworks/qdox/model/JavaMethod.java	2010-03-30 16:04:01 UTC (rev 725)
+++ trunk/qdox/src/java/com/thoughtworks/qdox/model/JavaMethod.java	2010-04-19 12:57:29 UTC (rev 726)
@@ -1,9 +1,9 @@
 package com.thoughtworks.qdox.model;
 
 import java.beans.Introspector;
+import java.util.ArrayList;
 import java.util.LinkedList;
 import java.util.List;
-import java.util.ArrayList;
 
 public class JavaMethod extends AbstractInheritableJavaEntity implements Member {
 
@@ -387,4 +387,54 @@
 		}
 		return result.toString();
 	}
+
+	/**
+	 * Equivalent of java.lang.reflect.Method.getGenericReturnType()
+	 * 
+	 * @return the generic returntype
+	 * @since 1.12.1
+	 */
+    public Type getGenericReturnType()
+    {
+        return returns;
+    }
+
+    /**
+     * Equivalent of java.lang.reflect.Method.getReturnType()
+     * 
+     * @return
+     * @since 1.12.1
+     */
+    public Type getReturnType() {
+	    return getReturnType( false );
+	}
+	
+    /**
+     * 
+     * @param resolve
+     * @return
+     * @since 1.12.1
+     */
+    public Type getReturnType( boolean resolve )
+    {
+        return getReturnType( resolve, getParentClass() );
+    }
+    
+    /**
+     * 
+     * @param resolve
+     * @param callingClass
+     * @return
+     * @since 1.12.1
+     */
+    protected Type getReturnType ( boolean resolve, JavaClass callingClass) {
+        Type result =  getReturns().resolve( this.getParentClass(), callingClass );
+        
+        //According to java-specs, if it could be resolved the upper boundary, so Object, should be returned  
+        if ( !resolve && !returns.getFullyQualifiedName().equals( result.getFullyQualifiedName() ) )
+        {
+            result = new Type( "java.lang.Object" );
+        }
+        return result;
+    }
 }

Added: trunk/qdox/src/java/com/thoughtworks/qdox/model/JavaMethodDelegate.java (0 => 726)

--- trunk/qdox/src/java/com/thoughtworks/qdox/model/JavaMethodDelegate.java	                        (rev 0)
+++ trunk/qdox/src/java/com/thoughtworks/qdox/model/JavaMethodDelegate.java	2010-04-19 12:57:29 UTC (rev 726)
@@ -0,0 +1,346 @@
+package com.thoughtworks.qdox.model;
+
+import java.util.List;
+
+/**
+ * This class can be used to access overridden methods while keeping a reference to the original class.
+ * This is especially useful when trying to resolve generics
+ * 
+ * @author Robert Scholte
+ * @since 1.12.1
+ */
+public class JavaMethodDelegate extends JavaMethod
+{
+
+    private JavaClass callingClass;
+    private JavaMethod originalMethod;
+    
+    public JavaMethodDelegate( JavaClass callingClass, JavaMethod originalMethod )
+    {
+        this.callingClass = callingClass;
+        this.originalMethod = originalMethod;
+    }
+    
+    public Type getReturnType( boolean resolve )
+    {
+        Type returnType = originalMethod.getReturnType( resolve, callingClass );  //TEntity
+        return returnType.resolve( originalMethod.getParentClass(), callingClass );
+    }
+    
+    protected Type getReturnType( boolean resolve, JavaClass callingClass )
+    {
+        return super.getReturnType( resolve, this.callingClass );
+    }
+
+    //Delegating methods
+    
+    public void addParameter( JavaParameter javaParameter )
+    {
+        originalMethod.addParameter( javaParameter );
+    }
+
+    public int compareTo( Object o )
+    {
+        return originalMethod.compareTo( o );
+    }
+
+    public boolean equals( Object obj )
+    {
+        return originalMethod.equals( obj );
+    }
+
+    public Annotation[] getAnnotations()
+    {
+        return originalMethod.getAnnotations();
+    }
+
+    public String getCallSignature()
+    {
+        return originalMethod.getCallSignature();
+    }
+
+    public String getCodeBlock()
+    {
+        return originalMethod.getCodeBlock();
+    }
+
+    public String getComment()
+    {
+        return originalMethod.getComment();
+    }
+
+    public String getDeclarationSignature( boolean withModifiers )
+    {
+        return originalMethod.getDeclarationSignature( withModifiers );
+    }
+
+    public Type[] getExceptions()
+    {
+        return originalMethod.getExceptions();
+    }
+
+    public Type getGenericReturnType()
+    {
+        return originalMethod.getGenericReturnType();
+    }
+
+    public int getLineNumber()
+    {
+        return originalMethod.getLineNumber();
+    }
+
+    public String[] getModifiers()
+    {
+        return originalMethod.getModifiers();
+    }
+
+    public String getName()
+    {
+        return originalMethod.getName();
+    }
+
+    public String getNamedParameter( String tagName, String parameterName )
+    {
+        return originalMethod.getNamedParameter( tagName, parameterName );
+    }
+
+    public JavaParameter getParameterByName( String name )
+    {
+        return originalMethod.getParameterByName( name );
+    }
+
+    public JavaParameter[] getParameters()
+    {
+        return originalMethod.getParameters();
+    }
+
+    public JavaClassParent getParent()
+    {
+        return originalMethod.getParent();
+    }
+
+    public JavaClass getParentClass()
+    {
+        return originalMethod.getParentClass();
+    }
+
+    public String getPropertyName()
+    {
+        return originalMethod.getPropertyName();
+    }
+
+    public Type getPropertyType()
+    {
+        return originalMethod.getPropertyType();
+    }
+
+    public Type getReturns()
+    {
+        return originalMethod.getReturns();
+    }
+
+    public Type getReturnType()
+    {
+        return getReturnType( false );
+    }
+
+    public JavaSource getSource()
+    {
+        return originalMethod.getSource();
+    }
+
+    public String getSourceCode()
+    {
+        return originalMethod.getSourceCode();
+    }
+
+    public DocletTag getTagByName( String name, boolean inherited )
+    {
+        return originalMethod.getTagByName( name, inherited );
+    }
+
+    public DocletTag getTagByName( String name )
+    {
+        return originalMethod.getTagByName( name );
+    }
+
+    public DocletTag[] getTags()
+    {
+        return originalMethod.getTags();
+    }
+
+    public DocletTag[] getTagsByName( String name, boolean inherited )
+    {
+        return originalMethod.getTagsByName( name, inherited );
+    }
+
+    public DocletTag[] getTagsByName( String name )
+    {
+        return originalMethod.getTagsByName( name );
+    }
+
+    public TypeVariable[] getTypeParameters()
+    {
+        return originalMethod.getTypeParameters();
+    }
+
+    public int hashCode()
+    {
+        return originalMethod.hashCode();
+    }
+
+    public boolean isAbstract()
+    {
+        return originalMethod.isAbstract();
+    }
+
+    public boolean isConstructor()
+    {
+        return originalMethod.isConstructor();
+    }
+
+    public boolean isFinal()
+    {
+        return originalMethod.isFinal();
+    }
+
+    public boolean isNative()
+    {
+        return originalMethod.isNative();
+    }
+
+    public boolean isPrivate()
+    {
+        return originalMethod.isPrivate();
+    }
+
+    public boolean isPropertyAccessor()
+    {
+        return originalMethod.isPropertyAccessor();
+    }
+
+    public boolean isPropertyMutator()
+    {
+        return originalMethod.isPropertyMutator();
+    }
+
+    public boolean isProtected()
+    {
+        return originalMethod.isProtected();
+    }
+
+    public boolean isPublic()
+    {
+        return originalMethod.isPublic();
+    }
+
+    public boolean isStatic()
+    {
+        return originalMethod.isStatic();
+    }
+
+    public boolean isStrictfp()
+    {
+        return originalMethod.isStrictfp();
+    }
+
+    public boolean isSynchronized()
+    {
+        return originalMethod.isSynchronized();
+    }
+
+    public boolean isTransient()
+    {
+        return originalMethod.isTransient();
+    }
+
+    public boolean isVarArgs()
+    {
+        return originalMethod.isVarArgs();
+    }
+
+    public boolean isVolatile()
+    {
+        return originalMethod.isVolatile();
+    }
+
+    public void setAnnotations( Annotation[] annotations )
+    {
+        originalMethod.setAnnotations( annotations );
+    }
+
+    public void setComment( String comment )
+    {
+        originalMethod.setComment( comment );
+    }
+
+    public void setConstructor( boolean constructor )
+    {
+        originalMethod.setConstructor( constructor );
+    }
+
+    public void setExceptions( Type[] exceptions )
+    {
+        originalMethod.setExceptions( exceptions );
+    }
+
+    public void setLineNumber( int lineNumber )
+    {
+        originalMethod.setLineNumber( lineNumber );
+    }
+
+    public void setModifiers( String[] modifiers )
+    {
+        originalMethod.setModifiers( modifiers );
+    }
+
+    public void setName( String name )
+    {
+        originalMethod.setName( name );
+    }
+
+    public void setParent( JavaClassParent parent )
+    {
+        originalMethod.setParent( parent );
+    }
+
+    public void setParentClass( JavaClass parentClass )
+    {
+        originalMethod.setParentClass( parentClass );
+    }
+
+    public void setReturns( Type returns )
+    {
+        originalMethod.setReturns( returns );
+    }
+
+    public void setSourceCode( String sourceCode )
+    {
+        originalMethod.setSourceCode( sourceCode );
+    }
+
+    public void setTags( List tagList )
+    {
+        originalMethod.setTags( tagList );
+    }
+
+    public void setTypeParameters( TypeVariable[] typeParameters )
+    {
+        originalMethod.setTypeParameters( typeParameters );
+    }
+
+    public boolean signatureMatches( String name, Type[] parameterTypes, boolean varArg )
+    {
+        return originalMethod.signatureMatches( name, parameterTypes, varArg );
+    }
+
+    public boolean signatureMatches( String name, Type[] parameterTypes )
+    {
+        return originalMethod.signatureMatches( name, parameterTypes );
+    }
+
+    public String toString()
+    {
+        return originalMethod.toString();
+    }
+}
Property changes on: trunk/qdox/src/java/com/thoughtworks/qdox/model/JavaMethodDelegate.java
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision
Name: svn:eol-style
   + native

Modified: trunk/qdox/src/java/com/thoughtworks/qdox/model/Type.java (725 => 726)

--- trunk/qdox/src/java/com/thoughtworks/qdox/model/Type.java	2010-03-30 16:04:01 UTC (rev 725)
+++ trunk/qdox/src/java/com/thoughtworks/qdox/model/Type.java	2010-04-19 12:57:29 UTC (rev 726)
@@ -350,5 +350,73 @@
         return "void".equals(getValue());
     }
 
+    /**
+     * 
+     * @param superClass
+     * @return
+     * @since 1.12.1
+     */
+    protected int getTypeVariableIndex( JavaClass superClass ) {
+        TypeVariable[] typeVariables = superClass.getTypeParameters();
+        for(int typeIndex=0;typeIndex<typeVariables.length; typeIndex++) {
+            if(typeVariables[typeIndex].getFullyQualifiedName().equals( getFullyQualifiedName())) {
+                return typeIndex;
+            }
+        }
+        return -1;
+    }
 
+    /**
+     * 
+     * @param parentClass
+     * @return
+     * @since 1.12.1
+     */
+    protected Type resolve( JavaClass parentClass )
+    {
+        return resolve( parentClass, parentClass );
+    }
+
+    /**
+     * 
+     * @param parentClass
+     * @param subclass
+     * @return
+     * @since 1.12.1
+     */
+    protected Type resolve( JavaClass parentClass, JavaClass subclass )
+    {
+        Type result = this;
+        int typeIndex = getTypeVariableIndex( parentClass );
+        if ( typeIndex >= 0 )
+        {
+            String fqn = parentClass.getFullyQualifiedName();
+            if ( subclass.getSuperClass() != null && fqn.equals( subclass.getSuperClass().getFullyQualifiedName() ) ) {
+                result = subclass.getSuperClass().getActualTypeArguments()[typeIndex];    
+            }
+            else if ( subclass.getImplementedInterfaces() != null )
+            {
+                for ( int i = 0; i < subclass.getImplementedInterfaces().length; i++ )
+                {
+                    if ( fqn.equals( subclass.getImplements()[i].getFullyQualifiedName() ) ) 
+                    {
+                        result = subclass.getImplements()[i].getActualTypeArguments()[typeIndex];
+                        break;
+                    }
+                }
+            }
+        }
+        
+        if ( this.actualArgumentTypes != null ) {
+            result = new Type( this.fullName, this.name, this.dimensions, this.context );
+            
+            result.actualArgumentTypes = new Type[this.actualArgumentTypes.length];
+            for (int i = 0; i < this.getActualTypeArguments().length; i++ )
+            {
+                result.actualArgumentTypes[i] = this.actualArgumentTypes[i].resolve( parentClass, subclass );
+            }
+        }
+        return result;
+    }
+
 }

Modified: trunk/qdox/src/test/com/thoughtworks/qdox/GenericsTest.java (725 => 726)

--- trunk/qdox/src/test/com/thoughtworks/qdox/GenericsTest.java	2010-03-30 16:04:01 UTC (rev 725)
+++ trunk/qdox/src/test/com/thoughtworks/qdox/GenericsTest.java	2010-04-19 12:57:29 UTC (rev 726)
@@ -2,6 +2,8 @@
 
 import com.thoughtworks.qdox.model.JavaClass;
 import com.thoughtworks.qdox.model.JavaField;
+import com.thoughtworks.qdox.model.JavaMethod;
+
 import junit.framework.TestCase;
 
 import java.io.StringReader;
@@ -251,5 +253,72 @@
         assertNotNull(envField);
         assertEquals("Map", envField.getType().getValue());
     } 
+    
+    // QDOX-207
+    public void testMethodReturnTypeExtends() throws Exception {
+        String superSource = "public abstract class Test<T> {\n" + 
+        		"        private T me;\n" + 
+        		"        public Test(T me) {\n" + 
+        		"            this.me = me;\n" + 
+        		"        }\n" + 
+        		"        public T getValue() {\n" + 
+        		"            return me;\n" + 
+        		"        }\n" + 
+        		"    }";
+        String subSource = "public class StringTest extends Test<String> {\n" + 
+        		"        public StringTest(String s) {\n" + 
+        		"            super(s);\n" + 
+        		"        }\n" + 
+        		"    }";
+        builder.addSource( new StringReader( superSource ) );
+        builder.addSource( new StringReader( subSource ) );
+        JavaMethod method = builder.getClassByName( "StringTest" ).getMethodBySignature( "getValue", null, true );
+        assertEquals( "T", method.getGenericReturnType().getFullyQualifiedName() );
+        assertEquals( "java.lang.Object", method.getReturnType().getFullyQualifiedName() );
+        assertEquals( "java.lang.Object", method.getReturnType( false ).getFullyQualifiedName() );
+        assertEquals( "java.lang.String", method.getReturnType( true ).getFullyQualifiedName() );
+    }
+    
+    public void testMethodReturnTypeImplements() throws Exception {
+        String source1="public interface GenericDao<TEntity, TKey> {\n" + 
+        		"public List<TEntity> getAll();\n" + 
+                "public TEntity getRandom();\n" + 
+        		"public TEntity findById(TKey key);\n" + 
+        		"public TEntity persist(TEntity entity);\n" + 
+        		"public TEntity[] persist(TEntity[] entities);\n" + 
+        		"public void delete(TEntity entity);\n" + 
+        		"public Map<TKey, TEntity> asMap();" +
+        		"}\r\n";
+        String source2="public interface SubjectDao extends GenericDao<Subject, Long> {\n" + 
+        		"public List<Subject> getEnabledSubjects();\n" + 
+        		"}\r\n";
+        String source3="public interface SubjectService extends RemoteService, SubjectDao {\r\n" + 
+        		"}";
+        builder.addSource( new StringReader( source1 ) );
+        builder.addSource( new StringReader( source2 ) );
+        builder.addSource( new StringReader( source3 ) );
+        JavaMethod method = builder.getClassByName( "GenericDao" ).getMethodBySignature( "getRandom", null, true );
+        assertEquals( "TEntity", method.getReturnType( true ).getGenericValue() );
+        method = builder.getClassByName( "GenericDao" ).getMethodBySignature( "getAll", null, true );
+        assertEquals( "List<TEntity>", method.getReturnType( true ).getGenericValue() );
+        method = builder.getClassByName( "GenericDao" ).getMethodBySignature( "asMap", null, true );
+        assertEquals( "Map<TKey,TEntity>", method.getReturnType( true ).getGenericValue() );
 
+        method = builder.getClassByName( "SubjectDao" ).getMethodBySignature( "getRandom", null, true );
+        assertEquals( "Subject", method.getReturnType( true ).getGenericValue() );
+        method = builder.getClassByName( "SubjectDao" ).getMethodBySignature( "getAll", null, true );
+        assertEquals( "List<Subject>", method.getReturnType( true ).getGenericValue() );
+        method = builder.getClassByName( "SubjectDao" ).getMethodBySignature( "asMap", null, true );
+        assertEquals( "Map<java.lang.Long,Subject>", method.getReturnType( true ).getGenericValue() );
+        
+        method = builder.getClassByName( "SubjectService" ).getMethodBySignature( "getRandom", null, true );
+        assertEquals( "Subject", method.getReturnType( true ).getGenericValue() );
+        method = builder.getClassByName( "SubjectService" ).getMethodBySignature( "getAll", null, true );
+        assertEquals( "List<Subject>", method.getReturnType( true ).getGenericValue() );
+        method = builder.getClassByName( "SubjectService" ).getMethodBySignature( "asMap", null, true );
+        assertEquals( "Map<java.lang.Long,Subject>", method.getReturnType( true ).getGenericValue() );
+    }
+    
+    
+
 }


To unsubscribe from this list please visit:

http://xircles.codehaus.org/manage_email

Reply via email to