I have a requirement to pass dynamic environment name as a prefix of configuration property. I will pass environment as VM argument from command line and all properties should be loaded for that environment.
My Configuration:
#Configuration
#EnableConfigurationProperties
#PropertySource("environmentDetails.yml")
#ConfigurationProperties(prefix="${environment}")
public class ConfigurationBean {
private String brokerUrl;
private String queueName;
private String receiverUserName;
private String receiverPassword;
public String getBrokerUrl() {
return brokerUrl;
}
public void setBrokerUrl(String brokerUrl) {
this.brokerUrl = brokerUrl;
}
public String getQueueName() {
return queueName;
}
public void setQueueName(String queueName) {
this.queueName = queueName;
}
public String getReceiverUserName() {
return receiverUserName;
}
public void setReceiverUserName(String receiverUserName) {
this.receiverUserName = receiverUserName;
}
public String getReceiverPassword() {
return receiverPassword;
}
public void setReceiverPassword(String receiverPassword) {
this.receiverPassword = receiverPassword;
}
}
environmentDetails.yml
spring:
profiles.active: default
---
spring:
profiles: default
environment:
brokerUrl: http://ip:port
queueName: testQueue
receiverUserName: testuser
receiverPassword: password
Here is the issue: You can't use .yml with #PropertySource: boot-features-external-config-yaml-shortcomings
YAML files can’t be loaded via the #PropertySource annotation. So in the case that you need to load values that way, you need to use a properties file.
You'll have to convert to .properties to do this.
Related
I'm following the 24.8.3 Merging Complex Types section of Spring Boot's 24. Externalized Configuration documentation.
I have this config.yaml file:
acme:
list:
- name: my name
description: my description
- name: another name
description: another description
The Properties file looks like this:
#ConfigurationProperties("acme")
#YamlPropertySource(value = { "classpath:/config.yaml" })
public class AcmeProperties {
private final List<MyPojo> list = new ArrayList<>();
public List<MyPojo> getList() {
return this.list;
}
}
The MyPojo class:
public class MyPojo {
private String name;
private String description;
public MyPojo(String name, String description) {
this.name = name;
this.description = description;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}
The test, which fails, looks like this:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = { AcmeProperties.class })
public class AcmePropertiesTest {
#Autowired
private AcmeProperties properties;
#Test
public void getOpScoringClusters() {
Assert.assertEquals(2, properties.getList().size()); // FAIL!
}
}
Spring Boot version 1.5.6.
Basically I want to have a list of typed properties. What am I doing wrong?
Several comments have highlighted multiple issues with the code presented.
Firstly, the fields inside a configuration properties can't be final as spring uses the setter to set the value.
Secondly, #YamlPropertySource is not something provided by spring so won't do anything in this context.
Thirdly, even if you did use the spring PropertySource annotation, unfortunately you can't use it with yaml files.
YAML files cannot be loaded by using the #PropertySource annotation.
I've created a sample project that uses the code you presented and has been modified so that it passes the unit test. It's using spring boot 2.x instead of 1.x but the only significant difference should be the annotations used in the test class.
https://github.com/michaelmcfadyen/spring-boot-config-props-demo
I try to initialize a Map in my SpringBoot application but I am doing something wrong.
My config.properties:
myFieldMap.10000.fieldName=MyFieldName
myFieldMap.10000.fieldName2=MyFieldName2
myFieldMap.10001.fieldName=MyFieldName
myFieldMap.10001.fieldName2=MyFieldName2
myFieldMap.10002.fieldName=MyFieldName
myFieldMap.10003.fieldName2=MyFieldName2
...
(Isn't it possible to use some kind of bracket notation like myFieldMap[10001].fieldName for maps (I saw it used for lists).
I tried with my MyConfig.class:
#PropertySource("classpath:config.properties")
#Component
public class MyConfig {
private java.util.Map<Integer, MyMapping> theMappingsMap = new HashMap<Integer, MyMapping>();
public Map<String, MyMapping> getTheMappingsMap() {
return theMappingsMap;
}
public void setTheMappingsMap(Map<String, MyMapping> theMappingsMap) {
this.theMappingsMap= theMappingsMap;
}
public class MyMapping {
private String fieldName;
private String fieldName2;
public String getFieldName() {
return fieldName;
}
public String getFieldName2() {
return fieldName2;
}
public void setFieldName(final String fieldName) {
this.fieldName = fieldName;
}
public void setFieldName2(final String fieldName) {
this.fieldName2 = fieldName;
}
}
}
How do I have to adapt my code to let SpringBoot initialize my configuration (Map) with the definitions in the config.properties file?
You are missing #ConfigurationProperties annotation. Try this
#PropertySource("classpath:config.properties")
#Configuration
#ConfigurationProperties
public class MyConfig {
private java.util.Map<String, MyMapping> myFieldMap = new HashMap<>();
....
}
Another issue with your code is, if you want to make MyMapping class as an inner class of MyConfig, then you need to declare it as static. Or else you can make it as a separate class.
I have a property file with key/value pairs that looks like below:
#state/city/counties
fl.regionA.counties=abc,def,ghi,jkl
fl.regionB.counties=xyz,qrs,tuv,wxy
The property file is loaded via code snippet below:
#Configuration
public class Config {
#Bean
public static PropertyPlaceholderConfigurer properties(){
...
}
How can I load the a list of StateRegionMappings where StateRegionMapping:
public class StateRegionMapping{
private List<String> counties;
private String state;
private String region;
...
}
Update 5/23/2017:
My other alternate key/value structure is like this:
states.config[0].state=fl
states.config[0].name=regionA
states.config[0].counties=abc,def,ghi,jkl
states.config[1].state=fl
states.config[1].name=regionB
states.config[1].counties=xyz,qrs,tuv,wxy
If I get you right, you want to configure a list of states where each state has a region and each region a list of counties. With properties files this would look like this:
states-config.states[0].name=fl
states-config.states[0].regions[0].name=regionA
states-config.states[0].regions[0].counties[0]=abc
states-config.states[0].regions[0].counties[1]=def
states-config.states[0].regions[0].counties[2]=ghi
states-config.states[0].regions[0].counties[3]=jkl
states-config.states[0].regions[1].name=regionB
states-config.states[0].regions[1].counties[0]=xyz
states-config.states[0].regions[1].counties[1]=qrs
states-config.states[0].regions[1].counties[2]=tuv
states-config.states[0].regions[1].counties[3]=wxy
With YAML this is a bit more readable:
states-config:
states:
- name: fl
regions:
- name: regionA
counties:
- abc
- def
- ghi
- jkl
- name: regionB
counties:
- xyz
- qrs
- tuv
- wxy
The needed java config would look like this:
#ConfigurationProperties("states-config")
public class Config {
private List<State> states = new ArrayList<>();
public List<State> getStates() {
return states;
}
public void setStates(List<State> states) {
this.states = states;
}
public static class State {
private String name;
private List<Region> regions = new ArrayList<>();
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Region> getRegions() {
return regions;
}
public void setRegions(List<Region> regions) {
this.regions = regions;
}
}
public static class Region {
private String name;
private List<String> counties = new ArrayList<>();
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<String> getCounties() {
return counties;
}
public void setCounties(List<String> counties) {
this.counties = counties;
}
}
}
To your update: this would work with the following config using your StateRegionMapping class:
#ConfigurationProperties("states")
public class Config {
private List<StateRegionMapping> config = new ArrayList<>();
public List<StateRegionMapping> getConfig() {
return config;
}
public void setConfig(List<StateRegionMapping> config) {
this.config = config;
}
}
Just one minor change: since in your StateRegionMapping class the region is named region, your must use this also in the properties instead of name:
states.config[0].state=fl
states.config[0].region=regionA
....
It is absolutely possible! Try this.
This should be present in your class where you want to load.
#Value("#{${passingscore.subjectwise}}")
private Map<String, String> passingScorePerSubjectMap;
The should be present in the application.properties file and define the key-value map properties like below.
passingscore.subjectwise= {'Maths': '40','Physics':'50','Chemistry':'70'}
I have a locations.properties file which looks like this:
location.endpoint=testadres,andertestadres
location.test=teststring
I'm trying to read this config file with following class:
#Configuration
#PropertySource("classpath:locations.properties")
public class LocationProperties {
#Value("#{'${location.endpoint}'.split(',')}")
private List<String> locations;
#Value("${location.test}")
private String test;
public String getTest() {
return this.test;
}
public List<String> getLocations() {
return this.locations;
}
//To resolve ${} in #Value
#Bean
public static PropertySourcesPlaceholderConfigurer propertyConfigInDev() {
return new PropertySourcesPlaceholderConfigurer();
}
}
But whenever I try to get the strings with getLocations() or getTest() I get null?
Just add .properties or .yml file to your /resources folder. Example
# simple.yml
demo:
connection:
username: sample
sample: My text
and add POJO class
#Component
#ConfigurationProperties(
prefix = "demo.connection",
locations = "classpath:sample.yml"
)
public class SampleSettings {
private String sample;
private String username;
..Getters and Setters mandatory
I'm using spring-config-server. I have it working, but Ideally, I'd like to generate a list of servers in a .yaml file that have properties.
#Resource
private List<Server> servers;
then:
#Component
public class Server {
#Value("${server.name}")
private String name;
}
in the (applicationName).yaml file:
servers:
-
name: test
-
name: test2
See I want a List<Server> generated dynamically from a config. The fact that this config is on a config server shouldn't be that different from a local .yaml file right?
Thanks for any help
we figured this out...
Trinity:
test: Goober
servers:
-
name: test
jmxURL: jmx://test
-
name: test2
jmxURL: jmx://test
that's the config (in config server)... this is the code
#Component
#EnableAutoConfiguration
#EnableConfigurationProperties
#ConfigurationProperties(prefix="Trinity")
public class ConfigFetcher {
List<Server> servers;
public List<Server> getServers() {
return servers;
}
public void setTest(String test) {
this.test = test;
}
public void setServers(List<Server> servers) {
this.servers = servers;
}
#EnableConfigurationProperties
#ConfigurationProperties(prefix="Trinity.servers")
public static class Server{
private String name;
private String jmxURL;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getJmxURL() {
return jmxURL;
}
public void setJmxURL(String jmxURL) {
this.jmxURL = jmxURL;
}
#Override
public String toString() {
return "Server [name=" + name + ", jmxUrl=" + jmxURL + "]";
}
}
}
in the main class (in my service in this case):
with the class having the following annotation
#EnableAutoConfiguration
#Autowired
private ConfigFetcher c;