Class cannot be cast to java.lang.reflect.ParameterizedType
Asked Answered
T

5

19

Currently the VariableService is @Autowired in my controller.

I realize I can implement the class ParameterizedType to make this error go away but I fear that I may be headed in the wrong direction. Is there a better way to do this or do I need to bite the bullet and implement ParameterizedType's methods?

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'contentController': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.fettergroup.cmt.service.VariableService com.fettergroup.cmt.web.ContentController.variableService; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'variableService' defined in ServletContext resource [/WEB-INF/dispatcher-servlet.xml]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [com.fettergroup.cmt.service.VariableService]: Constructor threw exception; nested exception is java.lang.ClassCastException: java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType

Variable Service

public class VariableService extends EntityService {
    public VariableService () {
        super.setEntityRepository(new VariableRepository());
    }
}

EntityService

public abstract class EntityService<T> {

    public EntityRepository<T> entityRepository;

    public T create(T entity) {
        return entityRepository.create(entity);
    }

    public T update(T entity) {
        return entityRepository.update(entity);
    }

    public void delete(T entity) {
        entityRepository.delete(entity);
    }

    public void setEntityRepository(EntityRepository<T> entityRepository) {
        this.entityRepository = entityRepository;
    }
}

Variable Repository

public class VariableRepository extends EntityRepository {

}

EntityRepository

@Repository
public abstract class EntityRepository<T> {

    //the equivalent of User.class
    protected Class<T> entityClass;

    @PersistenceContext(type= PersistenceContextType.TRANSACTION)
    public EntityManager entityManager;

    public EntityRepository () {
        //Get "T" and assign it to this.entityClass
        ParameterizedType genericSuperclass = (ParameterizedType) getClass().getGenericSuperclass();
        this.entityClass = (Class<T>) genericSuperclass.getActualTypeArguments()[0];
    }

    /**
     * Create this entity
     * @param t
     * @return 
     */
    public T create(T t) {
        entityManager.persist(t);
        return t;
    }

    /**
     * Update this entity
     * @param t
     * @return 
     */
    public T update(T t) {
        return entityManager.merge(t);
    }

    /**
     * Delete this entity
     * @param entity 
     */
    public void delete(T t) {
        t = this.update(t);
        entityManager.remove(t);
    }

    public void setEntityManager(EntityManager entityManager) {
        this.entityManager = entityManager;
    }
}
Tice answered 14/5, 2012 at 19:23 Comment(0)
N
21

Just saying, this is a pretty poor design for determining the entity type.. You should do the following instead of relying on reflection to infer its class def.. Not only will it get rid of that error, but it will be overall cleaner and at a low level, faster than reflection (not that it would really be an issue).

@Repository
public abstract class EntityRepository<T>{
    protected Class<T> entityClass;

    public EntityRepository(Class<T> entityClass){
        this.entityClass = entityClass;
    }

    //...
}


public class UserEntityRepository extends EntityRepository<User>{
    public UserEntityRepository(){
        super(User.class);
    }
}
Nessa answered 10/10, 2012 at 21:50 Comment(3)
I just wanted to say that this is the design approach i use for my data access layer. Let me know if you have questions.Nessa
can spring autowire the entityClass this way?Digitize
Having to give the actual class object of a type filled in as generic parameter is in no way "cleaner". It's convoluted as hell.Photoelectric
K
11

EntityRepository isn't ParameterizedType type. This class only extends ParameterizedType. This is also possible if spring proxied you class by cglib

We need check parents of class

public EntityRepository () {
    //Get "T" and assign it to this.entityClass
    Type genericSuperClass = getClass().getGenericSuperclass();

    ParameterizedType parametrizedType = null;
    while (parametrizedType == null) {
        if ((genericSuperClass instanceof ParameterizedType)) {
            parametrizedType = (ParameterizedType) genericSuperClass;
        } else {
            genericSuperClass = ((Class<?>) genericSuperClass).getGenericSuperclass();
        }
    }

    entityClass = (Class<T>) parametrizedType.getActualTypeArguments()[0];
}
Kasper answered 29/1, 2015 at 7:32 Comment(0)
F
5

In my case, adding pro guard rules solved the issue, because I was using the Type wrapped in Live Data.

But the issue failed to replicate in a new project. Possible that there were issues with multiple modules in the project.

Rule added:

-keep class androidx.lifecycle.LiveData { *; } 

Here is the thread to solution : ClassCastException java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType

If you have recently upgraded Gradle and Java in your project, you are most likely using R8. So you might wanna check out the other dependencies for your project to work, like :

GSON Proguard for R8

Retrofit Proguard

Furness answered 11/7, 2023 at 4:27 Comment(0)
B
3

It seems you are misusing ParameterizedType. In the EntityRepository constructor, you should be using something like the following, with the appropriate checks.

public EntityRepository () {
    //Get "T" and assign it to this.entityClass
    ParameterizedType genericSuperclass = (ParameterizedType) getClass().getGenericSuperclass();
    Type type = genericSuperclass.getActualTypeArguments()[0];
    if (type instanceof Class) {
      this.entityClass = (Class<T>) type;
    } else if (type instanceof ParameterizedType) {
      this.entityClass = (Class<T>) ((ParameterizedType)type).getRawType();
    }
}

This implementation is far from complete though, as you should also handle GenericArrayType values, as well as nested ParameterizedType.

Basrelief answered 14/5, 2012 at 20:18 Comment(2)
I added your content and imported java.lang.reflect.Type; and type does not have the method getRawType()Tice
oh, i forgot a cast. It type is of type ParameterizedType, you have to cast it to ParameterizedType in order to call getRawType().Basrelief
H
1

@Repository annotation needs to be removed from the class EntityRepository to solve the problem.

Read this thread

java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType

Hunker answered 19/3, 2017 at 14:49 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.