0

consider following code

@Getter
@Setter
@AllArgsConstructors
public class CourseGroupService {

  private MathRepository mathRepository;
  private BiologyRepository biologyRepository;
  private PhysicalRepository physicalRepository;
  private EnglishRepository englishRepository;
  private AlgebraRepository algebraRepository;
  private TrigonometryRepository trigonometryRepository;
  private ChemistryRepository chemistryRepository;
  private AnatomyRepository anatomyRepository;
  private HistoryRepository historyRepository;
  
  public CourseGroupService(
    MathRepository mathRepository,
    BiologyRepository biologyRepository,
    PhysicalRepository physicalRepository,
    EnglishRepository englishRepository,
    AlgebraRepository algebraRepository,
    TrigonometryRepository trigonometryRepository,
    ChemistryRepository chemistryRepository,
    AnatomyRepository anatomyRepository,
    HistoryRepository historyRepository,
  ) {
    this.mathRepository = mathRepository;
    this.biologyRepository = biologyRepository;
    this.physicalRepository = physicalRepository;
    this.englishRepository = englishRepository;
    this.algebraRepository = algebraRepository;
    this.trigonometryRepository = trigonometryRepository;
    this.chemistryRepository = chemistryRepository;
    this.anatomyRepository = anatomyRepository;
    this.historyRepository = historyRepository;
  }

}

I want to create the constructor of this class

public class CourseService extends CourseBase {

  private CourseGroupService courseGroupService;
  private MathRepository mathRepository;
  private BiologyRepository biologyRepository;
  private PhysicalRepository physicalRepository;
  private EnglishRepository englishRepository;
  private AlgebraRepository algebraRepository;
  private TrigonometryRepository trigonometryRepository;
  private ChemistryRepository chemistryRepository;
  private AnatomyRepository anatomyRepository;
  private HistoryRepository historyRepository;
  private CourseBaseOneRepository courseBaseOneRepository;
  private CourseBaseTwoRepository courseBaseTwoRepository;
  
  public CourseService(
    CourseBaseOneRepository courseBaseOneRepository,
    CourseBaseTwoRepository courseBaseTwoRepository
  ) {
  super(courseBaseOneRepository, courseBaseTwoRepository);
    this.courseGroupService = new courseGroupService (this.mathRepository,...,this.historyRepository); 
  }
  ...

}

The problem is this.mathRepository,..., this.historyRepository are not initialized. How can i initialize all this parameters without put them in the constructor. My goal is to have a constructor CourseService with 3 parameters .

How can i do this ?

lnikoli31
  • 11
  • 4
  • [The Java Tutorials - Initializing Fields](https://docs.oracle.com/javase/tutorial/java/javaOO/initial.html) – OH GOD SPIDERS Jul 06 '23 at 08:41
  • With *what* 3 parameters? If you can infer the correct values of all those fields from those 3 parameters there is no problem to solve. If not, there is. But this class looks like a prime candidate for refactoring into 3rd-normal form to me. Are those really all instance fields peculiar to a specific `CourseService`? – user207421 Jul 06 '23 at 08:47
  • @user207421 I want to factorize my class with these 3 instance fields knowing that to initialize the CourseGroupService field with its 9 parameters in the constructor of my CourseService – lnikoli31 Jul 06 '23 at 11:37

2 Answers2

0

Spring Boot has a little bit of different code when initializing the repository or other stereotypes inside the service file. You must add some annotations to make the project works.

First, you need @Autowired It is an annotation to automatically wire (inject) dependencies into a Spring bean by type. Then, you need the @Service annotation to indicate that a class is a service component in the business logic layer of your application.

You can change your code to:

import org.springframework.stereotype.Service;
import org.springframework.beans.factory.annotation.Autowired;

@Service
public class CourseService extends CourseBase {
    private CourseGroupService courseGroupService;

    @Autowired
    private MathRepository mathRepository;

    @Autowired
    private BiologyRepository biologyRepository;

    public CourseService(CourseBaseOneRepository courseBaseOneRepository, CourseBaseTwoRepository courseBaseTwoRepository) {
        super(courseBaseOneRepository, courseBaseTwoRepository);
        this.courseGroupService = new CourseGroupService(
            mathRepository,
            biologyRepository,
        );
   }
}
Rigsto
  • 128
  • 10
  • `@Service @RequiredArgsConstructor public class CourseService extends CourseBase { private final MathRepository mathRepository; } ` I prefer this. Refer to [this site](https://www.baeldung.com/java-spring-field-injection-cons) for why field injection is not recommended. – dauthDaert06 Jul 06 '23 at 09:22
  • @dauthDaert06 I don't want to use Autowired, because I'm thinking of writing unit tests for this service class. I want to factorize my constructor especially I want to know how to initialize my service constructor with GroupServiceGroup class which has a constructor with 9 parameters – lnikoli31 Jul 06 '23 at 11:41
  • @Dmytro Taranov 's answer explains it well. You don't need to write constructors manually. It is boilerplate code if you ask me. Just annotate GropuServiceGroup class with '@RequiredArgsConstructor' and make the repository fields private final and you should be good to go. SpringBoot will handle the rest. Can't you refactor that class for some reason? – dauthDaert06 Jul 06 '23 at 13:08
0

If you don't want to refactor your code and split this service into several smaller services, you have two options to solve the problem:

  1. Use field injection with @Autowired
@Service
public class UserService {
  
  @Autowired
  private UserRepository userRepository;
}

This way you explicitly get rid of constructor injection, because the @Autowired annotation use the set-method for injection.

However, I would not recommend this approach. The reasons for this can be found here

  1. It's better to use Lombok here with annotation @RequiredArgsConstructor.

This annotation will implicitly create a constructor for you with all the required fields. You can also make your fields final, which makes your class thread-safe

@Service
@RequiredArgsConstructor
public class UserService {

  private final UserRepository userRepository;
}