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!
Related
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 :)
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
I'm relatively new to Spring Boot and dependency injection overall, so please forgive any noob things going on here. I'm building an API and am having trouble when injecting dependencies into a POJO resource (DTO).
When I call the method in the POJO this.numComments = commentSvc.getAllForPhoto(this.getId()); I am getting a NullPointerException. However, when I do this from another spring-managed bean and pass the values into the constructor, it works fine.
After reading around, it looks like I need to do something with aspectJ and Load Time Weaving, but I'm not sure what that would look like in my code.
In essence, my approach looks something like this:
PhotoResource.java (POJO)
public class PhotoResource extends BaseRepresentable {
#Autowired
CommentService commentSvc;
private Long id;
private Integer numComments;
PhotoResource(PhotoEntity entity){
super(entity);
this.setId(entity.getId);
this.numComments = commentSvc.getAllForPhoto(this.getId());
}
}
CommentService.java
#Service
public class CommentService{
public List<CommentResource> getAllForPhoto(Long photoId) {
// code to get all comments for photo
}
}
Application.java
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class);
}
}
Spring won't inject the dependency unless you ask the Spring container to manage the bean. In order for commentSvc to be injected into PhotoResource class, you need to annotate it with #Component or #Bean or #Service, e.g.:
#Component
public class PhotoResource extends BaseRepresentable {
#Autowired
CommentService commentSvc;
}
And make sure the package of this class is included into #ComponentScan packages.
Also, the following won't compile:
#Service
public class CommentService(){
You don't need paranthesis to declare a class, it should be:
#Service
public class CommentService{
I'd like to have multiple #PostConstruct annotated methods in one configuration class, that should be called dependent on the #Profile. You can imagine a code snipped like this:
#Configuration
public class SilentaConfiguration {
private static final Logger LOG = LoggerFactory.getLogger(SilentaConfiguration.class);
#Autowired
private Environment env;
#PostConstruct #Profile("test")
public void logImportantInfomationForTest() {
LOG.info("********** logImportantInfomationForTest");
}
#PostConstruct #Profile("development")
public void logImportantInfomationForDevelopment() {
LOG.info("********** logImportantInfomationForDevelopment");
}
}
However according to the javadoc of #PostConstruct I can only have one method annotated with this annotation. There is an open improvement for that in Spring's Jira https://jira.spring.io/browse/SPR-12433.
How do you solved this requirement? I can always split this configuration class into multiple classes, but maybe you have a better idea/solution.
BTW. The code above runs without problems, however both methods are called regardless of the profile settings.
I solved it with one class per #PostConstruct method. (This is Kotlin but it translates to Java almost 1:1.)
#SpringBootApplication
open class Backend {
#Configuration
#Profile("integration-test")
open class IntegrationTestPostConstruct {
#PostConstruct
fun postConstruct() {
// do stuff in integration tests
}
}
#Configuration
#Profile("test")
open class TestPostConstruct {
#PostConstruct
fun postConstruct() {
// do stuff in normal tests
}
}
}
You can check for profile with Environment within a single #PostContruct.
An if statement would do the trick.
Regards,
Daniel