How can i get the value "TestValue" from application.properties file in springboot project. The messageVarible in not static final.
#Component
public class testMapper {
public String TestMessage() {
String message-variable = "TestValue";
// ...
}
}
you can add the property to application.properties or any other properties resource file loadable by spring boot. then you can read it inside your application like that
#Value("${messageVariable}")
private String messageVariable;
where you defined in your file like that
messageVariable=any message
or if you are using yaml file
messageVariable:any message
Related
If I have some global config properties value that want to set on application start up, one of the ways to do is by setting it in application.properties and then using #Value to inject those values. However, if I want to set the values by making an API call to get those properties value on application start up and then set the values (but want to use similar way as #Value), rather than getting and setting it via properties files, how should it be achieved ?
#Configuration
public class config {
#Value("${properties1}")
private String properties1;
#Value("${properties2}")
private String properties2;
}
I have done some web search on custom property source (https://projects.spring.io/spring-cloud/spring-cloud.html#customizing-bootstrap-property-sources), and tried to follow the example, but encountered the error that the placeholder could not be resolved. How to get back the value ?
Could not resolve placeholder 'property.from.sample.custom.source' in value "${property.from.sample.custom.source}"
#Configuration
public class CustomPropertySourceLocator implements PropertySourceLocator {
#Override
public PropertySource<?> locate(Environment environment) {
return new MapPropertySource("customProperty",
Collections.<String, Object>singletonMap("property.from.sample.custom.source", "worked as intended"));
}
}
#Service
public class MainService {
#Value("${property.from.sample.custom.source}")
private String value;
public void printValue() {
System.out.println("value - " + value);
}
}
Assuming you use Spring Boot, you can run the Spring Boot application and pass the arguments using the following Maven command (depends on the Spring Boot version):
Spring Boot 1.x: using -Drun.arguments:
spring-boot:run -Drun.arguments=--properties1=One,--properties2=Two
Spring Boot 2.x: using -Dspring-boot.run.arguments:
spring-boot:run -Dspring-boot.run.arguments=--properties1=One,--properties2=Two
Now you can access the values using the #Value annotation:
#Value("${properties1}")
private String properties1;
#Value("${properties2}")
private String properties2;
Note: Once the properties are defined in the properties files (ex. application.properties and/or application-dev.yml etc..), defined in the command line like above, they can be accessed through the #Value annotation.
Baeldung's website offers a nice article: Command-Line Arguments in Spring Boot.
I am not sure if we can set values to properties file after application is up. Because properties file will be injected to #Bean when application is running. But we can hack this.
First, Create a file that contains all the configuration file which will be load from properties file. This file will be our template and initial / default values of the configuration.
Let say we have below configuration as application.yml
config:
name: Anna
age: 18
Then create configuration file
#ConfigurationProperties(prefix = "config")
public class ConfigProperties {
private String name;
private Integer age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
Don't forget to modify our Application class
#SpringBootApplication
#EnableConfigurationProperties(ConfigProperties::class)
public class Application { ... }
Through here, we can just #Autowire the config class to get the value we want, rather than using a #Value.
Through here we already have the properties value to our config class. Then if you want to update the properties value (now already on config file) through an API, do a simple setName(...).
But, we have to be aware that this way is only work on a single run. When we restart the application, the value will use the default from properties file.
I know how I can access the application.properties values in #Service classes in Java Spring boot like below
#Service
public class AmazonClient {
#Value("${cloud.aws.endpointUrl}")
private String endpointUrl;
}
But I am looking for an option to access this value directly in any class (a class without #Service annotation)
e.g.
public class AppUtils {
#Value("${cloud.aws.endpointUrl}")
private String endpointUrl;
}
But this returns null. Any help would be appreciated.
I have already read here but didn't help.
There's no "magic" way to inject values from a property file into a class that isn't a bean. You can define a static java.util.Properties field in the class, load values from the file manually when the class is loading and then work with this field:
public final class AppUtils {
private static final Properties properties;
static {
properties = new Properties();
try {
ClassLoader classLoader = AppUtils.class.getClassLoader();
InputStream applicationPropertiesStream = classLoader.getResourceAsStream("application.properties");
applicationProperties.load(applicationPropertiesStream);
} catch (Exception e) {
// process the exception
}
}
}
You can easily achievw this by annotating ur app utils class with #component annotation . spring will take care of loading properties.
But if you don't want to do that approach , then look at the link below .
https://www.baeldung.com/inject-properties-value-non-spring-class
This may be silly question to ask but i'm unable to find any satisfactory solution to my problem. In java we don't have the concept of default variables so i am trying to give default value from properties file to my function parameters/arguments using #Value annotation, but i'm always getting null and i'm unable to figure why is this happening. Please help me to solve the issue or provide me some appropriate link/reference which may solve my issue.
MainApplication.java
#SpringBootApplication
public class Application
{
public static void main(String[] args)
{
ApplicationContext context = SpringApplication.run(NetappApplication.class, args);
Sample sample = context.getBean(Sample.class);
System.out.println(sample.check(null));
}
}
Sample.java
public interface Sample
{
public String check(String message);
}
SampleImpl.java
#Service
#PropertySource("classpath:app.properties")
public class SampleImpl implements Sample
{
#Value("${test}")
String message1;
#Override
public String check(#Value("${test}") String message)
{
return message;
}
}
app.properties
test=anand
But you are passing null to your method...
Perhaps what you want to do is to assign default value to test in case it's not defined in property file:
#Value("${test:default}");
Then, when properties are autowired by Spring if placeholder resolver doesn't get the value from props file, it will use what is after :.
The best use case for this (that I can think of) is when you create Spring configuration.
Let's say you have a configuration class: for DB access. Simply put:
#Configuration
public class DbConfig {
#Value("${url:localhost}")
String dbUrl;
// rest for driver, user, pass etc
public DataSource createDatasource() {
// here you use some DataSourceBuilder to configure connection
}
}
Now, when Spring application starts up, properties' values are resolved, and as I wrote above you can switch between value from property and a default value. But it is done once, when app starts and Spring creates your beans.
If you want to check incoming argument on runtime, simple null check will be enough.
#Value("${test}")
String message1;
#Override
public String check(String message) {
if (message == null) {
return message1;
}
}
My application expects to find a configuration file called MyPojo.json, loaded into MyPojo class by MyService class:
#Data // (Lombok's) getters and setters
public class MyPojo {
int foo = 42;
int bar = 1337;
}
It's not a problem if it doesn't exist: in that case, the application will create it with default values.
The path where to read/write MyPojo.json is stored in /src/main/resources/settings.properties:
the.path=cfg/MyPojo.json
which is passed to MyService through Spring's #PropertySource as follows:
#Configuration
#PropertySource("classpath:settings.properties")
public class MyService {
#Inject
Environment settings; // "src/main/resources/settings.properties"
#Bean
public MyPojo load() throws Exception {
MyPojo pojo = null;
// "cfg/MyPojo.json"
Path path = Paths.get(settings.getProperty("the.path"));
if (Files.exists(confFile)){
pojo = new ObjectMapper().readValue(path.toFile(), MyPojo.class);
} else { // JSON file is missing, I create it.
pojo = new MyPojo();
Files.createDirectory(path.getParent()); // create "cfg/"
new ObjectMapper().writeValue(path.toFile(), pojo); // create "cfg/MyPojo.json"
}
return pojo;
}
}
Since MyPojo's path is relative, when I run this from a Unit Test
#Test
public void testCanRunMockProcesses() {
try (AnnotationConfigApplicationContext ctx =
new AnnotationConfigApplicationContext(MyService.class)){
MyPojo pojo = ctx.getBean(MyPojo.class);
String foo = pojo.getFoo();
...
// do assertion
}
}
the cfg/MyPojo.json is created under the root of my project, which is definitely not what I want.
I would like MyPojo.json to be created under my target folder, eg. /build in Gradle projects, or /target in Maven projects.
To do that, I've created a secondary settings.properties under src/test/resources, containing
the.path=build/cfg/MyPojo.json
and tried to feed it to MyService in several ways, without success.
Even if called by the test case, MyService is always reading src/main/resources/settings.properties instead of src/test/resources/settings.properties.
With two log4j2.xml resources instead (src/main/resources/log4j2.xml and src/test/resources/log4j2-test.xml), it worked :/
Can I do the same with a property file injected by Spring with #PropertySource ?
You can use #TestPropertySource annotation for this.
Example:
For single property:
#TestPropertySource(properties = "property.name=value")
For property file
#TestPropertySource(
locations = "classpath:yourproperty.properties")
So, you provide path for MyPojo.json like
#TestPropertySource(properties = "path=build/cfg/MyPojo.json")
I've a spring bean which loads the property file depending upon their availability as shown below:-
#PropertySources({ #PropertySource(value = "classpath:user.properties"),
#PropertySource(value = "file:./config/user.properties", ignoreResourceNotFound = true) })
The property file is getting loaded, but when I try to read entire property file in one go via :-
Properties properties = PropertiesLoaderUtils.loadAllProperties("user.properties");
then I only get the properties from classpath. Do spring provide any mechanism to read all properties in one go?
That code of yours doesn't do what the annotations do. You have a couple of annotations that declare what to do. That logic isn't present at all in the code snippet.
There's no magic, if you want the same result, you need to translate the declarative aspects of those annotations in code (i.e. reading the classpath file then the file one and check if it exists and then merge those properties).
If you're ok to get extra keys, you could also simply inject the Environment as #PropertySource is going to update that.
Answering my own question, may be this may help someone.
Since I need to override the properties file contained in jar with external properties file (if present in specified folder) also I need to read entire property file in one go.
I've leveraged the spring behavior of loading last property read.
#PropertySources({ #PropertySource(value = "classpath:application.properties"),
#PropertySource(value = "file:./config/application.properties", ignoreResourceNotFound = true) })
Now if application.properties is present in ./config/ location then it'll override application.properties from classpath.
In main application.properties I've defined from where the external properties should get loaded i.e.
config.location=./config/
./config/ attribute can be overridden in case of production and test environment.
After this I've defined a bean to load all properties files (import statement skipped):-
#Component
public class PropertiesConfig {
private final Logger logger = LoggerFactory.getLogger(PropertiesConfig.class);
private final String[] PROPERTIES_FILENAMES = { "prop1.properties", "prop2.properties",
"prop3.properties" };
private String configLocation;
private Map<String, Properties> configProperties;
#Autowired
public PropertiesConfig(#Value("${config.location}") String configLocation) {
this.configLocation = configLocation;
configProperties = Arrays.stream(PROPERTIES_FILENAMES)
.collect(Collectors.toMap(filename -> filename, this::loadProperties));
}
public Properties getProperties(String fileName) {
if (StringUtils.isEmpty(fileName) || !configProperties.containsKey(fileName)) {
logger.info(String.format("Invalid property name : %s", fileName));
throw new IllegalArgumentException(
String.format("Invalid property name : %s", fileName));
}
return configProperties.get(fileName);
}
private Properties loadProperties(final String filename) {
final Resource[] possiblePropertiesResources = { new ClassPathResource(filename),
new PathResource(getCustomPath(filename)) };
final Resource resource = Arrays.stream(possiblePropertiesResources)
.filter(Resource::exists).reduce((previous, current) -> current).get();
final Properties properties = new Properties();
try {
properties.load(resource.getInputStream());
} catch (final IOException exception) {
throw new RuntimeException(exception);
}
logger.info("Using {} as user resource", resource);
return properties;
}
private String getCustomPath(final String filename) {
return configLocation.endsWith(".properties") ? configLocation : configLocation + filename;
}
}
Now you have a bean containing all the properties file in map which can be injected in any bean and can be overridden for any environment.