In my Spring MVC application, I want to read ALL key/values from a specify properties file.
I am including the properties file to my java class by
#PropertySource("classpath:user-form-validation-configuration.properties")
and can read a one key at a time
#Autowired
Environment env;
and env.getProperty("userIdEmail")
Please help me how to get all key/value as a map
Thanks
Manu
One way to achieve the same is Spring: access all Environment properties as a Map or Properties object and secondly is:
<bean id="myProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="location" value="classpath:user-form-validation-configuration.properties"/>
</bean>
For, Annotation based:
#Bean(name = "myProperties")
public static PropertiesFactoryBean mapper() {
PropertiesFactoryBean bean = new PropertiesFactoryBean();
bean.setLocation(new ClassPathResource(
"user-form-validation-configuration.properties"));
return bean;
}
Then you can pick them up in your application with:
#Resource(name = "myProperties")
private Map<String, String> myProperties;
Related
I have an xml bean configuration as follows:
<bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
<property name="dataSource" ref="dataSource" />
<property name="jpaDialect" ref="openJPADialect" />
</bean>
I want to add a new property defaultTimeout, however I don't want to hard code it.
I want to instead put some class that will retrieve the value of this property from some in memory cache (doesn't matter from where actually)
I've heard and used before - org.springframework.beans.factory.config.PropertyPlaceholderConfigurer However it retrieves values from a property file, which is not exactly what I need.
Could you please advise my direction?
I want to put instead of this property some class that will retrieve value of this property from some in memory cache (doesn't matter from where actually)
How about injecting your txManager into this some class and set the defaultTimeout there?
Try looking into the com.typesafe.config library https://www.javadoc.io/doc/com.typesafe/config/1.2.1. This allows you to load configuration files.
Use this library to create a bean of type config. Something like this. This is a java configuration, but could be adapted to an XML implementation.
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = "com.your.package")
public class WebMvcConfig extends WebMvcConfigurerAdapter {
#Bean
public Config properties() throws Exception {
String path = ""; // path to properties file
Config conf = ConfigFactory.parseFile(new File(path));
return conf;
}
}
Then in your component classes, you can autowire the bean and use the properties stored in the in memory bean.
#Autowired
private Config properties;
...
properties.getString("your property key");
I'm trying to learn pure Spring and to do that i'm converting my Spring-boot application to spring with pure xml configuration.
My question is how can I obtain session scoped property through xml configuration?
Right now i've got this:
#Autowired
private
ConcurrentHashMap<String,Subscription> subscriptionConcurrentHashMap;
(...)
#Bean
#SessionScope
private ConcurrentHashMap<String, Subscription> getConcurrentHashMap(){
return new ConcurrentHashMap<>();
}
And it works, but i'm not sure how to define generic java class as session scoped bean in xml.
I've found a way to this like that:
<bean name="subscriptionConcurrentHashMapBean" class="java.util.concurrent.ConcurrentHashMap" scope="session">
<aop:scoped-proxy/>
</bean>
and then just reference in controller bean:
<property name="subscriptionConcurrentHashMap" ref="subscriptionConcurrentHashMapBean"/>
Generic type of this hashMap apparently doesn't matter
Currently I'm converting the xml to java config. But I stuck at some part that I have been research for several days. Here the problem:
Xml config:
<jee:jndi-lookup id="dbDataSource" jndi-name="${db.jndi}" resource-ref="true" />
<beans:bean id="jdbcTemplate"
class="org.springframework.jdbc.core.JdbcTemplate" >
<beans:property name="dataSource" ref="dbDataSource"></beans:property>
</beans:bean>
So far I managed to convert this code:
<jee:jndi-lookup id="dbDataSource" jndi-name="${db.jndi}" resource-ref="true" />
to this :
#Bean(name = "dbDataSource")
public JndiObjectFactoryBean dataSource() {
JndiObjectFactoryBean bean = new JndiObjectFactoryBean();
bean.setJndiName("${db.jndi}");
bean.setResourceRef(true);
return bean;
}
And this :
<beans:bean id="jdbcTemplate"
class="org.springframework.jdbc.core.JdbcTemplate" >
<beans:property name="dataSource" ref="dbDataSource"></beans:property>
</beans:bean>
to this:
#Bean(name = "jdbcTemplate")
public JdbcTemplate jdbcTemplate() {
JdbcTemplate jt = new JdbcTemplate();
jt.setDataSource(dataSource);
return jt;
}
The problem is the method setDataSource() need DataSource object but I'm not sure how to relate both bean.How to pass the JndiObjectFactoryBean to DataSource?
Or do I need to use another method?
Extra Question:
The bean.setJndiName("${db.jndi}") , ${db.jndi} is refer to properties file but I always got NameNotFoundException, How to make it work?
Thanks!!
Instead of JndiObjectFactoryBean use a JndiDataSourceLookup instead. To use the ${db.jndi} in the method declare a method argument and annotate it with #Value.
#Bean(name = "dbDataSource")
public DataSource dataSource(#Value("${db.jndi}") String jndiName) {
JndiDataSourceLookup lookup = new JndiDataSourceLookup();
return lookup.getDataSource(jndiName);
}
Autowired methods and constructors can also use the #Value annotation. -- Spring Reference Guide.
#Bean methods are basically factory methods which are also auto wired methods and as such fall into this category.
In your factory method for the JdbcTemplate you can simply use a DataSource method argument to get a reference to the datasource (If you have multiple you can use the #Qualifier on the method argument to specify which one you want to use).
#Bean
public JdbcTemplate jdbcTemplate(DataSource ds) {
return new JdbcTemplate(ds);
}
I was trying to get file path from property file using #Value annotation, but getting Null.
My Property File is like
filepath=file:/src/main/resources/usmr/input/redemption.txt
My xml File is like that
<bean id="USMRFileReader" class="com.aexp.earn.api.batch.util.readers.USMRFileReader" />
<util:properties id="batchProps"
location="classpath:earn-api-batch_e0.properties" />
<batch:job id="balancingUSMRFileJob">
<batch:step id="step1">
<batch:tasklet>
<batch:chunk reader="USMRFileReader" writer="ControlReportWriter" processor="USMRListProcessor" commit-interval="1"></batch:chunk>
</batch:tasklet>
</batch:step>
</batch:job>
And My Java file is like that
#Component(value = "USMRFileReader")
#Scope("step")
public class USMRFileReader implements ItemReader<String> {
private static final Logger ILOGGER = LoggerFactory.getLogger(LoggerUtil.LOGGER_BATCH);
#Value("${batchProps['filepath']}")
private Resource resource;
But while executing this, null value is passing in resource variable.
Please Help
You can easy do that via #PropertySource annotation. So, for example your class should have #PropertySource annotation like this:
#PropertySource("classpath:earn-api-batch_e0.properties")
#Component(value = "USMRFileReader")
#Scope("step")
public class USMRFileReader implements ItemReader<String> { ... }
Then inject your resource:
#Value("${filepath}")
private Resource resource;
And voila! Trick is done.
Also, make sure you have PropertyPlaceholderConfigurer defined somewhere in order to read properties:
#Bean
public static PropertySourcesPlaceholderConfigurer propertyPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
You can use property-placeholder instead of util:properties
Replace this
<util:properties id="batchProps"
location="classpath:earn-api-batch_e0.properties" />
with below
<context:property-placeholder location="classpath:earn-api-batch_e0.properties"/>
Then you can get the property value from component:
#Component(value = "USMRFileReader")
#Scope("step")
public class USMRFileReader implements ItemReader<String> {
private static final Logger ILOGGER = LoggerFactory.getLogger(LoggerUtil.LOGGER_BATCH);
#Value("${filepath}")
private String resource;
EDIT:
Add context namespace in your configuration file
<beans xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/context">
Inject the complete environment into a bean and debug it in order to see, which properties are really loaded from which resource.
#Environment
private Environment env;
The Environment implements the PropertyResolver interface, which is your gate to all properties, that are loaded by the spring context. Debug the concrete implementation, that is injected.
Check if your file is really being loaded and that the property is there. Check if it is not somehow overwritten and set to null by something with a higher precedence.
If the property is in the Environment (you can check that easily by simply calling env.getProperty("filepath")), then this means, that your #Value annotation does not resolve the SPEL expression. This happens if you don't have
#Bean
public PropertySourcesPlaceholderConfigurer propertyPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
in a class that is handled by the component-scan.
How can i inject a properties file containing a Map to be used as additional constructor arg using the field.
With a Map being loaded from a properties file
the bean is currently setup using:
<bean id="graphDbService" class="org.neo4j.kernel.EmbeddedGraphDatabase"
init-method="enableRemoteShell" destroy-method="shutdown">
<constructor-arg index="0" value= "data/neo4j-db"/>
<constructor-arg index="1" value=? />
</bean>
Java Equivalent:
Map<String,String> configuration = EmbeddedGraphDatabase.loadConfigurations( "neo4j_config.props" );
GraphDatabaseService graphDb = new EmbeddedGraphDatabase( "data/neo4j-db", configuration );
Thanks
Something like this:
<bean id="configuration" class="org.neo4j.kernel.EmbeddedGraphDatabase"
factory-method="loadConfigurations">
<constructor-arg value="neo4j_config.props"/>
</bean>
<bean id="graphDbService" class="org.neo4j.kernel.EmbeddedGraphDatabase"
init-method="enableRemoteShell" destroy-method="shutdown">
<constructor-arg index="0" value="data/neo4j-db"/>
<constructor-arg index="1" ref="configuration" />
</bean>
This takes advantage of the ability to create beans using arbitrary static factory methods, in this case using loadConfigurations() as a factory method to create the configuration bean, which is then injected into the proper constructor of EmbeddedGraphDatabase.
Create a bean that loads the properties (and takes the file name as an argument) and inject that instead.
EDIT When using annotations, things like constructor injection become more simple:
#Bean
public Map<String,String> configuration() {
return EmbeddedGraphDatabase.loadConfigurations( "neo4j_config.props" );
}
#Bean
public GraphDatabaseService graphDb() {
return new EmbeddedGraphDatabase( "data/neo4j-db", configuration() );
}
Note that the second bean definition method "simply" calls the first. When this code is executed, Spring will do some magic so you can still override the bean elsewhere (i.e. beans still overwrite each other) and it will make sure that the method body will be executed only once (no matter how often and from where it was called).
If the config is in a different #Configuration class, then you can #Autowired it:
#Autowired
private Map<String,String> configuration;
#Bean
public GraphDatabaseService graphDb() {
return new EmbeddedGraphDatabase( "data/neo4j-db", configuration );
}