How to autowire a generic bean in spring - spring

How to autowire a generic bean in spring?
I have a dao implement as follows:
#Transactional
public class GenericDaoImpl<T> implements IGenericDao<T>
{
private Class<T> entityClass;
#Autowired
private SessionFactory sessionFactory;
public GenericDaoImpl(Class<T> clazz) {
this.entityClass = clazz;
}
...
}
Now I want to autowired the DaoImpl like this:
#Autowired
GenericDaoImpl<XXXEntity> xxxEntityDao;
I config in the spring xml:
<bean id="xxxEntityDao" class="XXX.GenericDaoImpl">
<constructor-arg name="clazz">
<value>xxx.dao.model.xxxEntity</value>
</constructor-arg>
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
But I doesn't work, How should I config it? or a good practice about generic Dao implement?

Work with your interfaces instead of implementations
Do not use #Transactional in your persistent layer as it is much more likely that it belongs to your service layer.
Those being said, it might make more sense to extend the generic dao and autowire that. An example would be something like :
public interface UserDao extends GenericDao<User> {
User getUsersByNameAndSurname(String name, String surname);
... // More business related methods
}
public class UserDaoImpl implements UserDao {
User getUsersByNameAndSurname(String name, String surname);
{
... // Implementations of methods beyond the capabilities of a generic dao
}
...
}
#Autowired
private UserDao userDao; // Now use directly the dao you need
But if you really really want to use it that way you have to declare a qualifier :
#Autowired
#Qualifier("MyBean")
private ClassWithGeneric<MyBean> autowirable;

There is an alternative way.
I change the GenericDaoImpl<T> to a common class without Generic but use the generic in function
level, and the entityClass can be configured in spring xml.

Related

Spring: Autowired is null in ejb class

I have the following situation:
#Controller
public class myController {
#Autowired
private IProxy service;
public ModelAndView init(HttpServletRequest request, HttpServletResponse response) throws Exception {
List<String> list = service.getName();
}
}
Then my Service is define as follow:
public interface IProxy {
public List<String> getName();
}
Proxy class is responsible for the lookup to the remote bean
#Service("service")
public class Proxy implements IProxy {
...
public List<String> getName() {
return myClass.getName();
}
And the implementation is the following:
#Interceptors(interceptor.class)
#Stateless
#Resource(name = "java:/db")
#Remote(MyClassRemote.class)
public class MyClassImpl extends MyEjb implements MyClassRemote{
#PersistenceContext(unitName = "db")
private EntityManager em;
#Resource
private SessionContext sctx;
#Autowired
public IMyRepo myRepo;
#Override
public List<String> getName() {
try {
return myRepo.getName(em);
}
catch (Exception ex) {
ex.printStackTrace();
throw ex;
}
finally {}
}
So, the problem is that here myRepo is null. I don't know why because IMyRepo and his implementation are always located within the path scanned by Spring.
Just one clarification: MyRepo class that implements IMyRepo is annotated with #Repository.
Any idea?
you can inject spring beans in EJB using Spring interceptors, as explained here in the official documentation. Basically you'll need to adjust your class as follows:
// added the SpringBeanAutowiringInterceptor class
#Interceptors({ interceptor.class, SpringBeanAutowiringInterceptor.class })
#Stateless
#Resource(name = "java:/db")
#Remote(MyClassRemote.class)
public class MyClassImpl extends MyEjb implements MyClassRemote{
// your code
}
You'll also need to define the context location in a beanRefContext.xml file (with your own application context file):
application-context.xml version
<bean id="context"
class="org.springframework.context.support.ClassPathXmlApplicationContext">
<constructor-arg>
<list>
<value>application-context.xml</value>
</list>
</constructor-arg>
</bean>
Java Configuration version:
<bean id="context"
class="org.springframework.context.annotation.AnnotationConfigApplicationContext">
<constructor-arg>
<list>
<value type="java.lang.Class">com.your.app.Configuration</value>
</list>
</constructor-arg>
</bean>
Spring beans and EJB are two different things, you can't just inject a Spring bean in an EJB, because that EJB is no Spring bean, so Spring doesn't know there is a field which should be injected by Spring (unless you use some fancy AOP stuff, which can enable injection into non-Spring-managed beans).

How can I set Mockito `when` method when instantiating mock objects in Spring?

The method described in this answer best suits me for instantiating my mock objects.
<bean id="dao" class="org.mockito.Mockito" factory-method="mock">
<constructor-arg value="com.package.Dao" />
</bean>
However, I also need to set the Mockito when method(s).
Can I do that in the XML, or is the only way to to it like:
when( objectToBestTested.getMockedObject()
.someMethod(anyInt())
).thenReturn("helloWorld");
within my test case?
The reason I ask, is because I don't otherwise need a getter for MockedObject, and I'd only be adding a getter so I can test ObjectToBeTested.
This is the way of how I use Mockito with Spring.
Lets assume I have a Controller that use a Service and this services inject its own DAO, basically have this code structure.
#Controller
public class MyController{
#Autowired
MyService service;
}
#Service
public class MyService{
#Autowired
MyRepo myRepo;
public MyReturnObject myMethod(Arg1 arg){
myRepo.getData(arg);
}
}
#Repository
public class MyRepo{}
Code below is for the junit test case
#RunWith(MockitoJUnitRunner.class)
public class MyServiceTest{
#InjectMocks
private MyService myService;
#Mock
private MyRepo myRepo;
#Test
public void testMyMethod(){
Mockito.when(myRepo.getData(Mockito.anyObject()).thenReturn(new MyReturnObject());
myService.myMethod(new Arg1());
}
}
If you are using standalone applications consider mock as below.
#RunWith(MockitoJUnitRunner.class)
public class PriceChangeRequestThreadFactoryTest {
#Mock
private ApplicationContext context;
#SuppressWarnings("unchecked")
#Test
public void testGetPriceChangeRequestThread() {
final MyClass myClass = Mockito.mock(MyClass.class);
Mockito.when(myClass.myMethod()).thenReturn(new ReturnValue());
Mockito.when(context.getBean(Matchers.anyString(), Matchers.any(Class.class))).thenReturn(myClass);
}
}
I dont really like create mock bean within the application context, but if you do make it only available for your unit testing.

Spring autowired annotation with java timertask

Autowired annotation doesn't work. I thought there must be a problem with Timertask or run method. My other classes working fine(I mean Autowired annotation initialize genericService without any problem) but in this class genericService value is null. Is there any idea?
public class UsersUpdateTask extends TimerTask {
#Autowired
GenericService genericService;
#Override
public void run() {
//genericService.save() gives null pointer.
}
}
My applicationContext definition;
<bean id="usersUpdateTask" class="myPackage.UsersUpdateTask">
</bean>
<bean id="genericLogger" class="utilPack.Logger">
</bean>
<bean id="genericService" class="servicePack.GenericService">
This class working perfectly;
public class Logger implements Serializable {
#Autowired
private GenericService genericService; //works fine
.....
}
There is a method in another class to call UsersUpdateTask's run method;
public void updateUsersList(){
timer.schedule(new UsersUpdateTask(), 1000, 60*60*1000);
}
Well there it is
timer.schedule(new UsersUpdateTask(), 1000, 60*60*1000);
you're creating the object yourself. Spring can't autowire objects it doesn't control or process. Use the injected UsersUpdateTask bean.

Injecting EJB 3 into Spring Bean

I am trying to inject EJB into Spring (3.1.2) service (both in different WARs)
Both are very simple (methods removed to simplify example):
EJB:
#Remote
public interface MyBean {
}
#Singleton
public class MyBeanImpl implements MyBean{
}
Service:
#Service
public class MyServiceImpl implements MyService{
}
At first sight thing is very simple, but I tried:
#EJB(lookup = "java:global/ejbApp/MyBeanImpl!com.my.MyBean")
private MyBean myBean;
and it didin't work. Then I also tried:
#EJB(mappedName = "java:global/ejbApp/MyBeanImpl!com.my.MyBean")
private MyBean myBean;
And
#Resource(mappedName = "java:global/ejbApp/MyBeanImpl!com.my.MyBean")
private MyBean myBean;
but neither worked.
I managed to inject my EJB using:
<jee:jndi-lookup id="myBean" jndi-name="java:global/ejbApp/MyBeanImpl!com.my.MyBean" />
in my spring configuration and in the service:
#Autowired
private MyBean myBean;
But I really dont like this solution. I would like to have my JNDI path in some annotation to be able to do e.g:
#EJB(lookup = MyBean.JNDI_NAME)
private MyBean myBean;
We have found quite nice and simple solution.
Into spring configuration file one has to put:
<bean class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor">
<property name="alwaysUseJndiLookup" value="true" />
</bean>
And that enables spring to search for the beans annotated with #Resource in JNDI.
So now one can do:
#Resource(mappedName = MyBean.JNDI_NAME)
private MyBean myBean;
Are you aiming to get rid of XML or to have JNDI name in annotation? If the former, I haven't tested it, but should work:
#Configuration
public class EjbCfg {
#Bean
public JndiObjectFactoryBean myBean() {
JndiObjectFactoryBean factory = new JndiObjectFactoryBean();
factory.setJndiName(MyBean.JNDI_NAME);
return factory;
}
}
Now you can simply inject:
#Autowired
private MyBean myBean;

Spring 3 DI using generic DAO interface

I'm trying to use #Autowired annotation with my generic Dao interface like this:
public interface DaoContainer<E extends DomainObject> {
public int numberOfItems();
// Other methods omitted for brevity
}
I use this interface in my Controller in following fashion:
#Configurable
public class HelloWorld {
#Autowired
private DaoContainer<Notification> notificationContainer;
#Autowired
private DaoContainer<User> userContainer;
// Implementation omitted for brevity
}
I've configured my application context with following configuration
<context:spring-configured />
<context:component-scan base-package="com.organization.sample">
<context:exclude-filter expression="org.springframework.stereotype.Controller"
type="annotation" />
</context:component-scan>
<tx:annotation-driven />
This works only partially, since Spring creates and injects only one instance of my DaoContainer, namely DaoContainer. In other words, if I ask userContainer.numberOfItems(); I get the number of notificationContainer.numberOfItems()
I've tried to use strongly typed interfaces to mark the correct implementation like this:
public interface NotificationContainer extends DaoContainer<Notification> { }
public interface UserContainer extends DaoContainer<User> { }
And then used these interfaces like this:
#Configurable
public class HelloWorld {
#Autowired
private NotificationContainer notificationContainer;
#Autowired
private UserContainer userContainer;
// Implementation omitted...
}
Sadly this fails to BeanCreationException:
org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.organization.sample.dao.NotificationContainer com.organization.sample.HelloWorld.notificationContainer; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [com.organization.sample.NotificationContainer] 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)}
Now, I'm a little confused how should I proceed or is using multiple Dao's even possible. Any help would be greatly appreciated :)
Ok, I think I've found a fairly reasonable solution for this puzzle. One way of dealing with this would be creating interface and implementations for each and every entity in my domain model (as Espen pointed out in his answer earlier). Now, consider having hundreds of entities and respectively hundreds of implementations. That wouldn't feel right, would it?
I've discarded strongly typed sub-interfaces and I'm using generic interface instead:
#Service // Using #Service annotation instead #Configurable as Espen pointed out
public class HelloWorld {
#Autowired
private DaoContainer<Notification> notificationContainer;
#Autowired
private DaoContainer<User> userContainer;
// Implementation omitted
}
Implementation for my DaoContainer interface would look something like this:
#Repository
public class DaoContainerImpl<E extends DomainObject> implements DaoContainer<E> {
// This is something I need in my application logic
protected Class<E> type;
public int getNumberOfItems() {
// implementation omitted
}
// getters and setters for fields omitted
}
And finally application context:
<context:spring-configured />
<context:component-scan base-package="com.organization.sample">
<context:exclude-filter expression="org.springframework.stereotype.Controller"
type="annotation" />
</context:component-scan>
<bean class="com.organization.sample.dao.DaoContainerImpl" id="userContainer">
<property name="type" value="com.organization.sample.domain.DiaryUser" />
</bean>
<bean class="com.organization.sample.dao.DaoContainerImpl" id="notificationContainer">
<property name="type" value="com.organization.sample.domain.DiaryNotification" />
</bean>
So basically I couldn't get pure generic autowiring to work, but this solution works for me (at least for now) :)
It's possible to autowire as many bean as you like.
But when you're using autowiring by type, it can be only one of bean of each interface. Your error message says you have none bean available in the Spring container of given interface.
A solution:
Your missing DAO implementations:
#Repository
public class NotificationContainerImpl implements NotificationContainer {}
#Repository
public class UserContainerImpl implements UserContainer {}
Your service class:
#Service
public class HelloWorld {
#Autowired
private NotificationContainer notificationContainer;
#Autowired
private UserContainer userContainer;
// Implementation omitted...
}
I replaced the #Configurable annotation with #Service. #Configurable is used together with AspectJ and is not what you want here. You must use #Component or a specialization of it like #Service.
Also remember to have all your Spring components inside your com.organization.sample package to enable the Spring container to find them.
I hope this helps!

Resources