From 8015d5f61271014cecc9e2085f9106f30fa4832d Mon Sep 17 00:00:00 2001 From: Richard Zowalla Date: Wed, 2 Sep 2026 20:37:56 +0200 Subject: [PATCH] [OPENJPA-2984] Record why an id class is no longer checked for Serializable The check was not lost in the rewrite. Jakarta Persistence 3.2 section 2.4.1 dropped both the public and the Serializable requirement for a primary key class, and bf3d2b1d9 removed the warning deliberately: the same commit deleted the message key, relaxed the matching public-ness rules in the kernel and added a test with a package private, non-serializable id class. Restoring the warning would fire against metadata the specification allows, including that test's own entity. What was missing is the reason, so both parsers now carry it where the check used to be, along with the consequence that does survive: a non-serializable id class cannot be used where OpenJPA serializes the identity object it wraps, which detached entities, remote commit events and a distributed data cache do. The manual still listed the pre-3.2 rules; its identity class criteria are corrected. Note that the constructor requirement is only that one without arguments exists, of any visibility, since validateAppIdClassMethods uses getDeclaredConstructor(). --- .../AnnotationPersistenceMetaDataParser.java | 7 ++++++ .../XMLPersistenceMetaDataParser.java | 7 +++++- .../src/doc/manual/jpa_overview_pc.xml | 25 +++++++++++-------- 3 files changed, 27 insertions(+), 12 deletions(-) diff --git a/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/AnnotationPersistenceMetaDataParser.java b/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/AnnotationPersistenceMetaDataParser.java index 7ab5207b05..d8912c73ab 100644 --- a/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/AnnotationPersistenceMetaDataParser.java +++ b/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/AnnotationPersistenceMetaDataParser.java @@ -637,6 +637,13 @@ private ClassMetaData parseClassAnnotations() { break; case ID_CLASS: if (isMetaDataMode()) { + // Jakarta Persistence 3.2 (section 2.4.1) no longer requires + // the primary key class to be public or to implement + // Serializable, so neither is validated here; see + // OPENJPA-2940 and OPENJPA-2984. A non-serializable id + // class does still prevent serializing the identity + // object it is wrapped in, which detached entities, + // remote commit events and a distributed data cache do. meta.setObjectIdType(((IdClass) anno).value(), true); } break; diff --git a/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/XMLPersistenceMetaDataParser.java b/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/XMLPersistenceMetaDataParser.java index 432f4d07bf..c84a24b90c 100644 --- a/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/XMLPersistenceMetaDataParser.java +++ b/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/XMLPersistenceMetaDataParser.java @@ -81,7 +81,6 @@ import java.io.File; import java.io.IOException; import java.io.InputStream; -import java.io.Serializable; import java.lang.reflect.Field; import java.lang.reflect.Member; import java.lang.reflect.Method; @@ -1347,6 +1346,12 @@ protected boolean startIdClass(Attributes attrs) } catch (Throwable t) { throw getException(_loc.get("invalid-id-class", meta, cls), t); } + // Jakarta Persistence 3.2 (section 2.4.1) no longer requires the primary + // key class to be public or to implement Serializable, so neither is + // validated here; see OPENJPA-2940 and OPENJPA-2984. A non-serializable + // id class does still prevent serializing the identity object it is + // wrapped in, which detached entities, remote commit events and a + // distributed data cache do. meta.setObjectIdType(idCls, true); return true; } diff --git a/openjpa-project/src/doc/manual/jpa_overview_pc.xml b/openjpa-project/src/doc/manual/jpa_overview_pc.xml index a34392f1bd..9fe864a886 100644 --- a/openjpa-project/src/doc/manual/jpa_overview_pc.xml +++ b/openjpa-project/src/doc/manual/jpa_overview_pc.xml @@ -838,17 +838,7 @@ following criteria: -The class must be public. - - - - -The class must be serializable. - - - - -The class must have a public no-args constructor. +The class must have a no-args constructor. @@ -881,6 +871,19 @@ hierarchy mirrors the inheritance hierarchy of the owning entity classes (see +Jakarta Persistence 3.2 no longer requires the identity class to be public or to +implement java.io.Serializable, and OpenJPA no longer +enforces either. An identity class that does not implement +Serializable can, however, not be used where OpenJPA has +to serialize the identity object it is wrapped in: serializing a detached +entity, remote commit events in a clustered configuration, and a distributed +data cache. Those fail with a +java.io.NotSerializableException naming the identity +class. + + + + Though you may still create identity classes by hand, OpenJPA provides the appidtool to automatically generate proper identity classes based on your identity fields. See