Configurar Spring Inj. Dependencia via Construtor

Prezados,

Estou iniciando no Spring e posso estar cometendo alguma falha “catastrófica”…

Seguinte tenho minha classe GenericHibernateDAO<T, ID extends Serializable> implements DAO<T, ID> que contem os metodos genericos de persistencia com Hibernate.
Tenho um Controller que possui um atributo airportDAO do tipo DAO (Interface implementada pelo GenericHibernateDAO)
No construtor do meu Controller eu recebo a Sessionfactory e dentro do construtor do controller eu faço:
airportDAO = new GenericHibernateDAO<Airport, Long>(sessionFactory);

No meu Spring-Servlet.xml eu tenho

[code]
… Codigo …

<bean id="genericHibernateDAO"
    class="com.apress.expertspringmvc.flight.dao.hibernate.GenericHibernateDAO">
    <constructor-arg>
        <ref bean="sessionFactory"/>
    </constructor-arg>
   
</bean>

<bean name="/airport"
    class="com.apress.expertspringmvc.flight.web.AirportController">
    <property name="airportDao" ref="genericHibernateDAO" />
</bean>[/code]

Quando chamo http://localhost:8080/SpringBook/app/airport

Recebo o seguinte erro:
.beans.factory.BeanCreationException: Error creating bean with name ‘genericHibernateDAO’ defined in ServletContext resource [/WEB-INF/spring-servlet.xml]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [com.apress.expertspringmvc.flight.dao.hibernate.GenericHibernateDAO]: Constructor threw exception; nested exception is java.lang.ClassCastException: java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType

Meu GenericHibernateDAO possui esse construtor:

public GenericHibernateDAO(SessionFactory sessionFactory) { this.persistentClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0]; this.sessionFactory = sessionFactory; }

Alguem sabe onde posso estar errando?

Vc não precisa instanciar o airportDAO.
O spring vai injetá-lo através do setAirportDao

<bean name="/airport"  
        class="com.apress.expertspringmvc.flight.web.AirportController">  
        <property name="airportDao" ref="genericHibernateDAO" />  
</bean>

[quote=fabiofalci]Vc não precisa instanciar o airportDAO.
O spring vai injetá-lo através do setAirportDao

<bean name="/airport"  
        class="com.apress.expertspringmvc.flight.web.AirportController">  
        <property name="airportDao" ref="genericHibernateDAO" />  
</bean>

[/quote]

Entendi.
Mas eu removi a instanciação no construtor do meu Airportcontroller, que ficou assim:

public AirportController(SessionFactory sessionFactory) {
	setCommandName("airport");
	setCommandClass(Airport.class);
	setFormView("airport");
	setSuccessView("airportSuccess");
}

Porém o erro continua:

Error creating bean with name 'genericHibernateDAO' defined in ServletContext resource [/WEB-INF/spring-servlet.xml]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [com.apress.expertspringmvc.flight.dao.hibernate.GenericHibernateDAO]: Constructor threw exception; nested exception is java.lang.ClassCastException: java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType

Cara, tem alguma coisa estranha no construtor do GenericHibernateDAO. Pq tu criou ele?
Pq não usar ‘set’?

E esse último código que mandaste, pq o construtor do AirportController recebe uma SessionFactory?

[quote=fabiofalci]Cara, tem alguma coisa estranha no construtor do GenericHibernateDAO. Pq tu criou ele?
Pq não usar ‘set’?

E esse último código que mandaste, pq o construtor do AirportController recebe uma SessionFactory?[/quote]

Pois é fabio, ele possui a SF porque dentro dele eu instanciava o DAO passando o SF. Sendo que removendo de dentro do construtor, realmente nao faz sentido haver SF.
Contudo não gostaria de fazer isso via setter devido. Através do construtor, sendo obrigatório a passagem do SF, não teria como ocorrer um nullpointer. Através do setter o programador pode esquecer de invocar este metodo e nao passar a SF…

O programador esquece, o Spring não! :wink:

Usar o construtor é ok, o caso ali é aquele código dentro do construtor

public GenericHibernateDAO(SessionFactory sessionFactory) {  
     this.persistentClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];  
     this.sessionFactory = sessionFactory;  
} 

Essa primeira linha, não está estourando ali? Para que vc precisa disso?

Pra não precisar ficar dando cast no genericHibernateDao nem ficar passando a entity como parametro. No caso a classe ficou assim:

[code]public class GenericHibernateDAO<T, ID extends Serializable> implements DAO<T, ID>{

private final Class<T> persistentClass;
private final SessionFactory sessionFactory;

public GenericHibernateDAO(SessionFactory sessionFactory) {
	this.persistentClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
	this.sessionFactory = sessionFactory;
}

protected Session getSession() {
	if (sessionFactory == null) {
		throw new IllegalStateException("A SessionFactory não foi informada ou está nula.");
	}
	return sessionFactory.openSession();
}

public Class<T> getPersistentClass() {
	return persistentClass;
}

public void flush() {
	getSession().flush();
}

public void clear() {
	getSession().clear();
}

/**
 * Use this inside subclasses as a convenience method.
 */
protected List<T> findByCriteria(Criterion... criterion) {
	Criteria crit = getSession().createCriteria(getPersistentClass());
	for (Criterion c : criterion) {
		crit.add(c);
	}
	return crit.list();
}

protected Query query(String hql) throws DAOException {
	return getSession().createQuery(hql);
}

/* Implementacoes da Interface DAO */

@Override
public T create(T entity) {
	getSession().saveOrUpdate(entity);
	return entity;
}

@Override
public T update(T entity) {
	getSession().saveOrUpdate(entity);
	return entity;
}

@Override
public T delete(T entity) {
	getSession().delete(entity);
	return entity;
}

@Override
public T findById(ID id) {
	return (T) getSession().load(getPersistentClass(), id);
}

@Override
public List<T> findAll() {
	return findByCriteria();

}

@Override
public List<T> findByExample(T exampleInstance, String[] excludeProperty) {
	Criteria crit = getSession().createCriteria(getPersistentClass());
	Example example =  Example.create(exampleInstance);
	for (String exclude : excludeProperty) {
		example.excludeProperty(exclude);
	}
	crit.add(example);
	return crit.list();
}[/code]

}

Entendi, blz.
Fizemos uma solução não tão automatizada assim, algo assim:

public AirpotHibernateDAO() {
	super(Airpot.class);
}

A ideia é a mesma, mas não pega automático do generics, mas sim passa-se explicitamente.

No caso da exception, ele está reclamando desse cast aqui

((ParameterizedType) getClass().getGenericSuperclass())

Ele não consegue fazer o cast do Class para ParameterizedType