Spring #Component not reading .properties field properly - java

I've got several #Configuration classes which do specify custom #ConfigurationProperties("sample") and are used within to instantiate several beans that are going to be used my business logic classes later on.
However, I've been trying to do this approach with an inner #Component class so I don't need to fit that within an existing specific or generic config and see what happens.
#Component
#ConfigurationProperties("myclass")
public class MyClass {
private String attribute;
(Constructor, getters and setters for attribute and other methods...)
}
And within my application.properties file I do specify that attribute value as myclass.attribute=value.
Doing it this way results in a null value everytime. Do #Component accept reading .properties file or should it still be in a #Configuration class?

I should have put it as a comment. But didn't want someone to miss this trivial thing.
Okay the issue is - You are missing the '$' (DOLLAR SYMBOL). Wondering why nobody noticed it?
In your properties file if you have this :
myclass.attribute=value
Then to access it in any class, do this:
#Value("${myclass.attribute}")
Noticed the $ symbol above??

Everything is working as expected, even using #ConfigurationProperties in class annotated with #Component. Please try :
application.properties :
myclass.attribute=value
MyClass class :
#Data
#Component
#ConfigurationProperties("myclass")
public class MyClass {
private String attribute;
}
Test class :
#RunWith(SpringRunner.class)
#SpringBootTest
public class FooTests {
#Autowired
private MyClass myClass;
#Test
public void test() {
System.out.println(myClass.getAttribute());
}
}

You do need the #EnableConfigurationProperties annotation on on of you configuration classes, eg the application class.
#SpringBootApplication
#EnableConfigurationProperties
public class MySpringBootApp {
public static void main(String[] args) {
SpringApplication.run(MySpringBootApp.class);
}
}

I've never used the #ConfigurationProperties annotation but if you want to set your attribute from a value in your application.properties I'll recommend using the #Value annotation :
application.properties :
myclass.attribute=foo
#Component
public class MyClass {
#Value("myclass.attribute")
private String attribute;
// ...
}
This way every instance of MyClass will have attribute with the default value foo

Related

How to get boolean value from application.yml in SpringBoot

I have application.yml that looks like this:
feature:
toggles:
checksLoginAndRegistration: true
I am trying to get it in my class with #Value annotation, but it's not working.
public class UMLUserRepository implements UserRepository {
#Value("${feature.toggles.checksLoginAndRegistration}")
private boolean checksLoginAndRegistration;
private void validateLoginNow(LoginInfo info, User user) {
checkKnownBlock(info, user.username);
if(checksLoginAndRegistration){
try {
service.validateLogin(user.username);
} catch (ValidationException alidationException) {
throw new Exception(user.username);
}
}
}
When I debug the code my checksLoginAndRegistration variable is set to false.
According to the comments you have used #Value annotation within a simple POJO. Not inside a Spring Bean like #Component, #Service or #Configuration.
You cannot inject a value to a POJO class using #Value.
This annotation can be used for injecting values into fields in Spring-managed beans, and it can be applied at the field or constructor/method parameter level.
But still you get value false for checksLoginAndRegistration parameter because it is an primitive type which has a default value false. If you chaged it to boxed type Boolean you can see the value of checksLoginAndRegistration is null
Update
#ConfigurationProperties(prefix = "feature.toggles")
public class AppConfig {
private Boolean checksLoginAndRegistration;
}
Then update your UMLUserRepository class, (We make checksLoginAndRegistration is a dependency to UMLUserRepository class)
public class UMLUserRepository implements UserRepository {
private final Boolean checksLoginAndRegistration;
public UMLUserRepository(Boolean checksLoginAndRegistration) {
this.checksLoginAndRegistration = checksLoginAndRegistration;
}
}
This is the class where you crate instance of UMLUserRepository class. An it should be a Spring Bean.
#Component (or #Service)
public class ClassYouInitatingUMLUserRepository {
#Autowire
private AppConfig appConfig;
public void yourMethod() {
UMLUserRepository repo = new UMLUserRepository(appConfig.getChecksLoginAndRegistration());
}
I would encourage you to check the possibility to convert UMLUserRepository class to a Spring bean. Then this won't be needed.
Hmm, it seems like you do everything correctly. I can suggest what can go wrong
Is it all what file contains?
If not, check is there only one feature key or not. If there's another one, remove it.
Have you added #Configuration annotation to your configuration class?
If not, add it.

Reading property from application.properties not working in java

I am trying to get this #Value running in an #Embeddable pojo class, but the value ist always false. All application.properties files are filled correctly. Is it maybe just not possible, because it's no srvice/ controller/ configuration?
#Embeddable
public class WebDestination implements Serializable {
#Value("${property.example}")
private boolean example;
public boolean isExample() {
return example;
}
public void setExample(boolean example) {
this.example= example;
}
}
You can only inject property value using #Value("${property.example}") in components that are managed by Spring container (classes that are annotated with #Service, #Controller, #Component, #Configuration and ...), you can't use it anywhere else.

How to create config class using Spring and share data across the whole code?

I need to create sth like Shared class, which I can use in the following way:
Shared.getProperty(key);
I tried to use Environment object, but it is always null. Where should it be specified and how?
I use .xml for my bean configuration.
I also have application.properties, where I want to retrieve data from.
// Shared.java
#Component
#ConfigurationProperties("prefix.for.application.properties")
public class Shared {
private String str;
// getters, setters
}
// application.properties
prefix.for.application.properties.str=STR
// other code
#Autovired
private Shared shared;
shared.getStr();
The best way is to have properties defined in application.properties file and then you can access these properties using #Value annotation.
The way I do it is using defining the values in application.properties and then creating a Configuration class for example:
Define constants in application.properties
app.email_subject =My app Registration
app.email_from =Some person
An annotated class
#Configuration
#ConfigurationProperties(prefix = "app")
public class GlobalProperties {
#Value("email_subject")
private String emailSubject;
#Value("email_from")
private String emailFrom;
// getters and setters
}
You can use this class anywhere you want like this:
#Service
public class SomeService {
#Autowired
private GlobalProperties globalProperties;
public someMethod() {
System.out.println(globalProperties.getEmailFrom());
}
}

Property values in yml file not loading into a class in springboot project

Please find the code below for application.yml
decrypt: /Users/Blahblah/Bleh
The above property we're trying to read into a Class please find the code for PropertyLoader.java
#Configuration
#Component
public class PropertyLoader implements InitializingBean{
#Value("${decrypt}")
private String decryptPath;
<--->
}
the value decryptPath is always null. Can anyone tell me what is wrong with the code?
Firstly application.yml should be under the src/main/resources/application.yml.
If you want to use this variables in constructor, you don't. Because spring inject #Value annotated variables after the construction.But if you want to do in constructer you can do like :
public class PropertyLoader implements InitializingBean{
private String decryptPath;
public PropertyLoader(#Value("${decrypt}") decrypPath) {
this.decryptPath = decryptPath;
}
}
It turns out since this class is implementing InitializingBean, the properties object won't be initialized until this class has completed execution. The #Value will always return null.

#PropertySource() is not working in bean defined in XML imported by #ImportResource()

Can not find correct answer to next situation in Internet. So, if it was already discussed somewher, just point out.
I jave UnitTest that is run by Spring:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration("classpath:spring/app-core-config.xml")
public class ConcurrentProcessingTest extends AbstractLSTest {
public void testMethod1(){
...
}
}
spring/app-core-config.xml contains some beans that use #PropertySource.
For example, Service1Impl:
#Service
#PropertySource("classpath:system/service1.properties")
public class Service1Impl {
#Value("${event.ack.warning}")
private String eventAckWarningComm;
#Value("${event.ack.info}")
private String eventAckInfoComm;
}
So, few classes with similar usage of #PropertySource are defined in spring/app-core-config.xml.
When I run mentioned UnitTest all works fine.
But I need some additional Java configuration for specific UnitTest.
So, I written next simple configuration for previous UnitTest:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = {ConcurrentProcessingTest.AppCoreConfiguration.class})
public class ConcurrentProcessingTest extends AbstractLSTest {
#Configuration
#ImportResource("classpath:spring/app-core-config.xml")
//#PropertySource("classpath:system/service1.properties") -- if uncommented, UT works
//But it is annoying to add all propery-files here
static class AppCoreConfiguration {
//Here I want to add extra configuration in Java style
}
public void testMethod1(){
...
}
}
But when I run this UnitTest, I get next exception:
Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder 'event.ack.warning' in string value "${event.ack.warning}"
at org.springframework.util.PropertyPlaceholderHelper.parseStringValue(PropertyPlaceholderHelper.java:174)
at org.springframework.util.PropertyPlaceholderHelper.replacePlaceholders(PropertyPlaceholderHelper.java:126)
at org.springframework.core.env.AbstractPropertyResolver.doResolvePlaceholders(AbstractPropertyResolver.java:194)
at org.springframework.core.env.AbstractPropertyResolver.resolveRequiredPlaceholders(AbstractPropertyResolver.java:158)
at org.springframework.context.support.PropertySourcesPlaceholderConfigurer$2.resolveStringValue(PropertySourcesPlaceholderConfigurer.java:175)
at org.springframework.beans.factory.support.AbstractBeanFactory.resolveEmbeddedValue(AbstractBeanFactory.java:800)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:871)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:858)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:480)
... 184 more
Could someone explain me why #PropertySource is not working in bean defined in XML imported by #ImportResource ?
After you have demarcated your class with respective propertysource you need to declare static propertySourcesPlaceHolderConfigurer bean like below in your configuration class
#Bean
public static PropertySourcesPlaceholderConfigurer xxxpropertyConfig() {
return new PropertySourcesPlaceholderConfigurer();
}

Categories

Resources