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.
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:
final class cannot be subclassed, so no proxy can be createdfinal method cannot be overridden, so the JPA provider cannot intercept calls to implement lazy loadingWithout 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.
When JPA entities or their methods are marked as final, the application can experience:
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.
@Entity
public final class User { // Noncompliant
@Id
private Long id;
private String username;
@OneToMany(fetch = FetchType.LAZY)
private List<Order> orders;
// getters and setters
}
@Entity
public class User {
@Id
private Long id;
private String username;
@OneToMany(fetch = FetchType.LAZY)
private List<Order> orders;
// getters and setters
}