Date: November 20 2023
Hibernate ORM, one of the most popular Java persistence frameworks, made significant leaps moving from version 5.6 to 6.x. These changes reflect modern Java standards, better integration with Jakarta EE, improved type-safe querying, and cleaner APIs.
If you’re planning to migrate your application or just want to understand what’s new, this post will guide you through the major changes with concrete examples and tips.
1. Jakarta Namespace Migration
What Changed?
Hibernate 6 fully embraces Jakarta Persistence API (JPA) 3.0, which means all javax.persistence packages have moved to jakarta.persistence.
This requires updating your imports throughout the codebase.
Migration Tip:
- Change all imports from:
import javax.persistence.Entity;
to:
import jakarta.persistence.Entity;
- Your persistence.xml should also reference Jakarta namespaces.
Example:
// Hibernate 5.x
import javax.persistence.Entity;
@Entity
public class User {
@Id
private Long id;
private String username;
}
// Hibernate 6.x
import jakarta.persistence.Entity;
@Entity
public class User {
@Id
private Long id;
private String username;
}
2. New Type-safe Querying with the Hibernate ORM Query Language (HQL)
Hibernate 6 introduces a more type-safe query API to replace the old string-based HQL queries, reducing runtime errors.
Example: Traditional HQL in Hibernate 5.6
String hql = "FROM User WHERE username = :username";
List<User> users = session.createQuery(hql, User.class)
.setParameter("username", "johndoe")
.list();
Hibernate 6.x Typed Query API
List<User> users = session.createQuery(
session.getCriteriaBuilder()
.createQuery(User.class)
.where(session.getCriteriaBuilder().equal(
session.getCriteriaBuilder().literal("username"), "johndoe"
))
).list();
More idiomatic usage leverages the Criteria API enhancements for type safety:
CriteriaBuilder cb = session.getCriteriaBuilder();
CriteriaQuery<User> cq = cb.createQuery(User.class);
Root<User> root = cq.from(User.class);
cq.select(root).where(cb.equal(root.get("username"), "johndoe"));
List<User> users = session.createQuery(cq).getResultList();
3. Simplified Configuration
Hibernate 6 simplifies its configuration APIs:
Before (Hibernate 5.6):
Configuration config = new Configuration();
config.configure("hibernate.cfg.xml");
SessionFactory sessionFactory = config.buildSessionFactory();
Now (Hibernate 6.x):
StandardServiceRegistry registry = new StandardServiceRegistryBuilder()
.configure("hibernate.cfg.xml")
.build();
Metadata metadata = new MetadataSources(registry).getMetadataBuilder().build();
SessionFactory sessionFactory = metadata.getSessionFactoryBuilder().build();
The new Metadata and MetadataSources APIs improve bootstrapping flexibility.
4. Improved Collection Mappings
Hibernate 6 introduces new collection types for better handling of lists, maps, and sets with more control over ordering and sorting.
Example: Using @OrderColumn for ordered lists
@Entity
public class Book {
@OneToMany
@OrderColumn(name = "chapter_order")
private List<Chapter> chapters;
}
Hibernate 6 improves the management of @OrderColumn and collection types so that changes in order are automatically detected and persisted.
5. New Session API and Improved Mutability Control
The Session interface has been enhanced with better support for mutability and state transitions:
Example: Evicting vs. Detaching
evict(entity)removes the entity from the session cache but keeps it persistent.detach(entity)fully detaches the entity.
Hibernate 6 clarifies these semantics with improved methods to reduce bugs in state management.
6. Legacy APIs Removed
Some deprecated features have been removed:
- The old Hibernate XML mappings (hbm.xml) have fewer supported features — annotation-based mappings are recommended.
- Certain legacy Criteria APIs are removed in favor of the JPA Criteria API.
7. Migration Tips Summary
| Migration Aspect | Recommendation |
|---|---|
| Namespace Change | Update imports from javax to jakarta |
| Querying | Prefer JPA Criteria API over HQL strings |
| Configuration | Use MetadataSources & SessionFactoryBuilder APIs |
| Mappings | Review collection mappings and ordering |
| Remove Deprecated APIs | Replace legacy Criteria and XML mappings |
| Test Thoroughly | Run integration tests and review cache behavior |
8. Practical Migration Example
Before (Hibernate 5.6):
import javax.persistence.Entity;
import javax.persistence.Id;
@Entity
public class Person {
@Id
private Long id;
private String name;
// getters/setters
}
// HQL query example
List<Person> persons = session.createQuery("from Person where name=:name", Person.class)
.setParameter("name", "Alice")
.list();
After (Hibernate 6.x):
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
@Entity
public class Person {
@Id
private Long id;
private String name;
// getters/setters
}
CriteriaBuilder cb = session.getCriteriaBuilder();
CriteriaQuery<Person> cq = cb.createQuery(Person.class);
Root<Person> root = cq.from(Person.class);
cq.select(root).where(cb.equal(root.get("name"), "Alice"));
List<Person> persons = session.createQuery(cq).getResultList();
9. Conclusion
Migrating from Hibernate 5.6 to 6.x involves some upfront effort, particularly around namespace changes and adopting the improved query APIs. However, the benefits are clear:
- Cleaner, type-safe queries that reduce runtime errors
- Full Jakarta EE 9+ compatibility
- Improved configuration and mapping flexibility
- Better support for modern Java idioms
If you maintain an enterprise app or library using Hibernate, start planning your migration soon. Testing and incremental upgrades are key to a smooth transition.
Would you like me to help with sample migration guides, code snippets for legacy queries conversion, or tips on using Hibernate 6 features like multitenancy or caching? Just say the word!
Next up: Using Jakarta Persistence API (JPA) 3.0 in Modern Java Apps — stay tuned!