From 72e2186947fc6f082aaab9931f1ee92967758d75 Mon Sep 17 00:00:00 2001 From: Richard Zowalla Date: Tue, 25 Aug 2026 18:53:30 +0200 Subject: [PATCH 1/2] [OPENJPA-2940] Add migration considerations for OpenJPA 4.2.0 (Jakarta Persistence 3.2) Documents the incompatibilities, default changes, platform/dependency requirements, database-specific changes, SPI changes and notable new features introduced by the Jakarta Persistence 3.2 implementation (#144), derived from the merged code changes and the PR review discussion. --- .../doc/manual/migration_considerations.xml | 1091 ++++++++++++++++- 1 file changed, 1074 insertions(+), 17 deletions(-) diff --git a/openjpa-project/src/doc/manual/migration_considerations.xml b/openjpa-project/src/doc/manual/migration_considerations.xml index f908de5b0a..8f72fb40e0 100644 --- a/openjpa-project/src/doc/manual/migration_considerations.xml +++ b/openjpa-project/src/doc/manual/migration_considerations.xml @@ -647,23 +647,1080 @@ DBDictionary.supportsQueryTimeout -
- PostgreSQL stores char fields as CHAR by default - - Previous releases stored Java char fields in numeric - (INTEGER) columns on PostgreSQL, following the generic - DBDictionary.StoreCharsAsNumbers=true default. - Starting with this release, StoreCharsAsNumbers defaults to - false on PostgreSQL 9 and later, so char - fields are mapped to CHAR columns. - - - Existing schemas created by earlier OpenJPA releases must either migrate the - affected columns to CHAR or restore the previous behaviour by - setting the property explicitly, e.g. - openjpa.jdbc.DBDictionary=postgres(StoreCharsAsNumbers=true). - An explicitly configured value is always respected and never overridden by the - PostgreSQL version detection. +
+ +
+ OpenJPA 4.2.0 +
+ Incompatibilities + + + OpenJPA 4.2.0 implements the Jakarta Persistence 3.2 specification and passes the + Jakarta Persistence 3.2 TCK. The following sections indicate changes that are incompatible + between OpenJPA 4.1.x releases and the 4.2.0 release. Most of them align OpenJPA with + the specification and cannot be switched off; where a configuration option restores + the previous behavior, it is mentioned in the respective section. Open follow-up items + from the review of this work are tracked under OPENJPA-2945. + +
+ Platform and Dependency Requirements + + OpenJPA 4.2.0 requires Java 17 or later at build and run time (4.1.x required + Java 11). All jars contain Java 17 class files. Java 21 and Java 25 runtimes are + supported; class files of newer JDKs are read through + xbean-asm9-shaded 4.30. + + + The jakarta.persistence:jakarta.persistence-api dependency was + raised from 3.1.0 to 3.2.0 (Jakarta EE 11 level). Applications must update explicit + dependencies on the API and recompile. Custom wrappers implementing + jakarta.persistence interfaces (EntityManager, + EntityManagerFactory, Query, + CriteriaBuilder, PersistenceUnitInfo, ...) + must implement the new 3.2 methods. The persistence_3_2.xsd and + orm_3_2.xsd schemas are bundled and selected for documents + declaring version="3.2"; version="3.1" + documents are still not accepted (use 3.0 or 3.2). + + + XML column mapping (XMLValueHandler) and the detection of + XML-mapped value classes now use jakarta.xml.bind (JAXB 4) + instead of javax.xml.bind (JAXB 2). The optional dependencies + are jakarta.xml.bind:jakarta.xml.bind-api 4.0.x and a JAXB 4 + runtime such as com.sun.xml.bind:jaxb-impl 4.0.x. Value classes + that are still annotated with javax.xml.bind.annotation + annotations are no longer recognized as XML column types and silently fall back to + the default (serialized) mapping. Migrate such classes to + jakarta.xml.bind.annotation. + + + The managed JDBC driver versions used for testing were raised: MySQL Connector/J 9.x + (com.mysql:mysql-connector-j, driver class + com.mysql.cj.jdbc.Driver), MariaDB Connector/J 3.5.x, Microsoft + mssql-jdbc 13.x and Derby 10.16.x (which itself requires Java 17). + MySQLDictionary now also recognises + com.mysql.cj.jdbc.exceptions.MySQLTimeoutException as a timeout + exception, so lock and query timeouts are classified correctly with Connector/J 8 + and later. Drivers are not shipped with OpenJPA; see + for the tested database and driver versions. + + + Build-only changes: the Maven profile test-h2-2 was removed + (use test-h2), and the legacy JPA 1.0 / 2.0 TCK profiles in + openjpa-integration/tck were replaced by the Jakarta Persistence + 3.2 TCK runner (-Ptck32-profile, run-tck32.sh). + +
+
+ SecurityManager Support Removed + + All AccessController.doPrivileged(...) calls were removed from + OpenJPA. Running OpenJPA under a Java SecurityManager with a + policy that grants permissions only to the OpenJPA jars is no longer supported (the + SecurityManager is deprecated for removal since Java 17 and + permanently disabled since Java 24, JEP 486). + + + As a consequence the public PrivilegedAction factory methods of + org.apache.openjpa.lib.util.J2DoPrivHelper (for example + getForNameAction, getClassLoaderAction, + newInstanceAction, getContextClassLoaderAction) + were removed; only getLineSeparator(), + getPathSeparator(), newInstance(Class) and + newDeamonThread(Runnable, String) remain. Third-party code + (custom product derivations, dictionaries, plugins, application server integrations) + using these helpers must call the JDK API directly. Plugin classes instantiated + through J2DoPrivHelper.newInstance may now have a non-public + no-argument constructor. + +
+
+ New JPQL Reserved Identifiers + + The JPQL grammar now knows the Jakarta Persistence 3.2 keywords + ID, VERSION, FIRST, + LAST, ON, NULLS, + CAST, STRING, INTEGER, + LONG, FLOAT, DOUBLE, + TREAT, UNION, INTERSECT, + EXCEPT, RIGHT and REPLACE + (case-insensitive), as well as the || concatenation operator. + In previous releases these words could be used as identification variables and + result aliases, for example SELECT e.id AS id FROM E e ORDER BY id + or SELECT first FROM Foo first. Such queries are now rejected + with a parse error, as required by section 4.4.1 of the specification. + + + With the exception of INTEGER, LONG, + FLOAT and DOUBLE the new keywords may still be + used as path components, so attributes named id, + version, first or replace + can still be navigated (o.version). Attributes named + integer, long, float or + double can no longer be referenced in a JPQL path expression; + rename them or access them through the Criteria API or native SQL. Rename + identification variables and aliases that collide with the new keywords (most + commonly id, version, first, + last and on). There is no soft-keyword mode + and no compatibility option. + +
+
+ JPQL Integer Literals are typed Integer + + Previous releases always created JPQL integer literals as + java.lang.Long, so SELECT 1 FROM ... or + e.intField + 1 produced Long results. + As required by section 4.8.5 of the specification, an integer literal without an + l/L suffix that fits into the + int range is now a java.lang.Integer; + arithmetic on Byte, Short and + Integer operands is promoted to Integer + (also in the Criteria API). + + + Application code that casts such results to Long must be + adapted to Integer or Number, or use an + explicit 1L literal. No compatibility option exists. + +
+
+ Query value conversion + + A String literal compared with a numeric path or parameter + (WHERE e.intField = '1', cb.equal(path, "12")) + is now parsed as a number of the path's type; previously a one-character literal was + compared as a Character and longer literals were rejected. The + character comparison is only used when the literal cannot be parsed as a number. + Selecting a collection- or map-valued attribute (SELECT e.addresses FROM + Employee e, query.select(root.get("addresses"))) is + treated as an implicit join and returns one row per element, typed as the element + type, instead of a collection-typed projection. + java.sql.Date values are no longer implicitly converted to + java.sql.Time or java.sql.Timestamp + when query values are compared (the same rule already applied to + java.util.Date). Enum names read from padded + CHAR columns are trimmed before Enum.valueOf(). + No compatibility option exists. + +
+
+ Query.getResultList() returns a materialized ArrayList + + Query.getResultList() previously returned a lazy + org.apache.openjpa.lib.rop.ResultList wrapper that streamed + rows on demand (see ) and became invalid + when the query or the EntityManager was closed. Jakarta + Persistence 3.2 requires a mutable List, so the result is now + copied into a java.util.ArrayList: all rows are fetched + immediately, the list stays usable after the EntityManager + is closed, and it is no longer an instance of ResultList. + Query.getResultStream() also materializes the complete result + first. Large result set collections on entity fields + () are not affected. + + + For very large query results use setFirstResult() / + setMaxResults() paging, or obtain the kernel query via + OpenJPAQuery.getDelegate() for lazy semantics. Code that casts + the result to ResultList or + DelegatingResultList must be changed. + +
+
+ Bulk DELETE no longer cascades + + In previous releases a JPQL or Criteria bulk DELETE against an + entity with cascade-delete or dependent relations (for example + @OneToMany(cascade=REMOVE) or an + @ElementCollection) was executed in memory: every instance was + loaded and removed through the persistence context, cascading to related entities + and cleaning up join table and element collection rows. As required by section + 4.10 of the specification, bulk operations do not cascade. A DELETE + query now issues a single SQL DELETE against the entity table(s); + related entities, join table rows and element collection rows are left untouched + and will cause foreign key violations unless the database defines + ON DELETE CASCADE. + + + Delete dependents explicitly (separate bulk deletes or em.remove()) + or rely on database-level cascades. Note that a bulk UPDATE or + DELETE that still has to be executed in memory now flushes all + pending changes of the persistence context after processing. No compatibility + option exists. See also . + +
+
+ FlushModeType.AUTO flushes whenever the context is dirty + + Previously a query only flushed pending changes when a dirty instance belonged to + a type in the query's access path, and never for SELECT queries + when was true. With + FlushModeType.AUTO (the default, + =true) and an active + transaction, a query now flushes whenever any instance in the persistence context + is new, dirty or deleted, regardless of the query's access path, and overrides + openjpa.IgnoreChanges. Applications with write-heavy transactions + may observe more flushes (and therefore earlier constraint or trigger evaluation). + + + To restore the previous behavior use FlushModeType.COMMIT on + the query or the EntityManager, or set + openjpa.FlushBeforeQueries to false or + with-connection. + +
+
+ Exceptions mark the transaction rollback-only; closed EntityManager checks + + As required by section 3.3.7.1 of the specification, every + RuntimeException raised by an EntityManager + or Query method now marks the active transaction for + rollback, except NoResultException, + NonUniqueResultException, + LockTimeoutException and + QueryTimeoutException. In previous releases the transaction + remained committable after, for example, an IllegalArgumentException + from find(), createNamedQuery() or an invalid + CriteriaQuery. Applications that caught such an exception and + committed the same transaction now receive a RollbackException + and must restart the transaction. + + + Operations on a closed EntityManager or its + Query objects now consistently throw + IllegalStateException. This includes + getEntityManagerFactory(), getCriteriaBuilder(), + getMetamodel(), getDelegate(), + setProperty(), isJoinedToTransaction(), + createEntityGraph(), createQuery(CriteriaQuery) + and Query.getHints(), getLockMode(), + closeAll() and the parameter accessors, which used to work on a + closed EntityManager. Further changes: + getLockMode()/setLockMode() on a bulk + UPDATE/DELETE query and + executeUpdate() on a SELECT query throw + IllegalStateException; + createQuery(CriteriaQuery) snapshots the criteria state, so + modifying the CriteriaQuery afterwards no longer affects the + created Query; isJoinedToTransaction() + returns true for an active resource-local transaction. + +
+
+ Argument validation in find(), getReference(), detach(), contains(), remove() + + find(cls, null) previously returned null, a + primary key of the wrong type or a non-entity class surfaced later as an OpenJPA + ArgumentException or a failed lookup, and removing a detached + unenhanced entity could be silently ignored. These methods now validate their + arguments as required by the specification and throw + IllegalArgumentException (marking the transaction for + rollback) for null keys, non-entity classes, primary keys of an + incompatible type (numeric widening such as Integer to + Long is accepted, narrowing is rejected), non-entities + passed to detach()/contains(), and detached + instances passed to remove(). getReference() + throws EntityNotFoundException also for unenhanced entities. + + + Guard against null keys, pass keys of the declared + @Id type and merge() detached instances before + removing them. No compatibility option exists. + +
+
+ EntityManager.close() with an active resource-local transaction + + Previously EntityManager.close() threw an + InvalidStateException while a resource-local transaction was + active; a deferred close existed only for managed (JTA) transactions with the + CloseOnManagedCommit compatibility flag. As required by sections + 3.3.2 and 7.7 of the specification, close() now always returns + and the persistence context is released when the transaction completes: + isOpen() reports false immediately while + em.getTransaction().commit()/rollback() + remain callable. + + + Code that relied on the exception to detect a leaked open transaction must check + em.getTransaction().isActive() itself and end the transaction + explicitly. There is no option to restore the exception. + +
+
+ EntityManagerFactory lifecycle and properties + + EntityManagerFactory.close() could previously be called more than + once, and methods of a closed factory either worked or failed deep inside the kernel. + Now getProperties(), createEntityManager(), + getCriteriaBuilder(), getMetamodel(), + getPersistenceUnitUtil() and + getSchemaManager() throw IllegalStateException + after close(), and a second close() throws as + well. createEntityManager(SynchronizationType.UNSYNCHRONIZED) + throws IllegalStateException instead of + UnsupportedOperationException (it is forbidden for + RESOURCE_LOCAL units and still unimplemented for JTA units). + + + EntityManagerFactory.getProperties() no longer creates a temporary + EntityManager to merge EntityManager-level + defaults (lock timeout, cache modes, fetch plan settings) into its result, and + null-valued entries are removed; read such defaults from + EntityManager.getProperties() instead. + addNamedQuery() now replaces an existing definition of the same + name and records flush mode, max results and lock mode; Criteria queries are stored + as JPQL text, which is not guaranteed to round-trip for complex criteria. + +
+
+ Query parameter API + + Reading an unbound parameter via getParameterValue() now throws + IllegalStateException (previously + IllegalArgumentException or null); + Parameter objects obtained from another query are rejected + with IllegalArgumentException; + getParameter(String, Class) now correctly accepts an exact or + wider type (the positional variant getParameter(int, Class) still + only accepts the exact type or a subtype). A parameter bound with + TemporalType.DATE is converted to java.sql.Date + (time of day dropped) instead of being passed through unchanged. + + + Catch IllegalStateException for unbound parameters and expect + java.sql.Date semantics for DATE-typed + parameters compared against TIMESTAMP columns. + +
+
+ StoredProcedureQuery semantics + + Positional stored procedure parameters are now resolved 1-based (previously the + 0-based column index was used as fallback, so position 1 could match the second + IN column), and only IN/INOUT/ + OUT columns are registered, so positional indexes shift for + PostgreSQL functions with a return value. When a procedure declares + OUT parameters the connection is kept open (with auto-commit + temporarily disabled) until the result list is closed, so that + REF_CURSOR results can be consumed; consume and close such + result lists promptly. + + + executeUpdate() now requires an active transaction + (TransactionRequiredException) and + getUpdateCount() returns -1 after it; + setLockMode()/getLockMode() throw + IllegalStateException; + getOutputParameterValue() throws + IllegalArgumentException for unknown names or positions; + NoResultException and + NonUniqueResultException propagate unwrapped; procedure + metadata lookup retries with the lower-cased name; an + orm.xml named-stored-procedure-query overrides + an annotation of the same name. + +
+
+ Criteria API and Metamodel + + Several OpenJPA extensions and lenient behaviors of the Criteria API were tightened + to the specification: CriteriaBuilder.array()/tuple() + reject nested compound selections and multiselect()/select() + reject duplicate aliases with IllegalArgumentException; + cb.literal(null) throws IllegalArgumentException + (use nullLiteral(Class)); Path.get() on a basic + path and From.getCorrelationParent() on a non-correlated + From throw IllegalStateException; + Metamodel.entity(Class)/embeddable(Class) throw + IllegalArgumentException for unknown types instead of + returning null; ParameterExpression.getPosition() + returns null (previously threw an internal exception). + + + Embeddable-typed attributes are no longer reported as associations + (isAssociation() is false, + getBindableType() is SINGULAR_ATTRIBUTE), + getBindableJavaType() returns the declared attribute type, and + getId(Class)/getDeclaredId(Class) require strict + type assignability. cb.treat(Root, Class) is now implemented; + treat() on joins and paths returns the argument unchanged without + narrowing, and TREAT only matches the exact treated class, not its + subclasses. Flatten nested selections, use unique aliases and adjust catch blocks + and null checks accordingly. + +
+
+ PersistenceUnitUtil.getIdentifier() returns the plain identifier + + PersistenceUnitUtil.getIdentifier() previously returned the + internal org.apache.openjpa.util.OpenJPAId wrapper + (LongId, StringId, ...) for managed + entities and null for new, detached or unenhanced entities and + for non-entities. It now returns the raw identifier value (the plain key or the + IdClass instance for compound identity), also for new, detached + and unenhanced entities, and throws IllegalArgumentException + for objects that are not entities. Code that cast the result to + OpenJPAId must use the plain value or call + OpenJPAEntityManager.getObjectId(). + +
+
+ Cache mode properties on EntityManager.setProperty() + + EntityManager.setProperty("jakarta.persistence.cache.retrieveMode", ...) + and "jakarta.persistence.cache.storeMode" previously accepted the + enum constants as well as their String names. The new + Jakarta Persistence 3.2 setters setCacheRetrieveMode() and + setCacheStoreMode() are now used to apply these properties, and + a String value is passed to the setter unconverted, which + fails with an IllegalArgumentException (argument type + mismatch); previously the call succeeded. Pass the + CacheRetrieveMode/CacheStoreMode enum + constant, or call the setters directly. String values given + as find(), refresh() or query hints continue + to work. + +
+
+ Default map key column renamed to <field>_KEY + + For Map-valued fields without @MapKeyColumn + the key column was previously named KEY (which most dictionaries + turned into KEY0 because KEY is a reserved + word). As required by section 11.1.35 of the specification, the default is now the + field name followed by _KEY (for example + PHONES_KEY). Schemas created by earlier releases no longer match: + schema validation fails, SynchronizeMappings=buildSchema adds a + new column and existing key data reads back as null. + + + Declare the existing column explicitly, for example + @MapKeyColumn(name="KEY0"), or rename the column in the + database. No compatibility option restores the old default. See also + . + +
+
+ Attribute overrides, @OrderBy and inverse map keys + + @AttributeOverride on an entity now also applies to the entity's + own declared fields (previously only mapped superclass fields were overridden), and + an override name without key./value. prefix on + an element collection Map refers to the map value instead of + failing. Attribute names in @OrderBy and overrides are resolved + case-insensitively as a fallback. @MapKeyColumn on the inverse + side of a @OneToMany(mappedBy) map is now written to the target + entity's table (additional UPDATE statements), and an + @ElementCollection whose table coincides with an entity's primary + table is no longer written separately. + + + Verify the column names produced by overrides that were previously ignored or + rejected, and @OrderBy values that differ from attribute names + only in case. + +
+
+ @SequenceGenerator without sequenceName + + A @SequenceGenerator annotation without + sequenceName previously fell back to the OpenJPA default + sequence OPENJPA_SEQUENCE, so all such generators shared one + database sequence. As defined by the specification, the generator name is now used + as the database sequence name, and DDL generation creates one sequence per + generator. orm.xml sequence-generator elements + are not affected. + + + For existing databases either add sequenceName="OPENJPA_SEQUENCE" + (or the previously used name) to each generator, or create the new per-generator + sequences. See . + +
+
+ AttributeConverter handling + + Support for jakarta.persistence.AttributeConverter was reworked. + @Converter(autoApply=true) classes found on the classpath are now + registered and applied to every basic attribute whose declared type matches + (excluding identifiers, version fields, relations, collections and maps) unless + the attribute declares its own @Convert; previously + autoApply was ignored. Class-level + @Convert(attributeName=...)/@Converts, + converters on embedded attributes, on mapped superclass attributes and on element + collection elements are honored (previously ignored or rejected). The database + column type is now derived from the converter's database type + Y instead of the attribute type X + (a Boolean to Integer converter now + yields an INTEGER column). + + + One converter instance per attribute is created lazily through the no-argument + constructor and shared between threads, so converters must be stateless. + RuntimeExceptions thrown by a converter surface as + jakarta.persistence.PersistenceException instead of + MetaDataException. @Convert(disableConversion=true) + only cancels an explicit converter on that attribute; it does not prevent an + autoApply converter from being applied. + + + Audit existing @Converter(autoApply=true) classes: attributes of + the matching type that were stored unconverted by 4.1.x are now written and read + through the converter and their generated column type changes. Remove + autoApply, declare an explicit converter, or pin the column type + with @Column(columnDefinition=...) where the old behavior is + required. + +
+
+ Access type determination and property accessors + + Implicit access type determination now follows the specification: only + access-defining annotations (@Id, @EmbeddedId, + @Version, @Basic, @Embedded, + the relationship annotations, @ElementCollection, + @Transient) decide the access type; supplementary annotations + such as @Column or @Temporal only count when + no access-defining annotation is present. A getter whose backing field is + @Transient is a per-attribute property override and no longer + makes the class "mixed"; an attribute annotated on both field and getter uses + property access; a subclass whose implicit access conflicts with its persistent + superclass inherits the superclass access type (previously an error); + @Basic may be combined with a more specific mapping annotation; + records always use field access; types declared as embeddable + only in orm.xml are mapped as embedded rather than serialized. + + + Boolean getters must have an upper-case character after is + (island() or isaBoolean() are no longer + persistent properties), and the setter for a property is derived from the actual + getter suffix (getdescription()/setdescription() + pairs are accepted). Entities that previously failed to load may now load with a + different access type than intended; add an explicit @Access + where fields and getters are both annotated, and review unusual boolean accessor + names. No compatibility option exists. + +
+
+ java.time.Instant and java.time.Year mapping + + java.time.Instant and java.time.Year + are now first-class persistent types: Instant maps to a + TIMESTAMP column and Year to an + INTEGER column. Previous releases had no type code for them and + stored such attributes through the generic object strategy as serialized binary + data. Existing columns created for such attributes are incompatible with the new + mapping: migrate the columns and data, or keep them serialized explicitly with + @Lob or an externalizer. java.util.Calendar + may now be used as a single-field identifier. + +
+
+ Generated DDL changes + + The DDL produced by the mapping tool, + and the new SchemaManager differs from previous releases: + + + jakarta.persistence.ForeignKey on + @JoinColumn, @JoinTable and + @SecondaryTable is now parsed. A named constraint + (ConstraintMode.CONSTRAINT) is emitted as a physical + foreign key even for relations that OpenJPA treats as logical; + NO_CONSTRAINT suppresses the key; + PROVIDER_DEFAULT keeps the 4.1.x behavior. Expect + additional ALTER TABLE ... ADD CONSTRAINT statements + and a stricter drop order. + + + Every declared @SecondaryTable is created, even if no + field is mapped to it. + + + The table-level comment is no longer emitted in + CREATE TABLE (column comments remain). + + + @Index(columnList="col DESC") is honored, + @JoinTable.indexes are created, + @Table(options) and @Column(options) + are appended verbatim, and @Column(secondPrecision) + takes precedence over scale and the dictionary's + DateFractionDigits for temporal columns. + + + + + Compare generated DDL against existing schemas before enabling schema + synchronization in production. + +
+
+ Jakarta Persistence schema generation and SQL scripts + + The jakarta.persistence.schema-generation.* properties are now + honored as described by the specification: scripts.action is + mapped to schema tool actions on its own (previously only + database.action was considered) and scripts are generated or + executed when the EntityManagerFactory is created rather + than lazily with the first EntityManager; explicit + create-source/drop-source values are + respected; java.io.Writer/Reader + targets and sources, file: URIs and absolute paths are accepted. + When Writer/Reader objects are + supplied, the corresponding keys are removed from the caller's property map, so the + map must be mutable. Persistence.generateSchema() defaults + database.action=create only if neither + database.action nor scripts.action is given. + A table dropped by an executed drop script is skipped by the next + buildSchema/add run in the same JVM (once by + default; until an EntityManagerFactory with schema-generation + properties starts when openjpa.SpecCompliantSchemaGeneration=true) + instead of being silently re-created. + + + SQL scripts (create, drop and load scripts) are now parsed as + ;-terminated statements that may span several lines, with + --, // and /* ... */ + comments stripped (string literals are not recognized). Previously every line was + one statement. Errors in scripts executed through schema generation are logged as + warnings on the channel instead of failing + start-up. Terminate every statement with ; and check the log + for script errors. Related SchemaTool changes: table + truncation continues after failing statements, dropping the last column of a table + drops the whole table, and the new DBDictionary.isDroppable(Sequence) + hook excludes system sequences. + + + Two options were added. openjpa.SpecCompliantSchemaGeneration=true + (also available as openjpa.Compatibility=SpecCompliantSchemaGeneration=true, + default false) enables strict Jakarta Persistence semantics: a + schema-generation configuration that resolves to no action (for example + database.action=none) also disables + openjpa.jdbc.SynchronizeMappings, @MapsId + foreign key columns are named <relation>_<targetPk>, + and on PostgreSQL identifiers are never quoted. Do not enable it on existing + databases created by earlier releases. The option + openjpa.jdbc.SyncMappingsExcludeTypes=a.B;c.D (or + SynchronizeMappings=buildSchema(ExcludeTypes=a.B;c.D)) excludes + entity classes from schema synchronization and drops their existing tables; only + list entities whose tables may be destroyed. See + and + . + +
+
+ Numeric versus character column type conflicts + + When two mappings, or the mapping and the reflected database column, disagreed on + an incompatible column type, previous releases failed with a + -bad-col MetaDataException (or logged a + warning with disableSchemaFactoryColumnTypeErrors). Conflicts + between numeric and character types are now silently resolved to + VARCHAR, and values are converted on read and write. As a side + effect, SynchronizeMappings=validate and + SchemaManager.validate() no longer report numeric versus + VARCHAR drift; verify such columns manually. All other + incompatible combinations still fail as before. + +
+
+ DELETE affecting zero rows tolerated for unversioned entities + + A DELETE statement reporting an update count of zero previously + always raised an OptimisticException, including rows already + removed by a database-level ON DELETE CASCADE. For entities + without a version strategy (no @Version and no state comparison + versioning) such a delete is now silently accepted. Entities with a version + strategy behave as before. Applications that relied on the exception to detect a + concurrently deleted unversioned row should add a @Version + attribute; subclasses of PreparedStatementManagerImpl may + override hasVersion(RowImpl). + +
+
+ Non-entity classes in persistence.xml + + Listing a class without persistence metadata in a persistence unit + (class element) previously failed at start-up with + "No registered metadata for type", in the runtime enhancer, in + getMetamodel() and during schema synchronization. Such classes + are now skipped with a warning on the openjpa.Enhance and + openjpa.jdbc.Schema logs. A forgotten @Entity + annotation is therefore no longer detected at start-up; watch the logs for the new + warnings. + +
+
+ Relaxed kernel checks + + Several early exceptions were relaxed to satisfy the specification: + a non-cascaded relation pointing at an object without a state manager is no longer + rejected at flush with "cant-cascade-persist"; the referenced row is looked up in + the database during flush (an extra SELECT for unenhanced or + subclass-enhanced entities) and truly transient references may now fail later with + a foreign key error. Modifying an embeddable obtained from a query projection no + longer throws; the modification is silently not persisted. Re-persisting an entity + after remove() and flush is tolerated. In addition, + orphanRemoval=true no longer downgrades + cascade=REMOVE/ALL, so removal is cascaded + immediately when both are combined. + +
+
+ Insert ordering across logical foreign keys + + Flush ordering previously delayed an insert only for physical (constraint-backed) + foreign keys. Rows related through logical foreign keys (no constraint declared in + the mapping, for example an externally created schema with real constraints) are + now also delayed until the referenced new row has been inserted. Statement order + at flush time may therefore change; tests asserting an exact SQL order may need to + be adjusted. There is no configuration switch. + +
+
+ Enhancer and runtime enhancement + + Classes enhanced by this release call new runtime methods (for example + ApplicationIds.getRelatedObjectId() for derived identities) and + fail on a 4.1.x runtime, while classes enhanced by 4.1.x still load but miss the + fixes of this release. Re-run the build-time enhancer + () with 4.2.0 when upgrading. + + + Runtime enhancement ( and the + Java agent) changed: class redefinition uses + Instrumentation.redefineClasses() and, if it fails, OpenJPA logs + "redefineClasses failed" at INFO and silently falls back to + subclass enhancement instead of throwing. getClass() calls in + user equals()/hashCode() implementations of + subclass-enhanced entities now see the entity class instead of the generated + subclass, and generated writeReplace() methods work with + non-public no-argument constructors. + +
+
+ Delayed collection proxies on Java 21 + + The delay-loading collection proxies (openjpa.ProxyManager=default(DelayCollectionLoading=true), + see ) now declare the Java 21 + SequencedCollection methods explicitly. + addFirst() and addLast() both delegate to + add(), so addFirst() appends instead of + prepending (previously DelayedLinkedListProxy prepended + after loading the collection), and reversed() returns a copy + rather than a write-through view for list and LinkedHashSet + proxies. Load the collection and reorder it explicitly where the position matters. + The ASM-generated non-delayed proxies are unchanged. + +
+
+ Static metamodel generator output + + Generated X_ classes now contain the Jakarta Persistence 3.2 + class_ field and QUERY_<NAME> / + MAPPING_<NAME> constants for named queries and result set + mappings declared on the type, and are annotated with + javax.annotation.processing.Generated instead of + jakarta.annotation.Generated when available. Regenerate the + metamodel classes and watch for name clashes with attributes named + class_. + +
+
+ Lifecycle callbacks and listeners + + Default entity listeners declared in several mapping files are now registered once + instead of once per file, and a callback declared both by annotation and in + orm.xml for the same method is registered once with the XML + declaration taking precedence. Callback parameter types are matched more leniently, + and listeners receive the managed entity instance (not the internal + ReflectingPersistenceCapable wrapper) on + AFTER_DELETE_PERFORMED for unenhanced entities. Applications that + depended on duplicate invocations must be adjusted. + +
+
+ persistence.xml resource handling + + An I/O error while reading a persistence.xml resource from the + classpath previously aborted createEntityManagerFactory(). Such + resources are now logged ("unreadable-persistence-xml") and skipped; schema + validation errors still abort. A unit that only exists in a skipped resource + surfaces later as a missing persistence unit. Resource streams are opened with + URL connection caching disabled. The 3.2 elements scope and + qualifier are exposed through + PersistenceUnitInfo. + +
+
+ Locale-independent case conversion + + Identifier normalization, JPQL parsing, in-memory LOWER()/ + UPPER() evaluation and SQL formatting used the JVM default + locale for case conversion. They now use Locale.ROOT + (Locale.ENGLISH for reserved word matching). This is only + observable under locales with special casing rules (Turkish, Azeri, Lithuanian), + where generated identifiers containing i/I + may now differ from those generated by earlier releases; use explicit + @Table/@Column names in that case. + +
+
+ Reserved word handling and MySQL delimiting + + Reserved word detection is now case-insensitive for all dictionaries, so generated + (defaulted) column, table and sequence names that equal a reserved word in a + different case may now receive a 0 suffix. + H2Dictionary additionally feeds its H2 2.x keyword list into + the naming rules. On MySQL (MySQLDictionary, not + MariaDBDictionary) reserved word identifiers are now + automatically delimited with back-ticks in all generated SQL, so previously + failing names such as KEY, TEXT or + LIBRARY work without manual delimiting. Tools comparing SQL text + must ignore the delimiters. Use explicit @Table/@Column + names if an old generated name must be kept. See + . + +
+
+ PostgreSQL + + Delimited identifiers: PostgresDictionary now strips the + double quotes from a quoted identifier whose inner text is a plain identifier + (letters, digits and underscores, not starting with a digit). PostgreSQL then folds + the name to lower case, so @Table(name="\"MyTable\"") now + addresses mytable and quoted reserved words such as + "Order" become bare keywords. Identifiers containing spaces or + other special characters keep their quotes. Do not rely on delimited identifiers to + preserve mixed case or to use reserved words as names on PostgreSQL; rename the + objects, or subclass PostgresDictionary and override + toDBName(). There is no configuration switch. + + + char/Character attributes: on PostgreSQL 9 + and later StoreCharsAsNumbers now defaults to + false, so such attributes map to CHAR(1) + columns instead of INTEGER columns holding code points, and the + Java default '\0' is stored as SQL NULL. + Existing INTEGER columns created by earlier releases fail + validation or return wrong values. Either migrate them to + CHAR(1) or restore the previous mapping with + openjpa.jdbc.DBDictionary=postgres(StoreCharsAsNumbers=true); + an explicitly configured value is respected (OPENJPA-2971). + + + Further fixes: java.util.UUID parameters are bound so that + both native uuid and varchar columns work (on + other databases a UUID is bound as VARCHAR unless the column is + a native UUID column); @Lob columns of type oid + are read and written through the large object API, which performs an implicit + COMMIT when reading in auto-commit mode; reflected + bool columns are reported as BOOLEAN, so + schema validation may now report boolean versus varchar drift that was previously + tolerated; DROP SEQUENCE IF EXISTS is emitted. + +
+
+ MySQL and MariaDB + + On MySQL 5.7+ and MariaDB 10.2+ temporal columns are now created as + DATETIME(6) and TIME(6) + (DateFractionDigits=6) instead of whole-second precision, so that + @Version attributes of type Instant or + LocalDateTime can distinguish updates within the same second. + The value is set at connection time and overrides a + DateFractionDigits value given in + . Existing columns keep working, but + schema validation or refresh may report or alter the precision. Use + @Column(secondPrecision=0) on individual columns, or subclass the + dictionary and reset dateFractionDigits after + connectedConfiguration(), to keep whole seconds. + + + MariaDBDictionary no longer replaces a configured positive + with Integer.MIN_VALUE + (the Connector/J 2.x streaming mode); the configured value is passed to the driver + unchanged. MySQLDictionary keeps the streaming behavior. + Subclass MariaDBDictionary and override + getBatchFetchSize(int) to restore streaming. + +
+
+ Microsoft SQL Server + + CURRENT_DATE and CURRENT_TIME are now + translated to CONVERT(DATE, GETDATE()) and + CONVERT(TIME, GETDATE()) instead of plain + GETDATE(), so the results are DATE/TIME + typed and comparisons against datetime columns may behave + differently. EXTRACT uses DATEPART and JPQL + time literals are rendered as CAST('hh:mm:ss' AS TIME). To + restore the previous SQL set + openjpa.jdbc.DBDictionary=sqlserver(CurrentDateFunction=GETDATE(),CurrentTimeFunction=GETDATE()). + +
+
+ Oracle + + Identity column sequences (ISEQ$$_*) are treated as system + sequences and excluded from drop actions, AUDSYS is treated as a + system schema, an @Index duplicating the primary key is skipped, + CEILING() is translated to CEIL(), and the new + Jakarta Persistence 3.2 functions are mapped to Oracle syntax + (EXCEPT as MINUS before Oracle 21, + LEFT/RIGHT via SUBSTR). + These are fixes; workarounds for the old behavior can be removed. + +
+
+ HSQLDB + + HSQLDictionary no longer disables + SupportsSelectForUpdate, so pessimistic locks now emit + SELECT ... FOR UPDATE; query timeouts are disabled + (SupportsQueryTimeout=false); OffsetTime + attributes are created as TIME instead of + TIME WITH TIME ZONE; numeric casts are sized + NUMERIC(128,32) so fractional digits are no longer truncated; + INFORMATION_SCHEMA and SYSTEM_LOBS are treated + as system schemas. Use openjpa.jdbc.DBDictionary=hsql(SupportsSelectForUpdate=false,SupportsQueryTimeout=true) + and @Column(columnDefinition="TIME WITH TIME ZONE") to restore + the previous behavior. On H2 2.x, table truncation now skips the + INFORMATION_SCHEMA meta tables. + +
+
+ SPI changes for custom store, dictionary and expression implementations + + Implementors of OpenJPA SPI interfaces must recompile and implement new methods: + BrokerFactory (createPersistenceStructure, + dropPersistenceStructure, validatePersistenceStructure, + truncateData; AbstractBrokerFactory + throws UnsupportedOperationException by default), + ExpressionFactory (newTypecastAsString, + newTypecastAsNumber, left, right, + replace, getNativeObjectId, version), + Result (getInstant, getYear), + Select (appendNullsPrecedence, + addSetOperatorSQL, getSetOperatorBuffer), + OpenJPAConfiguration (schema generation script accessors, + isSchemaGenerationExplicit, isSpecCompliantSchemaGeneration) + and JDBCConfiguration (get/setSyncMappingsExcludeTypes). + + + DBDictionary.SerializedData is now a record + (bytes() instead of the bytes field); + IdentifierRule.setReservedWords takes a + Collection and matches case-insensitively, so subclasses + overriding the Set variant no longer override; + JavaTypes.INSTANT (39) and JavaTypes.YEAR (40) + were added and must be handled by custom value handlers and strategies; + QueryExpressions gained nullPrecedence, + setOperationType and setOperands, which only + the JDBC store consumes, so a custom StoreQuery silently ignores + NULLS FIRST/LAST and set operations unless it is extended. + DBDictionary gained a number of public configuration fields + (ReplaceFunctionName, LeftFunctionName, + RightFunctionName, NaturalLogarithmFunction, + CeilingFunction, ExceptFunction, + TypecastToStringTypeName, IntegerCastTypeName, + SupportsUnsizedCharOnCast) and hooks + (isDroppable(Sequence), toJDBCEscapedDateTimeLiteral, + appendNullsPrecedence, getExtractField, + get/setMajorVersion, get/setMinorVersion). + +
+
+ Notable new features + + The following Jakarta Persistence 3.2 features are new in this release. They are + opt-in and do not change existing behavior unless noted: + + + JPQL: ID() and VERSION() functions, + CAST, LEFT, RIGHT, + REPLACE, the || operator, + UNION/INTERSECT/EXCEPT [ALL], + NULLS FIRST/LAST, TREAT in joins and + paths, JOIN ... ON, EXTRACT, + LOCAL DATE/TIME/DATETIME, additional math functions, + an optional SELECT clause and the implicit + this identification variable (bound automatically when a + FROM item declares no identification variable). See . + In-memory query execution (and custom StoreQuery + implementations) silently ignore + UNION/INTERSECT/EXCEPT + and NULLS FIRST/LAST; + LEFT/RIGHT, CAST and + EXTRACT are not available on Derby. + + + EntityManager: find(), + lock() and refresh() with + FindOption/LockOption/RefreshOption, + getReference(entity), cache mode and timeout accessors, + runWithConnection()/callWithConnection(), + createQuery(CriteriaSelect); + Query: getSingleResultOrNull(), + cache mode and timeout setters. + + + EntityManagerFactory: + runInTransaction()/callInTransaction() + (exceptions are rethrown wrapped in + org.apache.openjpa.persistence.PersistenceException), + getSchemaManager(), getName(), + getTransactionType(), getNamedEntityGraphs(); + PersistenceUnitUtil: getVersion(), + isInstance(), getClass(), + load(); programmatic bootstrap via + Persistence.createEntityManagerFactory(PersistenceConfiguration) + and the jakarta.persistence.dataSource property. + EntityManager.find(EntityGraph, ...), + createQuery(TypedQueryReference), + getNamedQueries() and + SynchronizationType.UNSYNCHRONIZED are not yet implemented. + + + Entity graphs (@NamedEntityGraph, + createEntityGraph(), getEntityGraph()), + CriteriaUpdate, CriteriaDelete, + CriteriaSelect set operations, + Join.on(), CriteriaBuilder.cast()/ + left()/right()/replace()/ + extract() and treat(Root), all of which + previously threw UnsupportedOperationException. + + + Mapping: Java records as @Embeddable (records are + always treated as managed types, regardless of + openjpa.RuntimeUnenhancedClasses), + @EnumeratedValue (an enum declaring such a field changes + its stored representation), @Version on + java.time.Instant and + java.time.LocalDateTime (give such columns at least + microsecond precision), @Column(secondPrecision, options), + @Table(options), repeatable + @SequenceGenerator/@TableGenerator, + ConstructorResult in result set mappings, inline result + mappings on @NamedNativeQuery, orm.xml + version 3.2, id classes without a public no-argument constructor, and + @MapsId with non-embeddable id classes. + + + jakarta.persistence.ForeignKey, + @Index sort order, @JoinTable.indexes + and @Converter(autoApply=true) are honored (see the + respective sections above for the effect on existing schemas). + + + The bundled Jakarta Persistence schemas are now included under the Eclipse + Foundation Specification License 1.1 instead of the CDDL. + +
From 3d0a70fe75128ea173b1f5bad390d9c303e74b9a Mon Sep 17 00:00:00 2001 From: Richard Zowalla Date: Sat, 29 Aug 2026 19:06:42 +0200 Subject: [PATCH 2/2] [OPENJPA-2940] List migration considerations newest release first Reverses the order of the top-level release sections in migration_considerations.xml so that the most recent release (OpenJPA 4.2.0) is listed first. Content is unchanged. --- .../doc/manual/migration_considerations.xml | 2832 ++++++++--------- 1 file changed, 1416 insertions(+), 1416 deletions(-) diff --git a/openjpa-project/src/doc/manual/migration_considerations.xml b/openjpa-project/src/doc/manual/migration_considerations.xml index 8f72fb40e0..ec66dcacb4 100644 --- a/openjpa-project/src/doc/manual/migration_considerations.xml +++ b/openjpa-project/src/doc/manual/migration_considerations.xml @@ -21,1706 +21,1706 @@ Migration Considerations -
- - OpenJPA 2.0.0 - -
- - Incompatibilities - - +
+ OpenJPA 4.2.0 +
+ Incompatibilities + - The following sections indicate changes that are incompatible - between OpenJPA 1.x.x releases and the 2.0 release. Some may - require application changes. Others can be remedied through the - use of compatibility options. If your application uses a - version 1.0 persistence.xml, compatibility options will be set - appropriately to maintain backward compatibility. OpenJPA 2.0 - applications using a version 2.0 persistence.xml and requiring - OpenJPA 1.x.x compatibility may need to configure the - appropriate compatibility options to get the desired behavior. + OpenJPA 4.2.0 implements the Jakarta Persistence 3.2 specification and passes the + Jakarta Persistence 3.2 TCK. The following sections indicate changes that are incompatible + between OpenJPA 4.1.x releases and the 4.2.0 release. Most of them align OpenJPA with + the specification and cannot be switched off; where a configuration option restores + the previous behavior, it is mentioned in the respective section. Open follow-up items + from the review of this work are tracked under OPENJPA-2945. -
- - getProperties() - - +
+ Platform and Dependency Requirements - The OpenJPAEntityManagerFactory interface getProperties() - method was changed to return a Map instead of a - Properties object. This change was made in order to - support the getProperties() method defined in the - JPA 2.0 specification. + OpenJPA 4.2.0 requires Java 17 or later at build and run time (4.1.x required + Java 11). All jars contain Java 17 class files. Java 21 and Java 25 runtimes are + supported; class files of newer JDKs are read through + xbean-asm9-shaded 4.30. -
-
- - Detach Behavior - - - The detach behavior has changed in several ways: - - - - In the 1.x.x release, managed entities - were flushed to the database as part of the - detach operation. This is no longer done in - 2.0. - - - - - In the 1.x.x release, entities were copied - and returned. In 2.0, for those methods - that have return values, the original - entities are returned. - - - - - In the 1.x.x release, managed entities still - exist in the persistent context. In 2.0, - they are removed. - - - - - In the 1.x.x release, the detach operation - is recursively cascaded to all referenced - entities. In 2.0, the detach operation is - only cascaded to those entities for which - Cascade=detach has been specified. - - - + The jakarta.persistence:jakarta.persistence-api dependency was + raised from 3.1.0 to 3.2.0 (Jakarta EE 11 level). Applications must update explicit + dependencies on the API and recompile. Custom wrappers implementing + jakarta.persistence interfaces (EntityManager, + EntityManagerFactory, Query, + CriteriaBuilder, PersistenceUnitInfo, ...) + must implement the new 3.2 methods. The persistence_3_2.xsd and + orm_3_2.xsd schemas are bundled and selected for documents + declaring version="3.2"; version="3.1" + documents are still not accepted (use 3.0 or 3.2). - Applications that use a 1.0 persistence.xml will - automatically maintain OpenJPA 1.x.x behavior. It is - possible for a version 2.0 application to revert back to - the 1.x.x behavior for some of these items by setting the - openjpa.Compatibility property as follows: - - CopyOnDetach=true - FlushBeforeDetach=true - CascadeWithDetach=true - + XML column mapping (XMLValueHandler) and the detection of + XML-mapped value classes now use jakarta.xml.bind (JAXB 4) + instead of javax.xml.bind (JAXB 2). The optional dependencies + are jakarta.xml.bind:jakarta.xml.bind-api 4.0.x and a JAXB 4 + runtime such as com.sun.xml.bind:jaxb-impl 4.0.x. Value classes + that are still annotated with javax.xml.bind.annotation + annotations are no longer recognized as XML column types and silently fall back to + the default (serialized) mapping. Migrate such classes to + jakarta.xml.bind.annotation. - In addition, a new method has been provided on the - - OpenJPAEntityManager - interface to return a copy of the entity: - - public <T> T detachCopy(T pc): - + The managed JDBC driver versions used for testing were raised: MySQL Connector/J 9.x + (com.mysql:mysql-connector-j, driver class + com.mysql.cj.jdbc.Driver), MariaDB Connector/J 3.5.x, Microsoft + mssql-jdbc 13.x and Derby 10.16.x (which itself requires Java 17). + MySQLDictionary now also recognises + com.mysql.cj.jdbc.exceptions.MySQLTimeoutException as a timeout + exception, so lock and query timeouts are classified correctly with Connector/J 8 + and later. Drivers are not shipped with OpenJPA; see + for the tested database and driver versions. -
-
- - Use of private persistent properties - - - In 1.x.x releases of OpenJPA, if property access was used, - private properties were considered persistent. This is - contrary to the JPA specification, which states that - persistent properties must be public or protected. In - OpenJPA 2.0 and later, private properties will not be - persistent by default. + Build-only changes: the Maven profile test-h2-2 was removed + (use test-h2), and the legacy JPA 1.0 / 2.0 TCK profiles in + openjpa-integration/tck were replaced by the Jakarta Persistence + 3.2 TCK runner (-Ptck32-profile, run-tck32.sh). +
+
+ SecurityManager Support Removed - Applications that use a 1.0 persistence.xml will - automatically maintain OpenJPA 1.x.x behavior. It is - possible for a version 2.0 application to revert back to - the 1.x.x behavior by setting the value of the - openjpa.Compatibility - property PrivatePersistentProperties to - true. If compile time enhancement is - used, this property must be specified at the time of - enhancement and at runtime. + All AccessController.doPrivileged(...) calls were removed from + OpenJPA. Running OpenJPA under a Java SecurityManager with a + policy that grants permissions only to the OpenJPA jars is no longer supported (the + SecurityManager is deprecated for removal since Java 17 and + permanently disabled since Java 24, JEP 486). -
-
- - Query.setParameter() - - - The Query interface setParameter() method behavior has - changed to throw an IllegalArgumentException (as required - by the JPA specification) if more parameter substitutions - are supplied than defined in the createQuery(), - createNamedQuery(), or createNativeQuery() invocation. - OpenJPA 1.2.x and prior versions silently ignored these - extraneous parameter substitutions and allowed the Query - to be processed. + As a consequence the public PrivilegedAction factory methods of + org.apache.openjpa.lib.util.J2DoPrivHelper (for example + getForNameAction, getClassLoaderAction, + newInstanceAction, getContextClassLoaderAction) + were removed; only getLineSeparator(), + getPathSeparator(), newInstance(Class) and + newDeamonThread(Runnable, String) remain. Third-party code + (custom product derivations, dictionaries, plugins, application server integrations) + using these helpers must call the JDK API directly. Plugin classes instantiated + through J2DoPrivHelper.newInstance may now have a non-public + no-argument constructor.
-
- - Serialization of Entities - - +
+ New JPQL Reserved Identifiers - In 1.x.x releases of OpenJPA, when an entity was serialized - after calling EntityManager.find(), detach() or detachAll() - then all - references were removed as expected, but when the same - entity instance was serialized after calling - EntityManager.clear() the proxy classes were not removed. + The JPQL grammar now knows the Jakarta Persistence 3.2 keywords + ID, VERSION, FIRST, + LAST, ON, NULLS, + CAST, STRING, INTEGER, + LONG, FLOAT, DOUBLE, + TREAT, UNION, INTERSECT, + EXCEPT, RIGHT and REPLACE + (case-insensitive), as well as the || concatenation operator. + In previous releases these words could be used as identification variables and + result aliases, for example SELECT e.id AS id FROM E e ORDER BY id + or SELECT first FROM Foo first. Such queries are now rejected + with a parse error, as required by section 4.4.1 of the specification. - This has two side-effects: - when entities are remoted across JVM boundaries (RPC) - or deserialized the OpenJPA runtime must be available - on the classpath (both client and server containers); - when entities are deserialized the OpenJPA runtime must - be the exact same revision as used to serialize the - entities due to the proxy classes using dynamically - generated serialVersionUID values. + With the exception of INTEGER, LONG, + FLOAT and DOUBLE the new keywords may still be + used as path components, so attributes named id, + version, first or replace + can still be navigated (o.version). Attributes named + integer, long, float or + double can no longer be referenced in a JPQL path expression; + rename them or access them through the Criteria API or native SQL. Rename + identification variables and aliases that collide with the new keywords (most + commonly id, version, first, + last and on). There is no soft-keyword mode + and no compatibility option. +
+
+ JPQL Integer Literals are typed Integer - Starting with OpenJPA 2.0, this behavior has been - modified, so that by default all proxies will be removed - during serialization. See - - on how the behavior changes based on the - DetachedStateField setting along with - - for more details on how to override the default - DetachedStateField setting. + Previous releases always created JPQL integer literals as + java.lang.Long, so SELECT 1 FROM ... or + e.intField + 1 produced Long results. + As required by section 4.8.5 of the specification, an integer literal without an + l/L suffix that fits into the + int range is now a java.lang.Integer; + arithmetic on Byte, Short and + Integer operands is promoted to Integer + (also in the Criteria API). - Applications that use a 1.0 persistence.xml will - automatically maintain the old behavior. It is - possible for a version 2.0 application to revert back to - the prior 1.x.x behavior by setting the following - openjpa.Compatibility property as follows: - - IgnoreDetachedStateFieldForProxySerialization=true - + Application code that casts such results to Long must be + adapted to Integer or Number, or use an + explicit 1L literal. No compatibility option exists.
-
- - openjpa.jdbc.QuerySQLCache - - +
+ Query value conversion - In prior 1.x.x releases, the openjpa.jdbc.QuerySQLCache - configuration property for Prepared SQL Cache accepted - value all to never drop items from the - cache, but this option is no longer supported and will cause - a PersistenceException with a root cause of a ParseException - to be thrown. See - - for details on the available configuration values. + A String literal compared with a numeric path or parameter + (WHERE e.intField = '1', cb.equal(path, "12")) + is now parsed as a number of the path's type; previously a one-character literal was + compared as a Character and longer literals were rejected. The + character comparison is only used when the literal cannot be parsed as a number. + Selecting a collection- or map-valued attribute (SELECT e.addresses FROM + Employee e, query.select(root.get("addresses"))) is + treated as an implicit join and returns one row per element, typed as the element + type, instead of a collection-typed projection. + java.sql.Date values are no longer implicitly converted to + java.sql.Time or java.sql.Timestamp + when query values are compared (the same rule already applied to + java.util.Date). Enum names read from padded + CHAR columns are trimmed before Enum.valueOf(). + No compatibility option exists.
-
-
- - Disabling AutoOff Collection Tracking - - - - The default behavior of OpenJPA in tracking collections is that - if the number of modifications to the collection exceeds the - current number of elements in collection then OpenJPA will - disable tracking the collections. OpenJPA 2.0 added a compatibility - property to disable turning off the collection tracking. - - - The behavior of Auto disabling of collection tracking can be - avoided by setting the value of the - openjpa.Compatibility property - autoOff to false. - The default behavior of auto disabling the collection tracking - is not changed. But when the above property is set then the - collection tracking will not be disabled automatically. - -
-
- - Internal Behavioral Differences - - - The following sections indicate internal changes between - OpenJPA 1.x.x releases and the 2.0 release. As these are - internal implementation specific behaviors not covered by - the JPA specification, no changes should be required for - applications that did not use or depend upon OpenJPA specific - APIs or behavior. - - -
- - PreUpdate/PostUpdate Life Cycle Callbacks - - +
+ Query.getResultList() returns a materialized ArrayList - If an entity was updated between the persist() - and commit() operations in OpenJPA 1.x, then - any PreUpdate and PostUpdate life cycle callback - methods would be executed. Starting in OpenJPA - 1.3 and 2.0, these callbacks will not get executed. + Query.getResultList() previously returned a lazy + org.apache.openjpa.lib.rop.ResultList wrapper that streamed + rows on demand (see ) and became invalid + when the query or the EntityManager was closed. Jakarta + Persistence 3.2 requires a mutable List, so the result is now + copied into a java.util.ArrayList: all rows are fetched + immediately, the list stays usable after the EntityManager + is closed, and it is no longer an instance of ResultList. + Query.getResultStream() also materializes the complete result + first. Large result set collections on entity fields + () are not affected. - The JPA 2.0 specification section on "Semantics - of the Life Cycle Callback Methods for Entities" - has been updated to include a Note that the - callback behavior for updating an entity after - the persist operation is implementation specific - and should not be relied upon. + For very large query results use setFirstResult() / + setMaxResults() paging, or obtain the kernel query via + OpenJPAQuery.getDelegate() for lazy semantics. Code that casts + the result to ResultList or + DelegatingResultList must be changed.
-
- - createEntityManagerFactory Exceptions - - +
+ Bulk DELETE no longer cascades - The JPA 2.0 specification section on - "Bootstrapping in Java SE Environments" states - that persistence providers must return null - if they are not a qualified provider for the - given persistence unit. + In previous releases a JPQL or Criteria bulk DELETE against an + entity with cascade-delete or dependent relations (for example + @OneToMany(cascade=REMOVE) or an + @ElementCollection) was executed in memory: every instance was + loaded and removed through the persistence context, cascading to related entities + and cleaning up join table and element collection rows. As required by section + 4.10 of the specification, bulk operations do not cascade. A DELETE + query now issues a single SQL DELETE against the entity table(s); + related entities, join table rows and element collection rows are left untouched + and will cause foreign key violations unless the database defines + ON DELETE CASCADE. - However, OpenJPA may throw a RuntimeException - if an error occurs while trying to create a - qualified persistence unit, like for invalid - openjpa.* specific configuration settings or - for schema validation failures. + Delete dependents explicitly (separate bulk deletes or em.remove()) + or rely on database-level cascades. Note that a bulk UPDATE or + DELETE that still has to be executed in memory now flushes all + pending changes of the persistence context after processing. No compatibility + option exists. See also . +
+
+ FlushModeType.AUTO flushes whenever the context is dirty - If the Apache Geronimo JPA 2.0 Spec APIs are - used, then any exceptions returned by a - persistence provider will be wrapped within - a PersistenceException. When the JPA 2.0 API - reference implementation is used, any - RuntimeExceptions will be returned to the - calling application without being wrapped. - Other JPA 2.0 API and implementation providers - or versions may behave differently. + Previously a query only flushed pending changes when a dirty instance belonged to + a type in the query's access path, and never for SELECT queries + when was true. With + FlushModeType.AUTO (the default, + =true) and an active + transaction, a query now flushes whenever any instance in the persistence context + is new, dirty or deleted, regardless of the query's access path, and overrides + openjpa.IgnoreChanges. Applications with write-heavy transactions + may observe more flushes (and therefore earlier constraint or trigger evaluation). -
-
- - openjpa.QueryCache default - - - In previous releases, the default value for the - openjpa.QueryCache property was true - when the openjpa.DataCache was enabled. Depending on - application characteristics, this default QueryCache - enablement actually could negate much of the potential - gains achieved by using the DataCache. Thus, the default - value for the openjpa.QueryCache property is now - false. + To restore the previous behavior use FlushModeType.COMMIT on + the query or the EntityManager, or set + openjpa.FlushBeforeQueries to false or + with-connection. +
+
+ Exceptions mark the transaction rollback-only; closed EntityManager checks - To re-enable the default QueryCache behavior, you need to - include the following property in your persistence.xml - configuration. - - <property name="openjpa.QueryCache" value="true"/> - + As required by section 3.3.7.1 of the specification, every + RuntimeException raised by an EntityManager + or Query method now marks the active transaction for + rollback, except NoResultException, + NonUniqueResultException, + LockTimeoutException and + QueryTimeoutException. In previous releases the transaction + remained committable after, for example, an IllegalArgumentException + from find(), createNamedQuery() or an invalid + CriteriaQuery. Applications that caught such an exception and + committed the same transaction now receive a RollbackException + and must restart the transaction. - If your configuration had previously enabled the QueryCache - explicitly, then you might have to include the - true value into your configuration - (if you relied on the previous default). Otherwise, your - current QueryCache enablement will continue to work. - - <property name="openjpa.QueryCache" value="true(CacheSize=1000, SoftReferenceSize=100)"/> - + Operations on a closed EntityManager or its + Query objects now consistently throw + IllegalStateException. This includes + getEntityManagerFactory(), getCriteriaBuilder(), + getMetamodel(), getDelegate(), + setProperty(), isJoinedToTransaction(), + createEntityGraph(), createQuery(CriteriaQuery) + and Query.getHints(), getLockMode(), + closeAll() and the parameter accessors, which used to work on a + closed EntityManager. Further changes: + getLockMode()/setLockMode() on a bulk + UPDATE/DELETE query and + executeUpdate() on a SELECT query throw + IllegalStateException; + createQuery(CriteriaQuery) snapshots the criteria state, so + modifying the CriteriaQuery afterwards no longer affects the + created Query; isJoinedToTransaction() + returns true for an active resource-local transaction.
-
-
-
- - OpenJPA 2.2.0 - -
- Incompatibilities - - The following sections indicate changes that are incompatible - between OpenJPA 2.1.x releases and the 2.2.0 release. - -
- - allocationSize Property of Sequence Generator - - +
+ Argument validation in find(), getReference(), detach(), contains(), remove() - In previous releases, specifying the allocationSize property of - sequence generator - affected only sequence definition in the database. During - schema creation, the INCREMENT BY clause of - CREATE SEQUENCE statement always - had a value of 1 and on DB2, Oracle and PostgreSQL databases a CACHE clause - was added with the value of allocationSize property. Such a statement caused - sequence values being cached in the database. Starting with OpenJPA 2.2.0, - sequence values are cached in the jvm memory and the allocationSize - property determines size of that cache. The CACHE clause is no longer used, - instead the INCREMENT BY clause gets its value equal to the - allocationSize property. Such a strategy reduces the number of database roundtrips - required for retrieving sequence values considerably. + find(cls, null) previously returned null, a + primary key of the wrong type or a non-entity class surfaced later as an OpenJPA + ArgumentException or a failed lookup, and removing a detached + unenhanced entity could be silently ignored. These methods now validate their + arguments as required by the specification and throw + IllegalArgumentException (marking the transaction for + rollback) for null keys, non-entity classes, primary keys of an + incompatible type (numeric widening such as Integer to + Long is accepted, narrowing is rejected), non-entities + passed to detach()/contains(), and detached + instances passed to remove(). getReference() + throws EntityNotFoundException also for unenhanced entities. - In order for the existing applications to work with OpenJPA - 2.2.0, you have to manually recreate or redefine sequences, specifying - the correct INCREMENT BY value and, possibly, correct initial sequence value. - Note that the default value of the allocationSize property is 50 and that - value is used if the property is not specified. + Guard against null keys, pass keys of the declared + @Id type and merge() detached instances before + removing them. No compatibility option exists. +
+
+ EntityManager.close() with an active resource-local transaction - The requirement for sequence modification applies to all databases that support sequences, regardless of - the CACHE clause being supported. The only exception is Firebird database - - since with this database the increment step is determined during sequence - value fetch, no migration activity is needed. + Previously EntityManager.close() threw an + InvalidStateException while a resource-local transaction was + active; a deferred close existed only for managed (JTA) transactions with the + CloseOnManagedCommit compatibility flag. As required by sections + 3.3.2 and 7.7 of the specification, close() now always returns + and the persistence context is released when the transaction completes: + isOpen() reports false immediately while + em.getTransaction().commit()/rollback() + remain callable. - To maintain the old behavior of sequence generator in OpenJPA 2.2.0, you can: - - - - Set the allocationSize property value to 1. - - - - - Additionally, if the CACHE clause has to be emitted in sequence definition, - this can be accomplished by overriding the - - DBDictionary.getCreateSequenceSQL method. - - - + Code that relied on the exception to detect a leaked open transaction must check + em.getTransaction().isActive() itself and end the transaction + explicitly. There is no option to restore the exception.
-
- - MetaModel Attributes for Arrays - - +
+ EntityManagerFactory lifecycle and properties - In previous releases OpenJPA's MetaModel implementation generated a ListAttribute for every array. This behavior is correct if the array - is annotated as a PersistentCollection, but not correct for un-annotated arrays (e.g. byte[], char[]). In OpenJPA 2.2.0 this behavior was corrected - so that arrays which are not stored as PersistentCollections will use a SingularAttribute instead of a ListAttribute. + EntityManagerFactory.close() could previously be called more than + once, and methods of a closed factory either worked or failed deep inside the kernel. + Now getProperties(), createEntityManager(), + getCriteriaBuilder(), getMetamodel(), + getPersistenceUnitUtil() and + getSchemaManager() throw IllegalStateException + after close(), and a second close() throws as + well. createEntityManager(SynchronizationType.UNSYNCHRONIZED) + throws IllegalStateException instead of + UnsupportedOperationException (it is forbidden for + RESOURCE_LOCAL units and still unimplemented for JTA units). - If your application uses the MetaModel API and your entities contain arrays of any of the following types: byte[], Byte[], char[], Character[] and - do not use the @PersistentCollection annotation with those fields you will need to update your application to use OpenJPA 2.2.0. - - In order for the existing applications to work with OpenJPA you may: - - - Regenerate the canonical metamodel classes - - - Set the Compatibility property UseListAttributeForArrays to true in persistence.xml - <property name="openjpa.Compatibility" value="UseListAttributeForArrays=true"/> - - - + EntityManagerFactory.getProperties() no longer creates a temporary + EntityManager to merge EntityManager-level + defaults (lock timeout, cache modes, fetch plan settings) into its result, and + null-valued entries are removed; read such defaults from + EntityManager.getProperties() instead. + addNamedQuery() now replaces an existing definition of the same + name and records flush mode, max results and lock mode; Criteria queries are stored + as JPQL text, which is not guaranteed to round-trip for complex criteria.
-
- - supportsSetClob Property. - - +
+ Query parameter API - In OpenJPA 2.2.0, code was added to allow the setting of CLOB or XML data larger than 4000 bytes. This functionality - was eventually back ported to previous releases, and enabled by the supportsSetClob property on the OracleDictionary. Setting this property - has no effect in 2.2.0 and later releases and any occurrence of it should be removed. + Reading an unbound parameter via getParameterValue() now throws + IllegalStateException (previously + IllegalArgumentException or null); + Parameter objects obtained from another query are rejected + with IllegalArgumentException; + getParameter(String, Class) now correctly accepts an exact or + wider type (the positional variant getParameter(int, Class) still + only accepts the exact type or a subtype). A parameter bound with + TemporalType.DATE is converted to java.sql.Date + (time of day dropped) instead of being passed through unchanged. -
-
- - useNativeSequenceCache Property. - - - In OpenJPA 2.2.0, code was added which changed the way sequences were generated, please see - for details. This functionality was eventually back ported - to previous releases, and enabled by the useNativeSequenceCache property on the DBDictionary. Setting this property - has no effect in 2.2.0 and later releases and any occurrence of it should be removed. If previous behavior is - desired (i.e. useNativeSequenceCache=true), please see the details described in section - . + Catch IllegalStateException for unbound parameters and expect + java.sql.Date semantics for DATE-typed + parameters compared against TIMESTAMP columns.
-
- - Cascade persist behavior - - +
+ StoredProcedureQuery semantics - In previous releases, OpenJPA would check the database for the - existence of the related Entity before persisting the relationship to - that Entity. This resulted in an extra Select being sent to the - database. In 2.2.0, code was added so that when cascading a persist to - a related Entity without persistence state, the persist (insert) will - happen without first checking the database. This may result in an - EntityExistsException if the related Entity already exists in the - database. To revert this behavior to the previous release, set the - value of the openjpa.Compatibility - property CheckDatabaseForCascadePersistToDetachedEntity - to true. + Positional stored procedure parameters are now resolved 1-based (previously the + 0-based column index was used as fallback, so position 1 could match the second + IN column), and only IN/INOUT/ + OUT columns are registered, so positional indexes shift for + PostgreSQL functions with a return value. When a procedure declares + OUT parameters the connection is kept open (with auto-commit + temporarily disabled) until the result list is closed, so that + REF_CURSOR results can be consumed; consume and close such + result lists promptly. + + + executeUpdate() now requires an active transaction + (TransactionRequiredException) and + getUpdateCount() returns -1 after it; + setLockMode()/getLockMode() throw + IllegalStateException; + getOutputParameterValue() throws + IllegalArgumentException for unknown names or positions; + NoResultException and + NonUniqueResultException propagate unwrapped; procedure + metadata lookup retries with the lower-cased name; an + orm.xml named-stored-procedure-query overrides + an annotation of the same name.
-
- - Life Cycle Event Manager Callback Behavior - - +
+ Criteria API and Metamodel - Life cycle event manager is used to manage entity's life cycle event callback. - In previous releases, Life cycle event manager is scoped to EntityManagerFactory. - This means listeners registered to an individual EntityManager may get life cycle - event callbacks for entity that it does not manage. + Several OpenJPA extensions and lenient behaviors of the Criteria API were tightened + to the specification: CriteriaBuilder.array()/tuple() + reject nested compound selections and multiselect()/select() + reject duplicate aliases with IllegalArgumentException; + cb.literal(null) throws IllegalArgumentException + (use nullLiteral(Class)); Path.get() on a basic + path and From.getCorrelationParent() on a non-correlated + From throw IllegalStateException; + Metamodel.entity(Class)/embeddable(Class) throw + IllegalArgumentException for unknown types instead of + returning null; ParameterExpression.getPosition() + returns null (previously threw an internal exception). - From 2.2.1 release, the default callback behavior of the life cycle event manager - is changed to scope to each EntityManager. - To revert this behavior to the previous release, set the - value of the openjpa.Compatibility - property SingletonLifecycleEventManager - to true. + Embeddable-typed attributes are no longer reported as associations + (isAssociation() is false, + getBindableType() is SINGULAR_ATTRIBUTE), + getBindableJavaType() returns the declared attribute type, and + getId(Class)/getDeclaredId(Class) require strict + type assignability. cb.treat(Root, Class) is now implemented; + treat() on joins and paths returns the argument unchanged without + narrowing, and TREAT only matches the exact treated class, not its + subclasses. Flatten nested selections, use unique aliases and adjust catch blocks + and null checks accordingly.
-
- - shared-cache-mode Property - - +
+ PersistenceUnitUtil.getIdentifier() returns the plain identifier - In the previous release, when the shared-cache-mode is enabled and the DataCache property is not set - or set to false, there will be no data caching. + PersistenceUnitUtil.getIdentifier() previously returned the + internal org.apache.openjpa.util.OpenJPAId wrapper + (LongId, StringId, ...) for managed + entities and null for new, detached or unenhanced entities and + for non-entities. It now returns the raw identifier value (the plain key or the + IdClass instance for compound identity), also for new, detached + and unenhanced entities, and throws IllegalArgumentException + for objects that are not entities. Code that cast the result to + OpenJPAId must use the plain value or call + OpenJPAEntityManager.getObjectId(). +
+
+ Cache mode properties on EntityManager.setProperty() - From 2.2.2 release, the caching will be turned on if the shared-cache-mode is enabled. Please see the - details described in section . + EntityManager.setProperty("jakarta.persistence.cache.retrieveMode", ...) + and "jakarta.persistence.cache.storeMode" previously accepted the + enum constants as well as their String names. The new + Jakarta Persistence 3.2 setters setCacheRetrieveMode() and + setCacheStoreMode() are now used to apply these properties, and + a String value is passed to the setter unconverted, which + fails with an IllegalArgumentException (argument type + mismatch); previously the call succeeded. Pass the + CacheRetrieveMode/CacheStoreMode enum + constant, or call the setters directly. String values given + as find(), refresh() or query hints continue + to work.
-
-
-
- - OpenJPA 2.3.0 - -
- Incompatibilities - - The following sections indicate changes that are incompatible - between OpenJPA 2.2.x releases and the 2.3.0 release. - -
- - MappingTool Behavior for DB2 and Derby - +
+ Default map key column renamed to <field>_KEY - In previous releases, the MappingTool mapped java.math.BigDecimal fields to the database type - DOUBLE, and as such, ignored column and precision values that might have been specified via the - jakarta.persistence.Column annotation. + For Map-valued fields without @MapKeyColumn + the key column was previously named KEY (which most dictionaries + turned into KEY0 because KEY is a reserved + word). As required by section 11.1.35 of the specification, the default is now the + field name followed by _KEY (for example + PHONES_KEY). Schemas created by earlier releases no longer match: + schema validation fails, SynchronizeMappings=buildSchema adds a + new column and existing key data reads back as null. - From the 2.3.0 release, java.math.BigDecimal fields are now mapped to the database type DECIMAL - and it is very likely that you will need to specify column and precision via - the jakarta.persistence.Column annotation. + Declare the existing column explicitly, for example + @MapKeyColumn(name="KEY0"), or rename the column in the + database. No compatibility option restores the old default. See also + .
-
- - RequiresSearchStringEscapeForLike DBDictionary Property - - +
+ Attribute overrides, @OrderBy and inverse map keys - In previous releases, the default value for the property RequiresSearchStringEscapeForLike is true and caused the - unexpected escape clause appended to the SQL statement. - For example, user created a named query like this: - SELECT o.computerName FROM CompUser o WHERE o.name LIKE ? - At run time the following query is generated: - SELECT t0.computerName FROM CompUser t0 WHERE (t0.name LIKE ? ESCAPE '\') - ESCAPE '\' shouldn't be appended to the query. + @AttributeOverride on an entity now also applies to the entity's + own declared fields (previously only mapped superclass fields were overridden), and + an override name without key./value. prefix on + an element collection Map refers to the map value instead of + failing. Attribute names in @OrderBy and overrides are resolved + case-insensitively as a fallback. @MapKeyColumn on the inverse + side of a @OneToMany(mappedBy) map is now written to the target + entity's table (additional UPDATE statements), and an + @ElementCollection whose table coincides with an entity's primary + table is no longer written separately. - From the 2.3.0 release, RequiresSearchStringEscapeForLike property is set to false by default. You can configure - RequiresSearchStringEscapeForLike property to be true if the old behavior is desired. + Verify the column names produced by overrides that were previously ignored or + rejected, and @OrderBy values that differ from attribute names + only in case.
-
- - Return value of aggregate functions in SELECT clause - - +
+ @SequenceGenerator without sequenceName - The JPA specification states "If SUM, AVG, MAX, or MIN is used, and there are no values to which the aggregate function can be - applied, the result of the aggregate function is NULL." Prior to this update, OpenJPA incorrectly returned 0 for SUM, AVG, MIN, - and MAX when a state field being aggregated is numeric. This behavior affects both JPQL and Criteria queries. With this update, - OpenJPA will return a null result value for these aggregate functions when a query returns no result. + A @SequenceGenerator annotation without + sequenceName previously fell back to the OpenJPA default + sequence OPENJPA_SEQUENCE, so all such generators shared one + database sequence. As defined by the specification, the generator name is now used + as the database sequence name, and DDL generation creates one sequence per + generator. orm.xml sequence-generator elements + are not affected. - To re-enable the prior behavior, you need to set the following persistence property in your persistence.xml or when - creating an EntityManagerFactory. - - <property name="openjpa.Compatibility" value="ReturnNullOnAggregateResult=false"/> - + For existing databases either add sequenceName="OPENJPA_SEQUENCE" + (or the previously used name) to each generator, or create the new per-generator + sequences. See .
-
-
-
- OpenJPA 3.2.0 -
- Incompatibilities - - The following sections indicate changes that are incompatible - between OpenJPA 3.1.x releases and the 3.2.0 release. - -
- SUM now always returns Double +
+ AttributeConverter handling - We did fix the SUM operation to always return Double as requested by the spec. - Previously we did return whatever Numeric the JDBC driver did serve, resulting in non portable code. + Support for jakarta.persistence.AttributeConverter was reworked. + @Converter(autoApply=true) classes found on the classpath are now + registered and applied to every basic attribute whose declared type matches + (excluding identifiers, version fields, relations, collections and maps) unless + the attribute declares its own @Convert; previously + autoApply was ignored. Class-level + @Convert(attributeName=...)/@Converts, + converters on embedded attributes, on mapped superclass attributes and on element + collection elements are honored (previously ignored or rejected). The database + column type is now derived from the converter's database type + Y instead of the attribute type X + (a Boolean to Integer converter now + yields an INTEGER column). -
-
- Invalid Column Name Changes - We did review and update the list of invalid column names for most DBDicationary. - The list of tested reserved words got enriched with previously forbidden column names to avoid backward - incompatibility issues. - The list can ge retrieved and configured via - - DBDictionary.getInvalidColumnWordSet + One converter instance per attribute is created lazily through the no-argument + constructor and shared between threads, so converters must be stateless. + RuntimeExceptions thrown by a converter surface as + jakarta.persistence.PersistenceException instead of + MetaDataException. @Convert(disableConversion=true) + only cancels an explicit converter on that attribute; it does not prevent an + autoApply converter from being applied. + + + Audit existing @Converter(autoApply=true) classes: attributes of + the matching type that were stored unconverted by 4.1.x are now written and read + through the converter and their generated column type changes. Remove + autoApply, declare an explicit converter, or pin the column type + with @Column(columnDefinition=...) where the old behavior is + required.
-
- MappingTool Behavior for HSQLDB +
+ Access type determination and property accessors - There have been 2 changes for Hypersonic (HSQLDB). - We fixed a bug which did cause long fields getting mapped to INTEGER - instead of BIGINT. + Implicit access type determination now follows the specification: only + access-defining annotations (@Id, @EmbeddedId, + @Version, @Basic, @Embedded, + the relationship annotations, @ElementCollection, + @Transient) decide the access type; supplementary annotations + such as @Column or @Temporal only count when + no access-defining annotation is present. A getter whose backing field is + @Transient is a per-attribute property override and no longer + makes the class "mixed"; an attribute annotated on both field and getter uses + property access; a subclass whose implicit access conflicts with its persistent + superclass inherits the superclass access type (previously an error); + @Basic may be combined with a more specific mapping annotation; + records always use field access; types declared as embeddable + only in orm.xml are mapped as embedded rather than serialized. - Java double fields previously got mapped to NUMERIC which - does lack fraction digits. Thus the value 7.3425343 got truncated to 7. - We now map double fields in Entities to DOUBLE SQL column types. + Boolean getters must have an upper-case character after is + (island() or isaBoolean() are no longer + persistent properties), and the setter for a property is derived from the actual + getter suffix (getdescription()/setdescription() + pairs are accepted). Entities that previously failed to load may now load with a + different access type than intended; add an explicit @Access + where fields and getters are both annotated, and review unusual boolean accessor + names. No compatibility option exists.
-
- Respect TIMESTAMP precision in Oracle +
+ java.time.Instant and java.time.Year mapping - Due to a bug we did hardcoded round at 3 digits precision. - So we essentially only allowed millis, even on a TIMESTAMP(6) field. - The new code does respect the second fractions and now defaults to 6. - It should be compatible but it might behave very subtle different. + java.time.Instant and java.time.Year + are now first-class persistent types: Instant maps to a + TIMESTAMP column and Year to an + INTEGER column. Previous releases had no type code for them and + stored such attributes through the generic object strategy as serialized binary + data. Existing columns created for such attributes are incompatible with the new + mapping: migrate the columns and data, or keep them serialized explicitly with + @Lob or an externalizer. java.util.Calendar + may now be used as a single-field identifier.
-
- Unary Operations return types +
+ Generated DDL changes - Before OpenJPA-3.2.0 Unary Operations like MIN, MAX, SUM, etc - did return whatever type got returned by the JDBC driver. For certain column types this could also have been internal - classes of that very JDBC driver. E.g. a SELECT MAX(a.someLocalDateField) .. might have returned - an instance of types com.oracle.jdbc.... or com.microsoft.sqlserver..., etc. - We now use the respective - DBDictionary to request the correct type from the ResultSet. + The DDL produced by the mapping tool, + and the new SchemaManager differs from previous releases: + + + jakarta.persistence.ForeignKey on + @JoinColumn, @JoinTable and + @SecondaryTable is now parsed. A named constraint + (ConstraintMode.CONSTRAINT) is emitted as a physical + foreign key even for relations that OpenJPA treats as logical; + NO_CONSTRAINT suppresses the key; + PROVIDER_DEFAULT keeps the 4.1.x behavior. Expect + additional ALTER TABLE ... ADD CONSTRAINT statements + and a stricter drop order. + + + Every declared @SecondaryTable is created, even if no + field is mapped to it. + + + The table-level comment is no longer emitted in + CREATE TABLE (column comments remain). + + + @Index(columnList="col DESC") is honored, + @JoinTable.indexes are created, + @Table(options) and @Column(options) + are appended verbatim, and @Column(secondPrecision) + takes precedence over scale and the dictionary's + DateFractionDigits for temporal columns. + + -
-
- PostgreSQL now supports setQueryTimeOut - PostgreSQL does now support client side setQueryTimeout. - User might see this come alive and now return different when the situation occurs. - This flag is automatically enabled if running against PostgreSQL 10 or later. - It can also be configured manually via - DBDictionary.supportsQueryTimeout + Compare generated DDL against existing schemas before enabling schema + synchronization in production.
-
-
-
- OpenJPA 4.2.0 -
- Incompatibilities - - - OpenJPA 4.2.0 implements the Jakarta Persistence 3.2 specification and passes the - Jakarta Persistence 3.2 TCK. The following sections indicate changes that are incompatible - between OpenJPA 4.1.x releases and the 4.2.0 release. Most of them align OpenJPA with - the specification and cannot be switched off; where a configuration option restores - the previous behavior, it is mentioned in the respective section. Open follow-up items - from the review of this work are tracked under OPENJPA-2945. - -
- Platform and Dependency Requirements - - OpenJPA 4.2.0 requires Java 17 or later at build and run time (4.1.x required - Java 11). All jars contain Java 17 class files. Java 21 and Java 25 runtimes are - supported; class files of newer JDKs are read through - xbean-asm9-shaded 4.30. - +
+ Jakarta Persistence schema generation and SQL scripts - The jakarta.persistence:jakarta.persistence-api dependency was - raised from 3.1.0 to 3.2.0 (Jakarta EE 11 level). Applications must update explicit - dependencies on the API and recompile. Custom wrappers implementing - jakarta.persistence interfaces (EntityManager, - EntityManagerFactory, Query, - CriteriaBuilder, PersistenceUnitInfo, ...) - must implement the new 3.2 methods. The persistence_3_2.xsd and - orm_3_2.xsd schemas are bundled and selected for documents - declaring version="3.2"; version="3.1" - documents are still not accepted (use 3.0 or 3.2). + The jakarta.persistence.schema-generation.* properties are now + honored as described by the specification: scripts.action is + mapped to schema tool actions on its own (previously only + database.action was considered) and scripts are generated or + executed when the EntityManagerFactory is created rather + than lazily with the first EntityManager; explicit + create-source/drop-source values are + respected; java.io.Writer/Reader + targets and sources, file: URIs and absolute paths are accepted. + When Writer/Reader objects are + supplied, the corresponding keys are removed from the caller's property map, so the + map must be mutable. Persistence.generateSchema() defaults + database.action=create only if neither + database.action nor scripts.action is given. + A table dropped by an executed drop script is skipped by the next + buildSchema/add run in the same JVM (once by + default; until an EntityManagerFactory with schema-generation + properties starts when openjpa.SpecCompliantSchemaGeneration=true) + instead of being silently re-created. - XML column mapping (XMLValueHandler) and the detection of - XML-mapped value classes now use jakarta.xml.bind (JAXB 4) - instead of javax.xml.bind (JAXB 2). The optional dependencies - are jakarta.xml.bind:jakarta.xml.bind-api 4.0.x and a JAXB 4 - runtime such as com.sun.xml.bind:jaxb-impl 4.0.x. Value classes - that are still annotated with javax.xml.bind.annotation - annotations are no longer recognized as XML column types and silently fall back to - the default (serialized) mapping. Migrate such classes to - jakarta.xml.bind.annotation. + SQL scripts (create, drop and load scripts) are now parsed as + ;-terminated statements that may span several lines, with + --, // and /* ... */ + comments stripped (string literals are not recognized). Previously every line was + one statement. Errors in scripts executed through schema generation are logged as + warnings on the channel instead of failing + start-up. Terminate every statement with ; and check the log + for script errors. Related SchemaTool changes: table + truncation continues after failing statements, dropping the last column of a table + drops the whole table, and the new DBDictionary.isDroppable(Sequence) + hook excludes system sequences. - The managed JDBC driver versions used for testing were raised: MySQL Connector/J 9.x - (com.mysql:mysql-connector-j, driver class - com.mysql.cj.jdbc.Driver), MariaDB Connector/J 3.5.x, Microsoft - mssql-jdbc 13.x and Derby 10.16.x (which itself requires Java 17). - MySQLDictionary now also recognises - com.mysql.cj.jdbc.exceptions.MySQLTimeoutException as a timeout - exception, so lock and query timeouts are classified correctly with Connector/J 8 - and later. Drivers are not shipped with OpenJPA; see - for the tested database and driver versions. + Two options were added. openjpa.SpecCompliantSchemaGeneration=true + (also available as openjpa.Compatibility=SpecCompliantSchemaGeneration=true, + default false) enables strict Jakarta Persistence semantics: a + schema-generation configuration that resolves to no action (for example + database.action=none) also disables + openjpa.jdbc.SynchronizeMappings, @MapsId + foreign key columns are named <relation>_<targetPk>, + and on PostgreSQL identifiers are never quoted. Do not enable it on existing + databases created by earlier releases. The option + openjpa.jdbc.SyncMappingsExcludeTypes=a.B;c.D (or + SynchronizeMappings=buildSchema(ExcludeTypes=a.B;c.D)) excludes + entity classes from schema synchronization and drops their existing tables; only + list entities whose tables may be destroyed. See + and + . +
+
+ Numeric versus character column type conflicts - Build-only changes: the Maven profile test-h2-2 was removed - (use test-h2), and the legacy JPA 1.0 / 2.0 TCK profiles in - openjpa-integration/tck were replaced by the Jakarta Persistence - 3.2 TCK runner (-Ptck32-profile, run-tck32.sh). + When two mappings, or the mapping and the reflected database column, disagreed on + an incompatible column type, previous releases failed with a + -bad-col MetaDataException (or logged a + warning with disableSchemaFactoryColumnTypeErrors). Conflicts + between numeric and character types are now silently resolved to + VARCHAR, and values are converted on read and write. As a side + effect, SynchronizeMappings=validate and + SchemaManager.validate() no longer report numeric versus + VARCHAR drift; verify such columns manually. All other + incompatible combinations still fail as before.
-
- SecurityManager Support Removed +
+ DELETE affecting zero rows tolerated for unversioned entities - All AccessController.doPrivileged(...) calls were removed from - OpenJPA. Running OpenJPA under a Java SecurityManager with a - policy that grants permissions only to the OpenJPA jars is no longer supported (the - SecurityManager is deprecated for removal since Java 17 and - permanently disabled since Java 24, JEP 486). + A DELETE statement reporting an update count of zero previously + always raised an OptimisticException, including rows already + removed by a database-level ON DELETE CASCADE. For entities + without a version strategy (no @Version and no state comparison + versioning) such a delete is now silently accepted. Entities with a version + strategy behave as before. Applications that relied on the exception to detect a + concurrently deleted unversioned row should add a @Version + attribute; subclasses of PreparedStatementManagerImpl may + override hasVersion(RowImpl). +
+
+ Non-entity classes in persistence.xml - As a consequence the public PrivilegedAction factory methods of - org.apache.openjpa.lib.util.J2DoPrivHelper (for example - getForNameAction, getClassLoaderAction, - newInstanceAction, getContextClassLoaderAction) - were removed; only getLineSeparator(), - getPathSeparator(), newInstance(Class) and - newDeamonThread(Runnable, String) remain. Third-party code - (custom product derivations, dictionaries, plugins, application server integrations) - using these helpers must call the JDK API directly. Plugin classes instantiated - through J2DoPrivHelper.newInstance may now have a non-public - no-argument constructor. + Listing a class without persistence metadata in a persistence unit + (class element) previously failed at start-up with + "No registered metadata for type", in the runtime enhancer, in + getMetamodel() and during schema synchronization. Such classes + are now skipped with a warning on the openjpa.Enhance and + openjpa.jdbc.Schema logs. A forgotten @Entity + annotation is therefore no longer detected at start-up; watch the logs for the new + warnings.
-
- New JPQL Reserved Identifiers +
+ Relaxed kernel checks - The JPQL grammar now knows the Jakarta Persistence 3.2 keywords - ID, VERSION, FIRST, - LAST, ON, NULLS, - CAST, STRING, INTEGER, - LONG, FLOAT, DOUBLE, - TREAT, UNION, INTERSECT, - EXCEPT, RIGHT and REPLACE - (case-insensitive), as well as the || concatenation operator. - In previous releases these words could be used as identification variables and - result aliases, for example SELECT e.id AS id FROM E e ORDER BY id - or SELECT first FROM Foo first. Such queries are now rejected - with a parse error, as required by section 4.4.1 of the specification. + Several early exceptions were relaxed to satisfy the specification: + a non-cascaded relation pointing at an object without a state manager is no longer + rejected at flush with "cant-cascade-persist"; the referenced row is looked up in + the database during flush (an extra SELECT for unenhanced or + subclass-enhanced entities) and truly transient references may now fail later with + a foreign key error. Modifying an embeddable obtained from a query projection no + longer throws; the modification is silently not persisted. Re-persisting an entity + after remove() and flush is tolerated. In addition, + orphanRemoval=true no longer downgrades + cascade=REMOVE/ALL, so removal is cascaded + immediately when both are combined. +
+
+ Insert ordering across logical foreign keys - With the exception of INTEGER, LONG, - FLOAT and DOUBLE the new keywords may still be - used as path components, so attributes named id, - version, first or replace - can still be navigated (o.version). Attributes named - integer, long, float or - double can no longer be referenced in a JPQL path expression; - rename them or access them through the Criteria API or native SQL. Rename - identification variables and aliases that collide with the new keywords (most - commonly id, version, first, - last and on). There is no soft-keyword mode - and no compatibility option. + Flush ordering previously delayed an insert only for physical (constraint-backed) + foreign keys. Rows related through logical foreign keys (no constraint declared in + the mapping, for example an externally created schema with real constraints) are + now also delayed until the referenced new row has been inserted. Statement order + at flush time may therefore change; tests asserting an exact SQL order may need to + be adjusted. There is no configuration switch.
-
- JPQL Integer Literals are typed Integer +
+ Enhancer and runtime enhancement - Previous releases always created JPQL integer literals as - java.lang.Long, so SELECT 1 FROM ... or - e.intField + 1 produced Long results. - As required by section 4.8.5 of the specification, an integer literal without an - l/L suffix that fits into the - int range is now a java.lang.Integer; - arithmetic on Byte, Short and - Integer operands is promoted to Integer - (also in the Criteria API). + Classes enhanced by this release call new runtime methods (for example + ApplicationIds.getRelatedObjectId() for derived identities) and + fail on a 4.1.x runtime, while classes enhanced by 4.1.x still load but miss the + fixes of this release. Re-run the build-time enhancer + () with 4.2.0 when upgrading. - Application code that casts such results to Long must be - adapted to Integer or Number, or use an - explicit 1L literal. No compatibility option exists. + Runtime enhancement ( and the + Java agent) changed: class redefinition uses + Instrumentation.redefineClasses() and, if it fails, OpenJPA logs + "redefineClasses failed" at INFO and silently falls back to + subclass enhancement instead of throwing. getClass() calls in + user equals()/hashCode() implementations of + subclass-enhanced entities now see the entity class instead of the generated + subclass, and generated writeReplace() methods work with + non-public no-argument constructors.
-
- Query value conversion +
+ Delayed collection proxies on Java 21 - A String literal compared with a numeric path or parameter - (WHERE e.intField = '1', cb.equal(path, "12")) - is now parsed as a number of the path's type; previously a one-character literal was - compared as a Character and longer literals were rejected. The - character comparison is only used when the literal cannot be parsed as a number. - Selecting a collection- or map-valued attribute (SELECT e.addresses FROM - Employee e, query.select(root.get("addresses"))) is - treated as an implicit join and returns one row per element, typed as the element - type, instead of a collection-typed projection. - java.sql.Date values are no longer implicitly converted to - java.sql.Time or java.sql.Timestamp - when query values are compared (the same rule already applied to - java.util.Date). Enum names read from padded - CHAR columns are trimmed before Enum.valueOf(). - No compatibility option exists. + The delay-loading collection proxies (openjpa.ProxyManager=default(DelayCollectionLoading=true), + see ) now declare the Java 21 + SequencedCollection methods explicitly. + addFirst() and addLast() both delegate to + add(), so addFirst() appends instead of + prepending (previously DelayedLinkedListProxy prepended + after loading the collection), and reversed() returns a copy + rather than a write-through view for list and LinkedHashSet + proxies. Load the collection and reorder it explicitly where the position matters. + The ASM-generated non-delayed proxies are unchanged.
-
- Query.getResultList() returns a materialized ArrayList +
+ Static metamodel generator output - Query.getResultList() previously returned a lazy - org.apache.openjpa.lib.rop.ResultList wrapper that streamed - rows on demand (see ) and became invalid - when the query or the EntityManager was closed. Jakarta - Persistence 3.2 requires a mutable List, so the result is now - copied into a java.util.ArrayList: all rows are fetched - immediately, the list stays usable after the EntityManager - is closed, and it is no longer an instance of ResultList. - Query.getResultStream() also materializes the complete result - first. Large result set collections on entity fields - () are not affected. + Generated X_ classes now contain the Jakarta Persistence 3.2 + class_ field and QUERY_<NAME> / + MAPPING_<NAME> constants for named queries and result set + mappings declared on the type, and are annotated with + javax.annotation.processing.Generated instead of + jakarta.annotation.Generated when available. Regenerate the + metamodel classes and watch for name clashes with attributes named + class_. +
+
+ Lifecycle callbacks and listeners - For very large query results use setFirstResult() / - setMaxResults() paging, or obtain the kernel query via - OpenJPAQuery.getDelegate() for lazy semantics. Code that casts - the result to ResultList or - DelegatingResultList must be changed. + Default entity listeners declared in several mapping files are now registered once + instead of once per file, and a callback declared both by annotation and in + orm.xml for the same method is registered once with the XML + declaration taking precedence. Callback parameter types are matched more leniently, + and listeners receive the managed entity instance (not the internal + ReflectingPersistenceCapable wrapper) on + AFTER_DELETE_PERFORMED for unenhanced entities. Applications that + depended on duplicate invocations must be adjusted.
-
- Bulk DELETE no longer cascades +
+ persistence.xml resource handling - In previous releases a JPQL or Criteria bulk DELETE against an - entity with cascade-delete or dependent relations (for example - @OneToMany(cascade=REMOVE) or an - @ElementCollection) was executed in memory: every instance was - loaded and removed through the persistence context, cascading to related entities - and cleaning up join table and element collection rows. As required by section - 4.10 of the specification, bulk operations do not cascade. A DELETE - query now issues a single SQL DELETE against the entity table(s); - related entities, join table rows and element collection rows are left untouched - and will cause foreign key violations unless the database defines - ON DELETE CASCADE. + An I/O error while reading a persistence.xml resource from the + classpath previously aborted createEntityManagerFactory(). Such + resources are now logged ("unreadable-persistence-xml") and skipped; schema + validation errors still abort. A unit that only exists in a skipped resource + surfaces later as a missing persistence unit. Resource streams are opened with + URL connection caching disabled. The 3.2 elements scope and + qualifier are exposed through + PersistenceUnitInfo. +
+
+ Locale-independent case conversion - Delete dependents explicitly (separate bulk deletes or em.remove()) - or rely on database-level cascades. Note that a bulk UPDATE or - DELETE that still has to be executed in memory now flushes all - pending changes of the persistence context after processing. No compatibility - option exists. See also . + Identifier normalization, JPQL parsing, in-memory LOWER()/ + UPPER() evaluation and SQL formatting used the JVM default + locale for case conversion. They now use Locale.ROOT + (Locale.ENGLISH for reserved word matching). This is only + observable under locales with special casing rules (Turkish, Azeri, Lithuanian), + where generated identifiers containing i/I + may now differ from those generated by earlier releases; use explicit + @Table/@Column names in that case.
-
- FlushModeType.AUTO flushes whenever the context is dirty +
+ Reserved word handling and MySQL delimiting - Previously a query only flushed pending changes when a dirty instance belonged to - a type in the query's access path, and never for SELECT queries - when was true. With - FlushModeType.AUTO (the default, - =true) and an active - transaction, a query now flushes whenever any instance in the persistence context - is new, dirty or deleted, regardless of the query's access path, and overrides - openjpa.IgnoreChanges. Applications with write-heavy transactions - may observe more flushes (and therefore earlier constraint or trigger evaluation). + Reserved word detection is now case-insensitive for all dictionaries, so generated + (defaulted) column, table and sequence names that equal a reserved word in a + different case may now receive a 0 suffix. + H2Dictionary additionally feeds its H2 2.x keyword list into + the naming rules. On MySQL (MySQLDictionary, not + MariaDBDictionary) reserved word identifiers are now + automatically delimited with back-ticks in all generated SQL, so previously + failing names such as KEY, TEXT or + LIBRARY work without manual delimiting. Tools comparing SQL text + must ignore the delimiters. Use explicit @Table/@Column + names if an old generated name must be kept. See + . +
+
+ PostgreSQL - To restore the previous behavior use FlushModeType.COMMIT on - the query or the EntityManager, or set - openjpa.FlushBeforeQueries to false or - with-connection. + Delimited identifiers: PostgresDictionary now strips the + double quotes from a quoted identifier whose inner text is a plain identifier + (letters, digits and underscores, not starting with a digit). PostgreSQL then folds + the name to lower case, so @Table(name="\"MyTable\"") now + addresses mytable and quoted reserved words such as + "Order" become bare keywords. Identifiers containing spaces or + other special characters keep their quotes. Do not rely on delimited identifiers to + preserve mixed case or to use reserved words as names on PostgreSQL; rename the + objects, or subclass PostgresDictionary and override + toDBName(). There is no configuration switch. -
-
- Exceptions mark the transaction rollback-only; closed EntityManager checks - As required by section 3.3.7.1 of the specification, every - RuntimeException raised by an EntityManager - or Query method now marks the active transaction for - rollback, except NoResultException, - NonUniqueResultException, - LockTimeoutException and - QueryTimeoutException. In previous releases the transaction - remained committable after, for example, an IllegalArgumentException - from find(), createNamedQuery() or an invalid - CriteriaQuery. Applications that caught such an exception and - committed the same transaction now receive a RollbackException - and must restart the transaction. + char/Character attributes: on PostgreSQL 9 + and later StoreCharsAsNumbers now defaults to + false, so such attributes map to CHAR(1) + columns instead of INTEGER columns holding code points, and the + Java default '\0' is stored as SQL NULL. + Existing INTEGER columns created by earlier releases fail + validation or return wrong values. Either migrate them to + CHAR(1) or restore the previous mapping with + openjpa.jdbc.DBDictionary=postgres(StoreCharsAsNumbers=true); + an explicitly configured value is respected (OPENJPA-2971). - Operations on a closed EntityManager or its - Query objects now consistently throw - IllegalStateException. This includes - getEntityManagerFactory(), getCriteriaBuilder(), - getMetamodel(), getDelegate(), - setProperty(), isJoinedToTransaction(), - createEntityGraph(), createQuery(CriteriaQuery) - and Query.getHints(), getLockMode(), - closeAll() and the parameter accessors, which used to work on a - closed EntityManager. Further changes: - getLockMode()/setLockMode() on a bulk - UPDATE/DELETE query and - executeUpdate() on a SELECT query throw - IllegalStateException; - createQuery(CriteriaQuery) snapshots the criteria state, so - modifying the CriteriaQuery afterwards no longer affects the - created Query; isJoinedToTransaction() - returns true for an active resource-local transaction. + Further fixes: java.util.UUID parameters are bound so that + both native uuid and varchar columns work (on + other databases a UUID is bound as VARCHAR unless the column is + a native UUID column); @Lob columns of type oid + are read and written through the large object API, which performs an implicit + COMMIT when reading in auto-commit mode; reflected + bool columns are reported as BOOLEAN, so + schema validation may now report boolean versus varchar drift that was previously + tolerated; DROP SEQUENCE IF EXISTS is emitted.
-
- Argument validation in find(), getReference(), detach(), contains(), remove() +
+ MySQL and MariaDB - find(cls, null) previously returned null, a - primary key of the wrong type or a non-entity class surfaced later as an OpenJPA - ArgumentException or a failed lookup, and removing a detached - unenhanced entity could be silently ignored. These methods now validate their - arguments as required by the specification and throw - IllegalArgumentException (marking the transaction for - rollback) for null keys, non-entity classes, primary keys of an - incompatible type (numeric widening such as Integer to - Long is accepted, narrowing is rejected), non-entities - passed to detach()/contains(), and detached - instances passed to remove(). getReference() - throws EntityNotFoundException also for unenhanced entities. + On MySQL 5.7+ and MariaDB 10.2+ temporal columns are now created as + DATETIME(6) and TIME(6) + (DateFractionDigits=6) instead of whole-second precision, so that + @Version attributes of type Instant or + LocalDateTime can distinguish updates within the same second. + The value is set at connection time and overrides a + DateFractionDigits value given in + . Existing columns keep working, but + schema validation or refresh may report or alter the precision. Use + @Column(secondPrecision=0) on individual columns, or subclass the + dictionary and reset dateFractionDigits after + connectedConfiguration(), to keep whole seconds. - Guard against null keys, pass keys of the declared - @Id type and merge() detached instances before - removing them. No compatibility option exists. + MariaDBDictionary no longer replaces a configured positive + with Integer.MIN_VALUE + (the Connector/J 2.x streaming mode); the configured value is passed to the driver + unchanged. MySQLDictionary keeps the streaming behavior. + Subclass MariaDBDictionary and override + getBatchFetchSize(int) to restore streaming.
-
- EntityManager.close() with an active resource-local transaction - - Previously EntityManager.close() threw an - InvalidStateException while a resource-local transaction was - active; a deferred close existed only for managed (JTA) transactions with the - CloseOnManagedCommit compatibility flag. As required by sections - 3.3.2 and 7.7 of the specification, close() now always returns - and the persistence context is released when the transaction completes: - isOpen() reports false immediately while - em.getTransaction().commit()/rollback() - remain callable. - +
+ Microsoft SQL Server - Code that relied on the exception to detect a leaked open transaction must check - em.getTransaction().isActive() itself and end the transaction - explicitly. There is no option to restore the exception. + CURRENT_DATE and CURRENT_TIME are now + translated to CONVERT(DATE, GETDATE()) and + CONVERT(TIME, GETDATE()) instead of plain + GETDATE(), so the results are DATE/TIME + typed and comparisons against datetime columns may behave + differently. EXTRACT uses DATEPART and JPQL + time literals are rendered as CAST('hh:mm:ss' AS TIME). To + restore the previous SQL set + openjpa.jdbc.DBDictionary=sqlserver(CurrentDateFunction=GETDATE(),CurrentTimeFunction=GETDATE()).
-
- EntityManagerFactory lifecycle and properties +
+ Oracle - EntityManagerFactory.close() could previously be called more than - once, and methods of a closed factory either worked or failed deep inside the kernel. - Now getProperties(), createEntityManager(), - getCriteriaBuilder(), getMetamodel(), - getPersistenceUnitUtil() and - getSchemaManager() throw IllegalStateException - after close(), and a second close() throws as - well. createEntityManager(SynchronizationType.UNSYNCHRONIZED) - throws IllegalStateException instead of - UnsupportedOperationException (it is forbidden for - RESOURCE_LOCAL units and still unimplemented for JTA units). + Identity column sequences (ISEQ$$_*) are treated as system + sequences and excluded from drop actions, AUDSYS is treated as a + system schema, an @Index duplicating the primary key is skipped, + CEILING() is translated to CEIL(), and the new + Jakarta Persistence 3.2 functions are mapped to Oracle syntax + (EXCEPT as MINUS before Oracle 21, + LEFT/RIGHT via SUBSTR). + These are fixes; workarounds for the old behavior can be removed. +
+
+ HSQLDB - EntityManagerFactory.getProperties() no longer creates a temporary - EntityManager to merge EntityManager-level - defaults (lock timeout, cache modes, fetch plan settings) into its result, and - null-valued entries are removed; read such defaults from - EntityManager.getProperties() instead. - addNamedQuery() now replaces an existing definition of the same - name and records flush mode, max results and lock mode; Criteria queries are stored - as JPQL text, which is not guaranteed to round-trip for complex criteria. + HSQLDictionary no longer disables + SupportsSelectForUpdate, so pessimistic locks now emit + SELECT ... FOR UPDATE; query timeouts are disabled + (SupportsQueryTimeout=false); OffsetTime + attributes are created as TIME instead of + TIME WITH TIME ZONE; numeric casts are sized + NUMERIC(128,32) so fractional digits are no longer truncated; + INFORMATION_SCHEMA and SYSTEM_LOBS are treated + as system schemas. Use openjpa.jdbc.DBDictionary=hsql(SupportsSelectForUpdate=false,SupportsQueryTimeout=true) + and @Column(columnDefinition="TIME WITH TIME ZONE") to restore + the previous behavior. On H2 2.x, table truncation now skips the + INFORMATION_SCHEMA meta tables.
-
- Query parameter API +
+ SPI changes for custom store, dictionary and expression implementations - Reading an unbound parameter via getParameterValue() now throws - IllegalStateException (previously - IllegalArgumentException or null); - Parameter objects obtained from another query are rejected - with IllegalArgumentException; - getParameter(String, Class) now correctly accepts an exact or - wider type (the positional variant getParameter(int, Class) still - only accepts the exact type or a subtype). A parameter bound with - TemporalType.DATE is converted to java.sql.Date - (time of day dropped) instead of being passed through unchanged. + Implementors of OpenJPA SPI interfaces must recompile and implement new methods: + BrokerFactory (createPersistenceStructure, + dropPersistenceStructure, validatePersistenceStructure, + truncateData; AbstractBrokerFactory + throws UnsupportedOperationException by default), + ExpressionFactory (newTypecastAsString, + newTypecastAsNumber, left, right, + replace, getNativeObjectId, version), + Result (getInstant, getYear), + Select (appendNullsPrecedence, + addSetOperatorSQL, getSetOperatorBuffer), + OpenJPAConfiguration (schema generation script accessors, + isSchemaGenerationExplicit, isSpecCompliantSchemaGeneration) + and JDBCConfiguration (get/setSyncMappingsExcludeTypes). - Catch IllegalStateException for unbound parameters and expect - java.sql.Date semantics for DATE-typed - parameters compared against TIMESTAMP columns. + DBDictionary.SerializedData is now a record + (bytes() instead of the bytes field); + IdentifierRule.setReservedWords takes a + Collection and matches case-insensitively, so subclasses + overriding the Set variant no longer override; + JavaTypes.INSTANT (39) and JavaTypes.YEAR (40) + were added and must be handled by custom value handlers and strategies; + QueryExpressions gained nullPrecedence, + setOperationType and setOperands, which only + the JDBC store consumes, so a custom StoreQuery silently ignores + NULLS FIRST/LAST and set operations unless it is extended. + DBDictionary gained a number of public configuration fields + (ReplaceFunctionName, LeftFunctionName, + RightFunctionName, NaturalLogarithmFunction, + CeilingFunction, ExceptFunction, + TypecastToStringTypeName, IntegerCastTypeName, + SupportsUnsizedCharOnCast) and hooks + (isDroppable(Sequence), toJDBCEscapedDateTimeLiteral, + appendNullsPrecedence, getExtractField, + get/setMajorVersion, get/setMinorVersion).
-
- StoredProcedureQuery semantics +
+ Notable new features - Positional stored procedure parameters are now resolved 1-based (previously the - 0-based column index was used as fallback, so position 1 could match the second - IN column), and only IN/INOUT/ - OUT columns are registered, so positional indexes shift for - PostgreSQL functions with a return value. When a procedure declares - OUT parameters the connection is kept open (with auto-commit - temporarily disabled) until the result list is closed, so that - REF_CURSOR results can be consumed; consume and close such - result lists promptly. + The following Jakarta Persistence 3.2 features are new in this release. They are + opt-in and do not change existing behavior unless noted: + + + JPQL: ID() and VERSION() functions, + CAST, LEFT, RIGHT, + REPLACE, the || operator, + UNION/INTERSECT/EXCEPT [ALL], + NULLS FIRST/LAST, TREAT in joins and + paths, JOIN ... ON, EXTRACT, + LOCAL DATE/TIME/DATETIME, additional math functions, + an optional SELECT clause and the implicit + this identification variable (bound automatically when a + FROM item declares no identification variable). See . + In-memory query execution (and custom StoreQuery + implementations) silently ignore + UNION/INTERSECT/EXCEPT + and NULLS FIRST/LAST; + LEFT/RIGHT, CAST and + EXTRACT are not available on Derby. + + + EntityManager: find(), + lock() and refresh() with + FindOption/LockOption/RefreshOption, + getReference(entity), cache mode and timeout accessors, + runWithConnection()/callWithConnection(), + createQuery(CriteriaSelect); + Query: getSingleResultOrNull(), + cache mode and timeout setters. + + + EntityManagerFactory: + runInTransaction()/callInTransaction() + (exceptions are rethrown wrapped in + org.apache.openjpa.persistence.PersistenceException), + getSchemaManager(), getName(), + getTransactionType(), getNamedEntityGraphs(); + PersistenceUnitUtil: getVersion(), + isInstance(), getClass(), + load(); programmatic bootstrap via + Persistence.createEntityManagerFactory(PersistenceConfiguration) + and the jakarta.persistence.dataSource property. + EntityManager.find(EntityGraph, ...), + createQuery(TypedQueryReference), + getNamedQueries() and + SynchronizationType.UNSYNCHRONIZED are not yet implemented. + + + Entity graphs (@NamedEntityGraph, + createEntityGraph(), getEntityGraph()), + CriteriaUpdate, CriteriaDelete, + CriteriaSelect set operations, + Join.on(), CriteriaBuilder.cast()/ + left()/right()/replace()/ + extract() and treat(Root), all of which + previously threw UnsupportedOperationException. + + + Mapping: Java records as @Embeddable (records are + always treated as managed types, regardless of + openjpa.RuntimeUnenhancedClasses), + @EnumeratedValue (an enum declaring such a field changes + its stored representation), @Version on + java.time.Instant and + java.time.LocalDateTime (give such columns at least + microsecond precision), @Column(secondPrecision, options), + @Table(options), repeatable + @SequenceGenerator/@TableGenerator, + ConstructorResult in result set mappings, inline result + mappings on @NamedNativeQuery, orm.xml + version 3.2, id classes without a public no-argument constructor, and + @MapsId with non-embeddable id classes. + + + jakarta.persistence.ForeignKey, + @Index sort order, @JoinTable.indexes + and @Converter(autoApply=true) are honored (see the + respective sections above for the effect on existing schemas). + + + The bundled Jakarta Persistence schemas are now included under the Eclipse + Foundation Specification License 1.1 instead of the CDDL. + + +
+
+
+
+ OpenJPA 3.2.0 +
+ Incompatibilities + + The following sections indicate changes that are incompatible + between OpenJPA 3.1.x releases and the 3.2.0 release. + +
+ SUM now always returns Double - executeUpdate() now requires an active transaction - (TransactionRequiredException) and - getUpdateCount() returns -1 after it; - setLockMode()/getLockMode() throw - IllegalStateException; - getOutputParameterValue() throws - IllegalArgumentException for unknown names or positions; - NoResultException and - NonUniqueResultException propagate unwrapped; procedure - metadata lookup retries with the lower-cased name; an - orm.xml named-stored-procedure-query overrides - an annotation of the same name. + We did fix the SUM operation to always return Double as requested by the spec. + Previously we did return whatever Numeric the JDBC driver did serve, resulting in non portable code.
-
- Criteria API and Metamodel +
+ Invalid Column Name Changes - Several OpenJPA extensions and lenient behaviors of the Criteria API were tightened - to the specification: CriteriaBuilder.array()/tuple() - reject nested compound selections and multiselect()/select() - reject duplicate aliases with IllegalArgumentException; - cb.literal(null) throws IllegalArgumentException - (use nullLiteral(Class)); Path.get() on a basic - path and From.getCorrelationParent() on a non-correlated - From throw IllegalStateException; - Metamodel.entity(Class)/embeddable(Class) throw - IllegalArgumentException for unknown types instead of - returning null; ParameterExpression.getPosition() - returns null (previously threw an internal exception). + We did review and update the list of invalid column names for most DBDicationary. + The list of tested reserved words got enriched with previously forbidden column names to avoid backward + incompatibility issues. + The list can ge retrieved and configured via + + DBDictionary.getInvalidColumnWordSet +
+
+ MappingTool Behavior for HSQLDB - Embeddable-typed attributes are no longer reported as associations - (isAssociation() is false, - getBindableType() is SINGULAR_ATTRIBUTE), - getBindableJavaType() returns the declared attribute type, and - getId(Class)/getDeclaredId(Class) require strict - type assignability. cb.treat(Root, Class) is now implemented; - treat() on joins and paths returns the argument unchanged without - narrowing, and TREAT only matches the exact treated class, not its - subclasses. Flatten nested selections, use unique aliases and adjust catch blocks - and null checks accordingly. + There have been 2 changes for Hypersonic (HSQLDB). + We fixed a bug which did cause long fields getting mapped to INTEGER + instead of BIGINT. -
-
- PersistenceUnitUtil.getIdentifier() returns the plain identifier - PersistenceUnitUtil.getIdentifier() previously returned the - internal org.apache.openjpa.util.OpenJPAId wrapper - (LongId, StringId, ...) for managed - entities and null for new, detached or unenhanced entities and - for non-entities. It now returns the raw identifier value (the plain key or the - IdClass instance for compound identity), also for new, detached - and unenhanced entities, and throws IllegalArgumentException - for objects that are not entities. Code that cast the result to - OpenJPAId must use the plain value or call - OpenJPAEntityManager.getObjectId(). + Java double fields previously got mapped to NUMERIC which + does lack fraction digits. Thus the value 7.3425343 got truncated to 7. + We now map double fields in Entities to DOUBLE SQL column types.
-
- Cache mode properties on EntityManager.setProperty() +
+ Respect TIMESTAMP precision in Oracle - EntityManager.setProperty("jakarta.persistence.cache.retrieveMode", ...) - and "jakarta.persistence.cache.storeMode" previously accepted the - enum constants as well as their String names. The new - Jakarta Persistence 3.2 setters setCacheRetrieveMode() and - setCacheStoreMode() are now used to apply these properties, and - a String value is passed to the setter unconverted, which - fails with an IllegalArgumentException (argument type - mismatch); previously the call succeeded. Pass the - CacheRetrieveMode/CacheStoreMode enum - constant, or call the setters directly. String values given - as find(), refresh() or query hints continue - to work. + Due to a bug we did hardcoded round at 3 digits precision. + So we essentially only allowed millis, even on a TIMESTAMP(6) field. + The new code does respect the second fractions and now defaults to 6. + It should be compatible but it might behave very subtle different.
-
- Default map key column renamed to <field>_KEY +
+ Unary Operations return types - For Map-valued fields without @MapKeyColumn - the key column was previously named KEY (which most dictionaries - turned into KEY0 because KEY is a reserved - word). As required by section 11.1.35 of the specification, the default is now the - field name followed by _KEY (for example - PHONES_KEY). Schemas created by earlier releases no longer match: - schema validation fails, SynchronizeMappings=buildSchema adds a - new column and existing key data reads back as null. + Before OpenJPA-3.2.0 Unary Operations like MIN, MAX, SUM, etc + did return whatever type got returned by the JDBC driver. For certain column types this could also have been internal + classes of that very JDBC driver. E.g. a SELECT MAX(a.someLocalDateField) .. might have returned + an instance of types com.oracle.jdbc.... or com.microsoft.sqlserver..., etc. + We now use the respective + DBDictionary to request the correct type from the ResultSet. +
+
+ PostgreSQL now supports setQueryTimeOut - Declare the existing column explicitly, for example - @MapKeyColumn(name="KEY0"), or rename the column in the - database. No compatibility option restores the old default. See also - . + PostgreSQL does now support client side setQueryTimeout. + User might see this come alive and now return different when the situation occurs. + This flag is automatically enabled if running against PostgreSQL 10 or later. + It can also be configured manually via + DBDictionary.supportsQueryTimeout
-
- Attribute overrides, @OrderBy and inverse map keys +
+
+
+ + OpenJPA 2.3.0 + +
+ Incompatibilities + + The following sections indicate changes that are incompatible + between OpenJPA 2.2.x releases and the 2.3.0 release. + +
+ + MappingTool Behavior for DB2 and Derby + - @AttributeOverride on an entity now also applies to the entity's - own declared fields (previously only mapped superclass fields were overridden), and - an override name without key./value. prefix on - an element collection Map refers to the map value instead of - failing. Attribute names in @OrderBy and overrides are resolved - case-insensitively as a fallback. @MapKeyColumn on the inverse - side of a @OneToMany(mappedBy) map is now written to the target - entity's table (additional UPDATE statements), and an - @ElementCollection whose table coincides with an entity's primary - table is no longer written separately. + In previous releases, the MappingTool mapped java.math.BigDecimal fields to the database type + DOUBLE, and as such, ignored column and precision values that might have been specified via the + jakarta.persistence.Column annotation. - Verify the column names produced by overrides that were previously ignored or - rejected, and @OrderBy values that differ from attribute names - only in case. + From the 2.3.0 release, java.math.BigDecimal fields are now mapped to the database type DECIMAL + and it is very likely that you will need to specify column and precision via + the jakarta.persistence.Column annotation.
-
- @SequenceGenerator without sequenceName +
+ + RequiresSearchStringEscapeForLike DBDictionary Property + + - A @SequenceGenerator annotation without - sequenceName previously fell back to the OpenJPA default - sequence OPENJPA_SEQUENCE, so all such generators shared one - database sequence. As defined by the specification, the generator name is now used - as the database sequence name, and DDL generation creates one sequence per - generator. orm.xml sequence-generator elements - are not affected. + In previous releases, the default value for the property RequiresSearchStringEscapeForLike is true and caused the + unexpected escape clause appended to the SQL statement. + For example, user created a named query like this: + SELECT o.computerName FROM CompUser o WHERE o.name LIKE ? + At run time the following query is generated: + SELECT t0.computerName FROM CompUser t0 WHERE (t0.name LIKE ? ESCAPE '\') + ESCAPE '\' shouldn't be appended to the query. - For existing databases either add sequenceName="OPENJPA_SEQUENCE" - (or the previously used name) to each generator, or create the new per-generator - sequences. See . + From the 2.3.0 release, RequiresSearchStringEscapeForLike property is set to false by default. You can configure + RequiresSearchStringEscapeForLike property to be true if the old behavior is desired.
-
- AttributeConverter handling +
+ + Return value of aggregate functions in SELECT clause + + - Support for jakarta.persistence.AttributeConverter was reworked. - @Converter(autoApply=true) classes found on the classpath are now - registered and applied to every basic attribute whose declared type matches - (excluding identifiers, version fields, relations, collections and maps) unless - the attribute declares its own @Convert; previously - autoApply was ignored. Class-level - @Convert(attributeName=...)/@Converts, - converters on embedded attributes, on mapped superclass attributes and on element - collection elements are honored (previously ignored or rejected). The database - column type is now derived from the converter's database type - Y instead of the attribute type X - (a Boolean to Integer converter now - yields an INTEGER column). + The JPA specification states "If SUM, AVG, MAX, or MIN is used, and there are no values to which the aggregate function can be + applied, the result of the aggregate function is NULL." Prior to this update, OpenJPA incorrectly returned 0 for SUM, AVG, MIN, + and MAX when a state field being aggregated is numeric. This behavior affects both JPQL and Criteria queries. With this update, + OpenJPA will return a null result value for these aggregate functions when a query returns no result. - One converter instance per attribute is created lazily through the no-argument - constructor and shared between threads, so converters must be stateless. - RuntimeExceptions thrown by a converter surface as - jakarta.persistence.PersistenceException instead of - MetaDataException. @Convert(disableConversion=true) - only cancels an explicit converter on that attribute; it does not prevent an - autoApply converter from being applied. + To re-enable the prior behavior, you need to set the following persistence property in your persistence.xml or when + creating an EntityManagerFactory. + + <property name="openjpa.Compatibility" value="ReturnNullOnAggregateResult=false"/> + +
+
+
+
+ + OpenJPA 2.2.0 + +
+ Incompatibilities + + The following sections indicate changes that are incompatible + between OpenJPA 2.1.x releases and the 2.2.0 release. + +
+ + allocationSize Property of Sequence Generator + + - Audit existing @Converter(autoApply=true) classes: attributes of - the matching type that were stored unconverted by 4.1.x are now written and read - through the converter and their generated column type changes. Remove - autoApply, declare an explicit converter, or pin the column type - with @Column(columnDefinition=...) where the old behavior is - required. + In previous releases, specifying the allocationSize property of + sequence generator + affected only sequence definition in the database. During + schema creation, the INCREMENT BY clause of + CREATE SEQUENCE statement always + had a value of 1 and on DB2, Oracle and PostgreSQL databases a CACHE clause + was added with the value of allocationSize property. Such a statement caused + sequence values being cached in the database. Starting with OpenJPA 2.2.0, + sequence values are cached in the jvm memory and the allocationSize + property determines size of that cache. The CACHE clause is no longer used, + instead the INCREMENT BY clause gets its value equal to the + allocationSize property. Such a strategy reduces the number of database roundtrips + required for retrieving sequence values considerably. -
-
- Access type determination and property accessors - Implicit access type determination now follows the specification: only - access-defining annotations (@Id, @EmbeddedId, - @Version, @Basic, @Embedded, - the relationship annotations, @ElementCollection, - @Transient) decide the access type; supplementary annotations - such as @Column or @Temporal only count when - no access-defining annotation is present. A getter whose backing field is - @Transient is a per-attribute property override and no longer - makes the class "mixed"; an attribute annotated on both field and getter uses - property access; a subclass whose implicit access conflicts with its persistent - superclass inherits the superclass access type (previously an error); - @Basic may be combined with a more specific mapping annotation; - records always use field access; types declared as embeddable - only in orm.xml are mapped as embedded rather than serialized. + In order for the existing applications to work with OpenJPA + 2.2.0, you have to manually recreate or redefine sequences, specifying + the correct INCREMENT BY value and, possibly, correct initial sequence value. + Note that the default value of the allocationSize property is 50 and that + value is used if the property is not specified. - Boolean getters must have an upper-case character after is - (island() or isaBoolean() are no longer - persistent properties), and the setter for a property is derived from the actual - getter suffix (getdescription()/setdescription() - pairs are accepted). Entities that previously failed to load may now load with a - different access type than intended; add an explicit @Access - where fields and getters are both annotated, and review unusual boolean accessor - names. No compatibility option exists. + The requirement for sequence modification applies to all databases that support sequences, regardless of + the CACHE clause being supported. The only exception is Firebird database - + since with this database the increment step is determined during sequence + value fetch, no migration activity is needed. -
-
- java.time.Instant and java.time.Year mapping - java.time.Instant and java.time.Year - are now first-class persistent types: Instant maps to a - TIMESTAMP column and Year to an - INTEGER column. Previous releases had no type code for them and - stored such attributes through the generic object strategy as serialized binary - data. Existing columns created for such attributes are incompatible with the new - mapping: migrate the columns and data, or keep them serialized explicitly with - @Lob or an externalizer. java.util.Calendar - may now be used as a single-field identifier. + To maintain the old behavior of sequence generator in OpenJPA 2.2.0, you can: + + + + Set the allocationSize property value to 1. + + + + + Additionally, if the CACHE clause has to be emitted in sequence definition, + this can be accomplished by overriding the + + DBDictionary.getCreateSequenceSQL method. + + +
-
- Generated DDL changes +
+ + MetaModel Attributes for Arrays + + - The DDL produced by the mapping tool, - and the new SchemaManager differs from previous releases: - - - jakarta.persistence.ForeignKey on - @JoinColumn, @JoinTable and - @SecondaryTable is now parsed. A named constraint - (ConstraintMode.CONSTRAINT) is emitted as a physical - foreign key even for relations that OpenJPA treats as logical; - NO_CONSTRAINT suppresses the key; - PROVIDER_DEFAULT keeps the 4.1.x behavior. Expect - additional ALTER TABLE ... ADD CONSTRAINT statements - and a stricter drop order. - - - Every declared @SecondaryTable is created, even if no - field is mapped to it. - - - The table-level comment is no longer emitted in - CREATE TABLE (column comments remain). - - - @Index(columnList="col DESC") is honored, - @JoinTable.indexes are created, - @Table(options) and @Column(options) - are appended verbatim, and @Column(secondPrecision) - takes precedence over scale and the dictionary's - DateFractionDigits for temporal columns. - - - - - Compare generated DDL against existing schemas before enabling schema - synchronization in production. - -
-
- Jakarta Persistence schema generation and SQL scripts - - The jakarta.persistence.schema-generation.* properties are now - honored as described by the specification: scripts.action is - mapped to schema tool actions on its own (previously only - database.action was considered) and scripts are generated or - executed when the EntityManagerFactory is created rather - than lazily with the first EntityManager; explicit - create-source/drop-source values are - respected; java.io.Writer/Reader - targets and sources, file: URIs and absolute paths are accepted. - When Writer/Reader objects are - supplied, the corresponding keys are removed from the caller's property map, so the - map must be mutable. Persistence.generateSchema() defaults - database.action=create only if neither - database.action nor scripts.action is given. - A table dropped by an executed drop script is skipped by the next - buildSchema/add run in the same JVM (once by - default; until an EntityManagerFactory with schema-generation - properties starts when openjpa.SpecCompliantSchemaGeneration=true) - instead of being silently re-created. + In previous releases OpenJPA's MetaModel implementation generated a ListAttribute for every array. This behavior is correct if the array + is annotated as a PersistentCollection, but not correct for un-annotated arrays (e.g. byte[], char[]). In OpenJPA 2.2.0 this behavior was corrected + so that arrays which are not stored as PersistentCollections will use a SingularAttribute instead of a ListAttribute. - SQL scripts (create, drop and load scripts) are now parsed as - ;-terminated statements that may span several lines, with - --, // and /* ... */ - comments stripped (string literals are not recognized). Previously every line was - one statement. Errors in scripts executed through schema generation are logged as - warnings on the channel instead of failing - start-up. Terminate every statement with ; and check the log - for script errors. Related SchemaTool changes: table - truncation continues after failing statements, dropping the last column of a table - drops the whole table, and the new DBDictionary.isDroppable(Sequence) - hook excludes system sequences. + If your application uses the MetaModel API and your entities contain arrays of any of the following types: byte[], Byte[], char[], Character[] and + do not use the @PersistentCollection annotation with those fields you will need to update your application to use OpenJPA 2.2.0. - - Two options were added. openjpa.SpecCompliantSchemaGeneration=true - (also available as openjpa.Compatibility=SpecCompliantSchemaGeneration=true, - default false) enables strict Jakarta Persistence semantics: a - schema-generation configuration that resolves to no action (for example - database.action=none) also disables - openjpa.jdbc.SynchronizeMappings, @MapsId - foreign key columns are named <relation>_<targetPk>, - and on PostgreSQL identifiers are never quoted. Do not enable it on existing - databases created by earlier releases. The option - openjpa.jdbc.SyncMappingsExcludeTypes=a.B;c.D (or - SynchronizeMappings=buildSchema(ExcludeTypes=a.B;c.D)) excludes - entity classes from schema synchronization and drops their existing tables; only - list entities whose tables may be destroyed. See - and - . + In order for the existing applications to work with OpenJPA you may: + + + Regenerate the canonical metamodel classes + + + Set the Compatibility property UseListAttributeForArrays to true in persistence.xml + <property name="openjpa.Compatibility" value="UseListAttributeForArrays=true"/> + + +
-
- Numeric versus character column type conflicts +
+ + supportsSetClob Property. + + - When two mappings, or the mapping and the reflected database column, disagreed on - an incompatible column type, previous releases failed with a - -bad-col MetaDataException (or logged a - warning with disableSchemaFactoryColumnTypeErrors). Conflicts - between numeric and character types are now silently resolved to - VARCHAR, and values are converted on read and write. As a side - effect, SynchronizeMappings=validate and - SchemaManager.validate() no longer report numeric versus - VARCHAR drift; verify such columns manually. All other - incompatible combinations still fail as before. + In OpenJPA 2.2.0, code was added to allow the setting of CLOB or XML data larger than 4000 bytes. This functionality + was eventually back ported to previous releases, and enabled by the supportsSetClob property on the OracleDictionary. Setting this property + has no effect in 2.2.0 and later releases and any occurrence of it should be removed.
-
- DELETE affecting zero rows tolerated for unversioned entities +
+ + useNativeSequenceCache Property. + + - A DELETE statement reporting an update count of zero previously - always raised an OptimisticException, including rows already - removed by a database-level ON DELETE CASCADE. For entities - without a version strategy (no @Version and no state comparison - versioning) such a delete is now silently accepted. Entities with a version - strategy behave as before. Applications that relied on the exception to detect a - concurrently deleted unversioned row should add a @Version - attribute; subclasses of PreparedStatementManagerImpl may - override hasVersion(RowImpl). + In OpenJPA 2.2.0, code was added which changed the way sequences were generated, please see + for details. This functionality was eventually back ported + to previous releases, and enabled by the useNativeSequenceCache property on the DBDictionary. Setting this property + has no effect in 2.2.0 and later releases and any occurrence of it should be removed. If previous behavior is + desired (i.e. useNativeSequenceCache=true), please see the details described in section + .
-
- Non-entity classes in persistence.xml +
+ + Cascade persist behavior + + - Listing a class without persistence metadata in a persistence unit - (class element) previously failed at start-up with - "No registered metadata for type", in the runtime enhancer, in - getMetamodel() and during schema synchronization. Such classes - are now skipped with a warning on the openjpa.Enhance and - openjpa.jdbc.Schema logs. A forgotten @Entity - annotation is therefore no longer detected at start-up; watch the logs for the new - warnings. + In previous releases, OpenJPA would check the database for the + existence of the related Entity before persisting the relationship to + that Entity. This resulted in an extra Select being sent to the + database. In 2.2.0, code was added so that when cascading a persist to + a related Entity without persistence state, the persist (insert) will + happen without first checking the database. This may result in an + EntityExistsException if the related Entity already exists in the + database. To revert this behavior to the previous release, set the + value of the openjpa.Compatibility + property CheckDatabaseForCascadePersistToDetachedEntity + to true.
-
- Relaxed kernel checks +
+ + Life Cycle Event Manager Callback Behavior + + - Several early exceptions were relaxed to satisfy the specification: - a non-cascaded relation pointing at an object without a state manager is no longer - rejected at flush with "cant-cascade-persist"; the referenced row is looked up in - the database during flush (an extra SELECT for unenhanced or - subclass-enhanced entities) and truly transient references may now fail later with - a foreign key error. Modifying an embeddable obtained from a query projection no - longer throws; the modification is silently not persisted. Re-persisting an entity - after remove() and flush is tolerated. In addition, - orphanRemoval=true no longer downgrades - cascade=REMOVE/ALL, so removal is cascaded - immediately when both are combined. + Life cycle event manager is used to manage entity's life cycle event callback. + In previous releases, Life cycle event manager is scoped to EntityManagerFactory. + This means listeners registered to an individual EntityManager may get life cycle + event callbacks for entity that it does not manage. -
-
- Insert ordering across logical foreign keys - Flush ordering previously delayed an insert only for physical (constraint-backed) - foreign keys. Rows related through logical foreign keys (no constraint declared in - the mapping, for example an externally created schema with real constraints) are - now also delayed until the referenced new row has been inserted. Statement order - at flush time may therefore change; tests asserting an exact SQL order may need to - be adjusted. There is no configuration switch. + From 2.2.1 release, the default callback behavior of the life cycle event manager + is changed to scope to each EntityManager. + To revert this behavior to the previous release, set the + value of the openjpa.Compatibility + property SingletonLifecycleEventManager + to true.
-
- Enhancer and runtime enhancement +
+ + shared-cache-mode Property + + - Classes enhanced by this release call new runtime methods (for example - ApplicationIds.getRelatedObjectId() for derived identities) and - fail on a 4.1.x runtime, while classes enhanced by 4.1.x still load but miss the - fixes of this release. Re-run the build-time enhancer - () with 4.2.0 when upgrading. + In the previous release, when the shared-cache-mode is enabled and the DataCache property is not set + or set to false, there will be no data caching. - Runtime enhancement ( and the - Java agent) changed: class redefinition uses - Instrumentation.redefineClasses() and, if it fails, OpenJPA logs - "redefineClasses failed" at INFO and silently falls back to - subclass enhancement instead of throwing. getClass() calls in - user equals()/hashCode() implementations of - subclass-enhanced entities now see the entity class instead of the generated - subclass, and generated writeReplace() methods work with - non-public no-argument constructors. + From 2.2.2 release, the caching will be turned on if the shared-cache-mode is enabled. Please see the + details described in section .
-
- Delayed collection proxies on Java 21 +
+
+
+ + OpenJPA 2.0.0 + +
+ + Incompatibilities + + + + The following sections indicate changes that are incompatible + between OpenJPA 1.x.x releases and the 2.0 release. Some may + require application changes. Others can be remedied through the + use of compatibility options. If your application uses a + version 1.0 persistence.xml, compatibility options will be set + appropriately to maintain backward compatibility. OpenJPA 2.0 + applications using a version 2.0 persistence.xml and requiring + OpenJPA 1.x.x compatibility may need to configure the + appropriate compatibility options to get the desired behavior. + +
+ + getProperties() + + - The delay-loading collection proxies (openjpa.ProxyManager=default(DelayCollectionLoading=true), - see ) now declare the Java 21 - SequencedCollection methods explicitly. - addFirst() and addLast() both delegate to - add(), so addFirst() appends instead of - prepending (previously DelayedLinkedListProxy prepended - after loading the collection), and reversed() returns a copy - rather than a write-through view for list and LinkedHashSet - proxies. Load the collection and reorder it explicitly where the position matters. - The ASM-generated non-delayed proxies are unchanged. + The OpenJPAEntityManagerFactory interface getProperties() + method was changed to return a Map instead of a + Properties object. This change was made in order to + support the getProperties() method defined in the + JPA 2.0 specification.
-
- Static metamodel generator output +
+ + Detach Behavior + + - Generated X_ classes now contain the Jakarta Persistence 3.2 - class_ field and QUERY_<NAME> / - MAPPING_<NAME> constants for named queries and result set - mappings declared on the type, and are annotated with - javax.annotation.processing.Generated instead of - jakarta.annotation.Generated when available. Regenerate the - metamodel classes and watch for name clashes with attributes named - class_. + The detach behavior has changed in several ways: + + + + In the 1.x.x release, managed entities + were flushed to the database as part of the + detach operation. This is no longer done in + 2.0. + + + + + In the 1.x.x release, entities were copied + and returned. In 2.0, for those methods + that have return values, the original + entities are returned. + + + + + In the 1.x.x release, managed entities still + exist in the persistent context. In 2.0, + they are removed. + + + + + In the 1.x.x release, the detach operation + is recursively cascaded to all referenced + entities. In 2.0, the detach operation is + only cascaded to those entities for which + Cascade=detach has been specified. + + + -
-
- Lifecycle callbacks and listeners - Default entity listeners declared in several mapping files are now registered once - instead of once per file, and a callback declared both by annotation and in - orm.xml for the same method is registered once with the XML - declaration taking precedence. Callback parameter types are matched more leniently, - and listeners receive the managed entity instance (not the internal - ReflectingPersistenceCapable wrapper) on - AFTER_DELETE_PERFORMED for unenhanced entities. Applications that - depended on duplicate invocations must be adjusted. + Applications that use a 1.0 persistence.xml will + automatically maintain OpenJPA 1.x.x behavior. It is + possible for a version 2.0 application to revert back to + the 1.x.x behavior for some of these items by setting the + openjpa.Compatibility property as follows: + + CopyOnDetach=true + FlushBeforeDetach=true + CascadeWithDetach=true + -
-
- persistence.xml resource handling - An I/O error while reading a persistence.xml resource from the - classpath previously aborted createEntityManagerFactory(). Such - resources are now logged ("unreadable-persistence-xml") and skipped; schema - validation errors still abort. A unit that only exists in a skipped resource - surfaces later as a missing persistence unit. Resource streams are opened with - URL connection caching disabled. The 3.2 elements scope and - qualifier are exposed through - PersistenceUnitInfo. + In addition, a new method has been provided on the + + OpenJPAEntityManager + interface to return a copy of the entity: + + public <T> T detachCopy(T pc): +
-
- Locale-independent case conversion +
+ + Use of private persistent properties + + - Identifier normalization, JPQL parsing, in-memory LOWER()/ - UPPER() evaluation and SQL formatting used the JVM default - locale for case conversion. They now use Locale.ROOT - (Locale.ENGLISH for reserved word matching). This is only - observable under locales with special casing rules (Turkish, Azeri, Lithuanian), - where generated identifiers containing i/I - may now differ from those generated by earlier releases; use explicit - @Table/@Column names in that case. + In 1.x.x releases of OpenJPA, if property access was used, + private properties were considered persistent. This is + contrary to the JPA specification, which states that + persistent properties must be public or protected. In + OpenJPA 2.0 and later, private properties will not be + persistent by default. -
-
- Reserved word handling and MySQL delimiting - Reserved word detection is now case-insensitive for all dictionaries, so generated - (defaulted) column, table and sequence names that equal a reserved word in a - different case may now receive a 0 suffix. - H2Dictionary additionally feeds its H2 2.x keyword list into - the naming rules. On MySQL (MySQLDictionary, not - MariaDBDictionary) reserved word identifiers are now - automatically delimited with back-ticks in all generated SQL, so previously - failing names such as KEY, TEXT or - LIBRARY work without manual delimiting. Tools comparing SQL text - must ignore the delimiters. Use explicit @Table/@Column - names if an old generated name must be kept. See - . + Applications that use a 1.0 persistence.xml will + automatically maintain OpenJPA 1.x.x behavior. It is + possible for a version 2.0 application to revert back to + the 1.x.x behavior by setting the value of the + openjpa.Compatibility + property PrivatePersistentProperties to + true. If compile time enhancement is + used, this property must be specified at the time of + enhancement and at runtime.
-
- PostgreSQL +
+ + Query.setParameter() + + - Delimited identifiers: PostgresDictionary now strips the - double quotes from a quoted identifier whose inner text is a plain identifier - (letters, digits and underscores, not starting with a digit). PostgreSQL then folds - the name to lower case, so @Table(name="\"MyTable\"") now - addresses mytable and quoted reserved words such as - "Order" become bare keywords. Identifiers containing spaces or - other special characters keep their quotes. Do not rely on delimited identifiers to - preserve mixed case or to use reserved words as names on PostgreSQL; rename the - objects, or subclass PostgresDictionary and override - toDBName(). There is no configuration switch. + The Query interface setParameter() method behavior has + changed to throw an IllegalArgumentException (as required + by the JPA specification) if more parameter substitutions + are supplied than defined in the createQuery(), + createNamedQuery(), or createNativeQuery() invocation. + OpenJPA 1.2.x and prior versions silently ignored these + extraneous parameter substitutions and allowed the Query + to be processed. +
+
+ + Serialization of Entities + + - char/Character attributes: on PostgreSQL 9 - and later StoreCharsAsNumbers now defaults to - false, so such attributes map to CHAR(1) - columns instead of INTEGER columns holding code points, and the - Java default '\0' is stored as SQL NULL. - Existing INTEGER columns created by earlier releases fail - validation or return wrong values. Either migrate them to - CHAR(1) or restore the previous mapping with - openjpa.jdbc.DBDictionary=postgres(StoreCharsAsNumbers=true); - an explicitly configured value is respected (OPENJPA-2971). + In 1.x.x releases of OpenJPA, when an entity was serialized + after calling EntityManager.find(), detach() or detachAll() + then all + references were removed as expected, but when the same + entity instance was serialized after calling + EntityManager.clear() the proxy classes were not removed. - Further fixes: java.util.UUID parameters are bound so that - both native uuid and varchar columns work (on - other databases a UUID is bound as VARCHAR unless the column is - a native UUID column); @Lob columns of type oid - are read and written through the large object API, which performs an implicit - COMMIT when reading in auto-commit mode; reflected - bool columns are reported as BOOLEAN, so - schema validation may now report boolean versus varchar drift that was previously - tolerated; DROP SEQUENCE IF EXISTS is emitted. + This has two side-effects: + when entities are remoted across JVM boundaries (RPC) + or deserialized the OpenJPA runtime must be available + on the classpath (both client and server containers); + when entities are deserialized the OpenJPA runtime must + be the exact same revision as used to serialize the + entities due to the proxy classes using dynamically + generated serialVersionUID values. -
-
- MySQL and MariaDB - On MySQL 5.7+ and MariaDB 10.2+ temporal columns are now created as - DATETIME(6) and TIME(6) - (DateFractionDigits=6) instead of whole-second precision, so that - @Version attributes of type Instant or - LocalDateTime can distinguish updates within the same second. - The value is set at connection time and overrides a - DateFractionDigits value given in - . Existing columns keep working, but - schema validation or refresh may report or alter the precision. Use - @Column(secondPrecision=0) on individual columns, or subclass the - dictionary and reset dateFractionDigits after - connectedConfiguration(), to keep whole seconds. + Starting with OpenJPA 2.0, this behavior has been + modified, so that by default all proxies will be removed + during serialization. See + + on how the behavior changes based on the + DetachedStateField setting along with + + for more details on how to override the default + DetachedStateField setting. - MariaDBDictionary no longer replaces a configured positive - with Integer.MIN_VALUE - (the Connector/J 2.x streaming mode); the configured value is passed to the driver - unchanged. MySQLDictionary keeps the streaming behavior. - Subclass MariaDBDictionary and override - getBatchFetchSize(int) to restore streaming. + Applications that use a 1.0 persistence.xml will + automatically maintain the old behavior. It is + possible for a version 2.0 application to revert back to + the prior 1.x.x behavior by setting the following + openjpa.Compatibility property as follows: + + IgnoreDetachedStateFieldForProxySerialization=true +
-
- Microsoft SQL Server +
+ + openjpa.jdbc.QuerySQLCache + + - CURRENT_DATE and CURRENT_TIME are now - translated to CONVERT(DATE, GETDATE()) and - CONVERT(TIME, GETDATE()) instead of plain - GETDATE(), so the results are DATE/TIME - typed and comparisons against datetime columns may behave - differently. EXTRACT uses DATEPART and JPQL - time literals are rendered as CAST('hh:mm:ss' AS TIME). To - restore the previous SQL set - openjpa.jdbc.DBDictionary=sqlserver(CurrentDateFunction=GETDATE(),CurrentTimeFunction=GETDATE()). + In prior 1.x.x releases, the openjpa.jdbc.QuerySQLCache + configuration property for Prepared SQL Cache accepted + value all to never drop items from the + cache, but this option is no longer supported and will cause + a PersistenceException with a root cause of a ParseException + to be thrown. See + + for details on the available configuration values.
-
- Oracle +
+
+ + Disabling AutoOff Collection Tracking + + + + The default behavior of OpenJPA in tracking collections is that + if the number of modifications to the collection exceeds the + current number of elements in collection then OpenJPA will + disable tracking the collections. OpenJPA 2.0 added a compatibility + property to disable turning off the collection tracking. + + + The behavior of Auto disabling of collection tracking can be + avoided by setting the value of the + openjpa.Compatibility property + autoOff to false. + The default behavior of auto disabling the collection tracking + is not changed. But when the above property is set then the + collection tracking will not be disabled automatically. + +
+
+ + Internal Behavioral Differences + + + The following sections indicate internal changes between + OpenJPA 1.x.x releases and the 2.0 release. As these are + internal implementation specific behaviors not covered by + the JPA specification, no changes should be required for + applications that did not use or depend upon OpenJPA specific + APIs or behavior. + + +
+ + PreUpdate/PostUpdate Life Cycle Callbacks + + - Identity column sequences (ISEQ$$_*) are treated as system - sequences and excluded from drop actions, AUDSYS is treated as a - system schema, an @Index duplicating the primary key is skipped, - CEILING() is translated to CEIL(), and the new - Jakarta Persistence 3.2 functions are mapped to Oracle syntax - (EXCEPT as MINUS before Oracle 21, - LEFT/RIGHT via SUBSTR). - These are fixes; workarounds for the old behavior can be removed. + If an entity was updated between the persist() + and commit() operations in OpenJPA 1.x, then + any PreUpdate and PostUpdate life cycle callback + methods would be executed. Starting in OpenJPA + 1.3 and 2.0, these callbacks will not get executed. -
-
- HSQLDB - HSQLDictionary no longer disables - SupportsSelectForUpdate, so pessimistic locks now emit - SELECT ... FOR UPDATE; query timeouts are disabled - (SupportsQueryTimeout=false); OffsetTime - attributes are created as TIME instead of - TIME WITH TIME ZONE; numeric casts are sized - NUMERIC(128,32) so fractional digits are no longer truncated; - INFORMATION_SCHEMA and SYSTEM_LOBS are treated - as system schemas. Use openjpa.jdbc.DBDictionary=hsql(SupportsSelectForUpdate=false,SupportsQueryTimeout=true) - and @Column(columnDefinition="TIME WITH TIME ZONE") to restore - the previous behavior. On H2 2.x, table truncation now skips the - INFORMATION_SCHEMA meta tables. + The JPA 2.0 specification section on "Semantics + of the Life Cycle Callback Methods for Entities" + has been updated to include a Note that the + callback behavior for updating an entity after + the persist operation is implementation specific + and should not be relied upon.
-
- SPI changes for custom store, dictionary and expression implementations +
+ + createEntityManagerFactory Exceptions + + - Implementors of OpenJPA SPI interfaces must recompile and implement new methods: - BrokerFactory (createPersistenceStructure, - dropPersistenceStructure, validatePersistenceStructure, - truncateData; AbstractBrokerFactory - throws UnsupportedOperationException by default), - ExpressionFactory (newTypecastAsString, - newTypecastAsNumber, left, right, - replace, getNativeObjectId, version), - Result (getInstant, getYear), - Select (appendNullsPrecedence, - addSetOperatorSQL, getSetOperatorBuffer), - OpenJPAConfiguration (schema generation script accessors, - isSchemaGenerationExplicit, isSpecCompliantSchemaGeneration) - and JDBCConfiguration (get/setSyncMappingsExcludeTypes). + The JPA 2.0 specification section on + "Bootstrapping in Java SE Environments" states + that persistence providers must return null + if they are not a qualified provider for the + given persistence unit. - DBDictionary.SerializedData is now a record - (bytes() instead of the bytes field); - IdentifierRule.setReservedWords takes a - Collection and matches case-insensitively, so subclasses - overriding the Set variant no longer override; - JavaTypes.INSTANT (39) and JavaTypes.YEAR (40) - were added and must be handled by custom value handlers and strategies; - QueryExpressions gained nullPrecedence, - setOperationType and setOperands, which only - the JDBC store consumes, so a custom StoreQuery silently ignores - NULLS FIRST/LAST and set operations unless it is extended. - DBDictionary gained a number of public configuration fields - (ReplaceFunctionName, LeftFunctionName, - RightFunctionName, NaturalLogarithmFunction, - CeilingFunction, ExceptFunction, - TypecastToStringTypeName, IntegerCastTypeName, - SupportsUnsizedCharOnCast) and hooks - (isDroppable(Sequence), toJDBCEscapedDateTimeLiteral, - appendNullsPrecedence, getExtractField, - get/setMajorVersion, get/setMinorVersion). + However, OpenJPA may throw a RuntimeException + if an error occurs while trying to create a + qualified persistence unit, like for invalid + openjpa.* specific configuration settings or + for schema validation failures. + + + If the Apache Geronimo JPA 2.0 Spec APIs are + used, then any exceptions returned by a + persistence provider will be wrapped within + a PersistenceException. When the JPA 2.0 API + reference implementation is used, any + RuntimeExceptions will be returned to the + calling application without being wrapped. + Other JPA 2.0 API and implementation providers + or versions may behave differently.
-
- Notable new features +
+ + openjpa.QueryCache default + + - The following Jakarta Persistence 3.2 features are new in this release. They are - opt-in and do not change existing behavior unless noted: - - - JPQL: ID() and VERSION() functions, - CAST, LEFT, RIGHT, - REPLACE, the || operator, - UNION/INTERSECT/EXCEPT [ALL], - NULLS FIRST/LAST, TREAT in joins and - paths, JOIN ... ON, EXTRACT, - LOCAL DATE/TIME/DATETIME, additional math functions, - an optional SELECT clause and the implicit - this identification variable (bound automatically when a - FROM item declares no identification variable). See . - In-memory query execution (and custom StoreQuery - implementations) silently ignore - UNION/INTERSECT/EXCEPT - and NULLS FIRST/LAST; - LEFT/RIGHT, CAST and - EXTRACT are not available on Derby. - - - EntityManager: find(), - lock() and refresh() with - FindOption/LockOption/RefreshOption, - getReference(entity), cache mode and timeout accessors, - runWithConnection()/callWithConnection(), - createQuery(CriteriaSelect); - Query: getSingleResultOrNull(), - cache mode and timeout setters. - - - EntityManagerFactory: - runInTransaction()/callInTransaction() - (exceptions are rethrown wrapped in - org.apache.openjpa.persistence.PersistenceException), - getSchemaManager(), getName(), - getTransactionType(), getNamedEntityGraphs(); - PersistenceUnitUtil: getVersion(), - isInstance(), getClass(), - load(); programmatic bootstrap via - Persistence.createEntityManagerFactory(PersistenceConfiguration) - and the jakarta.persistence.dataSource property. - EntityManager.find(EntityGraph, ...), - createQuery(TypedQueryReference), - getNamedQueries() and - SynchronizationType.UNSYNCHRONIZED are not yet implemented. - - - Entity graphs (@NamedEntityGraph, - createEntityGraph(), getEntityGraph()), - CriteriaUpdate, CriteriaDelete, - CriteriaSelect set operations, - Join.on(), CriteriaBuilder.cast()/ - left()/right()/replace()/ - extract() and treat(Root), all of which - previously threw UnsupportedOperationException. - - - Mapping: Java records as @Embeddable (records are - always treated as managed types, regardless of - openjpa.RuntimeUnenhancedClasses), - @EnumeratedValue (an enum declaring such a field changes - its stored representation), @Version on - java.time.Instant and - java.time.LocalDateTime (give such columns at least - microsecond precision), @Column(secondPrecision, options), - @Table(options), repeatable - @SequenceGenerator/@TableGenerator, - ConstructorResult in result set mappings, inline result - mappings on @NamedNativeQuery, orm.xml - version 3.2, id classes without a public no-argument constructor, and - @MapsId with non-embeddable id classes. - - - jakarta.persistence.ForeignKey, - @Index sort order, @JoinTable.indexes - and @Converter(autoApply=true) are honored (see the - respective sections above for the effect on existing schemas). - - - The bundled Jakarta Persistence schemas are now included under the Eclipse - Foundation Specification License 1.1 instead of the CDDL. - - + In previous releases, the default value for the + openjpa.QueryCache property was true + when the openjpa.DataCache was enabled. Depending on + application characteristics, this default QueryCache + enablement actually could negate much of the potential + gains achieved by using the DataCache. Thus, the default + value for the openjpa.QueryCache property is now + false. + + + To re-enable the default QueryCache behavior, you need to + include the following property in your persistence.xml + configuration. + + <property name="openjpa.QueryCache" value="true"/> + + + + If your configuration had previously enabled the QueryCache + explicitly, then you might have to include the + true value into your configuration + (if you relied on the previous default). Otherwise, your + current QueryCache enablement will continue to work. + + <property name="openjpa.QueryCache" value="true(CacheSize=1000, SoftReferenceSize=100)"/> +