Exploring the Compatibility of Java 16 Records with JPA Entities

Published on 2023.11.19

Introduction

Java 16 introduced a new feature called records, which provide a concise way to declare classes that are primarily used for holding immutable data. One important question that arises is how records interact with Java Persistence API (JPA) entities. In this article, we will explore the compatibility of Java 16 records with JPA entities.

Understanding JPA Entities

Before delving into the compatibility aspect, let's understand what JPA entities are. JPA entities are plain Java classes that are persistent, meaning their instances can be stored in a database using an ORM framework like Hibernate or EclipseLink.

Records and JPA

While Java records are great for holding immutable data, they are not suitable to be used as JPA entities. JPA relies on the presence of default constructors, non-final fields, and getter/setter methods, which are not available in records by default.

Making Records Compatible with JPA

Although records are not directly compatible with JPA entities, there are workarounds to make them work together. One approach is to define a regular Java class that acts as a wrapper around the record. This class can have JPA annotations, default constructors, and getter/setter methods as required.

Example

Let's take a look at an example to better understand how to make records compatible with JPA entities:

@Entity
@Table(name = "users")
public class UserEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    private int age;

    public UserEntity() {
        // default constructor for JPA
    }

    public UserEntity(UserRecord userRecord) {
        this.name = userRecord.name();
        this.age = userRecord.age();
    }

    // getters and setters
}

public record UserRecord(String name, int age) {
    // no need for constructor, getters or setters
}

In this example, the UserRecord is the immutable data holder class, while UserEntity is the JPA entity class. The UserEntity class has the required default constructor and getter/setter methods, and it acts as the bridge between JPA and the UserRecord.

Conclusion

In summary, Java 16 records are a powerful feature for holding immutable data, but they are not directly compatible with JPA entities due to the lack of default constructors, non-final fields, and getter/setter methods. However, by using a wrapper class, we can make records work seamlessly with JPA. It's important to carefully design the wrapper class to ensure it meets the requirements of JPA. As records evolve in future Java versions, it's possible that direct support for JPA entities will be added.