I want to create a class using new operator and in that class I want to read a property from application.yml file, how to do that in Spring Boot application ?
In other words I cannot use #Value, #Autowire, #Component annotations.
You need to do something like this:
#Configuration
#ConfigurationProperties(prefix = "test")
public class TestProperties{
private String testProperty1;
public String getTestProperty1() {
return testProperty1;
}
public void setTestProperty1(String testProperty1) {
this.testProperty1= testProperty1;
}
}
next in Your application.properties:
test.testPropety1 = yourProperty
You can implement this properties class as bean because of #Configuration annotation. Hope that helps in Your problem :)
Related
I am new to Spring Boot. Currently, I am trying to create a POJO class (SystemProperties.class) to read the value in a properties file (parameter.properties separate from application.properties but still under the same directory /src/main/resources. The issue happens when I am using the #ConstructorBinding in the class in order for it to be immutable.
#ConstructorBinding needs to be used with #EnableConfigurationProperties or #ConfigurationPropertiesScan.
#ConfigurationPropertiesScan will ignore #Configuration annotation which is needed when using #PropertySource to specify external
*.properties file.
A) SystemProperties.class
#Configuration
#PropertySource("classpath:parameter.properties")
#ConstructorBinding
#ConfigurationProperties(prefix = "abc")
public class SystemProperties {
private final String test;
public SystemProperties (
String test) {
this.test = test;
}
public String getTest() {
return test;
}
B) parameter.properties
abc.test=text1
I have tried to remove the #PropertySource annotation but the value cannot be retrieved unless it is from the application.properties. Any help is greatly appreciated!
The way to solve this is to split the class into two classes with two different concerns. With such solution, you retain the SystemProperties class you created and additionally add another class simply for loading the properties file parameters to make them available to your application.
The solution would be as follows:
#ConstructorBinding
#ConfigurationProperties(prefix = "abc")
public class SystemProperties {
private final String test;
public SystemProperties(
String test) {
this.test = test;
}
public String getTest() {
return test;
}
}
Notice that I have omitted the #Configuration and #PropertySource annotations.
#Configuration
#PropertySource("classpath:parameter.properties")
public class PropertySourceLoader {
}
Notice I have simply added this annotations on a new class, solely created to load the properties file.
Finally, you can add #ConfigurationPropertiesScan on your main application class to enable the property mapping mechanism.
Im trying to access the spring application name in a custom starter auto-configuration.
#Configuration
public class CustomAutoConfiguration {
#Value("${spring.application.name}")
private String appName;
}
spring.factories as,
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
co.test.CustomAutoConfiguration
In an application that uses this custom starter I have defined the application name in bootstrap.yaml
spring:
application:
name: test-app
However, I'm seeing that appName is null. My guess is this has something to do with the order of loading ? Anyway to achieve this ?
I had similar issue in past and I solved by autowiring org.springframework.core.env.Environment; something like this:
#Configuration
public class CustomAutoConfiguration {
#Autowired
private Evinronment env;
private String appName;
#PostConstruct
public void initialize(){
this.appName = env.getProperty("spring.application.name");
}
}
Not tested but it should work
Angelo
This is what worked in the end.
#Configuration
public class CustomAutoConfiguration implements EnvironmentAware {
#Override
public void setEnvironment(Environment environment) {
this.environment = environment;
}
// And then accessing via this.environment.getProperty("spring.application.name")
}
Might have something to do with the order in which bootstrap.yml gets loaded. We uaw #Value all the time in our #Configuration classes without issue, but we use application.properties. Have you tried setting it there? Or maybe on command line?
I believe that your configuration class needs getters and setters for a private field annotated with #Value, in order for Spring to be able to set the field!
I'm not sure if I understand it correctly, but from what I got, is that I can use #Value annotations to read values from my application.properties.
As I figured out this works only for Beans.
I defined such a bean like this
#Service
public class DBConfigBean {
#Value("${spring.datasource.username}")
private String userName;
#Bean
public String getName() {
return this.userName;
}
}
When the application starts I'm able to retrieve the username, however - how can I access this value at runtime?
Whenever I do
DBConfigBean conf = new DBConfigBean()
conf.getName();
* EDIT *
Due to the comments I'm able to use this config DBConfigBean - but my initial problem still remains, when I want to use it in another class
#Configurable
public SomeOtherClass {
#Autowired
private DBConfigBean dbConfig; // IS NULL
public void DoStuff() {
// read the config value from dbConfig
}
}
How can I read the DBConfig in a some helper class which I can define as a bean
Thanks
As Eirini already mentioned you must inject your beans.
The #Value annotation only works on Spring beans.
There is another way of accessing configuration with #ConfigurationProperties.
There you define a class that holds the configuration.
The main advantage is, that this is typesafe and the configuration is in one place.
Read more about this:
https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html#boot-features-external-config-vs-value
You shouldn't instantiate your service with the new operator. You should inject it, for example
#Autowired
private DBConfigBean dbConfig;
and then dbConfig.getName();
Also you don't need any #Bean decorator in your getName() method
You just need to tell spring where to search for your annotated beans. So in your configuration you could add the following:
#ComponentScan(basePackages = {"a.package.containing.the.service",
"another.package.containing.the.service"})
EDIT
The #Value, #Autowired etc annotations can only work with beans, that spring is aware of.
Declare your SomeOtherClass as a bean and add the package config in your #Configuration class
#Bean
private SomeOtherClass someOtherClass;
and then
#Configuration
#ComponentScan(basePackages = {"a.package.containing.the.service"
"some.other.class.package"})
public class AppConfiguration {
//By the way you can also define beans like:
#Bean
public AwesomeService service() {
return new AwesomeService();
}
}
Wrap your DBConfig with #Component annotation and inject it using #Autowired :
#Autowired
private DBConfig dbConfig;
Just add below annotation to your DBConfigBean class:
#PropertySource(value = {"classpath:application.properties"})
I'm new to the Java world and Spring boot, and I'm trying to access some configuration values located in a YAML file through the ConfigurationProperties annotation.
But whenever I try to access a configuration value anywhere in a service, I get a null value.
Here's the application.yml file:
my_config:
test: "plop"
Here's the ValidationProperties configuration class:
#Configuration
#ConfigurationProperties(prefix = "my_config")
public class ValidationProperties {
#NotNull
private String test;
public void setTest(String test) {
this.test = test;
}
public String getTest() {
return this.test;
}
}
A validator service that uses it:
#Service
public class MyValidator implements ConstraintValidator<MyConstraint, MyEntity> {
#Autowired
private ValidationProperties validationProperties;
#Value("${my_config.test}")
private String test;
#Override
public boolean isValid(MyEntity entity, ConstraintValidatorContext context) {
System.out.println(this.test); // null value, why?
}
}
I also added the #EnableConfigurationProperties annotation in my main class.
I'm not sure which annotation is supposed to do what, but I'm obviously missing something here. Also, if I try to access the value from the getter of the configuration file, I get an exception:
System.out.println(this.validationProperties.getTest());
will get me HV000028: Unexpected exception during isValid call.
Try adding #EnableConfigurationProperties(ValidationProperties.class)
on your main application class or any other #Configuration class.
Also putting #Component annotation on ValidationProperties should work.
No need to inject value via #Value annotation, just access it via getter of injected validationProperties object
I got this error running a JUnit test on a SpringBoot app, what I was missing is the annotation #SpringBootTest
We can externalize properties using <context:property-placeholder> and we can override the Spring bean properties by configuring <context:property-override> as follows:
<context:property-placeholder location="classpath:application.properties"/>
<context:property-override location="classpath:override.properties"/>
I want to move my XML config to JavaConfig.
#Configuration
#ComponentScan
#PropertySource("classpath:application.properties")
public class AppConfig {
#Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
}
But how to configure my override properties using Annotation?
PS:
I have a bean say MyBean as follows:
#Component
public class MyBean {
#Value("${someProp}")
private String someProp;
}
In my application.properties I have
someProp=TestValue
and in my override.properties i am overriding someProp value as
myBean.someProp=RealValue
No, It isn't.
But you could create a bean of type PropertyOverrideConfigurer in the configuration class whit the same result.
Update
For example:
#Bean public static PropertyOverrideConfigurer propertyOverrideConfigurer() {
PropertyOverrideConfigurer overrideConfigurer = new PropertyOverrideConfigurer();
overrideConfigurer.setLocation(new ClassPathResource("override.properties"));
return overrideConfigurer;
}
Note the static modifier, this is because BFPP should be instantiated early in the container lifecycle.
see http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/context/annotation/Bean.html for more info.