Date: January 25 2024
The release of Jakarta Persistence API (JPA) 3.0 marks a significant step forward for Java persistence, aligning the specification with the Jakarta EE 9+ namespace changes and introducing useful enhancements that modernize and simplify persistence in Java applications.
If you’re building new apps or migrating existing ones, understanding the changes in JPA 3.0 is crucial to leveraging the latest capabilities while ensuring compatibility and maintainability.
1. Jakarta Namespace Migration: The Most Obvious Change
The biggest visible change in JPA 3.0 is the move from javax.persistence
to jakarta.persistence
. This is part of the larger Eclipse Foundation-led transition from Java EE to Jakarta EE.
Migration Tip:
Update all your import statements:
// Old import
import javax.persistence.Entity;
// New import
import jakarta.persistence.Entity;
The change affects your persistence.xml
, annotations, and APIs.
2. New Features in JPA 3.0
a) Support for Java Records as Entities
JPA 3.0 allows Java Records to be used as immutable entities. This modernizes domain modeling by enabling concise immutable data carriers that reduce boilerplate.
Example:
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
@Entity
public record User(@Id Long id, String username, String email) {}
Records provide automatic getters, equals()
, hashCode()
, and toString()
, making entities lightweight and immutable by default.
b) Support for Attribute Converters for Collections
JPA 3.0 enhances AttributeConverter support, enabling easier mapping of collection attributes to database columns using converters.
Example:
If you want to store a list of tags as a comma-separated string:
import jakarta.persistence.AttributeConverter;
import jakarta.persistence.Converter;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
@Converter
public class StringListConverter implements AttributeConverter<List<String>, String> {
@Override
public String convertToDatabaseColumn(List<String> attribute) {
return attribute == null ? null : String.join(",", attribute);
}
@Override
public List<String> convertToEntityAttribute(String dbData) {
return dbData == null ? List.of() : Arrays.stream(dbData.split(",")).collect(Collectors.toList());
}
}
Usage in entity:
import jakarta.persistence.Convert;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import java.util.List;
@Entity
public class Article {
@Id
private Long id;
@Convert(converter = StringListConverter.class)
private List<String> tags;
// getters/setters
}
c) Improved Criteria API
JPA 3.0 adds enhancements to the Criteria API for building type-safe queries, including support for list-valued paths and subqueries improvements.
Example: Using list-valued paths
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Article> cq = cb.createQuery(Article.class);
Root<Article> root = cq.from(Article.class);
cq.where(cb.isMember("java", root.get("tags")));
List<Article> articles = entityManager.createQuery(cq).getResultList();
This queries for articles whose tags
collection contains "java"
.
3. Jakarta Persistence XML Changes
persistence.xml
remains essential for configuration, but the schema location and namespace must reflect Jakarta EE:
<persistence xmlns="https://jakarta.ee/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/persistence
https://jakarta.ee/xml/ns/persistence/persistence_3_0.xsd"
version="3.0">
<persistence-unit name="my-unit">
<class>com.example.User</class>
<properties>
<!-- properties -->
</properties>
</persistence-unit>
</persistence>
4. JPA 3.0 and Hibernate 6 Compatibility
Hibernate 6 is designed to work with JPA 3.0, so upgrading to Hibernate 6 often means you’re also adopting the Jakarta Persistence API 3.0.
Ensure your Hibernate version and dependencies align with JPA 3.0 to avoid conflicts.
5. Migration Tips for Existing Apps
- Change all
javax.persistence
imports tojakarta.persistence
. - Update your
persistence.xml
schema location and namespace. - Verify third-party dependencies support Jakarta EE 9+ namespaces.
- Test Java Records entities if you want to adopt them.
- Refactor attribute converters if needed for new collection support.
- Adjust your build tool configurations (Maven, Gradle) for Jakarta dependencies.
6. Practical Example: Migrating a Simple Entity
Hibernate 5.x + JPA 2.2
import javax.persistence.Entity;
import javax.persistence.Id;
@Entity
public class Customer {
@Id
private Long id;
private String name;
// getters/setters
}
Hibernate 6.x + JPA 3.0
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
@Entity
public class Customer {
@Id
private Long id;
private String name;
// getters/setters
}
That’s it! Just a namespace switch — but the implications are vast, so test thoroughly.
7. Conclusion
Jakarta Persistence API 3.0 modernizes Java persistence by:
- Aligning with Jakarta EE 9+ namespace changes.
- Adding support for modern Java features like Records.
- Enhancing attribute converters and the Criteria API.
Whether you’re starting fresh or migrating, embracing JPA 3.0 ensures your app is future-proof, cloud-ready, and able to leverage the evolving Java ecosystem.
Want to dive deeper? Next time, we’ll explore Advanced Hibernate Caching Strategies to supercharge your data layer’s performance!