#Component
public class AnnotationTest extends TestCase{
ServiceTest serviceTest;
#Autowired(required=false)
public void setServiceTest(ServiceTest serviceTest) {
this.serviceTest = serviceTest;
}
public void testAnnotation () {
new ClassPathXmlApplicationContext(new String[]{"/com/test/spring/ioc/beans.xml"});
serviceTest.annotationTest("testName", "testPassword");
}
error:
Exception in thread "main" java.lang.NullPointerException
at com.test.spring.ioc.AnnotationTest.invokeIoC(AnnotationTest.java:16)
at com.test.spring.ioc.AnnotationTest.main(AnnotationTest.java:13)
service class:
#Service
public class ServiceTestImpl implements ServiceTest{
#Autowired
AnnotationDAO annotationDAO;
public List<String> annotationTest(String name, String pssword) {
return annotationDAO.annotationTest(name, pssword);
}
}
DAO class:
#Repository("AnnotationDAO")
public class AnnotationDAOImpl implements AnnotationDAO{
public List<String> annotationTest(String name, String pssword) {
List<String> list = new ArrayList<String>();
list.add("Test 1");
list.add("Test 2");
return list;
}
}
beans.xml:
<bean id="service" class="com.test.spring.ioc.service.ServiceTestImpl"/>
<context:annotation-config />
<context:component-scan base-package="com.test.spring" />
how can I solve this?
EDIT:
it was giving warning msg:
WARNING: Autowired annotation is not supported on static methods: public static void
com.test.spring.ioc.AnnotationTest.setServiceTest(com.test.spring.ioc.service.ServiceTest)
i moved to junit test instead of java main method as shown above by adding #Component( i am not sure this is required).
Now i am getting new error as:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name
'annotationTest': Injection of autowired dependencies failed; nested exception is
org.springframework.beans.factory.BeanCreationException: Could not autowire field:
com.test.spring.ioc.service.ServiceTest com.test.spring.ioc.AnnotationTest.serviceTest;
nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No
unique bean of type [com.test.spring.ioc.service.ServiceTest] is defined: expected single
matching bean but found 2: [service, serviceTestImpl] at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProce ssPropertyValues(AutowiredAnnotationBeanPostProcessor.java:287)
The problem is, you are defining the same bean twice:
Once explicitly:
<bean id="service" class="com.test.spring.ioc.service.ServiceTestImpl"/>
And once through Component Scanning:
<context:component-scan base-package="com.test.spring" />
Get rid of one of them and it will work.
BTW: you don't need to instantiate the container yourself when testing, just use the Spring TestContext Framework:
#RunWith(SpringJUnit4ClassRunner.class)
// ApplicationContext will be loaded from "/applicationContext.xml"
// and "/applicationContext-test.xml"
// in the root of the classpath
#ContextConfiguration({"/applicationContext.xml",
"/applicationContext-test.xml"})
public class MyTest {
// class body...
}
And of course, with JUnit 4.x you should no longer extend from TestCase, but use annotated methods instead:
#Test
public void testAnnotation () {
serviceTest.annotationTest("testName", "testPassword");
}
The AnnotationTest class is not instantiated by spring, so Spring never has a chance to inject the serviceTest dependency:
You can either explicitly get you bean:
public static void main(String[] args) {
ApplicationContext ctx =
new ClassPathXmlApplicationContext(
new String[]{"/com/test/spring/ioc/beans.xml"});
serviceTest = ctx.getBean(ServiceTest.class);
invokeIoC();
}
or you could tell annotate your AnnotationTest class with #Component so that an instance will be created by the component-scan. Note, though I think that would be a bit of a hack as you'll be instantiating an AnnotationTest object and never use it, so I'd do away with the autowiring in the main and use getBean...
EDIT:
In order to do the autowiring of a static field, you'd also have to fool spring into thinking that serviceTest is not actually static (again, I don't think that's a good idea):
#Component
public class AnnotationTest {
static ServiceTest serviceTest;
...
#Autowired
public void setServiceTest(ServiceTest serviceTest) {
AnnotationTest.serviceTest = serviceTest;
}
}
Related
I have following project structure:
-module1
--src/main/java/at.flobau.demo.module1
---model
----Product.java
---service
----ProductService.java
---TestConfiguration.java
--src/test/java/at.flobau.demo.module1.service
---ProductServiceTest.java
-module2
--src/main/java/at.flobau.demo.main
---MainApplication.java
The Application class looks like this:
#SpringBootApplication(scanBasePackages = {"at.flobau.demo.main"})
#PropertySource(value = "classpath:application.properties")
#EnableJpaRepositories("at.flobau.demo.module1")
#EntityScan(basePackages = {"at.flobau.demo.module1"})
public class PocApplication {
public static void main(String[] args) {
SpringApplication.run(PocApplication.class, args);
}
}
The Service looks like this:
#Service
public class ProductService implements IProductService {
#Autowired
private IProductRepository productRepository;
...
}
The test Class looks like this:
#SpringBootTest
#ContextConfiguration(classes = { TestConfiguration.class }, loader =
AnnotationConfigContextLoader.class)
#RunWith(SpringRunner.class)
public class ProductServiceTest {
#Autowired
private ProductService productService;
...
}
The test configuration file looks like this:
#Configuration
#ComponentScan("at.flobau.demo")
public class TestConfiguration{ }
IntelliJ tells me, that the ProductService inside the test cannot be autowired. When i do run the test i get an exepction:
Error creating bean with name 'ProductServiceTest': Unsatisfied dependency expressed through field
'productService'; nested exception is
org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type
'at.flobau.demo.module1.products.service.ProductService' available: expected at least 1 bean which
qualifies as autowire candidate. Dependency annotations:
{#org.springframework.beans.factory.annotation.Autowired(required=true)}
You should avoid using field injection (even though is possible) and use constructor injection. This will solve this problem as you will be able to pass the service from the constructor but it will also be useful in the future as you can locate usages and trace objects in your code way better than field injections which are "hidden"
So I recommend instead of trying to solve your problem here to refactor your class in constructor injection and pass the service from there either by directly creating the object in your test or by creating a configuration for your test that will generate the object and give the arguments it requires
something like
#ContextConfiguration(classes = { GeneralTester.TestConfig.class })
#RunWith(SpringRunner.class)
public class GeneralTester {
#TestConfiguration
public static class TestConfig {
#Bean
public IProductService productService(final IProductRepository productRepository){
return new ProductService(productRepository);
}
#Bean
public IProductRepository productRepository(){
return mock(IProductRepository.class);
}
}
#Autowire
public IProductService productService;
#Autowire
public IProductRepository productRepository;
#Before
public void setUp() {
reset(productRepository);
}
#After
public void tearDown() {
verifyNoMoreInteractions(productRepository);
}
#Test
public void doSmth() {
//... your setup
when(productRepository.save(any())).thenReturn("something");
//... your call and assertions
verify(productRepository).save(any());
}
}
You can annotate your test class with #SpringBootTest(classes = ProductService.class)
Have you tried creating a bean of the service in the test configuration class?
#TestConfiguration
#ComponentScan("at.flobau.demo")
public class TestConfiguration {
#Bean
public ProductService productService() {
return new ProductService();
}
}
I have three classes 1)an Interface 2) A class which implements the interface 3) a static factory which return an instance second class as an instance Interface Class
public Interface MyInterface {
}
public class Myclass implements MyInterface {
}
public Class MyStaticFactory {
public static MyInterface getInstance() {
MyInterface myClassInstance = new Myclass();
return myClassInstance;
}
}
I want to create a bean of MyClass as an instance MyInterface. Mycode for that is
<bean id="staticFactory" class="MyStaticFactory">
</bean>
<bean id="myclass" class="MyInterface" factory-bean="staticFactory" factory-method="getInstance">
</bean>
But with the above code I am getting an exception
org.springframework.beans.factory.BeanCreationException: Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private MyInterface ; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [MyInterface] 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)}
at com.amazon.coral.reflect.instantiate.SpringInstantiatorFactory$1.newInstance(SpringInstantiatorFactory.java:175)
I am trying to access bean using the following code
#Autowired
private MyInterface MyclassInstance
Is It a valid thing to create a bean as as instance of InterfaceClass ? How can we load an instance of MyClass in a class variable of MyInterface using spring ?
You dont need to autowire any field as you have your own factory that will instantiate bean for you. Also you dont need to instantiate your factory class with static method in it. Instead you just can stay with:
<bean id="staticFactory" class="MyStaticFactory" factory-method="getInstance" />
Now let's say you have multiple implementation of MyInterface, you could do so by passing a parameter like:
<bean id="staticFactory" class="MyStaticFactory" factory-method="getInstance" scope="prototype">
<constructor-arg value="MyClass" />
</bean>
And in your factory class you could either use switch (from JDK 7) or if else ladder to check what's requested in parameter to method getInstance method and instantiate proper bean.
You could then do the following:
public static void main(String args[]) {
Application context = new ......
MyInterface myIface = context.getBean("staticFactory", MyInterface.class);
//myIface.mymethod();
}
My view on this is depending on the context, whether using XML based bean creation or using Java based "config"bean creation, the logic is pretty much the same.
You need to have a Class annotated with #Configuration if using Java configuration for you to create your beans, secondly, the Configuration class needs to be registered as a bean creator, i.e. the application context needs to be able to create and initialize the beans depending on their type (either Singleton or Prototype).
My configuration would look like this:
public Interface MyInterface {
void executeSomeMethod();
}
public class Myclass implements MyInterface {
#override
void executeSomeMethod(){
//some code executed here
}
}
The Configuration class would look something like this:
#Configuration
public MyConfigurationClass {
#Bean(name="someBeanName")
public MyInterface createBean() {
MyInterface bean = new Myclass();
return bean;
}
}
Assuming the MyConfigurationClass is registered in the application context, then using the bean would look something like:
#Component
public class SomeClassUsingTheBean {
#Autowired
MyInterface someBeanName;
public SomType method() {
someBeanName.executeSomeMethod();
}
}
Here are the files that I use:
component.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:jee="http://www.springframework.org/schema/jee"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd">
<context:component-scan
base-package="controllers,services,dao,org.springframework.jndi" />
</beans>
ServiceImpl.java
#org.springframework.stereotype.Service
public class ServiceImpl implements MyService {
#Autowired
private MyDAO myDAO;
public void getData() {...}
}
ServiceImplTest.java
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration("classpath*:conf/components.xml")
public class ServiceImplTest{
#Test
public void testMyFunction() {...}
}
Error:
16:22:48.753 [main] ERROR o.s.test.context.TestContextManager - Caught exception while allowing TestExecutionListener [org.springframework.test.context.support.DependencyInjectionTestExecutionListener#2092dcdb] to prepare test instance [services.ServiceImplTest#9e1be92]
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'services.ServiceImplTest': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private services.ServiceImpl services.ServiceImplTest.publishedServiceImpl; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [services.ServiceImpl] 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)}
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:287) ~[spring-beans.jar:3.1.2.RELEASE]
Make sure you have imported the correct package. If I remeber correctly there are two different packages for Autowiring. Should be :org.springframework.beans.factory.annotation.Autowired;
Also this looks wierd to me :
#ContextConfiguration("classpath*:conf/components.xml")
Here is an example that works fine for me :
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "/applicationContext_mock.xml" })
public class OwnerIntegrationTest {
#Autowired
OwnerService ownerService;
#Before
public void setup() {
ownerService.cleanList();
}
#Test
public void testOwners() {
Owner owner = new Owner("Bengt", "Karlsson", "Ankavägen 3");
owner = ownerService.createOwner(owner);
assertEquals("Check firstName : ", "Bengt", owner.getFirstName());
assertTrue("Check that Id exist: ", owner.getId() > 0);
owner.setLastName("Larsson");
ownerService.updateOwner(owner);
owner = ownerService.getOwner(owner.getId());
assertEquals("Name is changed", "Larsson", owner.getLastName());
}
I've done it with two annotations for test class: #RunWith(SpringRunner.class) and #SpringBootTest.
Example:
#RunWith(SpringRunner.class )
#SpringBootTest
public class ProtocolTransactionServiceTest {
#Autowired
private ProtocolTransactionService protocolTransactionService;
}
#SpringBootTest loads the whole context, which was OK in my case.
A JUnit4 test with Autowired and bean mocking (Mockito):
// JUnit starts with spring context
#RunWith(SpringRunner.class)
// spring loads context configuration from AppConfig class
#ContextConfiguration(classes = AppConfig.class)
// overriding some properties with test values if you need
#TestPropertySource(properties = {
"spring.someConfigValue=your-test-value",
})
public class PersonServiceTest {
#MockBean
private PersonRepository repository;
#Autowired
private PersonService personService; // uses PersonRepository
#Test
public void testSomething() {
// using Mockito
when(repository.findByName(any())).thenReturn(Collection.emptyList());
Person person = new Person();
person.setName(null);
// when
boolean found = personService.checkSomething(person);
// then
assertTrue(found, "Something is wrong");
}
}
For Spring 5.x and JUnit 5, writing unit tests is quite different.
We have to use #ExtendWith to register Spring extensions (SpringExtension). This brings Spring into play which activates part of the application context (instantiates and manages beans from selected configuration classes).
Note that this is different from the effect of #SpringBootTest which loads the full application context (and IMHO cannot be considered a unit test).
For example, let's create a configuration class FooConfig which produces a bean named foo1:
#Configuration
public class FooConfig
{
#Bean
public String foo1() { return "Foo1"; }
}
Now, let's write a JUnit 5 test case which injects foo1:
import static org.junit.jupiter.api.Assertions.*;
// ... more imports ...
#ExtendWith(SpringExtension.class)
#ContextConfiguration(classes = {
helloworld.config.FooConfig.class,
})
class FooTests
{
#BeforeAll
static void setUpBeforeClass() throws Exception {}
#AfterAll
static void tearDownAfterClass() throws Exception {}
#BeforeEach
void setUp() throws Exception {}
#AfterEach
void tearDown() throws Exception {}
#Autowired
private String foo1;
#Test
void test()
{
assertNotNull(foo1);
System.err.println(foo1);
}
}
In Spring 2.1.5 at least, the XML file can be conveniently replaced by annotations.
Piggy backing on #Sembrano's answer, I have this. "Look ma, no XML".
It appears I to had list all the classes I need #Autowired in the #ComponentScan
#RunWith(SpringJUnit4ClassRunner.class)
#ComponentScan(
basePackageClasses = {
OwnerService.class
})
#EnableAutoConfiguration
public class OwnerIntegrationTest {
#Autowired
OwnerService ownerService;
#Test
public void testOwnerService() {
Assert.assertNotNull(ownerService);
}
}
I think somewhere in your codebase are you #Autowiring the concrete class ServiceImpl where you should be autowiring it's interface (presumably MyService).
You should make another XML-spring configuration file in your test resource folder or just copy the old one, it looks fine, but if you're trying to start a web context for testing a micro service, just put the following code as your master test class and inherits from that:
#WebAppConfiguration
#RunWith(SpringRunner.class)
#ContextConfiguration(locations = "classpath*:spring-test-config.xml")
public abstract class AbstractRestTest {
#Autowired
private WebApplicationContext wac;
}
You can use #Import annotation. It's more readable and shorter than using the #ComponentScan annotation.
import org.springframework.context.annotation.Import;
#Import(value = {MyService.class, MyInjectedService.class})
public class JUnitTest {
#Autowired
private MyService service;
// ...
}
I have a Spring test :
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration("classpath:my-context.xml")
public class MyTest {
#Test
public void testname() throws Exception {
System.out.println(myController.toString());
}
#Autowired
private MyController myController;
}
This works fine when myController is defined in same class as MyTest but if I move MyController to another class it is not autowired, as running below returns null, so myController does not seem to be autowired correctly :
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration("classpath:my-context.xml")
public class MyTest {
#Test
public void testname() throws Exception {
System.out.println(new TestClass().toString());
}
}
#Controller
public class TestClass {
#Autowired
private MyController myController;
public String toString(){
return myController.toString();
}
}
Does autowiring only occur at within the class the test is being run from ? How can I enable autowiring on all classes that are instantiated by the test class ?
Update :
Thanks to the answers from smajlo & Philipp Sander I was able to fix this using this code to access this bean instead of creating the bean explicitly. This is already configured by Spring so I access it from the context :
ApplicationContext ctx = new ClassPathXmlApplicationContext("my-context.xml");
TestClass myBean = (TestClass) ctx.getBean("testClass");
When the bean is created explicitly it is not autowired by Spring.
new TestClass().toString()
If you creating object by manually invoking constructor obejct is not controlled by Spring so field won't be autowired.
EDIT:
maybe you want to create specific test-context and load both on test classes.. because for now i guess your way to do the testing is a little wrong.
Why do you need from test class access to another test class? This is not unit test anymore:)
Your TestClass will be never autowired no matter what annotation you will add, because you creating new instance..
try this:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration("classpath:my-context.xml")
public class MyTest {
#Autowired
private TestClass testClass;
#Test
public void testname() throws Exception {
System.out.println(testClass.toString());
}
}
#Controller
public class TestClass {
#Autowired
private MyController myController;
public String toString(){
return myController.toString();
}
}
As Sotirios Delimanolis already said:
MyTestClass needs to be managed by Spring to get autowired. to do this, simply at #Component to MyTestClass and autowire it
I have the following main class:
public class Startup implements UncaughtExceptionHandler {
#Autowired
private MessageListener messageListener;
private static Startup startup;
public static void main(String[] args) {
Startup start = new Startup();
start.init(args);
}
public void init(String[] args) {
context = new ClassPathXmlApplicationContext("applicationContext.xml");
startup = (Startup) context.getBean( "startup" );
startup.start(); //here the messageListener is used
}
// here goes the main class that calls the method where messageListener is used
}
#Component
public class ProdMessageListener
extends AbstractMessageListener implements MessageListener {...}
and
public abstract class AbstractMessageListener
implements MessageListener {...}
as well as
#Component
public interface MessageListener extends QueueAware {...}
#Component
public interface QueueAware {...}
My Spring context uses to locate all the classes and interfaces.
However the bean is not recognized and I get:
No qualifying bean of type
[com.ware.messaging.listener.MessageListener] found for
dependency.
Any ideas why autowiring does not work?
Just make sure you have added your base package to the spring context configuration like below to allow spring to load all the components into the container
<context:component-scan base-package="pakage1.package2"/>
Do you know what the problem was? Spring does not seem to autowire static fields. Now everything works.