Reputation: 377
I want to create a spring component that can be partially initialized automatically by spring (all those final fields) and partially initialized manually (the remaining non final fields). So I used lombok and tried a lots of variants but couldn't make it work:
(ex: adding @AllArgsConstructor(access = PACKAGE)
will not be instantiated by spring because of
Caused by: java.lang.NoSuchMethodException: Task.<init>())
@RequiredArgsConstructor
@Builder (toBuilder=true)
@Component
public class Task {
private final Repo1Repository repo1; //<- should be automatically initialized
private final Repo2Repository repo2; //<- should be automatically initialized
private final Repo3Repository repo3; //<- should be automatically initialized
private String tableName; //<- will be manually initialized with the builder
private boolean special; //<- will be manually initialized with the builder
...
}
Intended usage will be something like:
@RequiredArgsConstructor
@Configuration
public class ConfigurationClass {
private final Task task; //<- automatically injected
@Bean
public void createBean (){
return task.toBuilder ().tableName("TABLE").special(true).build();
}
@Bean
public void createBean2 (){
return task.toBuilder().tableName("TABLE2").special(true).build();
}
...
}
Using lombok 1.18.24 & spring 5.3.20 (from spring boot 2.6.8)
Upvotes: 1
Views: 362
Reputation: 8102
Although this may be possible somehow, I suggest a different approach.
Right now you are trying to mix two concerns: the modeling of the actual Task
class, and creating a templating mechanism for populating instances of Task
with default values. You should separate these concerns by explicitly modeling them:
@Builder
public class Task {
private final Repo1Repository repo1;
private final Repo2Repository repo2;
private final Repo3Repository repo3;
private final String tableName;
private final boolean special;
}
@AllArgsConstructor
@Component
public class TaskTemplate {
private final Repo1Repository repo1;
private final Repo2Repository repo2;
private final Repo3Repository repo3;
public Task.TaskBuilder builder() {
return Task.builder().repo1(repo1).repo2(repo2).repo3(repo3);
}
}
Upvotes: 2