#Value annotation doesn't return a value - java

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());

Related

Spring #ConfigurationProperties resolver ignores externalized properties

I use #ImportResource({"classpath:property-sources.xml"}) annotation to externalize path to some configuration files.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xmlns:util="http://www.springframework.org/schema/util"
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/util
http://www.springframework.org/schema/util/spring-util.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<util:properties id="externalProperties"
ignore-resource-not-found="true"
location="file:${dir.data}/foo.properties"
/>
<context:property-placeholder ignore-unresolvable="true" properties-ref="externalProperties"/>
</beans>
So, in application I can inject any property from foo.properties using #Value. Pretty common, yes.
However, when I'm trying to use #ConfigurationProperties to do do the same thing, Spring Boot completely ignores any property winthin that file. At first I've thought that something wrong with configuration, but if I put exactly the same property into application.yml it works. Compare:
foo.properties (ignored by #ConfigurationProperties resolver)
descriptions.foo.bar.baz = test
application.yml (successfully processed by #ConfigurationProperties resolver)
descriptions:
foo:
bar:
baz: test
There should be no difference. Also, there is nothing special in the bean itself:
#ConfigurationProperties(prefix = "descriptions", ignoreUnknownFields = false)
public class Descriptions {
private Map<String, String> foo = new HashMap<>();
public Map<String, String> getFoo() {
return foo;
}
public void setFoo(Map<String, String> foo) {
this.foo = foo;
}
}
Why #Value does always work and #ConfigurationProperties only works for application.yml ?
In your XML file you are loading a properties file into a Properties object, which then is passed to an additionally configured PropertySourcePlaceholderConfigurer. That is what all that namespace magic does.
The PropertySourcePlaceholderConfigurer will use the properties to resolve value expressions in #Value or xml. It will NOT add the loaded properties to the Environment. The Environment is what is being used by the ConfigurationPropertiesBindingPostProcessor in Spring Boot. This also runs very early in the process.
Instead what you should do is either put an #PropertySource on your #SpringBootApplication annotation class:
#PropertySource(value="file:${dir.data}/foo.properties", ignoreResourceNotFound=true)
Or specify which additional configuration files to load using the spring.config.additional-location property.
--spring.config.additional-location=file:${dir.data}/foo.properties
With the latter you don't need to change anything, just specify which files to load at startup.
public class someclassname{
#Value("${file.name}")
private String fileName;
FileInputStream fip = new FileInputStream(fileName);
Properties properties = new Properties();
properties.load(fip);
//read your file contents
}
The value of the file.name can be set in a properties file:
file.name=yourpath
PropertySource annotation can be used to achieve the same.
#Component
#PropertySource("classpath:foo.properties")
public class TestProperties {
#Value("${descriptions.foo.bar.baz}")
private String descriptions;
//getters and setters
}
ConfigurationProperties equivalent
import org.springframework.boot.context.properties.ConfigurationProperties;
#Configuration
#PropertySource("classpath:foo.properties")
#ConfigurationProperties
public class TestProperties {
private String descriptions;
//getters and setters
}
File foo.properties gives a Properties object which holds string=>string mapping "descriptions.foo.bar.baz" => "test". The string "descriptions.foo.bar.baz" in general can not be converted to structure like nested Map<String,Object>s.
On the other side, application.yml gives exactly the same structure as the application expects, nested Map<String,Object>s. So it works because of this, and because of type-erasure: at runtime jvm only knows that void setFoo(Map foo) expects a Map. So the application is going to throw a ClassCastException as soon as foo.get("bar") is used as String, because actual value would be a Map.

Spring: Is it possible to specify the default-lazy-init value when you're new-ing the application context?

I'm creating my Spring application context from an XML file like so:
this.applicationContext = new ClassPathXmlApplicationContext("classpath*:/spring-configuration/application-context.xml");
I know there's an option to specify the default-lazy-init in the XML file itself, like in this example:
<?xml version="1.0" encoding="UTF-8"?>
<beans
...
default-lazy-init="true">
...
</beans>
However, I want to decide whether or not to use default lazy init based on the context when this code is invoked... is there a way to do this? I basically want an extra configuration boolean I could pass to the ClassPathXmlApplicationContext constructor which would tell it whether to use default lazy init or not.
Read Spring Docs On Lazy-initialized Beans :
ApplicationContext eagerly create singleton bean during startup. This
type of instantation is good because errors in the configuration are
found at the beginning. But if you
don't want the pre-instantiation of a singleton bean at the beginning, then you can mark that
bean definition as being lazy-initialized.
Note : A lazy-initialized singleton bean is instantiated only when it is requested.
You can achieve lazy initialization of bean in two ways :
-> At <bean> level :
<bean id="demoBean" class="com.example.DemoBean" lazy-init="true"/>
-> At container level (where no beans will be pre-instantiated) :
<beans default-lazy-init="true">
...
</beans>
So, select the desired once according to your need.
Example to understand :
DemoBean.java :
package com.example;
public class DemoBean {
public DemoBean(){
System.out.println("DemoBean is initialized on the request.");
}
}
Main.java :
public class Main {
public static void main(String[] args) {
ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("application-context.xml");
context.getBean("demoBean");
}
}
Output:
DemoBean is initialized on the request.

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.

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.

Loading an application context by annotating a class

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 ...
}

Categories