diff --git a/openjpa-project/src/doc/manual/migration_considerations.xml b/openjpa-project/src/doc/manual/migration_considerations.xml index f908de5b0a..ec66dcacb4 100644 --- a/openjpa-project/src/doc/manual/migration_considerations.xml +++ b/openjpa-project/src/doc/manual/migration_considerations.xml @@ -21,600 +21,1119 @@ 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. + + + 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).
-
- - Use of private persistent properties - - +
+ SecurityManager Support Removed - 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. + 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). - 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. + 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.
-
- - Query.setParameter() - - +
+ New JPQL Reserved Identifiers - 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. + 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. -
-
- - Serialization of Entities - - - 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. + 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 - 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. + 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). - 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. + 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 - 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 - + 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.
-
- - openjpa.jdbc.QuerySQLCache - - +
+ Query.getResultList() returns a materialized ArrayList - 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. + 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.
-
-
- - 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 - - +
+ Bulk DELETE no longer cascades - 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. + 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. - 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. + 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 .
-
- - createEntityManagerFactory Exceptions - - +
+ FlushModeType.AUTO flushes whenever the context is dirty - 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. + 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). - 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. + 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 - 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. + 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.
-
- - openjpa.QueryCache default - - +
+ Argument validation in find(), getReference(), detach(), contains(), remove() - 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. + 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. - 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"/> - + 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 - 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)"/> - + 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.
-
-
-
- - 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 - - +
+ EntityManagerFactory lifecycle and properties - 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. + 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). - 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. + 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 - 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. + 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. - 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. - - - + Catch IllegalStateException for unbound parameters and expect + java.sql.Date semantics for DATE-typed + parameters compared against TIMESTAMP columns.
-
- - MetaModel Attributes for Arrays - - +
+ StoredProcedureQuery semantics - 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. + 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. - 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"/> - - - + 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.
-
- - supportsSetClob Property. - - +
+ Criteria API and Metamodel - 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. + 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.
-
- - useNativeSequenceCache Property. - - +
+ PersistenceUnitUtil.getIdentifier() returns the plain identifier - 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 - . + 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().
-
- - Cascade persist behavior - - +
+ Cache mode properties on EntityManager.setProperty() - 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. + 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.
-
- - Life Cycle Event Manager Callback Behavior - - +
+ Default map key column renamed to <field>_KEY - 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. + 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 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. + 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 + .
-
- - shared-cache-mode Property - - +
+ Attribute overrides, @OrderBy and inverse map keys - 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. + @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 2.2.2 release, the caching will be turned on if the shared-cache-mode is enabled. Please see the - details described in section . + Verify the column names produced by overrides that were previously ignored or + rejected, and @OrderBy values that differ from attribute names + only in case.
-
-
-
- - 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 - +
+ @SequenceGenerator without sequenceName - 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. + 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. - 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. + For existing databases either add sequenceName="OPENJPA_SEQUENCE" + (or the previously used name) to each generator, or create the new per-generator + sequences. See .
-
- - RequiresSearchStringEscapeForLike DBDictionary Property - - +
+ AttributeConverter handling - 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. + 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). - 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. + 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.
-
- - Return value of aggregate functions in SELECT clause - - +
+ Access type determination and property accessors - 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. + 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. - 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"/> - + 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.
-
-
-
- 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 +
+ java.time.Instant and java.time.Year mapping - 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. + 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.
-
- Invalid Column Name Changes +
+ Generated DDL 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 + 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.
-
- MappingTool Behavior for HSQLDB +
+ Jakarta Persistence schema generation and SQL scripts - There have been 2 changes for Hypersonic (HSQLDB). - We fixed a bug which did cause long fields getting mapped to INTEGER - instead of BIGINT. + 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. - 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. + 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. + + + +
+
+
+
+ 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 + + 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. + +
+
+ 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 + +
+
+ MappingTool Behavior for HSQLDB + + There have been 2 changes for Hypersonic (HSQLDB). + We fixed a bug which did cause long fields getting mapped to INTEGER + instead of BIGINT. + + + 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.
@@ -647,23 +1166,561 @@ DBDictionary.supportsQueryTimeout
-
- PostgreSQL stores char fields as CHAR by default +
+
+
+ + 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 + + + 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. + + + 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. + +
+
+ + RequiresSearchStringEscapeForLike DBDictionary Property + + + + 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. + + + 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. + +
+
+ + Return value of aggregate functions in SELECT clause + + + + 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. + + + 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 + + + + 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. + + + 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. + + + 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. + + + 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. + + + + +
+
+ + MetaModel Attributes for Arrays + + - 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. + 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. - 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. + 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"/> + + + + +
+
+ + supportsSetClob Property. + + + + 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. + +
+
+ + 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 + . + +
+
+ + Cascade persist behavior + + + + 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. + +
+
+ + Life Cycle Event Manager Callback Behavior + + + + 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. + + + 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. + +
+
+ + shared-cache-mode Property + + + + 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. + + + 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 . + +
+
+
+
+ + 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 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. + +
+
+ + 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. + + + + + + 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 + + + + 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): + + +
+
+ + 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. + + + 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. + +
+
+ + 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. + +
+
+ + Serialization of Entities + + + + 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. + + + 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. + + + 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. + + + 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 + + +
+
+ + openjpa.jdbc.QuerySQLCache + + + + 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. + +
+
+
+ + 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 + + + + 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. + + + 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. + +
+
+ + createEntityManagerFactory Exceptions + + + + 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. + + + 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. + +
+
+ + 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 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)"/> +