Can you please tell me how to use Spring Javaconfig to directly load/autowire a properties file to a java.util.Properties field?
Thanks!
Later edit - still searching for the answer:
Is it possible to load with Spring JavaConfig a properties file directly into a java.util.Properties field?
The XML base Way:
in spring config:
<util:properties id="myProperties" location="classpath:com/foo/my-production.properties"/>
in your class:
#Autowired
#Qualifier("myProperties")
private Properties myProperties;
JavaConfig Only
It looks like there is an annotation:
#PropertySource("classpath:com/foo/my-production.properties")
Annotating a class with this will load the properties from the file in to the Environment. You then have to autowire the Environment into the class to get the properties.
#Configuration
#PropertySource("classpath:com/foo/my-production.properties")
public class AppConfig {
#Autowired
private Environment env;
public void someMethod() {
String prop = env.getProperty("my.prop.name");
...
}
I do not see a way to directly inject them into the Java.util.properties. But you could create a class that uses this annotation that acts as a wrapper, and builds the properties that way.
declare a PropertiesFactoryBean.
#Bean
public PropertiesFactoryBean mailProperties() {
PropertiesFactoryBean bean = new PropertiesFactoryBean();
bean.setLocation(new ClassPathResource("mail.properties"));
return bean;
}
Legacy code had following config
<bean id="mailConfiguration" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="location" value="classpath:mail.properties"/>
</bean>
Converting that to Java config is super easy as shown above.
It is an old subject but there are also a more basic solution.
#Configuration
public class MyConfig {
#Bean
public Properties myPropertyBean() {
Properties properties = new Properties();
properties.load(...);
return properties;
}
}
There is also this approach for injecting properties directly using xml configurations. The context xml has this
<util:properties id="myProps" location="classpath:META-INF/spring/conf/myProps.properties"/>
and the java class just uses
#javax.annotation.Resource
private Properties myProps;
Voila!! it loads.
Spring uses the 'id' attribute in xml to bind to the name of variable in your code.
You can try this
#Configuration
public class PropertyConfig {
#Bean("mailProperties")
#ConfigurationProperties(prefix = "mail")
public Properties getProperties() {
return new Properties();
}
}
Make sure to define properties in application.properties
application.yml:
root-something:
my-properties:
key1: val1
key2: val2
Your type-safe pojo:
import java.util.Properties;
import org.springframework.boot.context.properties.ConfigurationProperties;
#ConfigurationProperties(prefix = "root-something")
public class RootSomethingPojo {
private Properties myProperties;
Your container configuration:
#Configuration
#EnableConfigurationProperties({ RootSomethingPojo .class })
public class MySpringConfiguration {
This will inject the key-value pairs directly into the myProperties field.
Related
How can I inject the following key-value file as a Properties variable or HashMap directly, using spring?
src/main/resources/myfile.properties:
key1=test
someotherkey=asd
(many other key-value pairs)
None of the following worked:
#Value("${apikeys}")
private Properties keys;
#Resource(name = "apikeys")
private Properties keys;
Sidenote: I don't know the keys inside the properties file in advance. So I cannot use #PropertyResource injection.
One way you could try to achieve this is by creating a bean in your configuration file:
#Bean
public Map<String, String> myFileProperties() {
ResourceBundle bundle = ResourceBundle.getBundle("myfile");
return bundle.keySet().stream()
.collect(Collectors.toMap(key -> key, bundle::getString));
}
Then you can easily inject this bean into your service e.g.
#Autowired
private Map<String, String> myFileProperties;
(Consider using constructor injection)
Also don't forget to
#PropertySource("classpath:myfile.properties")
In order to use Value annotation first you need to define in your applicationContext.xml below bean
<bean
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:myfile.properties"></property>
</bean>
Once you define your property file , you can use Value annotation.
You can use Annotation PropertySource:
Sample:
#PropertySource("myfile.properties")
public class Config {
#Autowired
private Environment env;
#Bean
ApplicationProperties appProperties() {
ApplicationProperties bean = new ApplicationProperties();
bean.setKey1(environment.getProperty("key1"));
bean.setsomeotherkey(environment.getProperty("someotherkey"));
return bean;
}
}
I want to configure a tomcat data source in Spring Boot, The properties of the database are stored in another property file (Say dbConnection.properties) with different keys.
For example
dbConnection.properties:
DATABASE_URL=SomeURL
DATABASE_USER=SomeUser
DATABASE_PASSWORD=SomePassword
From what I understand the properties related to a data source must be specified in application.properties as:
spring.datasource.url=jdbc:mysql://localhost/test
spring.datasource.username=dbuser
spring.datasource.password=dbpass
How do I pass the values from dbConnection.properties to application.properties?
From Spring Boot documentation
Property contributions can come from additional jar files on your classpath so you should not consider this an exhaustive list. It is also perfectly legit to define your own properties.
so you can have your own property file and it should be in your classpath,
Inject property using Value annotation
#Value("#{propFileName.propKeyName}")
All you need is override the Spring-Boot's Datasource default configuration. See the example above:
#Bean
#Primary
public DataSource dataSource() {
return DataSourceBuilder
.create()
.username("") // TODO: Get from properties
.password("") // TODO: Get from properties
.url("") // TODO: Get from properties
.driverClassName("") // TODO: Get from properties
.build();
}
In order to get from properties you can use the #Value annotation that #Saravana said you.
#Manish Kothari... try this,create a configuration class with the annotations like
#ConfigurationProperties.
#Component
#PropertySource("classpath:dbConnection.properties")
#ConfigurationProperties
public class ConfigurationClass{
//some code
}
and now it will call your DB properities... I hope this will work
There are multiple ways to do this
1.You can pass the property files from the command promopt
-Dspring.config.location=classpath:job1.properties,classpath:job2.properties
2.Way is to add #PropertySource annotation
public class AppConfig
#PropertySource("classpath:config.properties")
public class LoadDbProps{
#value("${DATABASE_USER}")
private String dbUserName;
private String dbUserName;
}
Later you can set this LoadDbProps to application.properties properties using #Bean configuration.
The below solution worked for me :
#Configuration
public class DataSourceConfig {
#Bean
public DataSource getDataSource() {
Properties properties = null;
InputStream inputStream = null;
DataSourceBuilder dataSourceBuilder =null;
try {
properties = new Properties();
inputStream = new FileInputStream("./src/main/resources/config.properties");
properties.load(inputStream);
dataSourceBuilder = DataSourceBuilder.create();
dataSourceBuilder.url(properties.getProperty("url"));
dataSourceBuilder.username(properties.getProperty("user"));
dataSourceBuilder.password(properties.getProperty("password"));
}
catch(Exception ex) {
System.out.println("CONFIG EXCEPTION :"+ex);
}
return dataSourceBuilder.build();
}
}
refer below link for more details:
https://howtodoinjava.com/spring-boot2/datasource-configuration/#:~:text=Spring%20boot%20allows%20defining%20datasource,a%20DataSource%20bean%20for%20us.
I've the following configuration file
#Configuration
#ComponentScan(basePackages = "com.foo")
#EnableTransactionManagement
public class AppSpringConfiguration {
#Autowired
private Environment env;
#Autowired
private ApplicationContext appContext;
#Value("#{cvlExternalProperties['dbDriverClassName']}")
private String dbDriverName;
#Bean
public PropertiesFactoryBean cvlExternalProperties() {
PropertiesFactoryBean res = new PropertiesFactoryBean();
res.setFileEncoding("UTF-8");
res.setLocation(new FileSystemResource(env.resolvePlaceholders("${MY_ENV_VAR}") + "external.properties"));
return res;
}
#Bean
public BasicDataSource datasource() {
BasicDataSource basicDataSource = new BasicDataSource();
basicDataSource.setDriverClassName("myDriverClassName");
basicDataSource.setUrl("MyDbUrl");
basicDataSource.setUsername("myUser");
basicDataSource.setPassword("myPass");
return basicDataSource;
}
}
And in the external properties file I've
dbUrl=jdbc:mysql://localhost:3306/someDb
dbUser=someUser
dbPassword=somePass
dbDriverClassName=com.mysql.jdbc.Driver
In which way I can use the cvlProperties inside the datasource() method?
I've tried
env.getProperty("dbDriverClassName")
env.getProperty("#cvlProperties['dbDriverClassName']")
But I'm not able to retrieve the properties.
The field dbDriverName is correctly filled, so that means the bean declaration is ok.
I want to use the PropertyFactoryBean class because in this way I can specify the encoding to use.
If I use the the following annotation on the top of the configuration class
#PropertySource("file:${MY_ENV_VAR}/external.properties")
I'm able to retrieve the properties with this piece of code
env.getProperty("dbDriverClassName")
But the encoding used by the PropertySource annotation is the windows default, and for me is not correct.
Can you help me?
At the moment the solution(that I don't love so much) is to declare the properties by using the annotation #Value
#Value("#{cvlExternalProperties['dbDriverClassName']}")
private String dbDriverClassName;
and then using it inside the java class
I have a spring application that is currently using *.properties files and I want to have it using YAML files instead.
I found the class YamlPropertiesFactoryBean that seems to be capable of doing what I need.
My problem is that I'm not sure how to use this class in my Spring application (which is using annotation based configuration).
It seems I should configure it in the PropertySourcesPlaceholderConfigurer with the setBeanFactory method.
Previously I was loading property files using #PropertySource as follows:
#Configuration
#PropertySource("classpath:/default.properties")
public class PropertiesConfig {
#Bean
public static PropertySourcesPlaceholderConfigurer placeholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
}
How can I enable the YamlPropertiesFactoryBean in the PropertySourcesPlaceholderConfigurer so that I can load YAML files directly?
Or is there another way of doing this?
Thanks.
My application is using annotation based config and I'm using Spring Framework 4.1.4.
I found some information but it always pointed me to Spring Boot, like this one.
With XML config I've been using this construct:
<context:annotation-config/>
<bean id="yamlProperties" class="org.springframework.beans.factory.config.YamlPropertiesFactoryBean">
<property name="resources" value="classpath:test.yml"/>
</bean>
<context:property-placeholder properties-ref="yamlProperties"/>
Of course you have to have the snakeyaml dependency on your runtime classpath.
I prefer XML config over the java config, but I recon it shouldn't be hard to convert it.
edit:
java config for completeness sake
#Bean
public static PropertySourcesPlaceholderConfigurer properties() {
PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer = new PropertySourcesPlaceholderConfigurer();
YamlPropertiesFactoryBean yaml = new YamlPropertiesFactoryBean();
yaml.setResources(new ClassPathResource("default.yml"));
propertySourcesPlaceholderConfigurer.setProperties(yaml.getObject());
return propertySourcesPlaceholderConfigurer;
}
To read .yml file in Spring you can use next approach.
For example you have this .yml file:
section1:
key1: "value1"
key2: "value2"
section2:
key1: "value1"
key2: "value2"
Then define 2 Java POJOs:
#Configuration
#EnableConfigurationProperties
#ConfigurationProperties(prefix = "section1")
public class MyCustomSection1 {
private String key1;
private String key2;
// define setters and getters.
}
#Configuration
#EnableConfigurationProperties
#ConfigurationProperties(prefix = "section2")
public class MyCustomSection1 {
private String key1;
private String key2;
// define setters and getters.
}
Now you can autowire these beans in your component. For example:
#Component
public class MyPropertiesAggregator {
#Autowired
private MyCustomSection1 section;
}
In case you are using Spring Boot everything will be auto scaned and instantiated:
#SpringBootApplication
public class MainBootApplication {
public static void main(String[] args) {
new SpringApplicationBuilder()
.sources(MainBootApplication.class)
.bannerMode(OFF)
.run(args);
}
}
If you'are using JUnit there is a basic test setup for loading YAML file:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(MainBootApplication.class)
public class MyJUnitTests {
...
}
If you're using TestNG there is a sample of test configuration:
#SpringApplicationConfiguration(MainBootApplication.class)
public abstract class BaseITTest extends AbstractTestNGSpringContextTests {
....
}
`
package com.yaml.yamlsample;
import com.yaml.yamlsample.config.factory.YamlPropertySourceFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.PropertySource;
#SpringBootApplication
#PropertySource(value = "classpath:My-Yaml-Example-File.yml", factory = YamlPropertySourceFactory.class)
public class YamlSampleApplication implements CommandLineRunner {
public static void main(String[] args) {
SpringApplication.run(YamlSampleApplication.class, args);
}
#Value("${person.firstName}")
private String firstName;
#Override
public void run(String... args) throws Exception {
System.out.println("first Name :" + firstName);
}
}
package com.yaml.yamlsample.config.factory;
import org.springframework.boot.env.YamlPropertySourceLoader;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.support.DefaultPropertySourceFactory;
import org.springframework.core.io.support.EncodedResource;
import java.io.IOException;
import java.util.List;
public class YamlPropertySourceFactory extends DefaultPropertySourceFactory {
#Override
public PropertySource createPropertySource(String name, EncodedResource resource) throws IOException {
if (resource == null) {
return super.createPropertySource(name, resource);
}
List<PropertySource<?>> propertySourceList = new YamlPropertySourceLoader().load(resource.getResource().getFilename(), resource.getResource());
if (!propertySourceList.isEmpty()) {
return propertySourceList.iterator().next();
}
return super.createPropertySource(name, resource);
}
}
My-Yaml-Example-File.yml
person:
firstName: Mahmoud
middleName:Ahmed
Reference my example on github spring-boot-yaml-sample So you can load yaml files and inject values using #Value()
I spend 5 to 6 hours in understanding why external configuration of yml/yaml file(not application.yml) are so different.I read various articles, stack overflow questions but didn't get correct answer.
I was stuck in between like I was able to use custom yml file value using YamlPropertySourceLoader but not able to use #Value because it is giving me error like
Injection of autowired dependencies failed; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder
'fullname.firstname' in value "${fullname.firstname}"
fullname is a property in yml.
Then I used "turtlesallthewaydown" given above solution, then at last I was able to use #Value without any issues for yaml files and I removed YamlPropertySourceLoader.
Now I understand the difference between YamlPropertySourceLoader and PropertySourcesPlaceholderConfigurer, a big thanks, however I have added these changes in my git repo.
Git Repo:
https://github.com/Atishay007/spring-boot-with-restful-web-services
Class Name: SpringMicroservicesApplication.java
If one will seek how to load yaml file into Properties in Spring, then there is a solution:
public Properties loadYaml(String fileName){
// fileName for eg is "my-settings.yaml"
YamlPropertySourceLoader ypsl = new YamlPropertySourceLoader();
PropertySource ps = ypsl.load(fileName, new ClassPathResource(fileName)).get(0);
Properties props = new Properties();
props.putAll((Map)ps.getSource());
return props;
}
I am using Spring 3 and also heavily utilize the well known #Autowire annotation. I would like to create a new annotation, let's call it #Property that autowires Java properties from set by .property files or vm arguments.
Considering the following class
class A {
#Property("my.a")
private int a;
}
if the property my.a is present, the property A.a is set.
Is such an annotation maybe already existing? If not I am aiming to create one, as mentioned above. Are the utilities given by spring to achieve my goal? I think about creating a BeanPostProcessor ...
Thanks for your hints!
There's already such an annotation - #Value
You should just define a PropertyPlaceHolderConfigurer, and configure it to resolve system properties.
Refer http://docs.spring.io/spring/docs/3.0.x/spring-framework-reference/html/
you can use #ImportResource to import XML configuration files. Then use context:property-placeholder to load properties
#Configuration
#ImportResource("classpath:/com/acme/properties-config.xml")
public class AppConfig {
private #Value("${jdbc.url}") String url;
private #Value("${jdbc.username}") String username;
private #Value("${jdbc.password}") String password;
public #Bean DataSource dataSource() {
return new DriverManagerDataSource(url, username, password);
}
}
properties-config.xml
<beans>
<context:property-placeholder location="classpath:/com/acme/jdbc.properties"/>
</beans>
jdbc.properties
jdbc.url=jdbc:hsqldb:hsql://localhost/xdb
jdbc.username=sa
jdbc.password=
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
TransferService transferService = ctx.getBean(TransferService.class);
// ...
}