I have 2 URLs among which 1 is specific to Dev and the other to Prod.
I am also using Spring profiling where i have seperate file for dev and prod application-dev.properties and application-prod.properties and my
appication.properties file look like this for Dev env
spring.profiles.active=dev
Now in my java code i want to have one property which will bind to the appropriate value depending on the spring profile i am using. How can i do it.
Current Java Class:-
//DEV
private static final String WIND_RESOURCE_EXTRACTOR_URL = "https://localhost:9090/dev";
//FOR PROD
//private static final String WIND_RESOURCE_EXTRACTOR_URL = "https://localhost:9090/prod";
SO i want to mention this properties in my application-dev.properties or application-prod.properties file and my java class should pick the correct value based on the current spring profile.
You just need to inject the value from your properties file. Assuming all the setup has already been done to read from the properties to the enviroment, i assume it has been.
public class MyClazz {
private final String myUrl;
#Autowired
public MyClazz(#Value("${my.url.property.name}") String myUrl){
this.myUrl = myUrl;
}
and within your two properties files place a my.url.property.name=WhateverValueIwant.
Related
I have the following settings in my spring-boot project
application.properties:
file_path=${lookup_path}
lookup-file.file_1=${file_path}/file1.lku
lookup-file.file_2=${file_path}/file2.lku
and a corresponding config class LookupFileConfiguration, and also handler class to use this configuration:
#Component
#ConfigurationProperties("lookup-file")
public class LookupFileConfiguration {
private String file_1;
private String file_2;
// getter and setter methods skipped here
}
#Component
public class MyHandler {
#Autowired
private LookupFileConfiguration files;
}
I tried to run from command line:
mvn test -Drun.arguments=--lookup_path=C:\\my-proj\target\test-classes\lookupFiles\\
But it is not working. lookup_path seems not be used in the application.properties.
If I hard-code in application.properties file
file_path=C:\\my-proj\target\test-classes\lookupFiles\\
it is working fine.
I know I can use profiles for different environments. However, my project will run test cases in Bamboo plan. So I can only use bamboo variable ${bamboo_build_working_directory} but cannot predict the directory for test. Please help with a proper solution/suggestion for such case.
Problem:
I have 3 parts in the software:
Client A service
Client B service
Target C service
I want to connect to C from A and B
I wrote a library with following setup:
/src/main/java/pkg.../TargetConnector.java
/src/main/java/pkg.../TargetConfig.java
/src/main/resources/application-dev.properties
/src/main/resources/application-tst.properties
/src/main/resources/application-prd.properties
My clients A and B both have there own sources and properties:
/src/main/java/pkg.../Client{A/B}Service.java
/src/main/java/pkg.../Client{A/B}Config.java
/src/main/resources/application-dev.properties
/src/main/resources/application-tst.properties
/src/main/resources/application-prd.properties
The properties of the Connector contains some login info for the service e.g.
target.url=https://....
target.usr=blablabla
target.key=mySHAkey
which is used in the TargetConfig to preconfigure the Connector e.g.
#Value("target.url")
String url;
#Value("target.usr")
String usr;
#Value("target.key")
String key;
#Bean
public TargetConnector connector() {
return new TargetConnector(url, usr, key);
}
Now when I use the connector jar in the client I can find the configuration via packagescan. The connector class is loaded but the problem is that it does not load the properties files.
Research
I found that multiple property files cannot have the same name (e.g. clients application-{profile}.properties clashes with the one from the connector), so I tried to rename application-{profile}.properties of the targetConnector to application-connector-{profile}.properties.
The properties whoever still do not get loaded, (which makes sense since I do not have a e.g connector-dev profile but my profile is simply named dev).
Furthermore, even if I try to explicitly load one of the property files from the connector with:
#PropertySource({"classpath*:application-connector-dev.properties"})
it cannot be found
Question
My question is actually 3 tiered:
How can I load a property file in a dependency jar at all?
How can I load the profiled version of the property file if the the properties file has a different name than application.properties? e.g. application-connector.properties
How can i combine the answers from question 1 and 2 to load the profiled version of the property in the jar?
If further explanation is needed, please ask.
Answer
I went for an approach as given in the accepted answer.
I Just created 3 configs for the dev, tst, prd profiles containing the values needed and annotated the config files with the correct profiles.
You are using #Configuration annotated class. Maybe you can have one per profile. Here you are an example:
#Configuration
#Profile("profileA")
#PropertySource({"classpath:application-profileA.properties"})
public class ConfigurationProfileA{
#Value("${target.url}")
String url;
#Value("${target.usr}")
String usr;
#Value("${target.key}")
String key;
#Bean
public TargetConnector connector() {
return new TargetConnector(url, usr, key);
}
}
Do the same for profile B (maybe you can structure this better but the key points here are the annotation #Profile("") and #PropertySource(""))
Once you have your config class, Spring will use the Configuration class you want by just filling -spring.profiles.active=profileA (or the name of the profile you have written in the #Profile("") annotation)
I think there is a typo in this line #PropertySource({"classpath*:application-connector-dev.properties"})
Please check by removing the asterik.
In order to run with a specific profile, you can run with option -spring.profiles.active=dev for example
If you don’t run with a profile, it will load the default profile in application.properties that you don’t seem to have.
Furthermore, an advice would be to always have an application.properties and put in it the common properties and the default values that you would override in other properties files.
Other mistake is how you assign properties with #Value annotation, you need to use #Value("${PROPERTY_FROM_PROPERTIES_FILE}")
I have a properties file called xyz.properties. Right now, I am able to load individual property of this file in my class annotated with #Component which is working perfectly fine.
However, I am thinking of making my project more modular, for which I need to read the whole xyz.properties file as one properties object so that i can pass it along. How can I do so ?
Update
Right now, I am loading individual property from the file like this
my applicationContext.xml has following entry
<context:property-placeholder location="classpath:xyz.properties" order="2" ignore-unresolvable="true"/>
and then i have the respective class as
#Component
public class XyzConfiguration {
#Value("${client.id}")
private String clientId;
#Value("${client.secret}")
private String clientSecret;
...
}
What I mean by pass it along
Right now, for each individual property I have to create a respective field in a class and then annotate it with respective property name. By doing so, I am making my nested module very spring framework specific. I might someday put this module on github for others as well and they may or may not use spring framework. For them it would be easier to create an object of this module by passing required parameters (ideally in case of a Properties object) so that my module will fetch the properties by itself.
You can try below code.
import org.springframework.core.io.support.PropertiesLoaderUtils;
import org.springframework.core.io.ResourceLoader;
import java.util.Properties;
private String fileLocator;
private Properties prop;
private ResourceLoader resourceLoader;
public void init() throws IOException {
//"fileLocator" must be set as a path of file.
final Resource resource = resourceLoader.getResource(fileLocator);
prop = PropertiesLoaderUtils.loadProperties(resource);
}
prop will have all values from your property file and then you can get any value by calling prop.getProperty() method.
Using Spring Boot 1.3.0.RELEASE
I have a couple of yaml files that describe several instances of a program. I now want to parse all those files into a List<Program> (Map, whatever), so I can later on search for the most appropriate instance for a given criteria in all the programs.
I like the approach with #ConfigurationProperties a lot, and it works good enough for a single yaml-file, but I haven't found a way yet to read all files in a directory using that method.
Current approach working for a single file:
programs/program1.yml
name: Program 1
minDays: 4
maxDays: 6
can be read by
#Configuration
#ConfigurationProperties(locations = "classpath:programs/program1.yml", ignoreUnknownFields = false)
public class ProgramProperties {
private Program test; //Program is a POJO with all the fields in the yml.
//getters+setters
I tried changing the locations to an Array listing all of my files locations = {"classpath:programs/program1.yml", "classpath:programs/program2.yml"} as well as using locations = "classpath:programs/*.yml", but that still only loads the first file (array-approach) or nothing at all (wildcard-approach).
So, my question is, what is the best way in Spring Boot to load a bunch of yaml files in a classpath-directory and parse them into a (List of) POJO, so they can be autowired in a Controller? Do I need to use Snakeyaml directly, or is there an integrated mechanism that I just haven't found yet?
EDIT:
A working approach is doing it manually:
private static final Yaml yaml = new Yaml(new Constructor(Program.class));
private static final ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
try {
for (Resource resource : resolver.getResources("/programs/*.yml")) {
Object data = yaml.load(resource.getInputStream());
programList.add((Program) data);
}
}
catch (IOException ioe) {
logger.error("failed to load resource", ioe);
}
In Spring, it is possible to load multiple configuration properties files using PropertySource annotation, but not YAML files. See section 26.6.4 in link below:
https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html#boot-features-external-config-typesafe-configuration-properties
However, from your problem, it seems that you can configure all your programs in single YAML and then get all list of programs in a single list.
Sample YAML (all.yaml)
programs:
- name: A
min: 1
max: 2
- name: B
min: 3
max: 4
Config.java
#Configuration
#ConfigurationProperties(locations={"classpath:all.yaml"})
public class Config{
private List<Program> programs;
public void setPrograms(List<Program> programs) {
this.programs = programs;
}
public List<Program> getPrograms() {
return programs;
}
}
What I am currently doing, as far as I understood your question, is nearly the same.
I am having an application.yml and also profile-specific yml files, e.g. application-{profile}.yml in my src/main/resources.
In the application.yml I have defined the default profile key-values, which are partially overridden by the profile-specific yml files.
If you want to have a type-safe and well defined access of your YML key/values, then you can use the following approach:
#ConfigurationProperties
public class AppSettings {
String name; // has to be the same as the key in your yml file
// setters/getters
}
In your Spring-Boot config, you have to add the following annotations onto your config class:
#ComponentScan
#EnableAutoConfiguration
#EnableConfigurationProperties( value = { AppSettings.class, SomeOtherSettings.class } )
public class SpringContextConfig {
#Autowired
private AppSettings appSettings;
public void test() {
System.out.println(appSettings.getName());
}
}
The #Autowiring is also accessible from other Beans.
The other way around (without an extra separated and type-safe class, is to access the YML-values via #Value("${name}").
To bring it together in a short manner:
Yes, it is possible to use several YAML files for your application via Spring-profiles. You define your current active spring profile via command args, programmatically or via your system env (SPRING_PROFILES_ACTIVE=name1,name2).
Therefore you can have several application.yml files for each profile (see above).
I have a properties file myprops.properties as follows:
Wsdl=someurl
UserName=user
UserPassword=pasword
Application=appName
And inside my controller I'm trying to access to set values in my service as follows
Properties prop = new Properties();
prop.load(new FileInputStream("resources/myprops.properties"));
myService.setWsdl(prop.getProperty("Wsdl"));
myService.setUserName(prop.getProperty("UserName"));
myService.setUserPassword(prop.getProperty("UserPassword"));
myService.setApplication(prop.getProperty("Application"));
my Issue is I just do not know what path to use. Its a Spring project if that makes any difference. and Idealy I would like to have the properties file in my "src/main/resources" folder
I realise this may be very simple to some but I have tried searching for the solution both here and on Google and I cannot seem to find a solution that has helped. I've tried moving the file around the project but cannot seem to figure it out
The Error I get is
java.io.FileNotFoundException: resources\drm.properties (The system cannot find the path specified)
any advice/explanation or even a link that clearly explains it would be great
well, src/main/resources are on the classpath, you just need to do.
Properties properties = PropertiesLoaderUtils.loadAllProperties("your properties file name");
If you are using spring, you could set your property placeholder.
<context:property-placeholder location="classpath:resources/myprops.properties" />
and in your beans you can inject the values from the properteis using the #Value annotation
#Autowired
public Foo(#Value("${Wsdl}") String wsdl) {
...
}
in the case above I used in the constructor, but its possible to use by Autowired field/setter.
So in your service you could have something like:
#Service
public class MyService {
private final String wsdl;
private final String username;
private final String password;
private final String application;
#Autowired
public MyService(
#Value("${Wsdl}") String wsdl,
#Value("${UserName}") String username,
#Value("${UserPassword}") String password,
#Value("${Application}") String application
) {
// set it to each field.
}
}
Given that src/main/resources is on the classpath, you could do:
Resource resource = new ClassPathResource("/myprops.properties");
Properties props = PropertiesLoaderUtils.loadProperties(resource);
Don't use a FileInputStream; use getResourceAsStream() to read it from the servlet context.
You can always count on mkyong. This is an example/tutorial on how to load and read property files.
http://www.mkyong.com/java/java-properties-file-examples/
This question should be marked as a duplicate:
Loading a properties file from Java package
How to use Java property files?
Load a property file in Java
Java Properties File not loading
Java NullPointerException on loading properties file
Not able to load properties file in Java