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;
}
}
Related
I would like to achieve not-trivial bean injection implementation.
I have a custom properties file:
#Getter
#Setter
#ConfigurationProperties
public class DatabaseProperties {
private String url;
private String username;
private String password;
}
I Here is the configuration file:
#Configuration
#EnableConfigurationProperties(DatabaseProperties.class)
public class DBConfig {
#Bean
#ConfigurationProperties(prefix = "datasource.database1")
public JdbcTemplate jdbcTemplateDatabase1(DatabaseProperties databaseProperties) {
DataSource dataSource = new DriverManagerDataSource(
databaseProperties.getUrl(),
databaseProperties.getUsername(),
databaseProperties.getPassword());
return new JdbcTemplate(dataSource);
}
#Bean
#ConfigurationProperties(prefix = "datasource.database2")
public JdbcTemplate jdbcTemplateDatabase2(DatabaseProperties databaseProperties) {
DataSource dataSource = new DriverManagerDataSource(
databaseProperties.getUrl(),
databaseProperties.getUsername(),
databaseProperties.getPassword());
return new JdbcTemplate(dataSource);
}
}
The goal I want to achieve is to instantiate a new DatabaseProperties instance based on prefix.
There are two possible solutions:
create two beans of type DatabaseProperties using corresponding prefixes and two JdbcTemplate beans where parameter is qualified DatabaseProperties bean accordingly.
in each JdbcTemplate bean provide 3 parameters (String url, String username, String password) and inject them through #Value
BUT Is it possible to get rid of creating DatabaseProperties beans for each JdbcTemplate or using #Value ?
You don't need create a DatabaseProperties. Spring already does this for us on datasources and proprierties variable
#Configuration
public class ConfigDataSource {
#Bean("datasource-1") // this name will qualify on #autowired
#ConfigurationProperties(prefix="spring.datasource.yourname-datasource-1") // this is the name for the prefix for datasource on .properties settings
public DataSource dataSourcePostgres() {
return DataSourceBuilder.create().build();
}
#Bean("datasource-2") // this name will qualify on #autowired
#ConfigurationProperties(prefix="spring.datasource.yourname-datasource-2") // this is the name for the prefix for datasource on .properties settings
public DataSource dataSourceMySql() {
return DataSourceBuilder.create().build();
}
}
.properties
# Its required use the same name declared in bean
spring.datasource.yourname-datasource-1.url=...
spring.datasource.yourname-datasource-1.jdbcUrl=${spring.datasource.yourname-datasource-1}
spring.datasource.yourname-datasource-1.username=user
spring.datasource.yourname-datasource-1.password=pass
spring.datasource.yourname-datasource-1.driver-class-name=your.driver
spring.datasource.yourname-datasource-2.url=...
spring.datasource.yourname-datasource-2.jdbcUrl=${spring.datasource.yourname-datasource-2}
spring.datasource.yourname-datasource-2.username=user
spring.datasource.yourname-datasource-2.password=pass
spring.datasource.yourname-datasource-2.driver-class-name=your.driver
using on services
#Awtowired
#Qualifier("datasource-1")
private DataSource dataSource1;
#Awtowired
#Qualifier("datasource-2")
private DataSource dataSource2;
public testJdbcTemplate(){
// You can qualifier JdbcTemplate below on bean and not necessary need instance on service
JdbcTemplate jdbcTemplateDatasource1 = new JdbcTemplate(dataSource1);
JdbcTemplate jdbcTemplateDatasource2 = new JdbcTemplate(dataSource2);
}
To my knowledge, there is no way around the fact that if you want to have access to multiple databases Spring will not be able to do the magic for you. You will need to create the two JdbcTemplate Spring-managed beans and then inject them where needed using the #Qualifier annotation.
This approach has two benefits:
It actually work;
You are explicit about what you are doing. A Spring application has already a good load of magic happening in there, so we might want to avoid some additional one when we need something a little bit more custom and that is not that complex to achieve.
I have a bean defined similar to below in my spring.xml. I am converting all my beans into annotation based. How can I inject the attributes in the below listed bean?
<bean
id = "dataPropDao"
class = "com.service.ref.DataPropDaoImpl"
p:dataSource-ref = "data.dataSource"
p:sql = "PROFILE_PKG.GetProfileByCode"
p:function = "true"/>
"p" namespace is used to set bean properties using setters. Equivalent of your code in Java config would be similar to:
#Configuration
class MyConfig {
#Bean
DataPropDaoImpl dataPropDao(DataSource datasource) {
DataPropDaoImpl dao = new DataPropDaoImpl();
dao.setDataSource(datasource);
dao.setSql("PROFILE_PKG.GetProfileByCode");
dao.setFunction(true);
return dao;
}
}
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
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.
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);
// ...
}