Best practice for @Value fields, Lombok, and Constructor Injection?

Viewed 22344

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!

2 Answers

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.

Related