|

What’s new in JPA 2.2


Take your skills to the next level!

The Persistence Hub is the place to be for every Java developer. It gives you access to all my premium video courses, monthly Java Persistence News, monthly coding problems, and regular expert sessions.


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

Support Java 8 Date and Time API

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.

8 Comments

  1. I miss a better subquery support in JPA. Subqueries only in the where/having-clause and you can only fetch one column is very limited. It is much easier to throw native SQL against the database instead of using JPA when one need subqueries. Even the proprietary hibernate criterion API is much more powerful.

    Greetings

    1. Avatar photo Thorben Janssen says:

      Yes, the subquery support is still very limited. You almost always need to use a native query.

  2. I would like to be able to declare @NamedQuery not only on Entities, but any class, services or service methods in particular. Queries are per use-case anyway, so this would be helpful for me

    1. Avatar photo Thorben Janssen says:

      I like the idea but the problem here is, that it needs to be a class that’s parsed by your JPA implementation. It would create a huge overhead at deploytime, if Hibernate would need to parse all classes of the application to search for a @NamedQuery annotation.

  3. Thanks for the info.
    Do you know what the Reference Implementation will be?
    Eclipselink is looking dead at the Moment…

    1. Avatar photo Thorben Janssen says:

      EclipseLink is still the reference implementation. It looks like they kept it in sync with the latest specification changes.

  4. Avatar photo Binh Thanh Nguyen says:

    Thanks, nice info.

Comments are closed.