Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -244,9 +244,9 @@ protected boolean synchronizeMappings(ClassLoader loader, JDBCConfiguration conf
if (tool.getRepository().getMetaData(cls, null, false) != null) {
throw mde;
}
// see MetamodelImpl for why such a class is skipped
conf.getLog("openjpa.jdbc.Schema").warn(
"Skipping schema synchronization for non-managed class: "
+ cls.getName());
_loc.get("skip-unmanaged-class", cls.getName()));
}
}
tool.record();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -183,3 +183,7 @@ alter-seq-disabled: The property "openjpa.jdbc.DBDictionary=disableAlterSeqenceI
which is defined in the entity''s sequence. With this SQL statement disabled, it is the \
responsibility of the user to ensure that the entity''s sequence definition matches the \
sequence defined in the database.
skip-unmanaged-class: The class "{0}" is listed in the persistence unit but \
has no persistence metadata, and is skipped during schema \
synchronization. If it was meant to be managed, check that it is \
annotated or mapped in orm.xml.
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@
import org.apache.openjpa.util.GeneratedClasses;
import org.apache.openjpa.util.ImplHelper;
import org.apache.openjpa.util.InternalException;
import org.apache.openjpa.util.MetaDataException;
import org.apache.openjpa.util.UserException;
import org.apache.openjpa.util.asm.ClassNodeTracker;

Expand Down Expand Up @@ -153,17 +152,16 @@ public void write(ClassNodeTracker cnt) throws IOException {

// set this before enhancement as well as after since enhancement
// uses a different metadata repository, and the metadata config
// matters in the enhancement contract. In order to avoid a
// NullPointerException, check for no metadata and throw an
// exception if none exists. Otherwise, don't do any warning here,
// since we'll issue warnings when we do the final metadata
// reconfiguration at the end of this method.
// matters in the enhancement contract.
ClassMetaData meta = enhancer.getMetaData();
if (meta == null) {
// non-entity classes (DTOs, listeners, ID classes) may be
// listed in persistence.xml <class> elements; skip them
if (log.isWarnEnabled())
log.warn(_loc.get("no-meta", cls));
// a persistence unit may legitimately list a class that is
// not a managed type; skip it rather than failing, and log
// it so that a forgotten annotation stays diagnosable.
// See MetamodelImpl for the reasoning.
if (log.isWarnEnabled()) {
log.warn(_loc.get("no-meta", cls.getName()));
}
continue;
}
configureMetaData(meta, conf, redefine, false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,16 +46,28 @@ public void setUp() {
}

/**
* Verify that a non-entity class listed in persistence.xml is
* gracefully skipped. Per JPA 3.2, persistence units may list
* non-entity managed classes (e.g. converters, listeners,
* ID classes, exceptions) which should not cause errors.
* Verify that a class listed in persistence.xml without persistence
* metadata is skipped rather than failing entity manager creation.
* <p>
* Jakarta Persistence 3.2 chapter 8 does not say what a provider must do
* with such a class, so the behaviour is provider defined; Hibernate and
* EclipseLink both skip, and the Jakarta Persistence TCK requires it,
* since its own persistence units list plain classes alongside entities.
* The skip is logged, so a forgotten annotation stays diagnosable; see
* MetamodelImpl and JDBCBrokerFactory.
*/
public void testMissingMetaData() {
// Should not throw — non-entity classes are silently skipped
emf.createEntityManager().close();
}

/**
* The metamodel is built over the same class list, and must skip the
* unmanaged class rather than fail.
*/
public void testMissingMetaDataInMetamodel() {
assertNotNull(emf.getMetamodel());
}

@Override
public void tearDown() {
emf.close();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
import org.apache.openjpa.kernel.exps.FilterListener;
import org.apache.openjpa.kernel.exps.Resolver;
import org.apache.openjpa.lib.util.J2DoPrivHelper;
import org.apache.openjpa.lib.log.Log;
import org.apache.openjpa.lib.util.Localizer;
import org.apache.openjpa.meta.ClassMetaData;
import org.apache.openjpa.meta.FieldMetaData;
Expand Down Expand Up @@ -89,9 +90,21 @@ public MetamodelImpl(MetaDataRepository repos) {

ClassMetaData meta = repos.getMetaData(cls, null, false);
if (meta == null) {
// Skip non-entity classes (e.g. exceptions, ID classes,
// listeners) that are listed in persistence.xml <class>
// elements but have no JPA metadata.
// OPENJPA-2940 / OPENJPA-2992: a class listed in a <class>
// element that resolves to no metadata is skipped rather
// than failing. Jakarta Persistence 3.2 chapter 8 says
// nothing about a listed class that is not an entity,
// embeddable, mapped superclass or converter, so the
// behaviour is provider defined, and both Hibernate and
// EclipseLink skip. The Jakarta Persistence TCK requires
// tolerating it: its persistence units list plain classes
// such as LineItemException alongside real entities.
// The skip is logged so that a forgotten @Entity annotation
// or a missing orm.xml entry stays diagnosable.
Log log = repos.getLog();
if (log.isWarnEnabled()) {
log.warn(_loc.get("skip-unmanaged-class", cls.getName()));
}
continue;
}
PersistenceType type = getPersistenceType(meta);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,3 +94,6 @@ decl-version-not-found: Declared version attribute of {1} type not found in {2}
version-not-found: Version attribute of {1} type not found in {2}
generic-type-param: Can not determine generic type parameter for field {0} of type {1} in {2}. \
Using java.lang.Object.
skip-unmanaged-class: The class "{0}" is listed in the persistence unit but \
has no persistence metadata, and is left out of the metamodel. If it was \
meant to be managed, check that it is annotated or mapped in orm.xml.
17 changes: 12 additions & 5 deletions openjpa-project/src/doc/manual/migration_considerations.xml
Original file line number Diff line number Diff line change
Expand Up @@ -718,11 +718,18 @@
Listing a class without persistence metadata in a persistence unit
(<literal>class</literal> element) previously failed at start-up with
"No registered metadata for type", in the runtime enhancer, in
<literal>getMetamodel()</literal> and during schema synchronization. Such classes
are now skipped with a warning on the <literal>openjpa.Enhance</literal> and
<literal>openjpa.jdbc.Schema</literal> logs. A forgotten <literal>@Entity</literal>
annotation is therefore no longer detected at start-up; watch the logs for the new
warnings.
<literal>getMetamodel()</literal> and during schema synchronization. Such a class
is now skipped instead, because a persistence unit may legitimately list
classes that are not managed types. The skip is logged as a warning on the
<literal>openjpa.MetaData</literal> log when the metamodel is built and on the
<literal>openjpa.jdbc.Schema</literal> log during schema synchronization, so a
forgotten <literal>@Entity</literal> annotation remains diagnosable.
</para>
<para>
Note that with the default <literal>openjpa.RuntimeUnenhancedClasses=unsupported</literal>
such a class is still rejected at start-up, by the runtime enhancer, with
"This configuration disallows runtime optimization"; the skip described above
applies once that check passes.
</para>
</section>
<section id="jpa_4.2_KernelLeniency">
Expand Down
Loading