How to use findAll() on CrudRepository returning a List instead of Iterable

Viewed 49281

I want to write a FindAll() method which returns a List of all Student objects. But the CRUDRepository only has Iterable<> findAll().

The goal is to get all students in a List and pass it to the API Controller so I can get all the students with a http GET.

What would be the best way to convert this method to List<> FindAll()

In my current code the findAll method in the StudentService gives me the Incompatible types found: Iterable. Required: List error.

Service

@Service
@RequiredArgsConstructor
public class StudentServiceImpl implements StudentService {

    @Autowired
    private final StudentRepository studentRepository;

    //Incompatible types found: Iterable. Required: List
    public List<Student> findAll() {
        return studentRepository.findAll();
    }
}

API Controller

@RestController
@RequestMapping("/api/v1/students")

public class StudentAPIController {

    private final StudentRepository studentRepository;

    public StudentAPIController(StudentRepository studentRepository) {
        this.studentRepository = studentRepository;
    }

    @GetMapping
    public ResponseEntity<List<Student>> findAll() {
        return ResponseEntity.ok(StudentServiceImpl.findAll());
    }
}

StudentRepository

public interface StudentRepository extends CrudRepository<Student, Long> {

}
9 Answers

You can simply define an abstract method List<Student> findAll() in the StudentRepository interface. Something simple like this:

public interface StudentRepository extends CrudRepository<Student, Long> {
    List<Student> findAll();
}

For CrudRepository you will need to use lambda expression in order to return a list

public List<Student> findAll() {
    List<Student> students = new ArrayList<>();
    studentRepository.findAll().forEach(students::add);
    return students;
}

Late to the party, but here's the way I normally do this (with streams / collect). Here assuming a CRUD repository of DingDong:

List<DingDong> dingdongs = StreamSupport //
    .stream(repository.findAll().spliterator(), false) //
    .collect(Collectors.toList());

Two options:

  1. instantiate a list from the iterable in your service method and return that like in Convert Iterator to ArrayList

  2. override the default spring data findAll() method to return the list - see https://docs.spring.io/spring-data/data-commons/docs/1.6.1.RELEASE/reference/html/repositories.html#repositories.custom-implementations

If there are many services that will be returning a list, I'd recommend the second option to set you up for extracting the logic when you've had to do it a few times.

default List<Student> getStudentList() {
    final List<Student> studentList = new LinkedList<>();

    Iterable<Student> iterable = findAll();
    iterable.forEach(studentList::add);

    return studentList;
}

An old approach for those of you who haven't used lambda expression yet but still expect to see working solution:

public List<Student> findAllStudents() {
    Iterable<Student> findAllIterable = studentRepository.findAll();
    return mapToList(findAllIterable);
}

private List<Student> mapToList(Iterable<Student> iterable) {
    List<Student> listOfStudents = new ArrayList<>();
    for (Student student : iterable) {
        listOfStudents.add(student);
    }
    return listOfStudents;
}

There's a simpler way:

List<Student> studentsList;     
studentsList = (List<Student>) studentRepository.findAll();

Add this in CrudRepository:

public interface StudentRepository extends CrudRepository<Student, Long> {
    List<Student> findAll();
}
Related