Подтвердить что ты не робот

Java.lang.Class нельзя передать в java.lang.reflect.ParameterizedType

Я застрял в этой проблеме в течение длительного времени. Я искал эту проблему на некоторое время, но ни одно из решений не работало.

Структура:

public interface GenericDAO<T extends Serializable, ID extends Serializable>

@Repository
public class AbstractGenericDAO<T extends Serializable, ID extends Serializable> 
    implements GenericDAO<T, ID> {

   private Class<T> persistentClass;

   @Autowired
   private SessionFactory sessionFactory;

   static Logger LOGGER = Logger.getLogger(AbstractGenericDAO.class);


   @SuppressWarnings("unchecked")
   public AbstractGenericDAO() {
       this.persistentClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
   }

   /**
    * @param entity
    * @return T
    * @throws DBException
    */
   @SuppressWarnings("unchecked")
   public T saveEntity(T entity) throws DBException {
       return saveEntity(entity, false);
   }

   /**
    * @param entity
    * @param explicitFlush
    * @return T
    * @throws DBException
    */
   @SuppressWarnings("unchecked")
   public T saveEntity(T entity, boolean explicitFlush) throws DBException {
       Session session = getSessionFactory().getCurrentSession();

       try {
           session.save(entity);
           if(explicitFlush) {
               session.flush();
               session.refresh(entity);
           }
       } catch (HibernateException he) {
           String errorMsg = "Could not save entity. Reason: " + he.getMessage();
           LOGGER.error(errorMsg, he);
           throw new DBException(errorMsg, he);
       }

       return entity;
   }

   /* (non-Javadoc)
    * @see com.amazon.fc.receive.dbaccess.dao.GenericDAO#getPersistentClass()
    */
   @SuppressWarnings("unchecked")
   public Class<T> getPersistentClass() {
       return persistentClass;
   }

   /**
    * @return the sessionFactory
    */
   public SessionFactory getSessionFactory() {
       return this.sessionFactory;
   }

   /**
    * @param sessionFactory the sessionFactory to set
    */
   @Autowired
   public void setSessionFactory(SessionFactory sessionFactory) {
       this.sessionFactory = sessionFactory;
   }
}

public interface ShlkActiveWorkflowDAO 
    extends GenericDAO<ShlkActiveWorkflow, Serializable> 

@Repository
public class ShlkActiveWorkflowDAOImpl 
    extends AbstractGenericDAO<ShlkActiveWorkflow, Serializable>
    implements ShlkActiveWorkflowDAO

Я также использую <context:component-scan> в своем application-config.xml  + <tx:annotation-driven /> в моем application-config.xml.

Просьба предоставить некоторую информацию о том, как исправить эту проблему.

Exception:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'abstractGenericDAO' 

Constructor threw exception; nested exception is java.lang.ClassCastException: java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:946)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:890)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:479)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:450)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:290)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:287)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:189)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:557)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:842)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:416)
    at com.coral.spring.Launcher.<init>(Launcher.java:95)
    at com.coral.spring.Launcher.main(Launcher.java:56)
Caused by: org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [com.workflow.dao.AbstractGenericDAO]: Constructor threw exception; nested exception is     
java.lang.ClassCastException: java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType
    at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:141)
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:72)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:938)
    ... 12 more
Caused by: java.lang.ClassCastException: java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType
    at com.workflow.dao.AbstractGenericDAO.<init>(AbstractGenericDAO.java:43)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
    at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:126)
    ... 14 more
4b9b3361

Ответ 1

Удалите аннотацию @Repository от AbstractGenericDAO и сделайте ее abstract:

public abstract class AbstractGenericDAO<T extends Serializable, ID extends Serializable> 
   implements GenericDAO<T, ID>

Ваша проблема возникает из-за того, что @Repository является специализацией @Component, что означает, что Spring попытается создать экземпляры AbstractGenericDAO для инъекций. Поскольку AbstractGenericDAO суперкласс (Object) не является общим, вы не сможете сбрасывать его Type на ParameterizedType, и поэтому эта строка кода не будет работать (так же, как если бы вы попытались создайте его вручную с помощью new AbstractGenericDAO()):

this.persistentClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];

Специализированный класс ShlkActiveWorkflowDAOImpl должен быть аннотирован с помощью @Repository. Когда Spring пытается создать экземпляр этого класса, произойдет неявный вызов конструктора AbstractGenericDAO, но на этот раз указанная выше строка кода будет работать как ожидалось. Это происходит потому, что getClass() возвращает ShlkActiveWorkflowDAOImpl.class, который является подклассом общего AbstractGenericDAO (поэтому работает downcast to ParameterizedType).

Так как ShlkActiveWorkflowDAOImpl extends AbstractGenericDAO<ShlkActiveWorkflow, Serializable> фактический тип ShlkActiveWorkflow будет правильно отражен во время выполнения. Это известное обходное решение, чтобы избежать передачи ссылки Class<T> на конструктор AbstractGenericDAO.

Если вас беспокоит аннотация @Autowired в AbstractGenericDAO, не будьте. Spring будет правильно подключать все, когда вы вставляете экземпляр одного из своих подклассов.

Ответ 2

Type genericSuperClass = getClass().getGenericSuperclass();

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

this.itemClass = (Class<T>) parametrizedType.getActualTypeArguments()[0];