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.
Related
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.
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
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());
}
}
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.
Using Spring 5 on Java 9....
Not even sure this is possible. Have a very simple class:
public class Exchange {
#Autowired
private OtherService other;
#JmsListener(destination = {some.queue})
#Transactional
public void receive(String payload) {
other.send(payload)
}
}
Both Exchange and OtherService just needs a couple of configuration properties (i.e. some.queue) to work. Would like to register (either through BeanDefinitionRegistryPostProcessor or ApplicationContextInitializer) multiple instances of the Exchange bean but with prefixed configuration properties. Anyway to alter attribute definition when registering a bean?
I think you want a combination of two things, #ConfigurationProperties and #Qualifier.
ConfigurationProperties let's you supply a prefix that applies to all of the #Value properties loaded injected in tho that class.
#Qualifier allows you to specify which one of potentially many valid #Autowire targets you'd like. Specify the bean name and you are set.
Quick untested example:
#Component("FooExchange")
#ConfigurationProperties(prefix = "foo")
class FooExchange implements Exchange {
#Value("enabled") private boolean enabled;
...
}
#Component("BarExchange")
#ConfigurationProperties(prefix = "bar")
class BarExchange implements Exchange {
#Value("enabled") private boolean enabled;
...
}
And the properties you'd define are:
foo.enabled = true
bar.enabled = true
And when you inject one:
#Autowired
#Qualifier("FooExchange")
private Exchange myInjectedExchange; // Which will get FooExchange
Edit: You may beed to annotate one of your configuration classes or your main class with #EnableConfigurationProperties to enable the configuration properties.