This issue arises when Java classes annotated with @Entity or @MappedSuperclass are declared final, or when methods within these classes are declared final. JPA providers require the ability to create proxy subclasses for lazy loading and other runtime optimizations, which is prevented by the final modifier.

Why is this an issue?

JPA (Java Persistence API) providers like Hibernate rely on runtime proxy generation to implement several key features:

To create these proxies, the JPA provider needs to generate a subclass of your entity class at runtime. This subclass overrides methods to add the lazy loading and tracking behavior.

When you declare a class or method as final, you prevent inheritance and method overriding. This breaks the proxy mechanism:

Without working proxies, lazy loading fails. Instead of loading data on demand, the JPA provider may fall back to eager loading, which can cause significant performance problems. In some cases, it may even cause runtime exceptions.

What is the potential impact?

When JPA entities or their methods are marked as final, the application can experience:

How to fix it

Remove the final modifier from the entity class declaration or its methods. This allows the JPA provider to create proxy subclasses for lazy loading and other optimizations. If you are using Hibernate, you can also implement an interface that declares all the attribute getters/setters.

Code examples

Noncompliant code example

@Entity
public final class User { // Noncompliant
    @Id
    private Long id;

    private String username;

    @OneToMany(fetch = FetchType.LAZY)
    private List<Order> orders;

    // getters and setters
}

Compliant solution

@Entity
public class User {
    @Id
    private Long id;

    private String username;

    @OneToMany(fetch = FetchType.LAZY)
    private List<Order> orders;

    // getters and setters
}

Resources

Documentation