'Spring Boot Failed to use @Value for injection
Spring Boot version <version>2.2.0.RELEASE</version>
Error goes as follows:
Description:
Parameter 2 of constructor in
com.shawn.foodrating.service.impl.AdServiceImplrequired a bean of typejava.lang.Integerthat could not be found.
Action:
Consider defining a bean of type 'java.lang.Integer' in your configuration.
My Code:
@Service
@Transactional(rollbackOn = Exception.class)
@AllArgsConstructor
public class AdServiceImpl implements AdService {
private AdRepository repository;
private FileService fileService;
@Value("${app.ad.DefaultPageSize}")
private Integer DEFAULT_PageSize;
@Value("${app.ad.ImagePath}")
private String AD_IMAGE_PATH;
@Value("${app.ad.ImageUrl}")
private String AD_IMAGE_URL;
Load property file
@SpringBootApplication
@PropertySource("classpath:app.properties")
public class FoodRatingApplication {
public static void main(String[] args) {
SpringApplication.run(FoodRatingApplication.class, args);
}
}
Not Sure what is wrong with it.
Solution 1:[1]
When you use Lombok's @AllArgsConstructor it must create a constructor for all your fields, those annotated with @Value and those that aren't.
Now Lombok doesn't even know anything about @Value annotation of spring. So the generated constructor looks something like this:
public AdServiceImpl(AdRepository repository, FileService fileService, Integer DEFAULT_PageSize, String AD_IMAGE_PATH, String AD_IMAGE_URL) {
this.repository = repository;
....
}
You can run Delombok to see the actually generated code.
Spring on the other hand when sees a single constuctor tries to call it to create the bean (AdServiceImpl) in this case, and only after that iterates through its fields and inject data annotated by @Value.
Now, when spring calls the constructor, it sees an integer (DEFAULT_PageSize), has no clue that its a value (and spring has to inject something brcause its a constructor injection), and throws an Exception.
So in terms of resolution:
Don't use all args constructor of lombok in this case and instead create a non-lombok constructor for AdRepository and FileService only)
Alternatively create a constructor with @Value annotated parameters instead of field injection (remove @Value on fields):
public AdServiceImpl(AdRepository repository, FileService fileService, @Value(${app.ad.DefaultPageSize}"} Integer DEFAULT_PageSize, @Value(...) String AD_IMAGE_PATH, @Value(...) String AD_IMAGE_URL) {
this.repository = repository;
....
}
Solution 2:[2]
Add to projeck lombok.config file with this lines:
lombok.copyableAnnotations += org.springframework.beans.factory.annotation.Qualifier
lombok.copyableAnnotations += org.springframework.beans.factory.annotation.Value
Solution 3:[3]
The root cause is that you are using Lombok @AllArgsConstructor while some of the properties are populated by @Value(..).
Replace the @AllArgsConstructor with @RequiredArgsConstructor and give it a try.
Note: Adding this comment for future references.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | krzysiek.ste |
| Solution 3 | Danny Leviev |
