Loading an application context by annotating a class - java

I am new at Spring and am wondering if one can load an application just by annotating the class whose variables must be injected (instead of using ApplicationContext ctx = new ApplicationContext("myAppContext")).
Let me give the following example:
I have this class TestSpring.java in which a string should be autowired
package mytest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
//Is it possible to put an annotation here that loads the application context "TestSpringContext.xm"??
public class TestSpring {
#Autowired
#Qualifier("myStringBean")
private String myString;
/**
* Should show the value of the injected string
*/
public void showString() {
System.out.println(myString);
}
}
The spring bean configuration file (TestSpringContext.xml) looks like this
<?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:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd"
>
<context:annotation-config />
<bean id="myStringBean" class="java.lang.String">
<constructor-arg value="I am an injected String."/>
</bean>
</beans>
Now I would like to display the value of the autowired string myString (declared in TestSpring.java) using following code in RunTestSpring.java:
package mytest;
public class RunTestSpring {
public static void main(String[] args) {
TestSpring testInstance = new TestSpring();
testInstance.showString();
}
}
Now my question, is it possible to run "RunTestSpring.java" successfully while loading the application context by just annotating RunTestSpring.java. If yes, with which annotation?

#Configurable is probably what you are looking for, it will ensure that objects which are not instantiated by Spring can have their dependencies autowired by Spring. However the catch is that it requires AspectJ compile time/load time weaving for it to work(not Spring AOP).
Here is one reference:
http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/aop.html#aop-atconfigurable

I would suggest writing a JUnit class that would use spring injection for environment initialization. Something like this -
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations="/spring/spring-wireup.xml", inheritLocations = true)
public class MyTestCase extends TestCase {
// your test methods ...
}

Related

Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'myAppDao':

I have a dao class which has a dependency on another utility class AuditStore.
package myapp;
#Repository
public class MyAppHibernateDao {
#Autowired
public void setAuditStore(AuditStore auditStore) {
ConnectorLoggingHelper.setAuditStore(auditStore);
}
}
The AuditStore.java
package myapp;
#Resource
public class AuditStore {
//too many dependencies in this class including db connection
}
Now I want to write integration test for the dao class which don't cover functionalities of 'AuditStore'.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration("classpath:META-INF/spring-myapp-db-connector-test.xml")
#TestExecutionListeners({DependencyInjectionTestExecutionListener.class, TransactionalTestExecutionListener.class})
public class MyAppHibernateDaoIntegrationTest {
#Test
public void test() {
//test code here
}
}
and my xml config file is
<!--spring-myapp-db-connector-test.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:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<!-- enable autowiring -->
<context:annotation-config/>
<bean id="myAppDao" class="myapp.MyAppHibernateDao">
</beans>
Whe I run this I am getting following errors.
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'myAppDao': Unsatisfied dependency expressed through method 'setAuditStore' parameter 0; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'myapp.AuditStore' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
The AuditStore is a very complex object and I don't use this classes functionality for testing (I need a null or mock of this class). Is there any way I can avoid creating a bean of AuditStore defined in xml and make things work.
I know that making #Autowired(required = false) would work, that would make change in the application code for test, so I am looking for other options.
Please help if there is any alternative.
If possible you should consider moving to annotation driven configuration and use something like #InjectMock. However, assuming you are required to stick with the approach you outlined in your question, you can define a mock instance of MyAppHibernateDao in spring-myapp-db-connector-test.xml in several ways:
Use a factory bean
Use Springockito. And, of course,
Declare the myAppDao bean in spring-myapp-db-connector-test.xml as follows:
<bean id="myAppDao" class="org.mockito.Mockito" factory-method="mock">
<constructor-arg value="myapp.MyAppHibernateDao"/>
</bean>
You can then #Autowire MyAppHibernateDao into MyAppHibernateDaoIntegrationTest and set expectations etc on it in your test/setup methods.

How mock spring component during tests without extracting interface from it?

There is a spring componet with #Component annotation, it is just java class (not interface) with annotated #Autowired fields. I am trying to create mock like that:
<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:tx="http://www.springframework.org/schema/tx"
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.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"
>
<bean id="myComponent" class="org.mockito.Mockito" factory-method="mock">
<constructor-arg value="com.MyComponent"/>
</bean>
</beans>
And got an exception that some of fields are not autowired. This happens, because when Spring see <constructor-arg value="com.MyComponent"/> it try to instantiate MyComponent bean and pass it to factory method.
I have tried to extract interface from component, in that case mocking works, but is there a way to make it working without extracting interface?
Also
I have tried adding type="java.lang.Class" but got same errors.
<bean id="myComponent" class="org.mockito.Mockito" factory-method="mock">
<constructor-arg type="java.lang.Class" value="com.MyComponent"/>
</bean>
Any ideas?
Spring cannot autowire the bean because the type of the created bean is java.lang.Object and not com.myComponent. Apparently the order of the definitions in the XML matters as well.
Jayway has a very nice blog post about this: Spring Integration Tests - Creating Mock Objects
You can create a FactoryBean which returns the correct class:
public class MockitoFactoryBean<T> implements FactoryBean<T> {
private Class<T> classToBeMocked;
/**
* Creates a Mockito mock instance of the provided class.
* #param classToBeMocked The class to be mocked.
*/
public MockitoFactoryBean(Class<T> classToBeMocked) {
this.classToBeMocked = classToBeMocked;
}
#Override
public T getObject() throws Exception {
return Mockito.mock(classToBeMocked);
}
#Override
public Class<?> getObjectType() {
return classToBeMocked;
}
#Override
public boolean isSingleton() {
return true;
}
}
Using this factory bean, you can create a config like this:
<bean id="myComponent" class="com.yourpackage.MockitoFactoryBean">
<constructor-arg name="classToBeMocked" value="com.myComponent" />
</bean>
This will mock your component and the object type will com.myComponent.
Update
This is the original answer and explanation (using EasyMock): Autowiring of beans generated by EasyMock factory-method?

how to know resource from which a bean is loaded in spring project.

I am new to spring framework. I am trying to know the list of xml files that are referenced while loading the beans.
By writing a class that is ApplicationContextAware, i am able to view the list of beans with :
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration("classpath:spring/sample-testcontext.xml")
public class SampleClass implements ApplicationContextAware {
#Autowired
ApplicationContext applicationContext;
#Test
public void testMethod() {
for (String beanName : applicationContext.getBeanDefinitionNames()) {
System.out.println("BeanName " + beanName);
}
}
}
But i want to know from which configuration files the beans are loaded.
Say "sample-testcontext.xml" contains
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util"
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://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd">
<beans:import resource="classpath*:spring/sample-testOneMorecontext.xml"/>
</beans:beans>
I want to know list of file names from which beans are loaded as "sample-testOneMorecontext.xml" and "sample-testcontext.xml".
Why would you want to do that exactly? I am not sure that the internal implementation keeps a record of that information once the context has loaded. However, there is a way to know from which resource a particular bean has been loaded. That can be useful if you have several bean definitions with the same name and you want to know which one has "won".
Taking back your example (btw, you don't need to implement ApplicationContextAware since you are autowiring it)
#ContextConfiguration
#ContextConfiguration("classpath:spring/sample-testcontext.xml")
public class SampleTest {
#Autowired
private ConfigurableApplicationContext context;
#Test
public void foo() {
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
for (String beanName : context.getBeanDefinitionNames()) {
System.out.println(beanName + " --> "+ beanFactory.getBeanDefinition(beanName).getResourceDescription());
}
}
}
This gives you something like (excluding the internal post processor bean definitions that the default implementation may register automatically)
beanFirst --> class org.SampleTest$Config
beanSecond --> class path resource [foobar.xml]
Where beanFirst was loaded from an inner class of the test (called Config) and beanSecond was loaded from a file called foobar.xml at the root of the classpath.

#Value annotation doesn't return a value

I have a class FichierCommunRetriever that use the #Value annotation of Spring. But I am struggling to make it work.
So in my application.properties I have :
application.donneeCommuneDossier=C\:\\test
application.destinationDonneeCommuneDossier=C\:\\dev\\repertoireDonneeCommune\\Cobol
My class FichierCommunRetriever is using those entries with the following code :
public class FichierCommunRetriever implements Runnable {
#Value("${application.donneeCommuneDossier}")
private String fichierCommunDossierPath;
#Value("${application.destinationDonneeCommuneDossier}")
private String destinationFichierCommunDossierPath;
}
We are loading application.properties with the following code in the class ApplicationConfig:
#ImportResource("classpath:/com/folder/folder/folder/folder/folder/applicationContext.xml")
In ApplicationConfig, I am defining a bean that use FichierCommunRetriever in a new thread like that :
Thread threadToExecuteTask = new Thread(new FichierCommunRetriever());
threadToExecuteTask.start();
I suppose that my problem is, since FichierCommunRetriever is running in a separate thread, the class can't reach the applicationContext and is not able to give a value.
I'm wondering if the annotation would work or I must change the way I'm getting those values?
In your applicationConfig you should define your bean this way:
#Configuration
public class AppConfig {
#Bean
public FichierCommunRetriever fichierCommunRetriever() {
return new FichierCommunRetriever();
}
}
Then, after Spring loads, you can access you bean via the application context
FichierCommunRetriever f = applicationContext.getBean(FichierCommunRetriever.class);
Thread threadToExecuteTask = new Thread(f);
threadToExecuteTask.start();
Now you are sure that your bean lives inside Spring context and that it is initialized.
In addition, in your Spring XML, you have to load the properties (this example uses the context namespace):
<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"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
...
<context:property-placeholder location="classpath:application.properties" />
...
</beans>
You create an instance of FichierCommunRetriever using new, instead of asking Spring to return a bean instance. So Spring isn't controlling the creation and injection of this instance.
You should have the following method in your config class, and call it to get the bean instance:
#Bean
public FichierCommunRetriever fichierCommunRetriever() {
return new FichierCommunRetriever();
}
...
Thread threadToExecuteTask = new Thread(fichierCommunRetriever());

spring injection works within user created instance?

I'm working with Spring, and I'm getting the injected instance as null when I create the instance with new operator, I can elobrate the scenario.
For example,
Let the class A and class B are injected into the class Main
class Main
{
#autowired
A a;
#autowired
B b;
//getter and setter
}
class MainExecute
{
public static void main()
{
// loading the spring config xml
Main main = new Main();
A a=main.getA();
// whether a will get the instance ( I'm getting a as null)
}
what could be the reason for this scenario
Please guide me on the same
Thanks in advance.
No, it won't get dependency injection.
Only objects created/managed by the spring container will get the facilities offered by spring dependency injection.
To elaborate on the above answers:
You need to let the spring IOC container create your objects for you, you don't explicitly create them. You can do this by creating a spring config xml file, here is a quick example:
META-INF\spring\my-spring-config.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"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
<bean id="myMainClass" class="org.foo.Main" />
<bean id="myA" class="org.foo.A" />
<bean id="myB" class="org.foo.B" />
</beans>
org.foo.MainExecute:
class MainExecute
{
public static void main()
{
ClassPathXmlApplicationContext appContext = new ClassPathXmlApplicationContext("META-INF\\spring\\my-spring-config.xml");
Main main = (Main) appContext.getBean("myMainClass");
}
}
In this example the Spring IOC container will instantiate an "A" bean and a "B" bean. It will then autowire these into the "Main" bean.

Categories