I'm developing a Java Spring application. I have some fields in my application which are configured using a .yml config file. I would like to import those values using an @Value annotation on the fields in question. I would also like to use the best-practice of constructor injection rather than field injection, but I would like to write my constructor using Lombok rather than manually. Is there any way to do all these things at once? As an example, this doesn't work but is similar to what I want to do:
@AllArgsConstructor public class my service { @Value("${my.config.value}") private String myField; private Object myDependency; ... }
In this case, what I want is Lombok to generate a constructor which sets only myDependency, and for myField to be read from my config file.
Thanks!
In Spring we can use the @Value annotation to set property or arguments values based on a SpEL expression. If we want to use the @Value annotation for a constructor argument we must not forget to add the @Autowired annotation on the constructor as well.
Constructor injection makes code more robust. It allows us to create immutable objects, preventing NullPointerException s and other errors. You can find the code example on GitHub.
Constructor Injection When using a constructor to set injected properties, you do not have to provide the autowire annotation.
There is nothing wrong with using the @Autowired annotation in production code. You can control the injection with your ApplicationContext as well as some properties on the annotation itself (such as required). So the developer certainly isn't 'giving up' on controlling how things are injected.
You need @RequiredArgsConstructor
and mark myDependency
as final. In this case, Lombok will generate a constructor based on 'required' final filed as argument, for example:
@RequiredArgsConstructor @Service public class MyService { @Value("${my.config.value}") private String myField; private final MyComponent myComponent; //... }
That is equal the following:
@Service public class MyService { @Value("${my.config.value}") private String myField; private final MyComponent myComponent; public MyService(MyComponent myComponent) { // <= implicit injection this.myComponent = myComponent; } //... }
Since here is only one constructor, Spring inject MyComponent
without the explicit use of the @Autowired
annotation.
Male sure you are using at least version 1.18.4 of Lombok. And that you have your desired annotation added to the lombok.config file.
lombok.copyableAnnotations += org.springframework.beans.factory.annotation.Value
Here is your class:
@AllArgsConstructor(onConstructor = @__(@Autowired)) public class MyService{ @Value("${my.config.value}") private String myField; private Object myDependency; }
And here is the lombok generated class:
public class MyService { @Value("${my.config.value}") private String myField; private Object myDependency; @Autowired @Generated public MyService(@Value("${my.config.value}") final String myField, final Object myDependency) { this.myField = myField; this.myDependency = myDependency; }
PS: Make sure you have the lombok.config file under /src/main/java folder. I tried adding it to /src/main/resources and it did not work.
Response taken from here.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With