Есть ли способ расширить службу Spring, чтобы управлять унаследованным объектом без дублирования кода?

#java #spring

#java #spring

Вопрос:

Я играю с приложением Spring с 2 контроллерами и 2 службами, которые управляют связанными объектами, и я хотел бы избежать дублирования кода. У меня есть, например Person , класс с его PersonRepository

 @Entity
@Inheritance(strategy = InheritanceType.JOINED)
public class Person {
    @Id
    Long id;
    String name;
    String surname;
}
 

И его дочерний User элемент с его UserRepository

 @Entity
@Inheritance(strategy = InheritanceType.JOINED)
public class User extends Person {
    String login;
    String password;
}
 

У меня есть простой пользовательский сервис с бизнес-логикой:

 @Service
public class PersonService {
    @Autowired
    PersonRepository repo;

    public Iterable<Person> getAll() {
        // Busines Logic
        return repo.findAll();
    }

}
 

Есть ли способ создать UserService, расширяющий или проксирующий PersonService, и реализовать какое-то «скрытие» репозитория? Что-то вроде этого:

 @Service
public class UserService extends PersonService {    
    @Autowired
    UserRepository repo;
}
 

это, очевидно, приводит к этой ошибке:
Несоответствие типов: невозможно преобразовать из итеративного <Person> в итеративный <User> с помощью такого контроллера

 @RestController
@RequestMapping(value = "/test", produces = MediaType.APPLICATION_JSON_VALUE)
public class DemoController {

    @Autowired
    UserService service;

    @GetMapping
    public void items() {
        Iterable<User> persons = service.getAll();
        return;
    }
}
 

Ответ №1:

Попробуйте следующую структуру:

Общий сервис и репозиторий:

 @NoRepositoryBean
public interface PersonRepository<T> extends JpaRepository<T, Long> {

}
 
 public class PersonService<T extends Person> {

    protected PersonRepository<T> repository;

    public <R extends PersonRepository<T>> PersonService(R repository) {
        this.repository = repository;
    }

    public Iterable<T> getAll() {
        return repository.findAll();
    }

}
 

Для объекта User:

 public interface UserRepository extends PersonRepository<User> {

}

 
 @Service
public class UserService extends PersonService<User> {

    public UserService(UserRepository repository) {
        super(repository);
    }

    public void additionalMethod() {
        User user = repository.getOne(1L);
    }
}
 

И я добавил объект Company по примеру объекта User:

 public interface CompanyRepository extends PersonRepository<Company> {

}
 
 @Service
public class CompanyService extends PersonService<Company> {

    public CompanyService(CompanyRepository repository) {
        super(repository);
    }

    public void additionalMethod() {
        Optional<Company> company = repository.findById(1L);
    }
}