Каким образом можно отрефакторить метод getAllProjects() в реализации сервиса?

У меня есть следующий сервис с реализацией внутри проекта:

@Service
public class ProjectServiceImpl implements ProjectService {
    
    @Autowired
    private ProjectRepository projectRepository;

    @Autowired
    private ProjectAdaptor projectAdaptor;

    @Override
    public List<Project> getAll() {
        return projectRepository.findAll();
    }

    @Override
    public List<Project> getAllProjects(Long companyId) {
        return projectRepository.getAll().stream()
                .filter(project -> project.getId() == companyId).findAny().orElse(null);
    }

    @Override
    public Project save(Project project) {
        return projectRepository.save(project);
    }

    @Override
    public List<ProjectDTO> findAllProducts() {
        List<Project> project = projectRepository.findAll();
        return projectAdaptor.databaseModelToUiDtoList(project);
    }
}

В котором есть метод getAll():

@Override
public List<Project> getAll() { 
 return projectRepository.findAll();    
} 

и соответственно к нему getAllProjects():

@Override 
public List<Project> getAllProjects(Long companyId) { 
  return projectRepository
   .getAll() 
   .stream() 
   .filter(project -> project.getId() == companyId) 
   .findAny() 
   .orElse(null); 
}

В связи с этим вопрос, каким образом отрефакторить вышепоказанный метод, который воспроизводит ошибку компиляции, связанную с типом Object:

Cannot resolve method getId in Object.

введите сюда описание изображения

Моя сущность Project имеет следующую структуру:

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Entity(name = "project_entity")
@Table(name = "projects")
public class Project {

    public Project(ProjectDTO projectDTO) {
        this.name = projectDTO.getName();
        this.abbreviation = projectDTO.getAbbreviation();
        this.customer = projectDTO.getCustomer();
    }

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "project_id")
    private Integer id;

    private String name;

    private String abbreviation;

    private String customer;
}

Нужно ли мне добавлять дополнительные аннотации Lombok над сущностью, чтобы решить данную проблему или есть способ просто объединить два метода в один в более правильном виде?

Буду очень благодарен за помощь по данному вопросу.


Ответы (2 шт):

Автор решения: Ilya Lisov

Хочу заметить еще, что не хорошая практика возвращать null, можно это все обернуть в Optional<T>, и еще findAny() в методе getAllProjects() подразумевает возвращение одного значения из стрима в обертке Optional, но Ваш метод возвращает List<Project>.

Для того, чтобы избежать описанной Вами проблемы:

  1. Замените getAll() в вызове на findAll(). Данный метод возвращает список объектов Project вместо Object.

  2. Или приводите к типу Project в лямбда-выражении

    .filter(((Project)project) -> project.getId() == companyId)

Разумеется, первый подход предпочтительнее. Отметьте мой ответ, если он помог Вам.

→ Ссылка
Автор решения: Bakuard
  1. Советую вам ещё раз хорошо подумать - стоит ли делать фильтрацию в памяти. Если у вас есть строгие гарантии что projectRepository.findAll() никогда не вернет большое кол-во объектов и будет вызываться редко - то Ваш подход с фильтрацией в памяти с использованием Stream уместен. Иначе, создайте в репозитории отдельный метод, который умел бы фильтровать проекты по companyId и вызывайте внутри сервиса именно его (или можно сделать на уровне репозитоиря метод, который принимает универсальный фильтр, например, через Criteria API).

  2. Ещё один важный момент - если ваш метод возвращает список, то он никогда не должен возвращать null. Это очень плохая практика. Если у вас нет объектов - просто верните пустой список.

  3. Непонятно, чем различаются методы projectRepository.findAll() и projectRepository.getAll(). Исходя из их названия напрашивается вывод, что они делают одно и тоже. В таком случае у вас дублирование кода. Если они делают разные вещи - то переименуйте один из методов так, чтобы это было сразу понятно.

  4. Транзакции желательно делать на уровен сервиса.

  5. Соблюдайте последовательность в наименовании методов. Если на уровне репозитория метод называется findAll(), то и на уровне сервиса его метод-обертка должен называться точно также.

→ Ссылка