Spring - #Value returns null - java

I have a properties file under /src/main/resources/ and I want to load data from it using Spring.
In my Spring-context.xml I have this :
<context:property-placeholder location="classpath:UserUtil.properties" />
and also have <context:component-scan base-package="com.myApp" />
and in my class I load it like :
#Value("${injectMeThis}")
private String injectMeThis;
but the value is always null
EDIT:
to check if the value, I use this :
System.out.println(new myClass().getInjectMeThis());

System.out.println(new myClass().getInjectMeThis());
Spring will only parse #Value annotations on beans it knows. The code you use creates an instance of the class outside the scope of Spring and as such Spring will do nothing with it.
Assuming you have setup your application context correctly a #Value cannot be null as that will stop the correct startup of your application.
Your XML file contains a <context:component-scan /> assuming myClass is part of that package the easiest solution is to add #Component to myClass and then retrieve the instance from the context instead of creating a new instance.

In your class, add class level annotation #PropertySource("UserUtil.properties"). This should solve the problem.

Related

How Spring loads properties file in memory?

Am really new to spring, so please don't get angry and bear with me for a while.
I'm trying to understand how application.properties or any other external config file values gets associated with the places where config file's keys (value="${log4j.configuration}") are mentioned to consume their values from file itself.
For example below is spring bean xml file:
<bean id = "propertiesToBeTaken"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath*:application.properties</value>
<value>classpath*:*keys.properties</value>
</list>
</property>
</bean>
<bean id="log4jLoader" class="my.loader.Log4jLoader">
<property name="log4jCongif" value="${log4j.configuration}" />
</bean>
As you can see, propertiesToBeTaken is an instance of class org.springframework.beans.factory.config.PropertyPlaceholderConfigurer.
And in second case ,log4jLoader is an instance of class my.loader.Log4jLoader, where log4j.configuration key's value is assigned to Log4jLoader class's instance variable log4jCongif.
My questions are below:
There is no locations variable in class PropertyPlaceholderConfigurer, then what is locations here and from where it came ? How can I relate locations to class's instance propertiesToBeTaken?
If lets say, application.properties key value pairs gets loaded into memory, then who or I mean which method loads that ? And even if it gets loaded then how those key value pairs of application.properties file are accessible to Log4jLoader's instance variables...?
Last but I think it could very stupid question, In class log4jLoader class, there is a setLog4jConfig(String log4jpropertiesLocation), but I really cant see who is calling this method. Just correct me here, Its not true, that In spring what ever the beans of object we have created, calls automatically class's instance methods. RIGHT ? I need to search more in code. CORRECT ?
Please put some light on my doubts here. Read about this alot on spring docs and online as well, but could not understand. Really want to understand how it's happening.
Thanks
Answers to your questions:
locations in bean config XML is referring to the setLocations method of PropertiesLoaderSupport class which Set locations of properties files to be loaded. PropertiesLoaderSupport is parent class of PropertyPlaceholderConfigurer in multi-level inheritance. See Official Document
When PropertyPlaceholderConfigurer gets instantiated by Spring IoC, these properties are set in the bean, now any other bean in the config XML asks for property values using ${key.name}, spring injects the value from the bean having value for this key. In your case Log4jLoader requires ${log4j.configuration} so it's value will be injected by PropertyPlaceholderConfigurer or it's any parent class.
setLog4jConfig spring calls this method when it has to give value to one of the property of the class Log4jLoader. In your case because of <property name="log4jCongif" value="${log4j.configuration}" /> configuration spring will call setter method of the property log4jCongif to inject the value. Yes spring can call instance methods (specially setter) as per the configuration.

Injecting property files overriding the one defined in the application

I need some help on injecting property value to a bean which is defined outside the web application.
The web application has a property file under src/main/resource.The spring application context xml has the property place holder defined as
<context:property-placeholder
location="classpath:test.properties,file:/etc/test1.properties"
ignore-resource-not-found="true"
/>
where test1.properties is another file which resides outside the application.The bean is injected with the property which is defined in the application (test.properties) ,but I want to inject the property that is defined in test1.properties (ideally the idea is to override the property values from application and read the one defined outside the application).
Thanks.
Hi use like below in applicationContext.xml
<util:properties id="property" location="classpath:test.properties"/>
In Java,
#Autowired
protected Properties property;
I guess this is what you are looking for
<context:property-placeholder location="file:c:/kp/sec.properties" order="1" ignore-resource-not-found="true" ignore-unresolvable="true" />
<context:property-placeholder location="classpath:kp-props.properties" order="2" />
If the file sec.properties exists take the value from sec.properties, if file or properties does not exist take the property from kp-props.properties file from resources directory(if the property is not found in either of place application will fail)
And say you have property my.prop and you can inject the property as follows.
#Component
public class KPProps {
#Value("${my.prop}")
private int props;
public void print(){
System.out.println(props);
}
}

ways to inject a object of a class in spring controller?

I need to inject a object of a java class in spring controller through applicaionContext.xml. My controller will be ,
#Controller
public class SpringController{
private MyClass obj;
}
I know I can do it with #Autowired annotation.
Is this really good to create a object for a controller through applicaionContext.xml ? Also can I inject a object of a class in controller using the <property> tag inside a <bean> tag ?
Is this really possible ? or please forgive me if it is a stupid question.
I need to know the possible ways for how to inject a object of a class in Spring controller ?
You can of course use #Autowired annotation to autowire the relationships, which can reduce the need to define the properties and constructor arguments for the controller in your applicationContext.xml file. And also to add a dependency to a class, you don't need to modify the configuration files.
But it has some disadvantages too, like if you use #Autowired, there will not be any explicit documentation for the wiring details between Spring managed beans. And to know the relationships between the beans, you have to go through your managed beans. But, if you use configuration files to define the relationships, the relationship details can be found in one place.
You can inject an object of a class into your controller through your applicaionContext.xml as below:
Constructor based injection:
#Controller
public class SpringController{
private MyClass obj;
public SpringController(MyClass obj){
this.obj=obj;
}
}
<bean id="myClassImpl" class="x.y.z.MyClassImpl"></bean>
<bean id="springController" class="x.y.z.web.controllers.SpringController">
<constructor-arg ref="myClassImpl"></constructor-arg>
</bean>
Setter based injection:
#Controller
public class SpringController{
private MyClass obj;
public void setObj(MyClass obj){
this.obj=obj;
}
public MyClass getObj(){
return obj;
}
}
<bean id="myClassImpl" class="x.y.z.MyClassImpl"></bean>
<bean id="springController" class="x.y.z.web.controllers.SpringController">
<property name="obj" ref="myClassImpl"></property>
</bean>
If you want to inject an object in a controller and you particularly want to you use xml,then instead of component scanning of Controller you should create a bean of the controller class of singleton scope in the application context.
Your controller class need not be annotated with #Controller.
you then have to you extend some Controller also like AbstractCommandController, AbstractController, AbstractFormController, AbstractWizardFormController, BaseCommandController, CancellableFormController, MultiActionController SimpleFormController, UrlFilenameViewController
Now to inject a particular object you can use Either Constructor and Setter based injection.
or you can use Autowring by name or type to auto inject the object.
Make sure that you have also declared the bean of that object also in Application Context.
After a DispatcherServlet has received a request and has done its work to resolve locales, themes and suchlike, it then tries to resolve a Controller, using a HandlerMapping. When a Controller has been found to handle the request, the handleRequest method of the located Controller will be invoked; the located Controller is then responsible for handling the actual request and - if applicable - returning an appropriate ModelAndView.
Thats it.
Actually, injection with xml and annotation is same behind the scene. Xml is old fashion while annotations are newer.
Basically, there are 2 types of injection types.
byName
Autowiring by property name. Spring container looks at the properties
of the beans on which autowire attribute is set to byName in the XML
configuration file. It then tries to match and wire its properties
with the beans defined by the same names in the configuration file.
You can give explicit names to beans both with xml and annotation.
#Service("BeanName")
#Component("BeanName")
#Controller("BeanName")
<bean name="BeanName" class="someclass"></bean>
and inject beans by using #Qualifier annotation.
#Autowired
#Qualifier("BeanName")
and with xml
<bean id="MyBean2" class="MyBean2 class">
<property name="Property of MyBean2 which refers to injecting bean" ref="BeanName" />
</bean>
byType
Autowiring by property datatype. Spring container looks at the
properties of the beans on which autowire attribute is set to byType
in the XML configuration file. It then tries to match and wire a
property if its type matches with exactly one of the beans name in
configuration file. If more than one such beans exists, a fatal
exception is thrown.
Default auto wiring mode is byType, so spring will look for matching type in auto wiring. However, older versions of Spring has default behavior none on injection. If you want to inject byType using xml, you should tell spring contaioner explicitly.
For example MyBean2 has a reference to MyBean, by setting autowired attribute to byType it handles injection automatically.
<bean id="MyBean" class="MyBean class">
<property name="Property of MyBean2 which refers to injecting bean" ref="BeanName" />
</bean>
<bean id="MyBean2" class="MyBean2 class"
autowire="byType">
</bean>
It also depends on where the injection take place in your code. There are 2 types, setter getter injection and constructor injection.
Note : There is no difference in #Controller since they are already in spring context.
See also
Spring Beans Auto wiring
I ran into such problem. I was getting "Ambiguous mapping found". (I use xml configuration as well and i am injecting a bean into my controller)
Then looking at my console i realized that my controller was being instantiated twice.
In more detailed look i noticed that my annotation
#Controller(value = "aController")
(Note value = "aController")
was different from my xml configuration where i was instatiating the same controller with different bean id
<bean id="aControleRRRRR" class="package.ControllerClassName"
p:property-ref="beanToInject" />
(Note id="aControleRRRRR")
So in conclusion your #Controller name (value = "aController") needs to be exactly the same as the name you give in the XML configuration (id="aControleRRRRR"), so that Spring can manage to distinct that they refer to the same bean (instance)
Hope this helps

Spring #Value annotations don't work, returning null

I have the following class:
#Component
public class MyClass {
#Value("${main.url}") private String mainUrl;
the following XML context:
<context:annotation-config/>
<context:component-scan base-package="mypackage"/>
<context:property-placeholder file-encoding="UTF-8" location="classpath:/app.properties" ignore-unresolvable="true"/>
and prop file:
main.url=veryniceurl.com
Injection doesn't work, it is always null.
I read a lot of similar examples and I thought that everything is ok but it isn't. Can anyone tell me if I forgot about something? I'm working with Mule ESB.
#Value doesn't seem to work with Mule. Instead you need to wire it up through the Mule XML, where I assume you are loading your component as a Spring Bean:
<spring:bean id="MyClass" class="com.example.MyClass">
<spring:property name="mainUrl" value="${main.url}"/>
</spring:bean>
Give an id to your properties and use this syntax :
#Value("#{jetProperties['jetBean.name']}")
<!-- define the properties file to use -->
<util:properties id="jetProperties" location="classpath:/jet.properties" />
From http://chrislovecnm.com/2010/03/08/spring-3-java-based-configuration-with-value/
Did you add the context placeholder in the dispatcher-servlet.xml ? As per here, Spring #Value annotation in #Controller class not evaluating to value inside properties file they seem to have solved it by adding it there instead of the application context

How to achieve conditional resource import in a Spring XML context?

What I would like to achieve is the ability to "dynamically" (i.e. based on a property defined in a configuration file) enable/disable the importing of a child Spring XML context.
I imagine something like:
<import condition="some.property.name" resource="some-context.xml"/>
Where the property is resolved (to a boolean) and when true the context is imported, otherwise it isn't.
Some of my research so far:
Writing a custom NamespaceHandler (and related classes) so I can register my own custom element in my own namespace. For example: <myns:import condition="some.property.name" resource="some-context.xml"/>
The problem with this approach is that I do not want to replicate the entire resource importing logic from Spring and it isn't obvious to me what I need to delegate to to do this.
Overriding DefaultBeanDefinitionDocumentReader to extend the behaviour of the "import" element parsing and interpretation (which happens there in the importBeanDefinitionResource method). However I'm not sure where I can register this extension.
Prior to Spring 4, the closest you can get using standard Spring components is:
<import resource="Whatever-${yyzzy}.xml"/>
where ${xyzzy} interpolates a property from the system properties. (I use a hacky custom version of the context loader class that adds properties from other places to the system properties object before starting the loading process.)
But you can also get away with importing lots of unnecessary stuff ... and use various tricks to only cause the necessary beans to be instantiated. These tricks include:
placeholder and property substitution
selecting different beans using the new Spring expression language,
bean aliases with placeholders in the target name,
lazy bean initialization, and
smart bean factories.
This is now completely possible, using Spring 4.
In your main application content file
<bean class="com.example.MyConditionalConfiguration"/>
And the MyConditionalConfiguration looks like
#Configuration
#Conditional(MyConditionalConfiguration.Condition.class)
#ImportResource("/com/example/context-fragment.xml")
public class MyConditionalConfiguration {
static class Condition implements ConfigurationCondition {
#Override
public ConfigurationPhase getConfigurationPhase() {
return ConfigurationPhase.PARSE_CONFIGURATION;
}
#Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
// only load context-fragment.xml if the system property is defined
return System.getProperty("com.example.context-fragment") != null;
}
}
}
And then finally, you put the bean definitions you want included in the /com/example/context-fragment.xml
See the JavaDoc for #Conditional
As mentioned earlier, this can be easily accomplished with profiles if you're using Spring 3.1+
<!-- default configuration - will be loaded if no profile is specified -->
<!-- This will only work if it's put at the end of the configuration file -->
<!-- so no bean definitions after that -->
<beans profile="default">
<import resource="classpath:default.xml" />
</beans>
<!-- some other profile -->
<beans profile="otherProfile">
<import resource="classpath:other-profile.xml" />
</beans>
otherProfile can be easily activated with e.g.
mvn install -Dspring.profiles.active=otherProfile
if you're using different profiles in tests, just add -DforkMode=never to make sure that the tests will run inside same VM, therefore the param spring.profiles.active wont be lost
With Spring 3.1.x you can use bean profiles to achieve conditional resource import and bean instantiation. This is of course of no help if you are using an earlier version :)
For the record, Robert Maldon explains how to accomplish conditional definition of beans in this post: http://robertmaldon.blogspot.com/2007/04/conditionally-defining-spring-beans.html. It is a bit long to copy it here (besides, I don't think I should copy-paste his article anyway).
The end result with this approach, adapted for your example, is:
<condbean:cond test="${some.property.name}">
<import resource="some-context.xml"/>
</condbean:cond>
It is certainly not so simple as Stephen C's solution, but it is much more poweful.
Another one to consider for Spring 3.0:
<alias name="Whatever" alias=""Whatever-${yyzzy}" />
where ${xyzzy} interpolates a property from the system properties.
Another option is to have your app load a modules-config.xml file that is located in the /conf folder and edit it during the install/config phase to uncomment the modules you want loaded.
This is the solution I'm using with a web application that serves as a container for different integration modules. The web application is distributed with all the different integration modules. A modules-config.xml is placed in tomcat's /conf folder and the conf folder is added to the classpath (via catalina.properties/common.loader property). My web app webapp-config.xml has a <import resource="classpath:/modules-config.xml"/> to get it loaded.
You can override contextInitialized(javax.servlet.ServletContextEvent event) in your own ContextLoaderListener and set required System property before super.contextInitialized(event) called like this
package com.mypackage;
import org.springframework.web.context.ContextLoaderListener;
public class MyContextLoaderListener extends ContextLoaderListener {
public void contextInitialized(javax.servlet.ServletContextEvent event) {
System.setProperty("xyz", "import-file-name.xml");
super.contextInitialized(event);
}
}
And than replace ContextLoaderListener to MyContextLoaderListener in your web.xml
<listener>
<listener-class>com.mypackage.MyContextLoaderListener</listener-class>
</listener>
Now you can use in your spring.xml
<import resource="${xyz}" />
I hope this will help.

Categories