I have the following setup:
#Component
public class ImplOne implements IFace{
}
#Component
public class ImplTwo implements IFace{
}
public interface IFace{
}
I am trying to get a reference of ImplOne by type:
#RunWith(SpringJUnit4ClassRunner.class)
public class ImplOneTest {
#Autowired
private ImplOne impl;
#Test
public void test(){
Assert.assertNotNull(impl);
}
}
Though with this I get the following exception:
org.springframework.beans.factory.NoSuchBeanDefinitionException:
No matching bean of type [some.package.TestBean] 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)}
I tried the following workarounds:
Remove "implements IFace" from ImplOne so the implementation class itself gets Proxied by cglib. Not acceptable because I also need to be able to get all implementations of IFace in my application code.
Doing method injection via a #Autowired public void setImplOne(IFace[] beans) and filtering the instance through instanceof check does not work, because the injected beans are subclasses of type java.lang.reflect.Proxy which doesn't offer any useful methods.
Changing #Component of ImplOne to #Component("implone") and using #Qualifier("implone").
Code:
#RunWith(SpringJUnit4ClassRunner.class)
public class ImplOneTest {
#Autowired
#Qualifier("implone")
private ImplOne impl;
#Test
public void test(){
Assert.assertNotNull(impl);
}
}
But I don't like the idea of having to name my beans just to be able to inject the concrete implementation.
Is there some way to do this elegantly, or atleast in some manner that only affects my test code? Also is there some special reason why my first example is unsupported?
Check if the exception is about the beans you think it is. Because the names don't match
Even if 1 is fixed, it is preferable to autowire by interface, not by concrete implementation. Most often (I can' know if this is true in your case), concrete implementations are proxied by spring (for transaction support, for example), and can be injected by interface only. And since you have two implementations of one interface, you have to provide a name, and either use #Autowired + #Qualifier, or use #Resource(name="") to inject what you want. And there is nothing wrong with this.
Ok, today i found a way to make this work afterall. Seems like the Spring-AOP-Autoproxy was to blame for this not to work.
Currently I am using AJDT in Eclipse for compile time weaving (CTW) and the TransactionAnnotationAspect. I also removed the aspectjweaver and cglib dependency in my project, so autoproxy is not even supported anymore, after removing the following config part from applicationcontext:
<aop:pointcut id="serviceOperation" expression="execution(* some.package..*(..)) && #target(org.springframework.stereotype.Service)" />
<aop:advisor pointcut-ref="serviceOperation" advice-ref="serviceTxAdvice" />
</aop:config>
<tx:advice id="serviceTxAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*" read-only="true" propagation="SUPPORTS" />
</tx:attributes>
</tx:advice>
And that was also the reason why #Configurable didn't work for me...
Adding the following line worked for me:
<aop:aspectj-autoproxy proxy-target-class="true"/>
Related
I want to test a whole Spring Batch but Ihave a problem. I have a service to delete rows in a DB and in a LDAP.
For the BD I have implemented a H2 in-memory database so no problems.
For the LDAP it's more difficult to have a in-memory LDAP so I want to fake the DAO LDapRepository calling method "delete" (LDapRepository is the interface and LDapRepositoryImpl annotated by #Repository the implementation)
So I tried to inject a mock in my configuration but it doesn't work.
The test fails with a null pointer exception when I try to make the fake call ldapRepository.removePerson (so ldapRepository is not correctly injected).
How is it possible to substitute the bean LDapRepository in my configuration ?
Here's the test code :
#ContextConfiguration(locations = {"classpath:purge/job-test.xml"})
public class PurgeJobTest {
#Autowired
private JobLauncherTestUtils jobLauncherTestUtils;
#InjectMocks
#Qualifier(value = "ldapRepositoryImpl")
private LdapRepository ldapRepository;
#Test
public void testExampleJob() throws Exception {
Mockito.doNothing().when(ldapRepository.removePerson(any(String.class)));
JobParameters jobParameters = new JobParametersBuilder()
.addString("fichierJob", "/purge/job-test.xml")
.addString("nomJob", "purgeJob").toJobParameters();
JobExecution exec =jobLauncherTestUtils.launchJob(jobParameters);
assertEquals(BatchStatus.COMPLETED, exec.getStatus());
}
}
OK so I admit my question was a little tricky but I want to share the answer to other people who faced a similar problem.
The null pointer exception was quite logic. Indeed the bean was not recognized in the context because nowhere it was correctly injected in it.
It's a common pitfall related by example in this post Injecting Mockito Mock objects using Spring JavaConfig and #Autowired.
or this other post : Injecting Mockito mocks into a Spring bean
So in my job-test.xml I commented the component-scan in which my "real" LdapRepository" and LdapRepositoryImpl were declared and replace them with :
<bean id="ldapRepository" class="org.mockito.Mockito" factory-method="mock">
<constructor-arg value="purge.batch.repository.LdapRepository" />
</bean>
<bean id="ldapRepositoryImpl" class="org.mockito.Mockito" factory-method="mock">
<constructor-arg value="purge.batch.repository.LdapRepositoryImpl" />
</bean>
(I could have place these bean declaration before the component-scan to give it priority)
And that works like a charm !
I have a singleton service class like the below.
#Service
public class SingletonClass{
#Autowired
private ContextProvider provider;
public Context run(){
context = provider.createContext();
updateContext(context)
}
ContextProvider class:
public abstract class ContextProvider implements MyInterface{
public abstract Context createContext();
}
configuration:
<bean name="provider"
class="xyz.s.s.ContextProvider" >
<lookup-method name="createContext"
bean="someBean" />
</bean>
<bean id="somebean" class="com.x.y.someclass" />
<bean id="singletonService" class="com.x.y.SingletonClass" />
When i try to run the above using Junit ->instead of creating the lookup bean on demand, I am getting the below error
org.springframework.beans.factory.BeanCreationException:
aused by: java.lang.AbstractMethodError
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeAwareMethods(AbstractAutowireCapableBeanFactory.java:1585)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1553)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:539)
It seems, the lookup method injection is not working in my case
I found the issue and fixed it.
I was having the abstract class implemented an interface. So at run time,
CGLIB unable to create a proxy class since there are unimplemented methods.
Compiler also did not complain, because this is abstract class and it did not expect us to add all implementations of the interface.
I removed the 'implements ' and it just works fine.
So the contextprovider will become,
public abstract class ContextProvider {
public abstract Context createContext();
}
Posting this message, since people might face same situation.
I know there are threads similar to this issue. Below is my class and I am configuring it in spring.xml file. Actually HumanResourceService is an interface having only one method.
#Endpoint
public class HolidayEndpoint {
#Autowired
private HumanResourceService humanResourceService;
#Autowired
public HolidayEndpoint(HumanResourceService humanResourceService) throws JDOMException {
this.humanResourceService = humanResourceService;
}
}
My problem is that in my spring.xml file, when I define HumanResourceService as bean, it cannot be instantiated as this is an interface. How can I mention an interface in spring configuration file. My spring.xml file is below
<bean id="holidayEndpoint" class="com.mycompany.hr.ws.HolidayEndpoint" autowire="constructor" >
<property name="humanResourceService" ref="humanResourceService" />
</bean>
<bean id="humanResourceService" class="com.mycompany.hr.service.HumanResourceService" />
You can't, Spring needs something it can make an instance from, the interface isn't enough.
In your spring.xml, the value of the class attribute for your bean with id="humanResourceService" should be the name of your implementation class, not the interface. Spring needs you to tell it what implementation class you want it to use for this.
I'm trying to use AOP into an existing (big) Spring project. The thing is that I don't want Spring to create proxies for all the objects in the ApplicationContext, mainly for performance but also because there are final classes that I cannot modify.
I've tried to make Spring search only inside "com.foo.bar.*" by defining the following aspect:
com.baz.MyAspect
#Aspect
public class MyAspect {
private static final Logger LOGGER = LoggerFactory.getLogger(MyAspect.class);
#Before("within(com.foo.bar.*) && " +
"execution(* com.foo.bar.MyController.handleRequest(..))")
public void getData() {
// Nothing yet
}
}
And I've added this lines to the configuration:
<?xml version="1.0" encoding="utf-8"?>
<beans ...>
<aop:aspectj-autoproxy proxy-target-class="true" />
<bean id="myAspect" class="com.baz.MyAspect"/>
</beans>
But when I run the app, I get the following Exception:
Initialization of bean failed; nested exception is org.springframework.aop.framework.AopConfigException: Could not generate CGLIB subclass of class [class com.foobar.FinalController]: Common causes of this problem include using a final class or a non-visible class; nested exception is java.lang.IllegalArgumentException: Cannot subclass final class com.foobar.FinalController
So it seems that Spring is scanning packages other than the ones defined in the within expression. I would like to know whether there is a way to specify the packages to be scanned or any other way to solve this problem.
yes you can define your point cut like this
the execution of any method defined in the bar package or a sub-package:
execution(* com.foo.bar...(..)) click here for detail
I use org.springframework.web.jsf.el.SpringBeanFacesELResolver in my JSF + Spring application. Every backing bean needs an interface to be resolved. I guess that it's interface type of dependency injection.
#{bean.text}
public interface IBean {
String getText();
}
#Named
#Scope("session")
public class Bean implements IBean {
public String getText() {
return "Hello World!";
}
}
I would like to get rid of the interface. It's kind of bureaucracy for me. Is it possible?
I finally solved it. The problem was in beans with scope depending on HTTP (request, session). By default interfaces should be manually created. This can be avoided by using proxies.
If using component scan:
<context:component-scan base-package="..." scoped-proxy="targetClass" />
Or in bean definition:
<bean ...>
<aop:scoped-proxy>
</bean>
See chapter 4.5.4.5 Scoped beans as dependencies in Spring documentation. http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/beans.html