Spring 3.2 Autowire generic types - java

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
}

Related

is it possible to create multiple spring beans (from different interfaces) with the same name?

I'm trying to create the following structure:
public interface A {string calculateA(){....}}
#Service("policy1")
public class APolicy1 implements A {
#Override
public String calculateA(){...}
}
#Service("policy2")
public class APolicy2 implements A {
#Override
public String calculateA(){...}
}
and another interface
public interface B{string calculateB(){....}}
#Service("policy1")
public class BPolicy1 implements B{
#Override
public String calculateB(){...}
}
#Service("policy2")
public class BPolicy2 implements B{
#Override
public String calculateB(){...}
}
and the classes that uses these beans:
#service
#Primary
public class Arouter implements A{
#Autowired
Map<String, A> AServices;
#Autowired
PolicyResolver policyResolver;
#Override
public String calculateA(){
String policy = policyResolver.getPolicy();
AServices.get(policy).CalculateA();
}
#service
#Primary
public class Brouter Implements B{
#Autowired
Map<String, B> AServices;
#Autowired
PolicyResolver policyResolver;
#Override
public String calculateB(){
String policy = policyResolver.getPolicy();
AServices.get(policy).CalculateB();
}
note: the idea here is to delegate to the correct business logic by some kind of policy
for example, if i'm running in policy a context and need to trigger Service B, then the router will call BPolicy2 method.
but I'm getting:
org.springframework.context.annotation.ConflictingBeanDefinitionException: Annotation-specified bean name 'policy1' for bean class [...apackage.APolicy1] conflicts with existing, non-compatible bean definition of same name and class [...bpackage.BPolicy1]
I would expect that since these are different bean types I would be able to give them the same name
edit: I have a solution: add a prefix to the beans the name and the routers will add the prefix to the policyResolver return value, but I'm it's less elegant
#qualifier annotation can be used to differentiate between different beans.
Here is a link with small example of #qualifier annotation usage in Spring :
https://memorynotfound.com/handling-multiple-autowire-dependencies-with-spring-qualifier/

Unable to Autowire through constructor

I am trying to Autowire a class through constructor.
#Component
public class Test<T extends Something>{
#Autowired
public Test(Class<T> entity)
doSomething(enity);
}
...
When I run the code I keep get the error message
Parameter 0 of constructor in com.test.Test required a bean of type 'java.lang.Class' that could not be found.
Action:
Consider defining a bean of type 'java.lang.Class' in your configuration.
Could someone please tell me where I am going wrong here. Thanks.
It says you that it could not find Class class marked as Bean etc
So you need to have a class wanted to be injected declared as #Bean ,#Component etc.
Here is an example:
#Configuration
public class Config {
#Bean
public<T> Class<T> tClass(){
return (some class to be returned);// you need to generify or pass some type of class which you want
}
}
//Here is injecting with no problems
#Component
public class Test<T> {
private Class<T> tClass;
#Autowired
public Test(Class<T> tClass) {
this.tClass = tClass;
}
}
Some how its better do define such architecture which would be better in this case:
public interface Foo<T> {
Class<T> getClassFromType();
}
#Component
public class FooIntegerImpl implements Foo<Integer>{
#Override
public Class<Integer> getClassFromType() {
return Integer.class;
}
}
#Component
public class FooStringImpl implements Foo<String>{
#Override
public Class<String> getClassFromType() {
return String.class;
}
}
#Component
public class Test {
private List<Foo> foo;
#Autowired
public Test(List<Foo> foo) {
this.foo = foo;
}
}
For such purposes for example you can define generic API which would be common for all cases , actually you can define AbstractCrudOperations and define crud things when someone need to inherit it would define type of object which need to be in and will have some methods defined
Actually in your case i dont know the logic what you want to implement but basic error is that Class could not be found as bean
I think this is helpful for you

Parameter 0 of constructor in ..... Spring Boot

I have a problem when launch my app. Could somebody help me to solve this issue?
Parameter 0 of constructor in com.journaldev.elasticsearch.service.BookServiceImpl required a bean of type 'com.journaldev.elasticsearch.dao.search.BookRepositorySearch' that could not be found.
Action:
Consider defining a bean of type 'com.journaldev.elasticsearch.dao.search.BookRepositorySearch' in your configuration.
GenericRepository
public interface GenericRepository<T, K> {
Map<String, Object> get(final K id);
}
GenericRepositoryImpl
public class GenericRepositoryImpl<T, K extends Serializable> implements GenericRepository<T, K> {
private RestHighLevelClient restHighLevelClient;
private ObjectMapper objectMapper;
public GenericRepositoryImpl(ObjectMapper objectMapper, RestHighLevelClient restHighLevelClient) {
this.objectMapper = objectMapper;
this.restHighLevelClient = restHighLevelClient;
}
#Override
public Map<String, Object> get(K id) {
return null;
}
}
BookRepositorySearch
#Component
public interface BookRepositorySearch extends GenericRepository<Book, Long> {}
BookService
public interface BookService {
Map<String, Object> get(final Long id);
}
BookServiceImpl
#Service
public class BookServiceImpl implements BookService {
private final BookRepositorySearch bookRepositorySearch;
public BookServiceImpl(BookRepositorySearch bookRepositorySearch) {
this.bookRepositorySearch = bookRepositorySearch;
}
#Override
public Map<String, Object> get(Long id) {
return null;
}
}
From your previous comments, looks like you want to keep BookRepositorySearch as an interface. If that's the case, you need to create a concrete instance of that interface and put #Component on that.
You don't need #Component on your interface declaration and you can't extend a class in an interface.
public interface BookRepositorySearch {}
Create a concrete type that implements the interface and extends extends GenericRepository<Book, Long> you want to autowire and put #Component on it:
#Component
public class BookRepositorySearchImpl
implements BookRepositorySearch
extends GenericRepository<Book, Long>
{}
https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#beans-factory-class-ctor
Instantiation with a constructor
When you create a bean by the
constructor approach, all normal classes are usable by and compatible
with Spring. That is, the class being developed does not need to
implement any specific interfaces or to be coded in a specific
fashion. Simply specifying the bean class should suffice. However,
depending on what type of IoC you use for that specific bean, you may
need a default (empty) constructor.
The Spring IoC container can manage virtually any class you want it to
manage; it is not limited to managing true JavaBeans. Most Spring
users prefer actual JavaBeans with only a default (no-argument)
constructor and appropriate setters and getters modeled after the
properties in the container. You can also have more exotic
non-bean-style classes in your container. If, for example, you need to
use a legacy connection pool that absolutely does not adhere to the
JavaBean specification, Spring can manage it as well.
I solved it with this configuration.
Look for #EnableAutoConfiguration in your Configuration file.
#Configuration
#EnableJpaRepositories(basePackages = "com.akog02.repostories")
#EntityScan(basePackages = "com.akog02.domain")
#EnableTransactionManagement
#EnableAutoConfiguration
public class WebConfiguration {
}
First of, You need to "tell" spring what to pass as a parameter. The simplest option is the one mentioned by #Berger in a comment. If for some reason that is not a good approach for you (eg. BookRepositorySearch is not a spring managed bean), you can make a java config file with some more logic:
#Configuration
public class Config {
// you can use #Autowired here
#Bean
public BookService bookService() {
return new BookServiceImpl(--pass your parameter here, get it however you want--)
}
}
edit:
Apparently Spring doesn't require #Autowired anymore (thanks #Mark Rotteveel).
So the problem is that spring doesn't have an instance of your class. The reason for that is (I think) that you use a class parameter instead of an interface. If You just create a marker interface that BookRepositorySearch implements and use that as an argument instead of the actual inplementation, I would expect it to work.
Another solution is what I wrote above already, but for the BookRepositorySearch class.
#Configuration
public class Config {
// you can use #Autowired here
#Bean
public BookRepositorySearch bookRepositorySearch () {
return new BookRepositorySearch();
}
}
This way Spring will have it's beloved instance ;)
How do you inherit a class as an interface?
#Component
public interface BookRepositorySearch extends GenericRepository<Book, Long> {}
Change this interface with a class then try again.
#Component
public class BookRepositorySearch extends GenericRepository<Book, Long> {}
You must add #EnableJpaRepositories("org.tennis.Tennnis.dao") in Prin

restrict user to autowire only interface

I have the following interface
public interface MTS{
public SrvResponse sendMessage(MTSModel msg);
public SrvResponse sendMessage(MTSModel msg, Type type);
}
the implementation
#Component
public class MTSImpl implements MTS {...}
Can I restrict user to autowire only interface private #Autowired MTS service; not MTSImpl in spring boot ?
Can I restrict user to autowire only interface private #Autowired MTS
service; not MTSImpl in spring boot ?
Spring doesn't provide such restrictions for injections.
As alternative you could "protected" your implementation class from clients by making it package private (the default access modifier) in a package that they don't use :
package foo.internal;
class MTSImpl implements MTS {
...
}
Or to hide it completely you could define it as an anonymous class :
#Bean
public MTS getMts() {
return new MTS() {
#Override
public SrvResponse sendMessage(MTSModel msg){
...
}
#Override
public SrvResponse sendMessage(MTSModel msg, Type type){
...
}
};
}

UML: Modelling association between class and interface

I have the following classes and interfaces:
public interface IPersistentObject { }
public class PersistentObject implements IPersistentObject { }
public interface IPersistentObjectDAO { }
public class PersistentDAO implements IPersistentObjectDAO { }
public interface IService1 { }
public class Service1 implements IService1{
#Autowired
private IPersistentObjectDAO persistentDAO;
}
public interface IService2 { }
public class Service2 implements IService2 {
#Autowired
private Iservice1 service1;
}
public class Bean {
private IService2 service2 = JSFUtil.resolveBean("service2");
}
<bean name="service1" class="Service1"/>
<bean name="service2" class="Service2"/>
My question is: How should i modelling these associations?
If it can help I'm using JSF, Spring and Hibernate
If you use interface, it means what your model should be
JSF bean/ inject - interface->implemented class(DAO)->DB entity
So your JSF beans should find and inject Spring interfaces.
Spring service can be separated jar, which you can inject to JSF front end .
in jsf
#ManagedProperty("#{handlerService}")
private HandlerService handlerService = null;
Spring
#Service("handlerService")
#Component
public class HandlerService {
#Autowired
private DomainService domainService;
If your problem is just modeling, just look here: http://www.uml-diagrams.org/generalization.html You will have to point FROM the class that implement TO the interface. Like: "Service2" ---l> "IService2"
If it's something else, please clarify your answer.
For Interfaces, the relation to its implementors is called "realization" not "generalization".
And it goes from the Interface to the Class that realize it, see below.
Class ----> Interface

Categories

Resources