JPA 2.2 was only a small release, and I think that’s ok. JPA 2.1 already provides a good enough toolset for most applications. But there was nevertheless some work to do.

Stream query results

This change is tracked in the JPA spec issue #99 and it might sound familiar to you. Hibernate introduced a similar feature in version 5.2.

The JPA interfaces Query and TypedQuery got a new method called getResultStream() which returns a Java 8 Stream of the query result. By default, this method delegates to getResultList().stream(). But a persistence provider, like Hibernate, can override it to provide a better implementation.

That’s what Hibernate already does with the stream() method of its proprietary version of the Query interface. Instead of fetching all records of the query result at once, it uses a ScrollableResult to scroll through the result records. This is way more efficient if you need to process a huge result set.

With JPA 2.2, you can use the following code to scroll through your query results.

Stream<Book> books = em.createQuery("SELECT b FROM Book b", Book.class).getResultStream(); books.map(b -> b.getTitle() + " was published on " + b.getPublishingDate()) .forEach(m -> log.info(m));

Make annotations @Repeatable

This is another Java 8 related change and it’s tracked in the JPA spec issue #115.

It allows you to use the same annotation multiple times for a class or attribute without using a container annotation. So, you can annotate your entity class with multiple @NamedQuery annotations without wrapping them in a @NamedQueries annotation. This makes the code much easier to read, as I showed when Hibernate made their annotations @Repeatable.

With JPA 2.2, the following annotations are repeatable:

AssociationOverride

AttributeOverride

Convert

JoinColumn

MapKeyJoinColumn

NamedEntityGraph

NamedNativeQuery

NamedQuery

NamedStoredProcedureQuery

PersistenceContext

PersistenceUnit

PrimaryKeyJoinColumn

SecondaryTable

SqlResultSetMapping

The Date and Time API was one of the most popular features in Java 8. It’s no surprise that a lot of developers were asking for official support in JPA even so you can add it with a simple AttributeConverter .

With JPA 2.2, you no longer need the converter. As documented in the JPA spec artifact 63, JPA 2.2 adds the support for java.time.LocalDate, java.time.LocalTime, java.time.LocalDateTime, java.time.OffsetTime and java.time.OffsetDateTime.

The classes of the Date and Time API provide all required information to map them to the correct database columns and there is no need for the old @Temporal annotation. You can simply use the classes of the Date and Time API as shown in the following code snippet.

@Entity public class MyEntity { @Id @GeneratedValue(strategy = GenerationType.AUTO) @Column(name = "id", updatable = false, nullable = false) private Long id; @Column private LocalDate date; @Column private LocalDateTime dateTime; ... }

Support CDI Injection in AttributeConverters

This is probably just a minor improvement for most developers. With JPA 2.2 you are able to use CDI injection in your AttributeConverter. You can review the discussion about this change in artifact 109.

The support for CDI Injection allows you to inject your reusable conversion implementation into an AttributeConverter.

@Converter(autoApply = true) public class MyAttributeConverter implements AttributeConverter<MyObject, String> { @Inject private Converter convert; @Override public String convertToDatabaseColumn(MyObject obj) { return convert.toString(obj); } @Override public MyObject convertToEntityAttribute(String s) { return convert.toMyObject(s); } }

Change Persistence Provider Discovery Mechanism for Java 9 Modules

A lot of frameworks and specifications require a few adaptions to work with the JDK9 module system. That’s also the case for the JPA specification and it got discussed in artifact #146.

The expert group changed the wording of the specification in a few places so that the persistence provider implementation now needs to provide a service provider configuration that can be used in a Java SE environment.

Summary

The JPA 2.2 MR provides just a small set of changes to adapt JPA to Java 8 and prepare it for the Java 9 module system. As I wrote at the beginning of this post, that’s not an issue because version 2.1 already provided a powerful toolset.

But I had hoped for a few more changes. The different JPA implementations support several proprietary features which would make the specification a lot better, like the support for ad-hoc joins in JPQL or a better API to load multiple entities by their primary key.