Does #Value field injection require to be under a #RestController / #Configuration class for it to work?
I went through countless tutorials no one seem to mention anything like it, but wen I tried on my own code it just doesn't work. I found suppose solution here: Spring Boot application.properties value not populating
But it didn't work in my case.
public class AuthenticationFilter extends UsernamePasswordAuthenticationFilter {
#Value("${token.secret}")
private String tokenSecret; <--- always null
#Value("${token.expiration_time}")
private String tokenTime; <--- always null
...
#PostConstruct <-- this was suggested but still null
public void init(){
log.info("tokenTime : {}", tokenTime);
log.info("tokenSecret: {}", tokenSecret);
}
}
I then moved these fields to my #Configuration or #RestController class the values does get populated, why is that? and how to fix this in my AuthenticationFilter?
#Configuration
#EnableWebSecurity
public class AppWebSecurity extends WebSecurityConfigurerAdapter {
#Value("${token.secret}")
private String tokenSecret;
#Value("${token.expiration_time}")
private String tokenTime;
....
}
Thank you
Related
Following is my code:
Why setter is mandatory. Without it, the class does not
read the property from the
application.yml file
correctly.
Thank you.
#Getter
#Setter
#NoArgsConstructor
#Configuration
#ConfigurationProperties(prefix = "test")
#EnableConfigurationProperties
public class KafkaTopicConfig {
private String bootstrapAddress;
#Value(value = "${test.bootstrapAddress}")
private String bootstrapAddressFromVariable;
should only use #Value in encapsulated components/services (we can call them configuration services).
This way, we will have all our configurations in one place, and that component will only have the responsibility of loading and providing them to other components.
https://stackabuse.com/the-value-annotation-in-spring
From baeldung.com... The Spring framework uses standard Java bean setters, so we must declare setters for each of the properties.
So it looks like you're using Lombok so I would make my class look more like this:
#ConfigurationProperties(prefix = "test")
#Data
public class KafkaTopicConfig {
private String bootstrapAddress;
}
Then in the main spring boot application class or a #Configuration class I would do:
#Configuration
#EnableConfigurationProperties({KafkaTopicConfig.class})
public MyApplicationConfig{
}
Then to use my configuration properties I would autowire it into the #Component where I wished to use it.
e.g.
#Component
public MyComponent{
private final KafkaTopicConfig config;
public MyComponent(KafkaTopicConfig config) {
this.config = config;
}
public void doStuff() {
if ("some address".equals(config.getBootstrapAddress())) {
blah();
}
}
}
Using the #Value inside the configuration properties feels confusing to me, and defeats the point of using configuration properties in the first place.
Suppose I have this service bean:
#Service
public class MyService{
private final HashMap<String,String> values;
...
}
with the values being:
com.foo:
values:
a: world
b: helo
I may want to create it inside of a configuration:
#Configuration
#ConfigurationProperties(prefix="com.foo")
public class MyConf{
private Map<String, String> values;
#Bean
public MyService myService(){
return new MyService(values);
}
}
But I fear that spring could do something strange like creating 2 beans or dunno what...is this a good practice or should I just move #ConfigurationProperties inside of the #Service itself?
You can inject your configuration directly into your Service
#Service
public class MyService{
private final MyConf conf;
public MyService(MyConf conf) {
this.conf = conf;
}
}
And remove the #Bean annotation from MyConf allong with myservice method.
You should not do that, as it will create two beans of the same type.
In your case, you have not mentioned different names for the beans
so it will override if spring.main.allow-bean-definition-overriding=true else it will fail.
PS: For #Service annotation to create a bean, the class package should be configured in the #ComponentScan or in the base scan package
If you want to use your properties values in your Service class (or anywhere else) you should just inject it :
#Service
public class MyService{
#Autowired
private MyConf myConf;
}
I have two service implementations:
Service interface:
/**
* Service used for resolving external ID for the entity.
*/
public interface ResolveService {
String valueToResolve(String id);
}
Implementation of Service - A:
#Service
public class ResolveServiceAImpl implements {
#Override
public String valueToResolve(String id) {
// grpc impl...
}
}
Implementation of Service - B:
#Service
public class ResolveServiceBImpl implements {
#Override
public String valueToResolve(String id) {
// jpa impl...
}
}
For now, this is resolved with #Qualifier and this implementation works:
#Qualifier("resolveServiceBImpl")
#Autowired
private ResolveService resolveService;
The problem for me is that I don't want to define in every class String value of #Qualifier. I would like to define #Qualifier value in one place, let's say in application.properties file.
application.properties:
resolve.service.active=resolveServiceBImpl
This implementation is not working:
#Value("'${resolve.service.active}')")
private String resolveServiceActive;
#Qualifier(resolveServiceActive)
#Autowired
private ResolveService resolveService;
The error I am getting is Attribute value must be constant. Cannot find bean with qualifier null.
Is there any other way how to resolve #Qualifier value, so that I need to assign it manually in every class separately?
#jonrsharpe tnx for answer.
I resolved it with a #Profile.
SOLUTION:
Service A Implementation:
#Service
#Profile("A")
public class ResolveServiceAImpl implements ResolveService {...
Service B Implementation:
#Service
#Profile("B")
public class ResolveServiceBImpl implements ResolveService {...
and application.properties:
spring.profiles.active=A
And for the test I used #ActiveProfiles("A").
This solved my problem.
I have a problem with spring boot when using autowired on a configuration class.
I have minimized the problem by creating a small spring boot project on github.
I created the MyBean class declaring it as #Component and attempting the autowired of the MyConf class which is declared as #Configuration (and reads the property in the file myconfig.properties). In theory, everything is in the spring context, but when the application starts myConfigProp variable in MyBean is null.
Where am I wrong?
I also tried the following solutions, all not working:
Insert the #DependsOn in MyBean
Commented on the #Component and configured MyBean as #Bean of spring
The last test I did (not present on github project) was to pass MyConfigProp as a parameter in MyBean constructor, and it worked.
#Component
public class MyBean {
String message;
public MyBean(MyConfigProp myConfigProp) {
this.message = myConfigProp.getMessage();
}
}
I am somewhat confused.
Looks like you're not Autowiring MyConfigProp's into MyBean:
#Component
public class MyBean {
String message;
#Autowired
public MyBean(MyConfigProp myConfigProp) {
this.message = myConfigProp.getMessage();
}
}
You need to add the #EnableConfigurationProperties(MyConfigProp.class) in your MyBean class so that it looks like:
MyBean.java
#Component
#EnableConfigurationProperties(MyConfigProp.class)
public class MyBean {
String message;
#Autowired
public MyBean(MyConfigProp myConfigProp) {
this.message = myConfigProp.getMessage();
}
}
MyConfigProp.java
#PropertySource("classpath:myconfig.properties")
#ConfigurationProperties(prefix = "config")
public class MyConfigProp {
private String message;
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
I tried all the solutions and the only one that actually solve the problem is to pass MyConfigProp as a parameter in MyBean constructor, as from post, even without #Autowired.
Code update
#Component
public class MyBean {
String message;
public MyBean (MyConfigProp myConfigProp) {
this.message = myConfigProp.getMessage ();
}
}
I share the rest for knowledge.
In detail, trying the proposed solutions, the result was:
Adding the #Component stereo-type on MyConfigProp annotation to
use #Autowired in MyBean not work, even adding #ComponentScan. It still launches NullPointerException
The annotation #EnableConfigurationProperties seems to be useful only if
#Configuration is not used on MyConfigProp and does not solve the problem
From the tests and the documentation readings, if I understand correctly, the problem is that I try to use the object in # Autowired in theMyBean constructor and, during the creation of this, Spring has not yet instantiatedMyConfigProp, hence theNullPointerException.
I updated the code by adding a solutions package with the possible solutions:
MyBeanWorked: Solution shown above.
WithoutConstructor: By moving the instruction into a method, the
startup is successful and the application works.
WorkedWithInjectProp: Not declared as #Component but configured as
#Bean. A little longer but, needing only a property, perhaps cleaner.
More details in the code.
I hope I have done something pleasant.
A field with #Autowired annotation
it works if the field is in a class with the annotation #Controller
but it does not work if the field is in a class with the annotation #Component
¿Can someone tell me how should I put a field with the #Autowired annotation in a class that has the #Component annotation?
Thanks and regards
In the class Modelo1Controller
#Controller
public class Modelo1Controller {
#Autowired
private SelectUtil selectUtil;
the selectUtil field has value and works correctly
But in the class Modelo
#Component
public class Modelo extends BeanCommon implements Serializable {
#Autowired
private SelectUtil selectUtil;
When I try to use the selectUtil field the value is null and I get NullPointerException
String text = selectUtil.getDescripcionBienText(value);
java.lang.NullPointerException: null
And the class SelectUtil
#Component
public class SelectUtil {
Finally I have made my application work
The main problem was that I used the new operator to instantiate the object in another code block
Every day I'm learning new Spring concepts
In any case, thanks and maybe the problem and the solution can be used by more people in the same situation