7

I have a Spring app that is using Hibernate and the Spring Data JPA's CrudRepository. Everything seems to work properly if the data that was queried for exists in the database. However, if there is a query that returns no result, the CrudRepository returns null and I get a NullPointerException. So for example http://localhost:8080/api/id=3 if there is a row with id 3 in the database it works fine. If there isn't a row with id of 3 it fails with a:

there was an unexpected error (type=Internal Server Error, status=500)

On the client side and a NullPointerException on the server side.

What is the proper way of dealing with a simple case of a "No Results" query?

Ali Dehghani
  • 46,221
  • 15
  • 164
  • 151
Kevin Vasko
  • 1,561
  • 3
  • 22
  • 45

2 Answers2

17

Inspect the return value, if it's not null, return some representation of it as a 200 OK response. Otherwise, return a 404 Not Found. In the end, you would have a controller like:

@RequestMapping(...)
public ResponseEntity<?> getOne(...) {
    Something something = repository.findOne(...);
    if (something == null)
        return ResponseEntity.notFound().build();

    return ResponseEntity.ok(something);
}


You can refactor the preceding code to incorporate Java 8's Optional<T>, as JB Nizet mentioned in the comments. Basically, Optional<T> is just a container that may or may not hold a value of type T. You can use this type as the return type of Spring Data JPA methods, something like the following:
public interface SomethingRepository extends CrudRepository<Something, Long> {
    Optional<Something> findById(Long id);
}

Then define one exception for 404 Not Found:

@ResponseStatus(HttpStatus.NOT_FOUND)
public class NotFoundException extends RuntimeException {}

If you throw an exception of type NotFoundException in your controllers, Spring MVC's exception resolver would catch that exception and convert it to a 404 Not Found HTTP response.

Finally your controller would be like:

@RequestMapping(...)
public Something getOne(...) {
    return repository.findById(id).orElseThrow(NotFoundException::new);
}


For more detailed discussions on:
Community
  • 1
  • 1
Ali Dehghani
  • 46,221
  • 15
  • 164
  • 151
  • 2
    Or you can throw an exception and have some exception annotated with `@ResponseStatus(HttpStatus.NOT_FOUND)`. Combined with the possibility for Spring-data-jpa to return an empty Optional rather than null, you can use: `Something something = somethingRepository.findById(id).orElseThrow(NotFoundException::new);` – JB Nizet Jun 10 '16 at 21:25
  • @JBNizet Yeap, that's a great idea. – Ali Dehghani Jun 10 '16 at 21:26
  • @JBNizet Updated the answer with your suggestion. Thanks – Ali Dehghani Jun 10 '16 at 21:49
  • Thank you, That worked. Would it be better to place the "@ResponseStatus" and "@RequestMapping" at my controller layer or my services layer? – Kevin Vasko Jun 13 '16 at 14:59
  • It's better to not expose controller-specific stuff into your service layer – Ali Dehghani Jun 13 '16 at 15:10
  • those who can searching the mentioned book REST best practices, can be download from link: https://github.com/transidai1705/java-ebooks/blob/master/%5BREST%20in%20Practice%20Hypermedia%20and%20Systems%20Architecture%20Kindle%20Edition%20by%20Ian%20Robinson%20-%202010%5D.pdf – Indrajeet Gour Nov 02 '19 at 18:02
1

None of the spring crud repository find methods throw an exception if no results are returned. They all return nulls. Since you are getting a null pointer exception on the server side you must be trying to perform an operation on the returned value without checking whether it's null first.

Robert Moskal
  • 21,737
  • 8
  • 62
  • 86