Reputation: 571
I have a abstract class AbstractService
which has a reference to AbstractDAO
class AbstractService{
protected AbstractDAO abstractDAO;
}
AbstractService
will be extended by actual service classes like ServiceClassA
, ServiceClassB
etc,
and AbstractDAO
will be extended by DaoClassA
, DaoClassB
etc.
Depending upon which class is extending AbstractService
, abstractDAO
should be an instance of DaoClassA
, DaoClassB
etc
I can achieve this by having the abstractDAO setter in the extending class like
class ServiceClassA{
@Autowired
@Qualifier("daoClassA")
public void setAbstractDAO(AbstractDAO abstractDAO) {
super.abstractDAO = abstractDAO;
}
}
Is there any way to have the setter setAbstractDAO
in AbstractService
class itself
and abstractDAO
gets Autowired depending upon the subclass maybe wth SPEL+Qualifier etc
We dont want to use any XML configuration for this
Upvotes: 9
Views: 16283
Reputation: 5295
I was solving similar problem like you did. I found another way, you don't have to create setter methods. Instead of, use regular constructors, but use Spring autowiring. Here is complete code:
Service classes:
public abstract class AbstractService {
protected final AbstractDAO dao;
// Constructor forces you to inject dao in subclass
public AbstractService(final AbstractDAO dao) {
this.dao = dao;
}
public final void service() {
// you can do something generic here with 'dao'
// no matter which subclass is injected
this.dao.doSomething();
}
}
@Component
public class ServiceClassA extends AbstractService {
@Autowired
public ServiceClassA(@Qualifier("daoClassA") final AbstractDAO dao) {
super(dao);
}
}
@Component
public class ServiceClassB extends AbstractService {
@Autowired
public ServiceClassB(@Qualifier("daoClassB") final AbstractDAO dao) {
super(dao);
}
}
Notice @Qualifier("daoClassA")
in subclass constructors
Field classes:
public interface AbstractDAO {
public void doSomething();
}
@Component
public class DaoClassA implements AbstractDAO {
@Override
public void doSomething() {
System.out.println("I am DaoClassA");
}
}
@Component
public class DaoClassB implements AbstractDAO {
@Override
public void doSomething() {
System.out.println("I am DaoClassB");
}
}
And finally, now you can call your generic service with concrete Service class and concrete DAO class: (of course you can autowire them somewhere)
((AbstractService) context.getBean("serviceClassA")).service();
((AbstractService) context.getBean("serviceClassB")).service();
will print:
I am DaoClassA
I am DaoClassB
Upvotes: 5
Reputation: 10709
No, there isn't. You cannot access to the class or bean name that is currently populating the AutowiredAnnotationBeanPostProcessor
from SPEL.
You could override AbstractBeanFactory.evaluateBeanDefinitionString
and add the beanDefinition
as variable in the BeanExpressionContext
. Then you can derive the Dao from the Service. using SPEL in @Value annotation.
Upvotes: 0
Reputation: 691635
I wouldn't do it like this. Indeed, there is a good chance that the ServiceClassA depends on some specific method of DaoClassA. In this case, you would have to cast the protected AbstractDAO to DaoClassA each time you want to call such a specific method.
I would make it generic, and reverse the way the dependencies are injected:
public class AbstractService<T extends AbstractDAO> {
protected T dao;
protected AbstractService(T dao) {
this.dao = dao;
}
// methods common to all the services
}
public class ServiceClassA extends AbstractService<DaoClassA> {
@Autowired
public ServiceClassA(DaoClassA dao) {
super(dao);
}
// methods specific to ServiceClassA
}
Upvotes: 8