MS13
MS13

Reputation: 377

Create a mixed initialized component for existing fields using lombok and spring

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

Answers (1)

Jan Rieke
Jan Rieke

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

Related Questions