Wednesday, 23 December 2015

JPA result lists and Java 8 streams

We recently changed a project to build using Java 8.
This decision was largely driven by the need to use the Date Time API available in Java 8 but several developers, including me, were itching to start using Functional Interfaces/programming and Lambdas.

Fortunately we have not gone down the road of "refactor" everything into Java 8 but new code is now being written using things like Streams and Lambdas. When the opportunity presents itself existing code is also being re-factored.

All was well until I started using Streams on result lists from JPA Entities (the same is valid for JPA query result lists). After changing code like this

into this
no results were being returned.

The result list is the returned by the zone.getPlaces() method whose type is List<Place>. No surprises there and in fact mocking this for a test would mean that the re-factored code would pass tests.
So what is causing the production code to behave differently?

Well the answer lies in the actual JPA implementation, in this case EclipseLink 2.5.2, and the IndirectList classes which are used to facilitate all the clever things which EclipseLink does under the hood. The actual explanation is too detailed to go into it here but there is a bug which does show what was wrong and, more importantly, that this has been fixed in EclipseLink versions 2.6 and beyond.

Worryingly tests which use mocks cannot not pick this problem up, tests which use the underlying JPA implementation would but do you want to write JUnit tests using the database?

Why is this important?

  • Because JUnit tests which mock database operations will provide false test results.
  • Because the JPA implementation we use for this project is provided by the application server we run the software on.
Newer versions of that application server which provide a later version of EclipseLink are available but that migration is a different story.

No comments:

Post a Comment