problem with injecting abstract class in spring - java

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.

Related

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

Spring Java Config: How to create ProxyFactoryBean with package-private target class constructor

Given the following Java code (from a 3rd-party-library outside of my control):
package some.third.party.lib;
interface MyInterface { ... }
and the following class A with a package-private constructor (this is its only constructor):
package some.third.party.lib;
[...]
class A implements MyInterface {
A() {}
}
ProxyFactoryBean.setTargetName expects the ID of an already instantiated bean.
Since my Spring Java Config class is in an application-specific package (and I don't want to change it to some.third.party.lib), I can't instantiate class A, since it's package-private.
I'm aware that I could use reflection to temporarily change the visibility of A's constructor, but I would like to avoid this if possible.
Q: (How) can I create a Spring (4.2.1.RELEASE) ProxyFactoryBean of a class A in Spring Java Config without having to use reflection (and without having to put my Java Config Class into the same package as A)?
Please note that when using Spring XML config, this situation does not occur, because Spring (in the background) creates a Bean for class A, probably also using reflection.

Spring dependency injection generic service class

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?

How to pass a constructor arg of one bean to a nested bean

I have two classes A and B. A holds B as a class field b.
A has two arguments in its constructor : public A(C c, D d){}.
B has two arguments in its constructor : public B(C c, D d){}.
A has a setter for B.
in the spring xml, I defined the Bean B nested inside A :
<bean id="B" class="java.util.B"/>
<bean id="A" class="java.util.A>
<property name="b" ref="B"/>
</bean>
if I load A as follows:
(A)SpringManager.getInstance().loadBean("A",new Object[] {c,d})
(assume that c and d are defined in the class that calles the loadBean function)
How do I pass the args that A got to B's constructor?
You can't. Either you are in charge or Spring is. What you are doing is wiring objects manually instead of using Spring to manage them. You can't expect Spring to provide magic to enable you to do that.
So you'll have to instantiate B first and then pass it to A:
B b = (B)SpringManager.getInstance().loadBean("B",new Object[] {c,d});
A a = (A)SpringManager.getInstance().loadBean("A",new Object[] {c,d});
a.setB(b);
And quite frankly: if you do it like that, I don't see why you are using Spring in the first place.

Spring: Injecting a private inner class as an outer class's member?

I have the following class structure
public class Outer{
private Mapper a;
....
private class MapperA implements Mapper {
}
private class MapperB implements Mapper {
}
}
In my Spring config file I would like to create a an Outer bean, and assign one of MapperA or MapperB as a property. Is this possible?
<bean id="outer" class="mypackage.Outer">
<property name="a" ?????='????' />
</bean>
Edit: Some more info, based on the feedback from answers:
I got lazy with my above example. I do have a public setter/getter for the Mapper instance variable.
The reason all of the Mapper classes are inner classes is because there could potentially be many of them, and they will only ever be used in this class. I just don't want a ton of cruft classes in my project. Maybe a factory method is a better idea.
Spring can instantiate private inner classes. The actual problem with your config is that they are also non-static, so you need a <constructor-arg .../>:
<bean id="outer" class="mypackage.Outer">
<property name = "a">
<bean class = "mypackage.Outer.MapperA">
<constructor-arg ref = "outer" />
</bean>
</property>
</bean>
Normally you'd need a setter for the Mapper within Outer, and an instance of the required Mapper. But as these are:
private
inner
classes, that becomes a bit tricky (as you've identified). If you make them public, I'm sure you could creae an instance using Outer$MapperA etc. But that seems a little nasty. So:
do they need to be inner and private ?
perhaps Outer can take a String, and determine from that whether to instantiate MapperA or MapperB. i.e. there's some factory capability here.
The simplest thing to do is to really determine if they need to be inner/private. If so, then they really shouldn't be referenced within the config, which should be talking about publicly accessible classes.
As far as I know, it's impossible until you make MapperA and MapperB usual public classes.
But if you do want to keep them as inner private classes then you can "inject" them manually.
You'll need to create method with #PostInit annotation and initialize your a field there (a = new MapperA () for example, or something more complex). With this approach you should also check that initialization callbacks are switched-on in your spring configuration.

Categories

Resources