Sorry for my English. I can not to do dependency injection for generic class in spring. Generic class:
abstract class BaseBO<Id, Entity, DAOClass extends DAO<Id, Entity>> implements BO<Id, Entity, DAOClass> {
DAOClass dao;
public DAOClass getDAO() {
return dao;
}
//...
}
Use generic class:
public class TaskBO extends BaseBO<Long, Task, TaskDAO> implements BO<Long, Task, TaskDAO> {
}
I want to do dependency injection in a class TaskBO for property TaskDAO.
But I can only to set dependency TaskDAO via a interface DAO for bean TaskBO:
<bean id="TaskBO" class="com.otv.model.bo.TaskBO">
<property name="DAO" ref="TaskDAO" />
</bean>
<bean id="TaskDAO" class="com.otv.model.dao.TaskDAO">
<property name="sessionFactory" ref="SessionFactory" />
</bean>
How to set dependency injection via class TaskDAO?
Attach stacktrace with error if you have one.
Before all use consistent case for property accessor:
abstract class BaseBO<Id, Entity, DAOClass extends DAO<Id, Entity>> implements BO<Id, Entity, DAOClass> {
DAOClass dao;
public DAOClass getDao() {
return dao;
}
//...
}
Most probably you need a setter for BaseBO.dao property
public void setDao(DAOClass dao) {
this.dao = dao;
}
or
public class TaskBO extends BaseBO<Long, Task, TaskDAO> implements BO<Long, Task, TaskDAO> {
public void setDao(TaskDAO dao) {
super.dao = dao;
}
}
Related
Hi my application was working fine, but on extending my Manager and Dao interface I am getting the error. I have tried the solution (changing <context:component-scan base-package="com.controller" /> to <context:component-scan base-package="com" />) posted in various posts but that gives me stackOverflowError . I think some annotations is required while extending the interfaces, but i do not know what annotation should be used there. Please guide me
//Controller
#Controller
public class Controller {
#Autowired
private Manager2<Entity> manager;
//Manager Interfaces and Impl
public interface Manager1 <T> {
public void add(T entity);
public List<T> getAll();
public T getById(Integer id);
public void delete(Integer id);
public void update(T entity);
}
public interface Manager2<T> extends Manager1<T> {
public List<Entity> getList(int Id);
}
#Service
public class ManagerImpl implements Manager2<Entity> {
#Autowired
private Manager2<Entity> dao;
}
//Dao Interfaces and Impl
public interface DAO1 <T> {
public void add(T entity);
public List<T> getAll();
public T getById(Integer id);
public void delete(Integer id);
public void update(T entity);
}
public interface DAO2<T> extends DAO1<T> {
public List<Entity> getList(int Id);
}
public class DaoImpl implements DAO2<Entity> {
#Autowired
private SessionFactory sessionFactory;
}
//declaration in servlet.xml
<context:component-scan base-package="com.controller" />
<bean id="dao" class="com.dao.DaoImpl"></bean>
<bean id="manager" class="com.service.ManagerImpl"></bean>
//Error from log file
nested exception is `org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.service.Manager2] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}`
the issue with stackoverflow happens because of this code
#Service
public class ManagerImpl implements Manager2<Entity> {
#Autowired
private Manager2<Entity> dao;
}
the reason for this behaviour is that it there's a recursive dependency which is never resolved. service needs another service with same bean recipe.
additionally, #autowired annotation is used for resolving dependency byType. that means that having 2 instantiated beans with save type would lead to an error, as spring is not able to understand what bean you really need. in this case you could use either #Resource (byName) or add #Qualifier annotation with name of a bean you need.
I have a list of services that extend an AbstractService class. The AbstractService holds the DAO (you can call it "repository") and has the getter/setter for the DAO:
/**
* #param <T> Entity type
* #param <K> Entity ID type
* #param <S> DAO type
*/
public abstract class AbstractService<T, K extends Serializable, S extends BaseDAO<T, K>> implements BaseService<T, K> {
private S dao;
public S getDAO() { return dao; }
public void setDAO(S dao) { this.dao = dao; }
// Then common methods to all my services, using the DAO, for instance
#Override
public Optional<T> findOne(K key) throws DataException {
return Optional.ofNullable(dao.findOne(key));
}
}
A service example:
#Service
public class EmployeeServiceImpl extends AbstractService<Employee, Integer, EmployeeDAO> implements EmployeeService {
// Some specific methods to that service
}
The related DAO (I use Spring Data JPA):
public interface EmployeeDAO extends BaseDAO<Employee, Integer> {
}
Extending
#NoRepositoryBean
public interface BaseDAO<T, K extends Serializable> extends JpaRepository<T, K> {
}
By the way I added the annotations #Service and #NoRepositoryBean while moving to JavaConfig.
My old XML config was:
<bean id="com.xxx.service._AbstractService" abstract="true" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager" ref="com.xxx.dao._TxManager" />
<property name="transactionAttributes">
<props>
<prop key="save*">PROPAGATION_REQUIRED,-com.xxx.DataException</prop>
<prop key="update*">PROPAGATION_REQUIRED,-com.xxx.DataException</prop>
<prop key="delete*">PROPAGATION_REQUIRED,-com.xxx.DataException</prop>
</props>
</property>
</bean>
<bean id="com.xxx.service.EmployeeService" parent="com.xxx.service._AbstractBO">
<property name="target">
<bean class="com.xxx.service.EmployeeServiceImpl">
<property name="DAO" ref="com.xxx.dao.EmployeeDAO"/>
</bean>
</property>
</bean>
First question, what is the proper way to inject the generic DAO and handle the service inheritance using JavaConfig?
Second question, how to translate the XML snippet about transactions (com.xxx.service._AbstractBO) to JavaConfig?
Here is what I have so far, 2 classes:
#Configuration
#ComponentScan("com.xxx.service")
public class SpringConfig {
}
And the persistence config
#Configuration
#EnableJpaRepositories("com.xxx.repository")
#EnableTransactionManagement
public class PersistenceConfig {
/* Here so far I defined the DataSource, the EntityManagerFactory,
the PlatformTransactionManager and the JpaVendorAdapter */
}
Thanks in advance for your time!
Here is what I ended up doing: instead of trying to translate my old XML config, I changed the classes design. Since DAOs are required anyway, I inject them in each concrete class constructor which calls a new abstract class constructor I added.
The abstract service:
final private S dao;
public AbstractService(S dao) {
super();
this.dao = dao;
}
// getter protected and setter removed
protected S getDAO() {
return dao;
}
And a concrete service example:
#Service
public class EmployeeServiceImpl extends AbstractService<Employee, Integer, EmployeeDAO> implements EmployeeService {
#Inject
public EmployeeServiceImpl(EmployeeDAO dao) {
super(dao);
}
}
The good thing is I didn't have to change the Java config I posted in my question, meaning #EnableJpaRepositories("com.xxx.repository") and #ComponentScan("com.xxx.service") are sufficient to generate and bind beans.
I want to use #Transactional annotation in the save() method of UserService(concrete class) as follows:
#Service
public class UserService {
#Transactional
public Long save(User userCommand, BindingResult result) {
...
}
}
I will use this service in MyRealm by autowiring.
public class MyRealm extends AuthorizingRealm {
#Autowired
private UserService userService;
}
However, it fails with the following error:
java.lang.IllegalArgumentException: Can not set n.r.c.s.user.UserService field n.r.c.s.realm.MyRealm.userService to com.sun.proxy.$Proxy48
Of course, it works if I remove the #Transational annotation.
My transaction manager setting is as follows:
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"></property>
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
Please, let me know what's wrong with my code?
Do I need to set up something like proxy?
When proxying is enabled you need to use interfaces, not implementations.
#Service
public class UserService implements SomeInterface {
#Transactional
public Long save(User userCommand, BindingResult result) {
...
}
}
public class MyRealm extends AuthorizingRealm {
#Autowired
private SomeInterface userService;
}
If you do not want to do this, you can always check your AOP config. you are probably doing proxy for a proxy somewhere.
If I specify what should be injected into a property, like
<property name="xxx" ref="some_bean" />
or
<property name="xxx">
<bean .../>
</property>
then I have to write a setter method.
May I use some annotation to avoid this like #autowired?
You can do this with constructor injection. 3 main ways to do this:
XML:
<bean id="beanA" class="com.BeanA">
<constructor-arg ref="beanB"/>
</bean>
<bean id="beanB" class="com.BeanB"/>
JavaConfig:
#Configuration
public class MyConfig {
#Bean
public BeanA beanA() {
return new BeanA(beanB());
}
#Bean
public BeanB beanB() {
return new BeanB();
}
}
Autowiring:
#Component
public class BeanA {
private final BeanB beanb;
// This assumes that there is a BeanB in your application context already
#Autowired
public BeanA(final BeanB beanB) {
this.beanB = beanB;
}
}
You can take Autowiring even further, and wire directly to the field:
#Component
public class BeanA {
// This assumes that there is a BeanB in your application context already
#Autowired
private final BeanB beanb;
}
I'm new to Java config. I have a code like this. SomeDao has its own dependency, shouldn't we set the dependencies since we are doing new?
Can someone please help me understand this code?
#Configuration
public class DAOConfiguration {
#Bean(name = "someDao")
public SomeDao someDao() {
return new SomeDao();
}
Are you familiar with how this is done in xml? It is extremely similar to that.
Here is an example of SomeDao being configured with Dep1 (via constructor injection) and Dep2 (via setter injection) in xml:
<bean id="someDao" class="com.example.SomeDao">
<constructor-arg ref="dep1"/>
<property name="dep2" ref="dep2"/>
</bean>
<bean id="dep1" class="com.example.Dep1" />
<bean id="dep2" class="com.example.Dep2" />
This same example in JavaConfig would be configured as such:
#Configuration
public class DAOConfiguration {
#Bean(name = "someDao")
public SomeDao someDao() {
final SomeDao someDao = new SomeDao(dep1());
someDao.setDep2(dep2());
return someDao;
}
#Bean(name="dep1")
public Dep1 dep1() {
return new Dep1();
}
#Bean(name-"dep2")
public Dep2 dep2() {
return new Dep2();
}
}
All three beans are still registered with the ApplicationContext too, so you can have all three of these beans autowired into another class, like so:
#Controller
public class MyController {
#Autowired
private SomeDao someDao;
#Autowired
private Dep1 dep1;
//...some methods
}