Spring #Autowire another implementation of the current service - java

I need to have an interface and then two implementations in different maven modules. Both impl services see api modul with interface but they don't see each other.
There is a default implementation and then transactional implementation. I want transactional impl service just load and call default impl service. Like this:
package my.app.core.api;
public interface MyService {
boolean process();
}
package my.app.core.impl
#Service
public class MyServiceImpl implements MyService {
#Override
public boolean process() {
// do something cool...
}
}
package my.app.somewhere.else.impl
#Service
#Transactional
public class TransactionalMyServiceImpl implements MyService {
#Autowire
private MyService myService;
#Override
public boolean process() {
myService.process();
}
}
Is it possible or do I need to #Autowire explicitly MyServiceImpl instead of interface? Which means to add maven dependancy to my.app.somewhere.else.impl.pom.

You can give different names to your services like so:
#Service
#Qualifier("transactionalMyService")
And then when you autowire you can use the name:
#Autowired
#Qualifier("transactionalMyService")
private MyService myService;

Related

Inject service depending on configuration in Java EE

My application currently uses a class into which two services get injected with the #Inject annotation.
#Stateless
public class MyClass {
#Inject
private SomeService someService;
#Inject
private OtherService otherService;
}
Both services are pretty similar and both extend an abstract Service class.
Here's what I'm trying to do...
My basic idea is that the MyClass class would look something like this:
#Stateless
public class MyClass {
#Inject
private Service service;
}
Depending on a configuration the application decides to either inject SomeService or OtherService
Example:
if (config.getValue().equals("some_service")) {
return new SomeService();
} else if (config.getValue().equals("other_service")) {
return new OtherService();
}
Does Jave EE provide a solution for this?
To make this work, you'll need to ensure that whatever "makes" SomeService eliminates Service from the list of types it can make, and whatever "makes" OtherService eliminates Service from the list of types it can make.
For example, if SomeService is a simple managed bean, you'll need to add the #Typed(SomeService.class) annotation to it:
#Typed(SomeService.class)
public class SomeService extends Service {
}
If, on the other hand, SomeService is produced by a producer method you'll have to do the same thing analogously:
#Produces
#ApplicationScoped
#Typed(SomeService.class)
private SomeService makeSomeService() {
return fabricateSomeService();
}
The #Typed annotation restricts the set of types to whatever is given, not what is inferred.
If you do this on both "concrete" services, then your getService() producer method as written in your answer above should work.
What do you mean by: "Depending on a configuration..." When do you decide what to use? At compiletime or runtime?
There are severaly ways to get this done:
1. #Alternative and beans.xml
Annotate SomeService and OtherService with #Alternative and activate one of them again in beans.xml with
<beans xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
<alternatives>
<class>SomeService</class>
</alternatives>
</beans>
2. With qualifier and Producer:
#Qualifier
#Retention(RUNTIME)
#Target({TYPE, METHOD, FIELD, PARAMETER})
public #interface First {}
And annotate both Beans with:
#First
#Stateless
public SomeService{ ... }
Now you can have a Producer-Class that looks like follows:
#Dependent
public class ServiceProducer {
#Inject
#First
private Service someService;
#Inject
#Second
private Service otherService;
#Produces
#Default
public Service getService() {
switch (someCondition) {
case SOME:
return someService;
case OTHER:
return otherService;
default:
return null;
}
}
}
And finally inject the Service where you want to use it:
#Inject
Service service;
3. Without Producer but with Qualifier-Annotations
You need to Annotate SomeService and OtherService to get this to work.
#Inject
Instance<Service> services;
public void someBussinessMethod(){
Annotation qualifier = someCondition ? new AnnotationLiteral<First>() {} : new AnnotationLiteral<Second>() {};
Service s = services.select(qualifier).get();
}
4. Without Qualifier
This ist in my eyes the ugliest and slowest solution but you can iterrate over the Injectend services and decide by the Class if you want to use it.
#Inject
Instance<Service> services;
public void doSomething() {
Class clazz = someCondition ? SomeService.class : OtherService.class;
Service first = services.stream().filter(s -> s.getClass() == clazz).findFirst().get();
}
A detailed explenation can be found here:
https://docs.jboss.org/cdi/learn/userguide/CDI-user-guide.html#injection
With respect to the comment by #kukeltje I used the #Produces annotation like this:
#ApplicationScoped
public class MyProducer {
#Inject
private SomeService someService;
#Inject
private OtherService otherService;
#Produces
#ApplicationScoped
public Service getService() {
switch (someCondition) {
case SOME:
return someService;
case OTHER:
return otherService;
default:
return null;
}
}
}
Usage:
#Stateless
public class MyClass {
#Inject
private Service service;
}

Instantiate Java Spring repository interface without #Autowire

This is my Spring repository interface.
#Repository
public interface WebappRepository extends CrudRepository<myModel, Long> {
}
In my controller, I can instantiate the WebappRepository even though it's an interface, because of Spring annotation magic.
public class controller{
#Autowire
WebappRepository repo;
public controller(){
}
}
But this variant, using the constructor, does not work, and rightly so, because WebappRepository is an interface.
public class controller{
WebappRepository repo;
public controller(){
this.repo = new WebappRepository();
}
}
Olivier Gierke himself advocates to avoid #Autowire fields at all costs. How can I "instantiate" the repository interface in my Spring application while avoiding the #Autowire?
Inject dependencies in constructor:
#Component
public class Controller{
WebappRepository repo;
#Autowire
public Controller(WebappRepository repo){
this.repo = repo;
}
}
If you're on Spring 4.3+ and your target class has just one constructor, you can omit autowired annotation. Spring will inject all the needed dependencies for it.
So writing just below constructor would suffice:
public controller(WebappRepository repo){
this.repo = repo;
}
Reference: https://docs.spring.io/spring/docs/4.3.x/spring-framework-reference/htmlsingle/#beans-autowired-annotation

How to autowire Spring service with Class name?

I have multiple services and I want to autowire this services dynamically with using their class names. I have a method named "runCustomService" and this methods takes service's class names as input parameter (like "Service1" or "Service2"). I want to autowire these services and call its run method. Is there any way to do this?
#Service
public class Service1 extends BaseService{
#Autowired
private AnotherService anotherService;
public void run(){ .... }
}
#Service
public class Service2 extends BaseService{
#Autowired
private AnotherService anotherService;
public void run(){ .... }
}
public void runCustomService(String serviceClassName){
BaseService baseService = //Create baseService object from serviceClassName
baseService.run();
}
You could use qualifiers on your two services and get the correct bean based on the qualifier name from the ApplicationContext.
#Service
#Qualifier("Service1")
public class Service1 extends BaseService{
#Service
#Qualifier("Service2")
public class Service2 extends BaseService{
#Autowired
ApplicationContext applicationContext;
public void runCustomService(String serviceClassName){
BaseService baseService = applicationContext.getBean(serviceClassName);
baseService.run();
}
Get an instance of ApplicationContext and get bean by a class name:
#Autowired
ApplicationContext ctx;
Use the method getBean(...):
BaseService baseService = ctx.getBean(Service1.class.getName());
However, as the other answer says, I recommend you to use #Qualifier(...) to inject a certain named conditionally.

#DAO and #Service beans clarification

I have a basic question. I've been reading through some tutorials about spring and hibernate integration and in most of them there are DAO and Service layers like below:
public interface TeamDAO {
public void addTeam(Team team);
public void updateTeam(Team team);
public Team getTeam(int id);
public void deleteTeam(int id);
public List<Team> getTeams();
}
Then the implementation of the DAO is provided using the SessionFactory. For example:
#Repository
public class TeamDAOImpl implements TeamDAO {
#Autowired
private SessionFactory sessionFactory;
//Implementation follows..
}
And then there's another service interface the same as the DAO interface like below:
public interface TeamService {
public void addTeam(Team team);
public void updateTeam(Team team);
public Team getTeam(int id);
public void deleteTeam(int id);
public List<Team> getTeams();
}
And the service implementation:
#Service
#Transactional
public class TeamServiceImpl implements TeamService {
//HERE IS MY QUESTION
#Autowired
private TeamDAO teamDAO;
//implementation follows
}
In the service implementation above where I marked "here is my question" I see that we inject only the interface TeamDAO which doesn't have the implementation of the TeamDAOImpl class. So how does the interface and its implementations get injected together in the service layer provided we only inject the interface TeamDAO and not TeamDAOImpl?
When you use #Autowired on an interface, Spring searches a bean instance whose class implements that interface. If it doesn't find any such bean, it fails. If it finds more than one class that implement the interface, it fails. Please refer to Spring #Autowired documentation for further details.
Spring injects TeamDAOImpl because it gets register as spring bean when you mark it as #Repository

Spring 3.2 Autowire generic types

So I have a number of generics in Spring 3.2 and ideally my architecture would look something like this.
class GenericDao<T>{}
class GenericService<T, T_DAO extends GenericDao<T>>
{
// FAILS
#Autowired
T_DAO;
}
#Component
class Foo{}
#Repository
class FooDao extends GenericDao<Foo>{}
#Service
FooService extends GenericService<Foo, FooDao>{}
Unfortunately with multiple implementations of the generics the autowiring throws an error about multiple matching bean definitions. I assume this is because #Autowired processes before type erasure. Every solution I've found or come up with looks ugly to me or just inexplicably refuses to work. What is the best way around this problem?
How about adding a constructor to the GenericService and move the autowiring to the extending class, e.g.
class GenericService<T, T_DAO extends GenericDao<T>> {
private final T_DAO tDao;
GenericService(T_DAO tDao) {
this.tDao = tDao;
}
}
#Service
FooService extends GenericService<Foo, FooDao> {
#Autowired
FooService(FooDao fooDao) {
super(fooDao);
}
}
Update:
As of Spring 4.0 RC1, it is possible to autowire based on generic type, which means that you can write a generic service like
class GenericService<T, T_DAO extends GenericDao<T>> {
#Autowired
private T_DAO tDao;
}
and create multiple different Spring beans of it like:
#Service
class FooService extends GenericService<Foo, FooDao> {
}
Here is a closest solution. The specialized DAOs are annotated at the business layer. As in the question from OP, the best effort would be having an annotated DAO in the EntityDAO generic template itself. Type erasure seems to be not allowing the specialized type information to get passed onto the spring factories [resulting in reporting matching beans from all the specialized DAOs]
The Generic Entity DAO template
public class EntityDAO<T>
{
#Autowired
SessionFactory factory;
public Session getCurrentSession()
{
return factory.getCurrentSession();
}
public void create(T record)
{
getCurrentSession().save(record);
}
public void update(T record)
{
getCurrentSession().update(record);
}
public void delete(T record)
{
getCurrentSession().delete(record);
}
public void persist(T record)
{
getCurrentSession().saveOrUpdate(record);
}
public T get(Class<T> clazz, Integer id)
{
return (T) getCurrentSession().get(clazz, id);
}
}
The Generic Entity Based Business Layer Template
public abstract class EntityBusinessService<T>
implements Serializable
{
public abstract EntityDAO<T> getDAO();
//Rest of code.
}
An Example Specialized Entity DAO
#Transactional
#Repository
public class UserDAO
extends EntityDAO<User>
{
}
An Example Specialized Entity Business Class
#Transactional
#Service
#Scope("prototype")
public class UserBusinessService
extends EntityBusinessService<User>
{
#Autowired
UserDAO dao;
#Override
public EntityDAO<User> getDAO()
{
return dao;
}
//Rest of code
}
You can remove the #autowire annotation and perform delayed “autowire” using #PostConstruct and ServiceLocatorFactoryBean.
Your GenericService will look similar to this
public class GenericService<T, T_DAO extends GenericDao<T>>{
#Autowired
private DaoLocator daoLocatorFactoryBean;
//No need to autowried, autowireDao() will do this for you
T_DAO dao;
#SuppressWarnings("unchecked")
#PostConstruct
protected void autowireDao(){
//Read the actual class at run time
final Type type;
type = ((ParameterizedType) getClass().getGenericSuperclass())
.getActualTypeArguments()[1];
//figure out the class of the fully qualified class name
//this way you can know the bean name to look for
final String typeClass = type.toString();
String daoName = typeClass.substring(typeClass.lastIndexOf('.')+1
,typeClass.length());
daoName = Character.toLowerCase(daoName.charAt(0)) + daoName.substring(1);
this.dao = (T_DAO) daoLocatorFactoryBean.lookup(daoName);
}
daoLocatorFactoryBean does the magic for you.
In order to use it you need to add an interface similar to the one below:
public interface DaoLocator {
public GenericDao<?> lookup(String serviceName);
}
You need to add the following snippet to your applicationContext.xml
<bean id="daoLocatorFactoryBean"
class="org.springframework.beans.factory.config.ServiceLocatorFactoryBean">
<property name="serviceLocatorInterface"
value="org.haim.springframwork.stackoverflow.DaoLocator" />
</bean>
This is a nice trick and it will save you little boilerplate classes.
B.T.W I do not see this boilerplate code as a big issue and the project I working for uses matsev approach.
Why do you want a generic service ? Service classes are meant for specific units of work involving multple entities. You can just inject a repository straight into a controller.
Here is an example of generic repository with constructor argument, you could also make each method Generic instead and have no constructor argument. But each method call would require class as parameter:
public class DomainRepository<T> {
#Resource(name = "sessionFactory")
protected SessionFactory sessionFactory;
public DomainRepository(Class genericType) {
this.genericType = genericType;
}
#Transactional(readOnly = true)
public T get(final long id) {
return (T) sessionFactory.getCurrentSession().get(genericType, id);
}
Example of bean definition for the generic repository - you could have multple different beans, using different contstructor args.
<bean id="tagRepository" class="com.yourcompnay.data.DomainRepository">
<constructor-arg value="com.yourcompnay.domain.Tag"/>
</bean>
Depdncy injection of bean using resource annotation
#Resource(name = "tagRepository")
private DomainRepository<Tag> tagRepository;
And this allows the Domainreposiroty to be subclassed for specific entities/methods, which woul dallow autowiring :
public class PersonRepository extends DomainRepository<Person> {
public PersonRepository(){
super(Person.class);
}
...
You should use autowiring in classes which extends these generics
For this question one needs to understand about what autowire is. In common terms we can say that through autowire we create a object instance/bean at the time of deployment of the web app. So now going with the question if you are declaring autowiring in multiple places with the same name. Then this error comes. Autowiring can be done in multiple ways so if you are using multiple type of autowiring technique, then also one could get this error.
Complete Generic Solution using Spring 4:
Domain Class
#Component
class Foo{
}
#Component
class Bar{
}
DAO Layer
interface GenericDao<T>{
//list of methods
}
class GenericDaoImpl<T> implements GenericDao<T>{
#Autowired
SessionFactory factory;
private Class<T> domainClass; // Get Class Type of <T>
public Session getCurrentSession(){
return factory.getCurrentSession();
}
public DaoImpl() {
this.domainClass = (Class<T>) GenericTypeResolver.resolveTypeArgument(getClass(), DaoImpl.class);
}
//implementation of methods
}
interface FooDao extends GenericDao<Foo>{
//Define extra methods if required
}
interface BarDao extends GenericDao<Bar>{
//Define extra methods if required
}
#Repository
class FooDao extends GenericDaoImpl<Foo> implements FooDao{
//implementation of extra methods
}
#Repository
class BarDao extends GenericDaoImpl<Bar> implements BarDao{
//implementation of extra methods
}
Service Layer
interface GenericService<T>{
//List of methods
}
class GenericServiceImpl<T> implements GenericService<T>{
#Autowire
protected GenericDao<T> dao; //used to access DAO layer
}
class FooService extends GenericService<Foo>{
//Add extra methods of required
}
class BarService extends GenericService<Bar>{
//Add extra methods of required
}
#Service
class FooServiceImpl extends GenericServiceImpl<Foo> implements GenericService<Foo>{
//implementation of extra methods
}
#Service
class BarServiceImpl extends GenericServiceImpl<Bar> implements GenericService<Bar>{
//implementation of extra methods
}

Categories

Resources