How to combine two environment variable in #Value annotation - java

I have application.yaml as following
environment: ${ZK_ENVIRONMENT}
END_POINT_URL:
dev: http://sampledev.uk.com
qa: http://sampleqa.uk.com
prod: http://sampleprod.uk.com
environment values can be dev,qa or prod. I need o inject END_POINT_URL based on environment in #Value.Tried the following, it's not working.
#Value("${END_POINT_URL}.${environment}")
private String url;

This should work, just did a quick test as well
#Value("${END_POINT_URL.${environment}}")
#SpringBootApplication
public class DemoApplication {
#Value("${END_POINT_URL.${environment}}")
private String value;
#PostConstruct
public void init() {
System.out.println(value);
}
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
ZK_ENVIRONMENT:dev
Output : http://sampledev.uk.com

Related

#ConfigurationProperties and #EnableConfigurationProperties cannot bind any properties in .yml or .properties

I want to new a project like mybatis-spring-boot-starter, I use springboot 2.3.2, but something wrong.
First of all, I define a BatisProperties.java like following:
#ConfigurationProperties(prefix = BatisProperties.MYBATIS_PREFIX)
public class BatisProperties {
public static final String MYBATIS_PREFIX = "batis";
private String MyClassName;
...
}
then, a BatisAutoConfiguration.java
#Configuration
#ConditionalOnClass({ SqlSessionFactory.class, SqlSessionFactoryBean.class })
#EnableConfigurationProperties(BatisProperties.class)
public class BatisAutoConfiguration implements InitializingBean {
private final BatisProperties properties;
#Override
public void afterPropertiesSet() throws Exception {
checkConfigFileExists();
}
private void checkConfigFileExists() {
System.out.println(this.properties.getMyClassName());//null here
if (this.properties.isCheckConfigLocation() && //code from mybatis-spring-booot-starter
StringUtils.hasText(this.properties.getConfigLocation())) {
Resource resource = this.resourceLoader.getResource(this.properties.getConfigLocation());
Assert.state(resource.exists(),
"Cannot find config location: " + resource + " (please add config file or check your Mybatis configuration)");
}
}
And in /resource/META_INF/spring.factories
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
xxx.BatisAutoConfiguration
above are all in a starter, I compile it to a jar file and use this jar file in another project(project TWO), in project TWO, I define .properties or .yml in /resource directory, contents are:
batis.my-class-name=xxxx.xxxx
Finally, a DemoApplication.java or Test.java like following:
DemoApplication.java
#SpringBootApplication
public class DemoApplication {
#Autowired
private BatisProperties properties;
private static BatisProperties batisProperties;
#PostConstruct
public void init() {
batisProperties = properties;
}
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
System.out.println(batisProperties.toString());//xxxx.BatisProperties#436390f4
System.out.println(batisProperties.getMyClassName());//null
}
}
Test.java
#SpringBootTest
class Test {
#Autowired
private BatisProperties properties;
#Test
void contextLoads() {
System.out.println(properties);// some bean in Spring IOC
System.out.println(properties.getDatasourceConfigProviderClassName());// null
}
}
Above comments are the results: We can find BatisProperties Bean in Spring IOC, but all properties are null.
So anybody can help? I don't know whether it is caused by the version of SpringBoot
I would improve the BatisProperties class to be as:
#Configuration
#ConfigurationProperties(prefix = "batis")
public class BatisProperties {
private String MyClassName;
...
// Make sure you have getters and setter for properties!
// If you use Lombok, put #Data on this class.
...
}
There is no need to explicitly have BatisAutoConfiguration.java. Just let Spring initialize it for you. Completely remove the class BatisAutoConfiguration.java. Also do not use static fields for the property class.
Try the following:
#SpringBootApplication
#EnableAutoConfiguration
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
Or also more explicit, but not needed:
#SpringBootApplication
#ComponentScan(basePackages = {"my.app.org"}) // prefix, where BatisProperties is
#EnableAutoConfiguration
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
or:
#SpringBootApplication
#EnableAutoConfiguration
#Import(BatisProperties.class)
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
The BatisProperties should be available anywhere in your App.

how to set application.properties runtime through API?

I want to update the application.properties when i login the application.
public class DemoApplication {
#Value("${spring.application.webServer}")
private String webServer;
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
#RequestMapping("/setProperty")
public String webServer() {
return webServer;
}
}
I want to set the application.properties while calling setProperty endpoint.is it possible to do with spring boot!

Spring Boot loading a list from a config file returns empty list

I just created a really basic spring boot application using spring initializer and am trying things out. I want to load a list from a yaml configuration file, but it always returns empty.
I have a custom configuration class
#ConfigurationProperties("example-unit")
#EnableConfigurationProperties
public class ConfigurationUnit {
public List<String> confiList = new ArrayList<>();
public List<String> getConfiList() {
return this.confiList;
}
}
And my main class looks like this
#SpringBootApplication
public class DemoApplication {
static ConfigurationUnit configurationUnit = new ConfigurationUnit();
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
List<String> hello = configurationUnit.getConfiList();
System.out.print("");
}
}
I have put the application.yaml into resources folder.
example-unit:
- string1
- string2
- hello22
I searched here and online, but can't figure out what's the issue and nothing I changed helped. I know I must be doing something wrong.
This statement is wrong static ConfigurationUnit configurationUnit = new ConfigurationUnit();
you should not create the object
Spring only injects the properties into the beans that are handled by application context, and spring creates beans of classes that are annotated with # Configuration
ConfigurationUnit
#Configuration
#ConfigurationProperties("example-unit")
public class ConfigurationUnit {
public List<String> confiList;
public List<String> getConfiList() {
return this.confiList;
}
}
DemoApplication In the spring boot main get the bean from applicationcontext and from it get the list object
#SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
ApplicationContext context = SpringApplication.run(DemoApplication.class, args);
ConfigurationUnit unit = context.getBean("configurationUnit"):
System.out.print(unit. getConfiList());
}
}
Put your list under prefix.property. In your case example-unit.confi-list:. Usually provide a setter for your property: setConfiList(List<String> strings). But since you already initialized it as empty Array list this setter is obsolete says this. There is also advice to add Enable-annotation to Application class:
Application class should have #EnableConfigurationProperties annotation
Here is the reference on how Spring Bboot Configurtion Binding works.
Specifically for your question, this is an example of app that achives your goal:
application.yml
example-unit:
confiList:
- string1
- string2
- hello22
sources
#SpringBootApplication
#EnableConfigurationProperties(ConfigurationUnit.class)
public class DemoApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(DemoApplication.class, args);
ConfigurationUnit configurationUnit = context.getBean(ConfigurationUnit.class);
System.out.println(configurationUnit.getConfiList());
}
}
#ConfigurationProperties("example-unit")
public class ConfigurationUnit {
public List<String> confiList = new ArrayList<>();
public List<String> getConfiList() {
return this.confiList;
}
}
Here is an example :
Application.yml:
example-unit: string1,string2,hello22
ConfigurationUnit.class:
#Component
#PropertySource(value="classpath:application.yml")
public class ConfigurationUnit {
#Value("#{'${example-unit}'.split(',')}")
private List<String> confiList;
public List<String> getConfiList() {
return confiList;
}
}
DemoFileLoadApplication.class:
#SpringBootApplication
public class DemoFileLoadApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(DemoFileLoadApplication.class, args);
ConfigurationUnit configurationUnit = context.getBean(ConfigurationUnit.class);
System.out.println(configurationUnit.getConfiList());
}
}
Output:
[string1, string2, hello22]

Spring boot #Value is null

Before we start, yes I know there's another question out there but they are not the same issue and I couldn't find anything to solve this.
Ok, I have
package a
imports ...
#SpringBootApplication
public class LauncherApplication implements CommandLineRunner {
#Autowired
private SubListener subListener;
#Value("${proj.id}")
private String testy;
public static void main(String[] args) {
SpringApplication.run(LauncherApplication.class, args);
}
#Override
public void run(String... args) throws Exception {
System.out.println(subListener.getProjID());
System.out.println(testy);
}
}
Then on my subListener
package a.b
imports ...
#Component
public class SubListener {
#Value("${proj.id}")
private String projID;
public String getProjID() {
return projID;
}
}
and finally inside my resources folder on application.properties
proj.id=Hello from file
Now, by all accounts this should work, the SpringBootApplication has the component scan thing, the bean is marked as #component and is a subpackage of the springbootapplication, the properties file has the default name and in the default directory. I can't find a single reason for this not to work. Also mind you that when I call the property on testy it works, it only return null when it's returning from the sublistener.
Thank you for your time
EDIT:
New launcherApplication
#SpringBootApplication
public class LauncherApplication {
public static void main(String[] args) {
SpringApplication.run(LauncherApplication.class, args);
}
#Bean
public CommandLineRunner runner(SubListener subListener){
CommandLineRunner runner = new CommandLineRunner() {
#Override
public void run(String... args) throws Exception {
System.out.println(subListener.getProjID());
}
};
return runner;
}
}
It still returns null though
My only guess would be that the #Value annotation inside your SubListener class is from the wrong package. Can you please check that you are using this import and not something else:
import org.springframework.beans.factory.annotation.Value;
I've copied your code and it's working for me. If you still can't get it working then I'd recommend trying to reproduce it in a new empty project.

Can not read properties file based on active profile

Hello java programmers,
I have a problem with reading the properties file based on active profile. I have created a spring boot application and I would like to deploy my application for different environments such as development and production. I have searched quit a lot, but I could not find a solution for my problem.
I have set a profile in the edit configuration menu.
I have a properties file called application-dev.properties in my src/main/resources and I have a Settings.java where I would like to read the properties file.
This is my Settings.java
#Configuration
#Component
public class Settings {
private static Logger log = Logger.getLogger(Settings.class);
#Value("${TradingBot.production}")
public boolean isProduction;
#Value("${api.KEY}")
public static String API_KEY;
#Value("${api.ORDERS_URL}")
public static String ORDERS_URL;
#Value("${api.TRADES_URL}")
public static String TRADES_URL;
#Value("${api.PARTICIPANTS_URL}")
public static String PARTICIPANTS_URL;
#Value("${api.INDIVIDUAL_URL}")
public static String INDIVIDUAL_URL;
#Value("${api.BALANCE_URL}")
public static String BALANCE_URL;
#Value("${api.TRANSACTIONS_URL}")
public static String TRANSACTIONS_URL;
#Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer(){
return new PropertySourcesPlaceholderConfigurer();
}
}
According to the spring documentation this should be enough to read the correct properties file, unfortunately I get an empty String when I print the value.
When I run the project it will give me the following output.
2016-10-31 13:44:04.011 INFO 32992 --- [ main] TradingBot : The following profiles are active: dev
I hope someone can help me.
Thanks to M.Denium I knew what the problem was. I could solve it by adding the #Value property at the setter for Example:
public static String API_KEY;
public static String ORDERS_URL;
public static String TRADES_URL;
public static String PARTICIPANTS_URL;
public static String INDIVIDUAL_URL;
public static String BALANCE_URL;
public static String TRANSACTIONS_URL;
#Value("${api.KEY}")
public void setAPI_KEY(String API_KEY) {
this.API_KEY = API_KEY;
}
#Value("${api.ORDERS_URL}")
public void setORDERS_URL(String ORDERS_URL) {
this.ORDERS_URL = ORDERS_URL;
}
#Value("${api.TRADES_URL}")
public void setTRADES_URL(String TRADES_URL) {
this.TRADES_URL = TRADES_URL;
}
#Value("${api.PARTICIPANTS_URL}")
public void setPARTICIPANTS_URL(String PARTICIPANTS_URL) {
this.PARTICIPANTS_URL = PARTICIPANTS_URL;
}
#Value("${api.INDIVIDUAL_URL}")
public void setINDIVIDUAL_URL(String INDIVIDUAL_URL) {
this.INDIVIDUAL_URL = INDIVIDUAL_URL;
}
#Value("${api.BALANCE_URL}")
public void setBALANCE_URL(String BALANCE_URL) {
this.BALANCE_URL = BALANCE_URL;
}
#Value("${api.TRANSACTIONS_URL}")
public void setTRANSACTIONS_URL(String TRANSACTIONS_URL) {
this.TRANSACTIONS_URL = TRANSACTIONS_URL;
}
In this case the variable will still be static and it can get the value from the property file.

Categories