This entry deals with how to do constructor injection with @RequiredArgsConstructor at lombok.
It may be a little edge case, but there may be other people who want to do it, so I hope it will be helpful.
TL;DR;
If you want to do something about the title, add the following line to lombok.config.
#lombok.copyableAnnotations += org.springframework.beans.factory.annotation.Qualifier
import lombok.RequiredArgsConstructor;
import lombok.ToString;
import lombok.Value;
@RequiredArgsConstructor
@ToString
@Value
public class MyComponent {
private final String name;
}
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MyComponentConfiguration {
@Bean(name="myComponentA")
public MyComponent myComponentA() {
return new MyComponent("name A");
}
@Bean(name="myComponentB")
public MyComponent myComponentB() {
return new MyComponent("name B");
}
}
@Service
@RequiredArgsConstructor
@Slf4j
public class MyService {
@Qualifier("myComponentA")
private final MyComponent myComponentAdash;
@Qualifier("myComponentB")
private final MyComponent myComponentBdash;
public void sayHello() {
log.info("myComponentA->" + myComponentAdash.getName());
log.info("myComponentB->" + myComponentBdash.getName());
}
}
If you try to start it in this state, the following error will occur.
Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2020-07-19 22:00:45.510 ERROR 16076 --- [ main] o.s.b.d.LoggingFailureAnalysisReporter :
***************************
APPLICATION FAILED TO START
***************************
Description:
Parameter 0 of constructor in info.beambitious.sandbox.lombokqualifiertest.MyService required a single bean, but 2 were found:
- myComponentA: defined by method 'myComponentA' in class path resource [info/beambitious/sandbox/lombokqualifiertest/MyComponentConfiguration.class]
- myComponentB: defined by method 'myComponentB' in class path resource [info/beambitious/sandbox/lombokqualifiertest/MyComponentConfiguration.class]
Action:
Consider marking one of the beans as @Primary, updating the consumer to accept multiple beans, or using @Qualifier to identify the bean that should be consumed
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':bootRun'.
> Process 'command 'C:\Java\Amazon Corretto\jdk1.8.0_222\bin\java.exe'' finished with non-zero exit value 1
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.
* Get more help at https://help.gradle.org
BUILD FAILED in 8s
3 actionable tasks: 2 executed, 1 up-to-date
In lombok's @RequiredArgsConstructor, I'm trying to specify a value for two fields of MyComponent type by constructor injection, but the value is different from the one specified by @Bean's name and I can't tell.
Delombok MyService and take a look at the automatically generated code.
java -jar .\lombok.jar delombok --print .\src\main\java\info\beambitious\sandbox\lombokqualifiertest\MyService.java
The constructor created by lombok's @RequiredArgsConstructor does not have @Qualifier. ,
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
@Service
public class MyService {
@java.lang.SuppressWarnings("all")
private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(MyService.class);
@Qualifier("myComponentA")
private final MyComponent myComponentAdash;
@Qualifier("myComponentB")
private final MyComponent myComponentBdash;
public void sayHello() {
log.info("myComponentA->" + myComponentAdash.getName());
log.info("myComponentB->" + myComponentBdash.getName());
}
@java.lang.SuppressWarnings("all")
public MyService(final MyComponent myComponentAdash, final MyComponent myComponentBdash) {
this.myComponentAdash = myComponentAdash;
this.myComponentBdash = myComponentBdash;
}
}
When I was looking at StackOverflow because I was in trouble, [is it possible to add qualifiers in @RequiredArgsConstructor (onConstructor = @__ (@Autowired))?](Https://stackoverflow.com/questions/38549657/is-it -possible-to-add-qualifiers-in-requiredargsconstructoronconstructor) I found.
(Reference): Issue745 on GitHub referenced in the above article.
Specify the value as introduced in TL; DR; in lombok.config and try delombok.
@java.lang.SuppressWarnings("all")
public MyService(@Qualifier("myComponentA") final MyComponent myComponentAdash, @Qualifier("myComponentB") final MyComponent myComponentBdash) {
this.myComponentAdash = myComponentAdash;
this.myComponentBdash = myComponentBdash;
}
This time, @Qualifier is written in the constructor.
If you clean it and then run it, the program will work normally.
gradlew clean
gradlew bootRun
(Omission)
2020-07-19 22:18:53.006 INFO 14200 --- [ main] i.b.s.l.LombokQualifierTestApplication : Started LombokQualifierTestApplication in 1.658 seconds (JVM running for 2.305)
2020-07-19 22:18:53.010 INFO 14200 --- [ main] i.b.s.lombokqualifiertest.MyService : myComponentA->name A
2020-07-19 22:18:53.011 INFO 14200 --- [ main] i.b.s.lombokqualifiertest.MyService : myComponentB->name B
As an alternative, it works if you rename the fields in MyService, but this entry covers how to explicitly specify them in the Qualifier.
private final MyComponent myComponentA;
private final MyComponent myComponentB;
The code used in this entry can be found on GitHub. ](Https://github.com/hrkt/lombok-qualifier-test/releases/tag/0.0.1)
Recommended Posts