Spring dependency injection generic service class - java

i have a generic dao class and i'm trying to use spring dependency injection but i have the following error
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'BaseDao' defined in ServletContext resource [/WEB-INF/applicationContext.xml]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [com.abgc.fab.dao.BaseDao]: Constructor threw exception; nested exception is java.lang.ClassCastException: sun.reflect.generics.reflectiveObjects.TypeVariableImpl cannot be cast to java.lang.Class
my applicationContext.xml file
<bean id="BaseDao" class="com.abgc.fab.dao.BaseDao">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
my basedao class :
public class BaseDao<TEntity> extends CommonDao<TEntity> implements IBaseDao<TEntity> {
}
public abstract class CommonDao<TEntity> extends FabObject implements ICommonDao<TEntity> {
public CommonDao() {
Type t = getClass().getGenericSuperclass();
ParameterizedType pt = (ParameterizedType) t;
this.classEntity = (Class<TEntity>) pt.getActualTypeArguments()[0];
}
any help please ?

Is TEntity an actual class or your type parameter?
From what it looks to me TEntity is only the name of your type parameter, which I believe does not work.
you would need something like
class ConcreteNominationHibernateDAO
extends BaseDao<ConcreteNominationSubclass> {...}

Having a deep hierarchy you'll need to use something like TypeTools (which I authored):
class DeviceDao extends BaseDao<Device> {}
Class<?> entityType = TypeResolver.resolveRawArgument(IBaseDao.clas, DeviceDao.class);
assert entityType == Device.class;
Note: As always, type arguments can only be resolved at runtime if they're captured in a type definition. So subclassing BaseDao is necessary.

Check for Annotations #Entity,#Service, etc. Maybe you have missed something. So the DAO class cannot call the POJO Class and the bean can't be initialized.

Per the javadoc, ParameterizedType.getActualTypeArguments returns a Type[]. A Type is not necessarily a Class and therefore the cast to Class is not safe.
Per the answer here by Piotr Findeisen:
The expression
getClass().getGenericSuperclass()).getActualTypeArguments()[0]
refers to value substituted to first type parameter of AbstractHibernateDAO (which in the AbstractHibernateDAO.java is denoted by T). The type substituted by subclass NominationHibernateDAO is still not concrete, it is T extends Nomination, which is definitely not a java.lang.Class instance, but a Type instance (TypeVariableImpl is an implementation of a Type).
If the NominationHibernateDAO was declared with something like that:
class NominationHibernateDAO extends AbstractHibernateDAO<Nomination, Integer> { ...
then the AbstractHibernateDAO constructor magic would work. Alternatively, you can (or you even should?) instantiate a subclass of NominationHibernateDAO declared like this:
class ConcreteNominationHibernateDAO
extends NominationHibernateDAO<ConcreteNominationSubclass> { ...
or
new NominationHibernateDAO<ConcreteNominationSubclass>() {}
This, again, would not trigger the problem.
Are you sure the NominationHibernateDAO class is meant to be used as a Spring bean?

Related

How to to prevent Spring to create an "abstract" generic type repository that is just to be extended?

If I want to do something like this:
public interface LongIdRepo<T> extends PagingAndSortingRepository<T, Long> {}
because I would like to extend it like:
public interface MyRepo extends LongIdRepo<My> {}
it is not possible because :
org.springframework.beans.factory.BeanCreationException: Error
creating bean with name 'longIdRepo': Invocation of init method
failed; nested exception is java.lang.IllegalArgumentException: Not a
managed type: class java.lang.Object
Is there some way to make Spring to ignore the LongIdRepo bean creation?
Try this #NoRepositoryBean annotation
#NoRepositoryBean
public interface LongIdRepo<T> extends PagingAndSortingRepository<T, Long> {}

How can an injected superclass Bean get the wrong instance ( subclass Bean instance) injected?

Problem:
I had some unexpected behaviour when injecting a Bean(In a filter) with 2 subclasses which I injected in two other classes (Servlets). Now the injected superclass could hold a reference to a subclass instance at runtime (changeing with each container restart).
I must have made a serious mistake but I can't quite figure out what exactly.
Additional information:
I use Java EE6
Class structure:
In the filter I inject the super class which holds a random instance to one of the subclasses or the superclass:
#EJB
private ClientLogger clientLogger;
The super class been starts like this:
#Stateless
#LocalBean
public class ClientLogger implements HcpEntityBeanLogger<Client> {
private Client client;
public ClientLogger(){
}
....
}
This subclass bean I inject in one of my Servlets:
#Stateless
#LocalBean
public class AdminClientLogger extends ClientLogger {
public AdminClientLogger(){
}
...
}
Solution attempt:
So as far as I understand the subclass which gets last injected will be the instance referenced by clientLogger, but why, why can't I have 3 different instances and use inheritance here?
Edit:
I faced this problem again when injecting multiple query beans which all implement the same interface, all of them would hold a reference to the same instance.
The solution was to add beanName wenn injecting the interface with EJB
#EJB(beanName="name of your bean class or name specified in #Stateless(name=".."))
You can use the lookup attribute on the #EJB annotation and get the required subclass injected. E.g.
#EJB(lookup="java:global/rest/AdminClientLogger")
private ClientLogger clientLogger;
Obviously you would have to change the JNDI lookup path in the example above.
So basically this happens when you forget to reference to the concrete sub class. Then the container will apparently just inject the same instance of one of the concrete classes;
There are a number of ways to reference the concrete class:
lookup (example from #NiranjanBhat)
#EJB(lookup="java:global/rest/AdminClientLogger")
private ClientLogger clientLogger;
beanName
#EJB(beanName="name of your bean class or name specified in #Stateless(name=".."))
there is also
name
beanInterface
mappedName
how to use them you can take from the java docs about EJB

CDI: get manually instance of bean of class which is declared with generics

This is the way how I get manually instance of cdi bean:
Bean<?> bean = (Bean<?>)beanManager.resolve(beanManager.getBeans(Foo.class));
Foo foo=(Foo) beanManager.getReference(bean, bean.getBeanClass(), beanManager.createCreationalContext(bean));
if I declare Foo class this way:
#Dependent
public class Foo{
...
}
everything works. However, if I declare class Foo this way
#Dependent
public class Foo<T>{
...
}
cdi container can't create cdi bean. How can I get manually cdi bean of class declared with generics (Foo)?
What you are looking for is probably javax.enterprise.util.TypeLiteral.
It is a utility class allowing you to specify a (bean) type along with the type variable. It then allows to retrieve the raw type as well as the actual type parameter inside. Here is a code snippet:
// define the type you want
TypeLiteral<Foo<Bar>> typeLiteral = new TypeLiteral<Foo<Bar>>() {};
// now search for beans; note that getBeans allows to specify Annotations as well!
Set<Bean<?>> beans = beanManager.getBeans(typeLiteral.getType());
// and apply resolution - you should get the one you want here
Bean<?> bean = beanManager.resolve(beans);

why I can't inject child bean class of not bean abstract parent class

I have a parametrized abstract class with one parametrized constructor:
public abstract class BasicEntidadController<T extends Entidad> implements Serializable {
public BasicEntidadController(EntidadBean<T> entidadSessionBean) {....}
// other methods
}
and a child class extending it:
#SessionScoped
#Named
public class TiendaController extends BasicEntidadController<Tienda> implements Serializable {...}
and WELD reports an error telling me that "BasicEntidadController" is not proxyable....
org.jboss.weld.exceptions.UnproxyableResolutionException: WELD-001435 Normal scoped bean class org.wgualla.sandbox.entity.BasicEntidadController is not proxyable because it has no no-args constructor - Managed Bean [class org.wgualla.sandbox.tienda.TiendaController] with qualifiers [#Any #Default #Named].
Why WELD is trying to create a proxy of this abstract/no-bean class???
Must I do all classes, in inheritance tree, proxyables if I want to inject/use in EL expresion just the last child in the tree?
Thanks in advance.
By definition a java bean has "The class must have a public default constructor (with no arguments)."
See http://en.wikipedia.org/wiki/JavaBeans#JavaBeans_API
I would suggest that you change your constructor to
public BasicEntidadController() {....}
// other methods
and then add a setter method
setEntidadSessionBean(EntidadBean<T> entidadSessionBean)
Or even better - read about dependancy injection. You can then use something like
#Autowired
EntidadBean<T> entidadSessionBean;
See http://www.vogella.com/articles/SpringDependencyInjection/
Hope this helps

problem with injecting abstract class in spring

I have two abstract classes
class abstract A {
//some methods .
}
class abstract B extends A {
private C c ;
//other methods
}
Spring config file :
<bean id="b" class="B" abstract="true">
<property name="c" ref="C" /> //I have reference for C else where
</bean>
When I run the program , the class c is not getting injected . It is coming as null . Am i missing something ?
abstract=true means that the bean specification is a 'template' for other bean declarations to extend, it does not mean the class is abstract. I suspect bean with id b is not being created since it is a template/abstract definition. Remove abstract=true and make B a concrete type and it should work.
Documentation here: http://static.springsource.org/spring/docs/3.0.x/reference/beans.html#beans-child-bean-definitions
You don't show a setter for C in the abstract class B. You must use either setting or constructor injection. The code as posted can't work.
You should also specify B as the parent bean for C; likewise A for B.
Although the use of 'abstract="true"' is not meant to indicate that the bean specification is for an abstract class, it is still required for an abstract class bean definition so that pre-instantiation is not attempted on that class (which would fail for an abstract class). This is indicated in a note below the section that the above link points to (http://static.springsource.org/spring/docs/3.0.x/reference/beans.html#beans-child-bean-definitions). If this were a situation where the super class was not an abstract class, then yes, 'abstract="true"' should not be used.

Categories

Resources