QDox
  1. QDox
  2. QDOX-205

Expose Type.actualTypeArguments and add JavaClass.typeParameters

    Details

    • Type: Bug Bug
    • Status: Closed Closed
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: 1.10.1
    • Fix Version/s: 1.11
    • Component/s: None
    • Labels:
      None
    • Number of attachments :
      0

      Description

      I have two classes where first (GenericControllerImpl) is some generic purpose controller with common CRUD methods. Second class (GroupControllerImpl) extends parent to add some REST methods.
      With QDox I can't resolve type variables from GenericControllerImpl. JavaClass returned after parsing GroupControllerImpl also has no parent class.

      Code

      Test code
              JavaDocBuilder builder = new JavaDocBuilder();
              JavaSource source = builder.addSource(new File("GroupControllerImpl.java"));
      
              System.out.println(source.getClasses()[0].getParentClass());
      
              source = builder.addSource(new File("GenericControllerImpl.java"));
              System.out.println(source.getClasses()[0].getImplementedInterfaces()[0].asType());
      

      Classes looks next:

      GroupControllerImpl
      package org.code_house.web;
      
      import org.code_house.dataaccess.GroupDAO;
      import org.code_house.domain.Group;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.web.bind.annotation.ModelAttribute;
      import org.springframework.web.bind.annotation.RequestMapping;
      
      public class GroupControllerImpl extends
          GenericControllerImpl<Group, Long, GroupDAO> {
      
          @Autowired
          public void setUserDao(GroupDAO dao) {
              this.dao = dao;
          }
      
          @RequestMapping("/x")
          @ModelAttribute("test")
          public Boolean doSomething() {
              return null;
          }
      }
      
      GenericControllerImpl.java
      package org.code_house.web;
      
      import java.util.List;
      
      import org.code_house.dataaccess.GenericDAO;
      import org.springframework.beans.factory.InitializingBean;
      import org.springframework.util.Assert;
      import org.springframework.web.bind.annotation.PathVariable;
      import org.springframework.web.bind.annotation.RequestBody;
      import org.springframework.web.bind.annotation.RequestMapping;
      
      
      public abstract class GenericControllerImpl<T, K, D extends GenericDAO<T, K>>
          implements GenericController<T, K>, InitializingBean {
      
          protected D dao;
      
          @RequestMapping
          public T create(@RequestBody T object) {
              dao.create(object);
              return object;
          }
      
          @RequestMapping
          public Boolean update(@PathVariable K id, @RequestBody T object) {
              dao.update(object);
              return true;
          }
      
          @RequestMapping
          public T read(@PathVariable K id) {
              return dao.readById(id);
          }
      
          @RequestMapping
          public Boolean remove(@PathVariable K id) {
              return dao.deleteById(id);
          }
      
          @RequestMapping
          public List<T> getAllRecords() {
              return dao.getAll();
          }
      
          public void afterPropertiesSet() {
              Assert.notNull(dao);
          }
      }
      

        Activity

        Hide
        Robert Scholte added a comment -

        getParentClass() is used for innerClasses. You'll have to use getSuperClass() to get it's ... well, super class.
        Hope this will solve your problem.

        Show
        Robert Scholte added a comment - getParentClass() is used for innerClasses. You'll have to use getSuperClass() to get it's ... well, super class. Hope this will solve your problem.
        Hide
        Lukasz Dywicki added a comment -

        Robert - yes you answer resolved first problem - the getSuperClass returns correct type with generic information.. After your response I also found resolution of no generic information about implemented interfaces in "GenericControllerImpl":

        source = builder.addSource(new File("GenericControllerImpl.java"));
        System.out.println(source.getClasses()[0].getImplements()[0].asType()); // Type contains actualArgumentTypes
        

        The problem I still have is type level variables - to get this kind of information from Type I have to access actualArgumentTypes in Type class:

        Field declaredField = tz.getClass().getDeclaredField("actualArgumentTypes");
        declaredField.setAccessible(true);
        return (Type[]) declaredField.get(tz);
        

        Is there any other way of getting this stuff?

        Second thing is - how to get generic class type variables? Code below don't contain any information about generic declaration and I can't find any method in JavaClass to check if class is generic.

        source = builder.addSource(new File("GenericController.java"));
        source.getClasses()[0].asType().getGenericValue();
        

        Regards,
        Lukasz

        Show
        Lukasz Dywicki added a comment - Robert - yes you answer resolved first problem - the getSuperClass returns correct type with generic information.. After your response I also found resolution of no generic information about implemented interfaces in "GenericControllerImpl": source = builder.addSource( new File( "GenericControllerImpl.java" )); System .out.println(source.getClasses()[0].getImplements()[0].asType()); // Type contains actualArgumentTypes The problem I still have is type level variables - to get this kind of information from Type I have to access actualArgumentTypes in Type class: Field declaredField = tz.getClass().getDeclaredField( "actualArgumentTypes" ); declaredField.setAccessible( true ); return (Type[]) declaredField.get(tz); Is there any other way of getting this stuff? Second thing is - how to get generic class type variables? Code below don't contain any information about generic declaration and I can't find any method in JavaClass to check if class is generic. source = builder.addSource( new File( "GenericController.java" )); source.getClasses()[0].asType().getGenericValue(); Regards, Lukasz
        Hide
        Robert Scholte added a comment -

        The actualArgumentTypes are used to build the genericValue, as String representing of this Type. I haven't thought of a reason to expose these types, but if it's required I'm willing to do so.
        I guess I should try to follow the java-api and just use the methodname used with ParameterizedType
        I think after that you'll have all the access required, right?

        Show
        Robert Scholte added a comment - The actualArgumentTypes are used to build the genericValue, as String representing of this Type. I haven't thought of a reason to expose these types, but if it's required I'm willing to do so. I guess I should try to follow the java-api and just use the methodname used with ParameterizedType I think after that you'll have all the access required, right?
        Hide
        Robert Scholte added a comment -

        Lukasz,

        I've just deployed a snapshot to http://snapshots.repository.codehaus.org/. Could you confirm that this is what you requested.

        Show
        Robert Scholte added a comment - Lukasz, I've just deployed a snapshot to http://snapshots.repository.codehaus.org/ . Could you confirm that this is what you requested.
        Hide
        Lukasz Dywicki added a comment - - edited

        Robert thank you for helping me,
        Snapshot version works well. I can get information about parameters.

        Class are declared as below:

        class GenericControllerImpl<T, K, D extends GenericDAO<T, K>>
            implements GenericController<T, K>
        	
        class GroupControllerImpl extends
            GenericControllerImpl<Group, Long, GroupDAO>
        	
        interface GenericController<T, K> 
        

        And following code prints

        source = builder.addSource(new File(path + "GenericControllerImpl.java"));
        Type type = source.getClasses()[0].asType();
        // prints 'org.code_house.web.GenericControllerImpl' 
        System.out.println(type.toGenericString());
        
        type = source.getClasses()[0].getImplements()[0];
        // prints 'GenericController<T,K>'
        System.out.println(type.toGenericString());
        

        I can't get declared parameters in class. The actual parameters are resolved correctly but we don't have access to type parameters - in that case I can't determine with parameters where should be bound.

        I can get following information:
        Class GenericControllerImpl implements interface GenericController with parameters T, K.
        but I also need information:
        Class GenericControllerImpl are declared with parameters T, K, D.
        If I'll get this information I can do something more:
        Class GroupControllerImpl provides following parameters: Group (T), Long (L), GroupDAO (D). The parameters Group (T), Long (K) are passed to GenericController mapped to T, K.

        It is possible to obtain this information using current code base?

        Show
        Lukasz Dywicki added a comment - - edited Robert thank you for helping me, Snapshot version works well. I can get information about parameters. Class are declared as below: class GenericControllerImpl<T, K, D extends GenericDAO<T, K>> implements GenericController<T, K> class GroupControllerImpl extends GenericControllerImpl<Group, Long , GroupDAO> interface GenericController<T, K> And following code prints source = builder.addSource( new File(path + "GenericControllerImpl.java" )); Type type = source.getClasses()[0].asType(); // prints 'org.code_house.web.GenericControllerImpl' System .out.println(type.toGenericString()); type = source.getClasses()[0].getImplements()[0]; // prints 'GenericController<T,K>' System .out.println(type.toGenericString()); I can't get declared parameters in class. The actual parameters are resolved correctly but we don't have access to type parameters - in that case I can't determine with parameters where should be bound. I can get following information: Class GenericControllerImpl implements interface GenericController with parameters T, K. but I also need information: Class GenericControllerImpl are declared with parameters T, K, D. If I'll get this information I can do something more: Class GroupControllerImpl provides following parameters: Group (T), Long (L), GroupDAO (D). The parameters Group (T), Long (K) are passed to GenericController mapped to T, K. It is possible to obtain this information using current code base?
        Robert Scholte made changes -
        Field Original Value New Value
        Summary Broken inheritance hierarchy when using generic parent class Expose Type.actualTypeArguments and add JavaClass.typeParameters
        Hide
        Robert Scholte added a comment -

        Lukasz,

        I noticed we only provided typeParameters for methods, not for classes yet. I've added them, you should be able to access them by calling JavaClass.getTypeParameters().
        Another snapshot deployed, ready to be reviewed.

        btw, I changed the title of this issue: it didn't cover the real issue.

        Show
        Robert Scholte added a comment - Lukasz, I noticed we only provided typeParameters for methods, not for classes yet. I've added them, you should be able to access them by calling JavaClass.getTypeParameters(). Another snapshot deployed, ready to be reviewed. btw, I changed the title of this issue: it didn't cover the real issue.
        Hide
        Lukasz Dywicki added a comment -

        Robert,
        I built code from sources - everything works.
        I would notice that getValue method in TypeVariable can throw NullPointerException - the bounds field are not always initialized.

        Thank you very much for working on this issue.
        Best regards,
        Lukasz Dywicki

        Show
        Lukasz Dywicki added a comment - Robert, I built code from sources - everything works. I would notice that getValue method in TypeVariable can throw NullPointerException - the bounds field are not always initialized. Thank you very much for working on this issue. Best regards, Lukasz Dywicki
        Robert Scholte made changes -
        Assignee Robert Scholte [ rfscholte ]
        Status Open [ 1 ] Closed [ 6 ]
        Resolution Fixed [ 1 ]
        Fix Version/s 1.11 [ 16104 ]

          People

          • Assignee:
            Robert Scholte
            Reporter:
            Lukasz Dywicki
          • Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved: