Unable to read properties in Spring - java

I have a properties file in src/main/resources.
Spring 4.0 and Java 1.8 project.
mock.properties
key=test
WEB-INF/web.xml
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/mvc-dispatcher-servlet.xml</param-value>
</context-param>
WEB-INF/mvc-dispatcher-servlet.xml
<context:component-scan base-package="com.x.y.z.*">
</context:component-scan>
<context:annotation-config />
<context:spring-configured />
<context:property-placeholder location="classpath:mock.properties"
order="-1" ignore-resource-not-found="true" ignore-unresolvable="true" />
<mvc:annotation-driven />
Controller.java ... I can access the value of property key in controller.
#Controller
#RequestMapping("/xyz")
public class EC2Controller {
#Value("${key}")
String v;
}
Helper.java ... Can't access any property.Always gets "null"
#Component
public class Helper {
#Value("${key}")
String v;
}
I also tried various options suggested on forums and spring docs but helper is just not able to read the prop.I tried following as well
#Configuration
#PropertySource("classpath:mock.properties")
public class Helper {
#Value("${key}")
String v;
#Bean
public static PropertySourcesPlaceholderConfigurer
propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
}
and
#Configuration
#PropertySource("classpath:mock.properties")
public class Helper {
#Autowired
Environment env;
String v = env.getProperty("key");
}
nothing works.

The answer depends on whether you are using the springonfig.xml mvc-dispatcher-servlet.xml that you show above. Based on your code samples, it looks like you are not (unless there is something missing).
Your mvc-dispatcher-servlet.xml includes context:property-placeholder, so it should be sufficient. But if you are not using it, or want to use an #Configuration (Java config) class instead (you can mix xml and Java config in the same app) then you need a PropertySourcesPlaceHolderConfigurer to resolve ${} in #Value, such as:
#Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
See documentation at https://docs.spring.io/spring/docs/4.2.4.RELEASE/javadoc-api/org/springframework/context/annotation/PropertySource.html, which states:
In order to resolve ${...} placeholders in definitions or #Value annotations using properties from a PropertySource, one must register a PropertySourcesPlaceholderConfigurer...
Note that the documentation states this happens automatically when using context:property-placeholder in XML - but as noted it's not clear from your code samples whether you are using that.

You could try this code snippet, and use ${key} to inject value:
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:/demo.properties</value>
</list>
</property>
</bean>
or this, and use #{app.key} to inject value:
<?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-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/context/spring-util-3.2.xsd" profile="dev">
...
<util:properties id="app" location="app.properties" />
...
</beans>
Hope to help you.

Related

Using Profile Properties in ClientInterceptor

I have a profiles.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: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.xsd">
<!-- Local -->
<beans profile="local">
<util:properties id="localProperties">
<prop key="property">localProperty</prop>
</util:properties>
<context:property-placeholder properties-ref="localProperties" ignore-unresolvable="true" />
</beans>
<!-- Dev -->
<beans profile="dev">
<util:properties id="devProperties">
<prop key="property">devProperty</prop>
</util:properties>
<context:property-placeholder properties-ref="devProperties" ignore-unresolvable="true" />
</beans>
</beans>
and I have a org.springframework.ws.client.support.interceptor.ClientInterceptor that I want to use values from profiles.xml:
#Component
public class HeaderInjector implements ClientInterceptor {
#Value("${property}")
private static String someProperty;
#Override
public boolean handleRequest(MessageContext messageContext)
throws WebServiceClientException {
//want to use someProperty here based on value from profiles.xml
}
}
How can I do this? I tried adding #ImportResource("profiles.xml") at the top of the class like
#Component
#ImportResource("profiles.xml")
public class SoapLeadPipeHeaderInjector implements ClientInterceptor {
but someProperty never gets set.
First of all there is nothing about Spring Integration in your question, so be careful with choosing tags for questions.
#ImportResource("profiles.xml") can be applied on the #Configuration class if you start application context from annotations.
If your main entry point is XML configuration, your #Component must be scanned via <context:component-scan base-package="..."/> then.
See more info in the Spring Framework Reference Manual.

why #autowired is not working when I access a bean

When I access a bean from spring bean configuration file using BeanFactory like this:
public class Person {
private String id,address;
#Autowired
private Customer customer;
//setters & getters
}
and bean configuration file
<bean name="person" class="com.ram.spring.model.Person"></bean>
<bean class="com.ram.spring.model.Customer">
<property name="email" value="ram#adp.com"></property>
<property name="name" value="Ram"></property>
</bean>
here is the executor class
public class PersonExecutor {
public static void main(String[] args) {
BeanFactory context = new XmlBeanFactory(new ClassPathResource("Spring.xml"));
Person person = (Person)context.getBean("person");
System.out.println(person.getCustomer());
}
}
when I execute this, I got null.is BeanFactory not supported for annotations?? any ideas??
Approach 1: Include below code in your xml
<beans xmlns="http://www.springframework.org/schema/beans"
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-3.0.xsd">
<context:annotation-config />
<!-- Remaining bean declaration -->
</beans>
Approach 2: Remove #Autowired and inject customer in your xml file only.
<bean name="person" class="com.ram.spring.model.Person">
<property name="customer" ref="customer"></property>
</bean>
<bean name="customer" class="com.ram.spring.model.Customer">
<property name="email" value="ram#adp.com"></property>
<property name="name" value="Ram"></property>
</bean>
You have to use AnnotationConfigApplicationContext or
you have to add to yor Spring.xml to activate the annotation scan.
As #jens suggested
you should active annotation scan
<context:component-scan base-package="package_path">
</context:component-scan>
<context:annotation-config />
hope that helped
Why doesn't it work?
When using Spring with an XML context, using annotations is not activated by default. This means #Autowired, #Transactional, #PostConstruct and any other annotation you will use will simply not be exploited.
How do I fix it?
To make Spring aware of annotations, you need to add the following line:
<context:annotation-config />
Thus, Spring will search for annotations in the beans it creates and process them accordingly.
This requires activating the context namespace. At the top of your context, make sure you have all context related links and arguments1:
<beans xmlns="http://www.springframework.org/schema/beans"
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-3.0.xsd">
<context:annotation-config />
<!-- Your context -->
</beans>
You do not need <context:component-scan /> in your case. This would be useful if you used full-annotation context (e.g. classes annotated with #Component). See the difference between <context:annotation-config /> and <context:component-scan /> in this answer.
Alternate solution
As Naman Gala suggested, you could also drop #Autowired completely and inject all dependencies in XML. See the related answer for more details.
1 This includes the xmlns:context attribute (xmlns = XML NameSpace) and two URLs in xsi:schemaLocation.

Autowired/Resource does not work when I remove spring-webmvc.jar

following the answer given in this question, I have removed the spring-webmvc.jar file from my lib to avoid a repetition with the one in the core project. However, when I do this, it seems that the #Autowired for at least a bean does not work any more.
The class having the #Autowired is the following (in which none of the field is filled):
public class SecurityUserCheckBeforeControllerHandler implements BeforeControllerHandler
{
#Resource(name = "userService")
private UserService userService;
#Autowired
private CMSPageContextService cmsPageContextService;
#Override
public boolean beforeController(final HttpServletRequest request, final HttpServletResponse response,
final HandlerMethod handler) throws IOException
{
// Code where the autowired fields are used (-> produces null pointer)
}
}
The spring configuration can be summarized as follows:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
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/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd">
<context:component-scan base-package="my.package" scope-resolver="de.hybris.platform.spring.IgnoreTenantScopeMetadataResolver" />
<mvc:annotation-driven ignore-default-model-on-redirect="true" validator="validator">
<mvc:message-converters>
<bean class="org.springframework.http.converter.ResourceHttpMessageConverter"/>
<bean class="org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter"/>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter" />
</mvc:message-converters>
</mvc:annotation-driven>
<alias name="defaultBeforeControllerHandlersList" alias="beforeControllerHandlersList" />
<util:list id="defaultBeforeControllerHandlersList" >
<bean class="be.sbh.site.storefront.interceptors.beforecontroller.SecurityUserCheckBeforeControllerHandler" />
<!-- other beans in the list -->
</util:list>
<alias alias="cmsPageContextService" name="defaultCMSPageContextService" />
<bean id="defaultCMSPageContextService"
class="de.hybris.platform.acceleratorcms.services.impl.DefaultCMSPageContextService">
<!-- Properties -->
</bean>
<alias alias="userService" name="defaultUserService"/>
<bean id="defaultUserService" class="de.hybris.platform.servicelayer.user.impl.DefaultUserService" parent="abstractBusinessService">
<!-- Properties -->
</bean>
</beans>
If I follow the advise given in most of the similar questions (i.e. adding an #Component above the class that would be scanned), the bean will be created twice:
with the list given in the config file:
The autowired fields will be null which will still give a NullPointerException when the bean in the list is used
by the component-scan:
The fields are correctly autowired but the bean is not used in the list.
Strangely, if I put back the spring-webmvc.jar previously removed because of this question, the #Autowired will work as expected.
Trying to compare the stacktraces between the two configurations, I saw that the beans are created at different moments in the class org.springframework.context.support.AbstractApplicationContext during the startup of the server.
Last point: there is no error during the compilation and the startup of the server.
Do you have any idea for a solution please?
Thank you for reading me,
Laurent

Autowired spring bean null for cacheManager using ehcache spring annotations

I'm still new to spring and I'm trying to get ehcache spring annotations setup correctly. I'm using Spring 3.2.3 ehCache 2.4 and ehcache-spring-annotations-1.2.
When I try to access the reference to the cacheManager, it is always null. All the jars are on the build path, ehcache.xml is in the classpath and there are no xml errors. I've tried also including the classes in the component scan and using #Resource instead of Autowired. I'm stuck!
Application context:
<?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:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:ehcache="http://ehcache-spring-annotations.googlecode.com/svn/schema/ehcache-spring"
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://ehcache-spring-annotations.googlecode.com/svn/schema/ehcache-spring
ehcache-spring-1.1.xsd">
<context:component-scan base-package="org.springframework.cache.ehcache.EhCacheManagerFactoryBean,com .defaultPackage,net.sf.ehcache.CacheManager" />
<!-- ehCache Annotation settings -->
<ehcache:annotation-driven cache-manager="ehCacheManager" />
<bean id="ehCacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
<property name="configLocation" value="classpath:ehcache.xml" />
<property name="shared" value="true"/>
</bean>
Wrapper
#Component
public final class MyCache implements Serializable {
#Autowired
private CacheManager ehCacheManager;
private getCacheManager() {
return ehCacheManger; // this is always null
}...}
It seems you are trying to use the EhCacheManagerFactoryBean as your cache manager.
Looking at Spring caching documentation, you need to declare another bean to be your CacheManager created from the factory.

Accessing PropertySources in the Spring 3.1 application xml

I'm using the Spring ApplicationContextInitializer to add PropertySources to the Enviroment. I have verified that that part is working as in it's loading the properties into the PropertySources. The part that I'm struggling with is figuring out how to access the Property values that were loaded in the ApplicationContextInitializer within the Spring XML configuration as well as the Java code itself.
Here is a snippit of my ApplicationContextInitializer:
public class ExternalPropertiesApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
#Override
public void initialize(ConfigurableApplicationContext applicationContext) {
Properties properties = load_properties_from_external_source();
PropertiesPropertySource propertySource = new PropertiesPropertySource("external", properties);
applicationContext.getEnvironment().getPropertySources().addFirst(propertySource);
}
}
So this loads up my Properties which has key,value pairs like:
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mydb
jdbc.username=user
jdbc.password=passwd
My Spring configuration file looks like this:
<context:component-scan base-package="com.example"/>
<context:property-placeholder ignore-resource-not-found="true" system-properties-mode="OVERRIDE"/>
<bean id="myds" class="org.apache.tomcat.jdbc.pool.DataSource" destroy-method="close">
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
This is failing because it doesn't recognize ${jdbc.driverClassName}. I also tried #{external.jdbc.driverClassName} which fails too. The first fails because I'm not explicitly loading jdbc.properties in my Spring configuration file (which is the intent). The latter fails because it can't find the external bean. What step am I missing? How do I expose the property values that were loaded externally?
I also have a Java class like so:
package com.example;
#Component
public class MyClass {
#Value("${jdbc.url}")
private String jdbcUrl;
}
Similar to the Spring configuration, how would I access the jdbc.url property values that were loaded upon initialization?
Oh and here is a snippit of the web.xml:
<context-param>
<param-name>contextInitializerClasses</param-name>
<param-value>com.example.ExternalPropertiesApplicationContextInitializer</param-value>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
There were a couple of issues with the Spring configuration file that was the culprit.
Specifically, in the heading, I had:
<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-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
despite being on Spring 3.1. That caused Spring to revert to the old PropertyPlaceholderConfigurer rather than the new PropertySourcesPlaceholderConfigurer.
Once I changed the 3.0.xsd reference to 3.1.xsd, it started to resolve the issue. The new header looks like so:
<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-3.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.1.xsd">
The second issue was this line:
<context:property-placeholder ignore-resource-not-found="true" system-properties-mode="OVERRIDE"/>
Because of the system-properties-mode attribute, Spring again reverted back to the old PropertyPlaceholderConfigurer and not the new PropertySourcesPlaceholderConfigurer.
When using the old PropertyPlaceholderConfigurer, it doesn't pick up the values from the new Environment which was why the property values weren't being picked up in the Spring Context configuration.

Categories

Resources