Where to store config info for spring mvc 3.x - spring

Where is a good place to store custom config info in spring mvc 3.x and how would I access that info globally via any controller?
Is there a built in config manager?

I assume 'custom config' means a configuration file the code reads / you / your operations team can update?
One easy solution is to use spring beans xml configuration file and deploy your war in exploded fashion.
Create a configuration java class:
// File: MyConfig.java ------------------------------------
public class MyConfig {
private String supportEmail;
private String websiteName;
// getters & setters..
}
Configure the class as a Spring bean and set its properties on your spring beans xml file (can also create a new file and use <import resource="..."/>):
// File: root-context.xml ----------------------------------------
<beans ...>
...
<bean class="com.mycompany.MyConfig">
<property name="supportEmail" value="support#mycompany.com"/>
<property name="websiteName" value="Hello Site"/>
</bean>
...
</beans>
Inject your configuration class (eg: in a controller)
// File: HelloController.java ------------------------------------
#Controller
#RequestMapping("/hello")
public class HelloController {
#Autowired MyConfig config;
// ...
}
However updates to the configuration would require re-deploy / server restarts

You can also use <context:property-placeholder>.
It looks like this.
myapp.properties:
foo=bar
spring beans xml:
<context:property-placeholder location="classpath:myapp.properties"/>
Or
<context:property-placeholder location="file:///path/to/myapp.properties"/>
Controller:
import org.springframework.beans.factory.annotation.Value;
...
#Controller
public class Controller {
#Value("${foo}")
private String foo;
If you want to get properties programmatically, you can use Environment with #PropertySource.
Configuration:
#Configuration
#PropertySource("classpath:myapp.properties")
public class AppConfig {
#Bean
public PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
Controller:
#Controller
public class Controller {
#Value("${foo}")
private String foo;
#Autowired
private Environment env;
#RequestMapping(value = "dosomething")
public String doSomething() {
env.getProperty("foo");
...
}
Hope this helps.

Related

#Autowired not working in spring Integration

In service implementation,with help of #Autowired i am injecting CollectInfo object in serviceImpl but i am getting NullPointerException.
package net.group.cts.service.serviceImpl;
#Service
public class EmployeeImpl implements EmployeeService {
#Autowired
CollectInfo info;
public void processData(){
info.getName();
}
}
package net.group.cts.model;
#Component
public class CollectInfo (){
String name;
public String getName(){
name = name + "Mr.";
return name;}
}
}
Xmlconfig.xml
<context:annotation-config/>
<context:component-scan base-package="net.group.cts"/>
<bean id="info" class="net.group.emp.model.CollectInfo "/>
You cannot inject a bean in a class if this class is not a Spring bean.
EmployeeImpl is not annotated with any Spring bean stereotype such as #Component or #Service.
Add one of them on EmployeeImpl and ensure that the two classes are located inside the package scanned by Spring <context:component-scan base-package="net.group.emp.service"/>
and it should be ok.
Besides, both annotating a bean with #Component :
#Component
public class CollectInfo (){...}
and configuring it in the Spring xml configuration :
<bean id="info" class="net.group.emp.model.CollectInfo "/>
is redundant. It will finally create two beans : one name collectInfo and another named info.
I advise you to favor annotation over xml configuration as it is possible (it is the very most of cases).

Using spring to load properties as System properties

I'm using Spring 4.1.6.
I have something like the following:
foo.properties:
valueX=a
valueY=b
Spring bean:
<context:property-placeholder location="classpath:foo.properties" ignore-unresolvable="false" ignore-resource-not-found="false" />
<bean id="foo" class="com.foo.bar.MyClass" >
<property name="someValue" value="${valueX}" />
</bean>
I have a non-Spring class which also needs to use a value from foo.properties.
Non Spring Class:
public void doSomething() {
String valueY = System.getProperty("valueY");
}
When Spring loads foo.properties, is there a way to populate all the properties into System properties so that I can get "valueY" using System.getProperty("valueY").
I don't want to load foo.properties again in my non-Spring class.
The context:property-placeholder will create a PropertySourcesPlaceholderConfigurer config bean for you. You cannot access the properties from this bean programatically as stated here.
What you can do is to load the properties into a separate spring bean as given below.
#Bean(name = "mapper")
public PropertiesFactoryBean mapper() {
PropertiesFactoryBean bean = new PropertiesFactoryBean();
bean.setLocation(new ClassPathResource("application.properties"));
return bean;
}
and then set the system property when the context load is finished using a listener as given below. Got the code from this answer
#Component
public class YourJobClass implements ApplicationListener<ContextRefreshedEvent> {
#Resource(name = "mapper")
private Properties myTranslator;
public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
System.setProperties(myTranslator);
}
}

How to add implemetation of RequestDataValueProcessor using code and not as xml configuration

I have a bean like follows
<bean name="requestDataValueProcessor" class="com.bom.DOMRequestDataValueProcessor"/>
DOMRequestDataValueProcessor implements the RequestDataValueProcessor.
I am doing my mvc configuration using the following class and not by xml configuration file.
#Configuration
#EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
}
How can i add the above bean in the configuration ?
From Pro Spring Mvc book:
To config a RequestDataValueProcessor, we need to add it to the
application context and then register it with the name,
requestDataValueProcessor. This is the name the framework uses to
detect the registered instance.
So you probably need to do something like:
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = {"com.bom"})
public class WebConfig extends WebMvcConfigurerAdapter {
#Bean
public RequestDataValueProcessor
requestDataValueProcessor() {
return new DOMRequestDataValueProcessor();
}
}
you should enable the components scanning. See Spring doc : http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/beans.html#beans-java
<beans>
<context:component-scan base-package="com.acme"/>
</beans>
#Bean(name = { "requestDataValueProcessor" })
public DOMRequestDataValueProcessor getRequestDataValueProcessor() {
final DOMRequestDataValueProcessor domRequestDataValueProcessor = new DOMRequestDataValueProcessor();
return domRequestDataValueProcessor;
}

#Value not resolved when using #PropertySource annotation. How to configure PropertySourcesPlaceholderConfigurer?

I have following configuration class:
#Configuration
#PropertySource(name = "props", value = "classpath:/app-config.properties")
#ComponentScan("service")
public class AppConfig {
and I have service with property:
#Component
public class SomeService {
#Value("#{props['some.property']}") private String someProperty;
I receive error when I want to test the AppConfig configuration class with
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'someService': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private java.lang.String service.SomeService.someProperty; nested exception is org.springframework.beans.factory.BeanExpressionException: Expression parsing failed; nested exception is org.springframework.expression.spel.SpelEvaluationException: EL1008E:(pos 0): Field or property 'props' cannot be found on object of type 'org.springframework.beans.factory.config.BeanExpressionContext'
The issue is documented in SPR-8539
but anyway I cannot figure out how to configure PropertySourcesPlaceholderConfigurer to get it work.
Edit 1
This approach works well with xml configuration
<util:properties id="props" location="classpath:/app-config.properties" />
but I want to use java for configuration.
as #cwash said;
#Configuration
#PropertySource("classpath:/test-config.properties")
public class TestConfig {
#Value("${name}")
public String name;
//You need this
#Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
}
If you use #PropertySource, properties have to be retrieved with:
#Autowired
Environment env;
// ...
String subject = env.getProperty("mail.subject");
If you want to retrieve with #Value("${mail.subject}"), you have to register the prop placeholder by xml.
Reason:
https://jira.springsource.org/browse/SPR-8539
I found the reason #value was not working for me is, #value requires PropertySourcesPlaceholderConfigurer instead of a PropertyPlaceholderConfigurer. I did the same changes and it worked for me, I am using spring 4.0.3 release. I configured this using below code in my configuration file.
#Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
Don't you need a method on your #Configuration class that returns PropertySourcesPlaceholderConfigurer, annotated #Bean and is static, to register any #PropertySource with Spring?
http://www.baeldung.com/2012/02/06/properties-with-spring/#java
https://jira.springsource.org/browse/SPR-8539
I had the very same problem. #PropertySource is not playing well with #Value. A quick workaround is to have an XML configuration which you'll refer to it from your Spring Java Configuration using #ImportResource as usual and that XML configuration file will include a single entry: <context:property-placeholder /> (of course with the needed namespace ceremony). Without any other change #Value will inject properties in your #Configuration pojo.
This can also be configured in java this way
#Bean
public static PropertySourcesPlaceholderConfigurer properties() {
PropertySourcesPlaceholderConfigurer configurer = new PropertySourcesPlaceholderConfigurer();
configurer.setIgnoreUnresolvablePlaceholders(true);
configurer.setIgnoreResourceNotFound(true);
return configurer;
}
That looks mighty complicated, can't you just do
<context:property-placeholder location="classpath:some.properties" ignore-unresolvable="true"/>
then in code reference:
#Value("${myProperty}")
private String myString;
#Value("${myProperty.two}")
private String myStringTwo;
where some.properties looks something like this
myProperty = whatever
myProperty.two = something else\
that consists of multiline string
For java based config you can do this
#Configuration
#PropertySource(value="classpath:some.properties")
public class SomeService {
And then just inject using #value as before
Since Spring 4.3 RC2 using PropertySourcesPlaceholderConfigurer or <context:property-placeholder> is not needed anymore. We can use directly #PropertySource with #Value. See this Spring framework ticket
I have created a test application with Spring 5.1.3.RELEASE.
The application.properties contains two pairs:
app.name=My application
app.version=1.1
The AppConfig loads the properties via #PropertySource.
package com.zetcode.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
#Configuration
#PropertySource(value = "application.properties", ignoreResourceNotFound = true)
public class AppConfig {
}
The Application injects the properties via #Value and uses them.
package com.zetcode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
#ComponentScan(basePackages = "com.zetcode")
public class Application {
private static final Logger logger = LoggerFactory.getLogger(Application.class);
#Value("${app.name}")
private String appName;
#Value("${app.version}")
private String appVersion;
public static void main(String[] args) {
var ctx = new AnnotationConfigApplicationContext(Application.class);
var app = ctx.getBean(Application.class);
app.run();
ctx.close();
}
public void run() {
logger.info("Application name: {}", appName);
logger.info("Application version: {}", appVersion);
}
}
The output is:
$ mvn -q exec:java
22:20:10.894 [com.zetcode.Application.main()] INFO com.zetcode.Application - Application name: My application
22:20:10.894 [com.zetcode.Application.main()] INFO com.zetcode.Application - Application version: 1.1
The thing is: as far as I get it, <util:propertes id="id" location="loc"/>, is just a shorthand for
<bean id="id" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="location" value="loc"/>
</bean>
(see documentation of util:properties). Thus, when you use util:properties, a standalone bean is created.
#PropertySource, on the other hand, as documentation says is an
annotation providing a convenient and declarative mechanism for
adding a PropertySource to Spring's Environment'.
(see #PropertySource doc). So it doesn't create any bean.
Then "#{a['something']}" is a SpEL expression (see SpEL), that means "get something from bean 'a'". When util:properties is used, the bean exists and the expression is meaningful, but when #PropertySource is used, there is no actual bean and the expression is meaningless.
You can workaround this either by using XML (which is the best way, I think) or by issuing a PropertiesFactoryBean by yourself, declaring it as a normal #Bean.
Another thing that may be happening: ensure your #Value annotated values are not static.
In my case, depends-on="bean1" was within property-placeholder was causing the issue. I removed that dependency and used #PostConstruct to achieve the same original functionality and was able to read the new values too.
If you are configuring with xml, after adding
<context:property-placeholder location="..."/>
Make sure your annotations are activated. In my case properties were not fetched for this reason:
<context:annotation-config/>
for me it worked
spring.cloud.config.server.git.default-label=main
spring.cloud.config.server.native.searchLocations=file:///Users/${your username}/Projects/git-local-repositories/
spring.profiles.active=native

Initialize a string with data from property file in controller

I would like to Initialize a string with data from a property file in a spring controller:
#Controller
public class MyController {
private string dbName;
.....
....
}
and in my property file: (myApp.properties)
dbName=EMPLOYEE
I found an example here but in the example of sun, they use an init() method. But where should I call my init() method as there is no constructor of the Controller
You can move the configuration into a different class, initialize that class through spring XML definition like this :
<bean id="configuration" class="examples.Configuration">
<property name="dbNAme" value="EMPLOYEE">
</bean>
create a class like this :
public class Configuration {
public string dbName;
}
then reference it from your code.
#Controller
public class MyController {
#Autowired
private Configuration config;
}

Resources