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;
}
}
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];
}
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);
}
}
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
.
@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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With