For upgrade notes for Cayenne 4.2 and older, see UPGRADE-4.2-and-older.md.
This is a high-level overview of 5.0 changes. Check the next section for milestone-by-milestone upgrade instructions.
Snapshot versions are now a constant value — the dev version of 5.0 will always be 5.0-SNAPSHOT,
so you can stay at the bleeding edge of development if needed:
<dependency>
<groupId>org.apache.cayenne</groupId>
<artifactId>cayenne</artifactId>
<version>5.0-SNAPSHOT</version>
</dependency>The new Class Generation UI in CayenneModeler simplifies configuration, allows multiple cgen setups
per project, and includes a template editor. Custom templates are now part of the project XML
configuration and don't require separate setup in either Modeler or Maven/Gradle plugins.
(not)exists is now directly supported by the Expression API (including Expression, the expression
parser, and the Property API) — no need to construct a subquery manually. The feature can handle any
expression and spawn several sub-queries per expression if needed:
long count = ObjectSelect.query(Artist.class)
.where(Artist.PAINTING_ARRAY.dot(Painting.PAINTING_TITLE).like("painting%").exists())
.selectCount(context);ANY and ALL subqueries are now supported, as well as case-when expressions:
import static org.apache.cayenne.exp.ExpressionFactory.*;
// ...
Expression caseWhenExp = caseWhen(
List.of(betweenExp("estimatedPrice", 0, 9),
betweenExp("estimatedPrice", 10, 20)),
List.of(wrapScalarValue("low"),
wrapScalarValue("high")),
wrapScalarValue("error"));- Per CAY-2875 a
java.util.UUIDattribute now honors the JDBC type of the column it is mapped to, instead of always being converted to a 36-char string:
- A binary column (
BINARY,VARBINARY,LONGVARBINARY) stores the UUID in its 16-byte big-endian form, most significant bits first.VARBINARY(16)is the recommended mapping for new models — it uses less than half the space ofVARCHAR(36)and indexes better. - A character column keeps storing the canonical string, so existing models are unaffected and need no data migration.
- Any other JDBC type is passed to the driver as an object, which makes a PostgreSQL native
uuidcolumn work.
UUIDValueType is deprecated and no longer registered, replaced by
org.apache.cayenne.access.types.UUIDType.
-
Per CAY-3007
SelectByIdis deprecated. Instead, useObjectSelectdirectly with the newbyId(..)andbyIds(..)methods:// before Artist a = SelectById.query(Artist.class, 42).selectOne(ctx); List<Artist> list = SelectById.query(Artist.class, 1, 2, 3).select(ctx); DataRow row = SelectById.dataRowQuery(Artist.class, 42).selectOne(ctx); // after Artist a = ObjectSelect.query(Artist.class).byId(42).selectOne(ctx); List<Artist> list = ObjectSelect.query(Artist.class).byIds(1, 2, 3).select(ctx); DataRow row = ObjectSelect.query(Artist.class).byId(42).fetchDataRows().selectOne(ctx);
The same matches are available as expressions via the entity
SELFproperty (Artist.SELF.eqId(42),Artist.SELF.idsIn(1, 2, 3),Artist.SELF.eqIdMap(map), etc.) and on to-one relationship properties. -
Per CAY-3010
LocalDate,LocalTimeandLocalDateTimeare passed to and from the JDBC driver directly, instead of being converted throughjava.sql.Date/Time/Timestampin the JVM default time zone. Reads are faster, and application behavior changes in these cases:
- A
LocalDateTimeinside a DST gap of the JVM zone is no longer shifted. E.g. with the JVM inAmerica/New_York,LocalDateTime.of(2021, 3, 14, 2, 35)(a time that does not exist in that zone) used to be stored and read back as03:35; now it round-trips as02:35. MySQL already behaved this way. - Values no longer depend on the JVM default zone: a value stored under one zone and read under another comes back unchanged. Previously it was shifted by the offset difference on all databases except MySQL.
- Sub-millisecond precision is no longer truncated on write.
LocalTime.of(13, 45, 30, 123_456_000)used to reach the database as13:45:30.123; now it is sent as is and the database rounds to the column precision, so aTIME(3)column may store13:45:30.123or13:45:30.124depending on the database. java.timeattributes now work on SQLite, stored asyyyy-MM-dd HH:mm:ss,yyyy-MM-ddandHH:mm:sstext with a seconds fraction appended only when non-zero.
Exceptions: PostgreSQL timestamp with time zone columns (Cayenne's default mapping of TIMESTAMP) are an instant
type and keep the previous JVM-zone conversion; Derby and SQL Server still shift DST-gap timestamps on write due to
engine / driver limitations. LocalDateValueType, LocalTimeValueType and LocalDateTimeValueType are deprecated
and no longer registered.
- Per CAY-3014
org.apache.cayenne.query.QueryChain(deprecated in 5.0-M3) was removed. To run several queries together, execute them one by one, wrapping them in an explicit transaction if they must share one:
runtime.performInTransaction(() -> {
List<Artist> artists = ObjectSelect.query(Artist.class).select(context);
List<Painting> paintings = ObjectSelect.query(Painting.class).select(context);
return null;
});- Per CAY-3015
org.apache.cayenne.query.RefreshQuerywas removed. It was not a query, but a carrier for four cache management operations, each of which has a direct replacement:
-
new RefreshQuery(objects)/new RefreshQuery(object)→context.invalidateObjects(objects). In nested contexts, there was previously an issue with cascading invalidation (intermediate contexts would not get invalidated). This was fixed in the current version ofinvalidateObjects. -
new RefreshQuery("group1", "group2")→runtime.getDataDomain().getQueryCache().removeGroup("group1"), once per group. -
new RefreshQuery(query)→ run the query itself, with its cache strategy set toLOCAL_CACHE_REFRESHorSHARED_CACHE_REFRESH. A query with no caching needs no change, as refreshing it was the same as running it:ObjectSelect.query(Artist.class) .cacheStrategy(QueryCacheStrategy.SHARED_CACHE_REFRESH) .cacheGroup("artists") .select(context);
-
new RefreshQuery()(refresh everything) has no direct replacement. To start over, create a newObjectContext. To also drop shared state, callruntime.getDataDomain().getQueryCache().clear()andruntime.getDataDomain().getSharedSnapshotCache().clear().
- Per CAY-3016
org.apache.cayenne.query.RelationshipQuerywas removed. It was an internal mechanism for resolving relationship faults. If you were running it explicitly, useObjectSelectmatching on the reverse relationship instead:
// before
// List<Painting> paintings = context.performQuery(new RelationshipQuery(artist.getObjectId(), "paintingArray"));
// after
List<Painting> paintings = ObjectSelect.query(Painting.class)
.where(Painting.TO_ARTIST.eq(artist))
.select(context);-
Per CAY-3017
ObjectContextno longer extendsDataChannel. This doesn't change the overall architecture (there are still "channels" downstream from an ObjectContext). But the channel methods are no longer accessible on the context itself. Application code wasn't ever not supposed to use them, as everything you need to do, you can do via the ObjectContext API. -
Per CAY-3020 Cayenne no longer supports Java serialization of contexts, queries and mapping objects.
Persistent,ObjectContext,ObjectId,Query,Expression,Ordering,EntityResolver,DataMap, etc. do not implementjava.io.Serializableanymore, and the customreadObject/writeObjectlogic that re-attached deserialized contexts and objects to the runtime is gone. The class generation templates no longer emitserialVersionUID,writeObject/readObjectandwriteState/readState. -
Per CAY-3021
org.apache.cayenne.query.ObjectIdQuerywas removed. It was an internal mechanism for resolving objects by id via the caches. Its use cases have direct replacements:
// object lookup via the caches (ObjectIdQuery.CACHE)
Artist a = (Artist) context.objectForPK(id);
// forced refresh from the database (ObjectIdQuery.CACHE_REFRESH)
Artist a = ObjectSelect.query(Artist.class).where(Artist.SELF.eqId(id)).selectOne(context);
// committed snapshot lookup (fetchingDataRows == true), from the snapshot cache or the database
DataRow row = context.getObjectStore().getSnapshot(id);
// committed snapshot lookup in the snapshot cache only (ObjectIdQuery.CACHE_NOREFRESH)
DataRow row = context.getObjectStore().getCachedSnapshot(id);-
Per CAY-3022 the
ObjectContextquery API was cleaned up:ObjectContext.performGenericQuery(Query)was renamed toexecute(Query).ObjectContext.performQuery(Query)andCayenne.objectForQuery(ObjectContext, Query)are deprecated in favor ofObjectContext.select(Select)andObjectContext.selectOne(Select).EJBQLQuery,SQLTemplateandProcedureQuerynow implementSelect<T>, so every selecting query can be passed toselect(..).- The
DataContextconvenience methodsperformNonSelectingQuery(..)andperformQuery(String, ..)(all flavors) are deprecated. Useexecute(Query),SQLExec/MappedExecupdate(..), andMappedSelect.query(name).select(context)instead.
// before
List<Artist> artists = context.performQuery(new EJBQLQuery("select a from Artist a"));
List<QueryResult> result = context.performGenericQuery(SQLExec.query("DELETE FROM ARTIST"));
// after
List<Artist> artists = context.select(new EJBQLQuery<>("select a from Artist a"));
List<QueryResult> result = context.execute(SQLExec.query("DELETE FROM ARTIST"));- Per CAY-3023
QueryResultwas redesigned from a class holding the entire multipart result to a sealed interface describing a single item of it.SQLExec.execute(..),MappedExec.execute(..)andProcedureCall.call(..)now return aList<QueryResult>holding the items in the order the query produced them, so callers that know the shape of their query should access them by index.QueryResulthasSelect,Update,IteratorandOutParametersrecord variants, replacing theisSelectResult()/getSelectResult()/getUpdateCount()accessors, so a multipart result can also be scanned with a pattern-matching switch:
List<QueryResult> result = SQLExec.query(sql).execute(context);
int updated = ((QueryResult.Update) result.getFirst()).count();
for (QueryResult item : result) {
switch (item) {
case QueryResult.Select<?> select -> process(select.objects());
case QueryResult.Update update -> process(update.counts());
case QueryResult.Iterator<?> iterator -> process(iterator.iterator());
case QueryResult.OutParameters out -> process(out.values());
}
}Stored procedure OUT parameters are no longer disguised as a one-row result set. They arrive as a dedicated
QueryResult.OutParameters item (a map keyed by parameter name).
The cgen templates now emit List<QueryResult> instead of the old QueryResult<?> for the perform* methods
of mapped exec queries, so regenerate your classes via Modeler ("Tools" → "Generate Classes") or the AI plugin
if you have generated classes with multipart queries.
-
Per CAY-3024
org.apache.cayenne.QueryResponsewas removed. Everything that used to return aQueryResponse-ObjectContext.performGenericQuery(..), etc. - now returnList<QueryResult>. See CAY-3023 above for the example of how to process the result. CustomDataChannelQueryFilterimplementations now require a new signature. -
Per CAY-3027
org.apache.cayenne.lifecycle.id.StringIdQuerywas removed fromcayenne-lifecycle. It was a pseudo-query that could only returnDataRows and neededObjectContext.execute(..)to run. Its replacement isorg.apache.cayenne.lifecycle.id.StringIdFetcher, a set of static methods that fetch persistent objects for one or more String IDs, possibly spanning multiple entities:
// before
StringIdQuery query = new StringIdQuery("E1:3", "E1:4", "E2:6");
List<QueryResult> response = context.execute(query);
// ... convert DataRows to objects per entity
// after
Map<String, Persistent> objects = StringIdFetcher.fetch(context, "E1:3", "E1:4", "E2:6");
Persistent e1 = StringIdFetcher.fetchOne(context, "E1:3");The map is keyed by the String IDs passed in, and IDs with no matching object are absent from it.
-
The
org.apache.cayenne.query.ParameterizedQueryinterface was removed, together with thecreateQuery(Map)methods ofSQLTemplate,ProcedureQueryandObjectSelectthat implemented it. Applying parameters to a mapped query is now the job of the query descriptor - overrideQueryDescriptor.buildQuery(Map)if you have a customQueryDescriptorthat supports parameters. This does not affect the user-facingMappedSelect/MappedExecAPI. -
The
groupIdofcayenne-modelerandcayenne-wocompatchanged fromorg.apache.cayenne.modelertoorg.apache.cayenne. Artifact ids and versions are unchanged. If you depend on any of them directly, update the coordinates:
<dependency>
<groupId>org.apache.cayenne</groupId>
<artifactId>cayenne-modeler</artifactId>
<version>5.0-XX</version>
</dependency>DataChannel.onQuery(..),DataChannelQueryFilter.onQuery(..)andDataChannelQueryFilterChain.onQuery(..)take an extraboolean iteratedResultparameter, which istruewhen the caller expects aResultIterator(viaObjectContext.iterator(..)and friends) rather than a list. It replaces the internalIteratedQueryDecoratorwrapper, so query filters now see the actual query instead of the wrapper. CustomDataChannelimplementations and query filters need to add the parameter and pass it down the chain:
public List<QueryResult> onQuery(ObjectContext context, Query query, boolean iteratedResult,
DataChannelQueryFilterChain chain) {
return chain.onQuery(context, query, iteratedResult);
}-
DataContext.performIteratedQuery(Query)(deprecated earlier in 5.0) was removed. UseObjectContext.iterator(Select)instead; to iterate overDataRows, pass aDataRowquery, e.g.ObjectSelect.dataRowQuery(Artist.class)orSQLSelect.dataRowQuery(sql). -
EventManagerlistener registration no longer takes a listener method name to be looked up via reflection.addListener(..)andaddNonBlockingListener(..)now take the event class and anEventHandlercallback, which is normally an unbound method reference to the listener method:
// before
eventManager.addListener(this, "snapshotsChanged", SnapshotEvent.class, subject, sender);
// after
eventManager.addListener(this, SnapshotEvent.class, MyListener::snapshotsChanged, subject, sender);The listener object is still passed and is still held via a weak reference, so an unregistered listener is
released once it becomes unreachable. This only holds when the handler does not capture the listener: a bound
reference such as this::snapshotsChanged or a capturing lambda keeps the listener alive for as long as the
EventManager is. The listener method no longer needs to be public. The reflection-based
org.apache.cayenne.util.Invocation class and the SnapshotEventListener interface (which was only ever a
naming convention for the reflective lookup) were removed.
-
Per CAY-2912 SQL logging was redesigned to be compact and single-line. The
JdbcEventLoggerinterface and itsSlf4jJdbcEventLogger/FormattedSlf4jJdbcEventLoggerimplementations were removed and replaced byorg.apache.cayenne.log.SqlLogger(default implementationSlf4jSqlLogger). Log output now goes to a logger namedcayenne-sql(previouslyorg.apache.cayenne.log.JdbcEventLogger) — update your logging configuration accordingly. Each statement is logged as one line combining the SQL, its bindings and the result count (e.g.... bind:[user_id:15] selected:1); transaction boundaries moved toDEBUG. If you bound a customJdbcEventLoggerin a DI module, rebindSqlLoggerinstead.As part of this change the
cayenne.query_execution_time_logging_thresholdproperty no longer has any effect — the slow-query threshold warning it controlled has been removed. TheConstants.QUERY_EXECUTION_TIME_LOGGING_THRESHOLD_PROPERTYconstant is retained (deprecated) but ignored. A newcayenne.jdbc.log.batch.thresholdproperty (default 3) controls how many batch rows are logged in full before the bindings are truncated to[first]..N..[last]. -
Per CAY-2954 selecting queries are no longer wrapped in transactions internally by Cayenne. Using connections in "auto-commit" mode instead has a significant positive impact on DB performance. This should not affect manually-managed transactions. But in theory, in some rare cases this may still change consistency behavior of disjoint prefetches (as multiple related selects will no longer be wrapped in a single transaction). We'd like to look at the actual cases to propose a mitigation approach, but one possible solution may be changing to "joint" prefetches.
-
Per CAY-2956 the dedicated Oracle 8 adapter has been removed.
org.apache.cayenne.dba.oracle.Oracle8Adapterand its supporting classes no longer exist, and theOracleSniffernow maps all Oracle versions toOracleAdapterregardless of the JDBC driver version. If you referencedOracle8Adapterexplicitly (e.g. in a DataNode adapter configuration or custom DI bindings), switch toorg.apache.cayenne.dba.oracle.OracleAdapter. -
Per CAY-2957 the legacy HSQLDB adapter (HSQL <= 1.8) has been removed.
org.apache.cayenne.dba.hsqldb.HSQLDBNoSchemaAdapterno longer exists, and theHSQLDBSniffernow maps all. If you happen to be on those older HSQL versions, update to the latest one. -
Per CAY-2970 deferred batch parameter values (e.g. a generated PK propagated to a dependent PK or FK within the same transaction) are now represented by the dedicated
org.apache.cayenne.access.DeferredValuetype instead of a barejava.util.function.Supplier. Cayenne now resolves only its ownDeferredValueinstances, leaving user-suppliedSupplierattribute values untouched. If you have custom code that fed deferred values into batch bindings orObjectIdsnapshots viaSupplier, implementDeferredValueinstead — it is a@FunctionalInterface, so an existing lambda orSupplierimplementation can usually be adapted with a minimal change. -
Per CAY-2981 DataNodes are no longer a part of the XML mapping. DataNodes / DataSources are defined in runtime. DataMaps are linked to them in runtime as well. Opening a project in the Modeler upgrades it to version 13, which drops every
<node>element (reporting any encountered removals). The new API to replace XML mapping is described below.A node is defined either from a bare
DataSource, or from aDataNodeDescriptor. TheDataSourceflavor is a shortcut for a node that needs no customization — it gets a generated name and the default settings:DataSource dataSource = CayenneDataSource.of("jdbc:postgresql://localhost:5432/mydb") .userName("user") .password("secret") .pool(1, 5) .build(); CayenneRuntime runtime = CayenneRuntime.of() .addConfig("cayenne-project.xml") .defaultDataNode(dataSource) .build();
Switch to a
DataNodeDescriptorwhen the node has to be customized, e.g., to let Cayenne create the schema on the first connection, pin the adapter, give the node a stable name, etc.:DataNodeDescriptor node = DataNodeDescriptor.of("node1") .dataSource(dataSource) .createSchemaIfNeeded() .build(); CayenneRuntime runtime = CayenneRuntime.of() .addConfig("cayenne-project.xml") .defaultDataNode(node) .build();
Both flavors work with any number of nodes. Projects that used to declare several
<node>s link each node to its DataMaps by name, mixing the two forms as needed. A default node remains optional, and picks up every DataMap not linked to a node explicitly:CayenneRuntime runtime = CayenneRuntime.of() .addConfig("cayenne-project.xml") .addDataNode(ds1, "map1", "map2") .addDataNode(DataNodeDescriptor.of("node2").dataSource(ds2).createSchemaIfNeeded().build(), "map3") .defaultDataNode(ds3) .build();
cayenne.jdbc.*properties are still recognized.Core API changes:
- The set of DataNodes is supplied to the stack as a single
DataNodeDescriptorsDI binding. - Nodes defined from a bare
DataSourceare named after the domain (cayenne-0,cayenne-1, ...). Use aDataNodeDescriptorif you need a stable name forDataDomain.getDataNode(String),CayenneRuntime.getDataSource(String)orSQLTemplate.setDataNodeName(String). - In CayenneModeler, the DataNode editors and the "Create DataNode" / "Link DataMap" actions were removed
org.apache.cayenne.configuration.runtime.DataSourceFactorywas removed and is no longer an extension pointorg.apache.cayenne.configuration.runtime.DbAdapterFactorywas removed and is no longer an extension point. A recommended way to add a custom adapter isCoreModule.extend(binder).addAdapterDetector(...), or you can set it directly on DataNodeDescriptororg.apache.cayenne.access.dbsync.SchemaUpdateStrategyFactorywas removed and is no longer an extension point. Set it directly on DataNodeDescriptor if needed.
- The set of DataNodes is supplied to the stack as a single
-
Per CAY-2985
DataDomainbecame mostly immutable. TheDataDomain(String)constructor and all the setters below were removed in favor of a single full constructor that takes every collaborator and setting. Only DataNodes, DataMaps, filters and listeners can still be added (and removed) after creation. Replacements for the removed setters:setName(String)— the name comes from the project XML, and can be overridden with thecayenne.domain.nameproperty (Constants.DOMAIN_NAME_PROPERTY).setEntityResolver(EntityResolver)— keep usingaddDataMap(..)/removeDataMap(..)to change resolver contents.setEntitySorter(EntitySorter)— the sorter is produced by the newEntitySorterFactoryDI service. Bind your ownEntitySorterFactoryto replace it.setEventManager(EventManager)— bindEventManagerin a DI module instead.setQueryCache(QueryCache)— bindQueryCachein a DI module instead.setSharedSnapshotCache(DataRowStore),setDataRowStoreFactory(DataRowStoreFactory)andgetDataRowStoreFactory()— bindDataRowStoreFactoryin a DI module to customize the cache.setSharedCacheEnabled(boolean)— use the "Shared Cache" checkbox in the Modeler.setValidatingObjectsOnCommit(boolean)— use the "Object Validation" checkbox in the Modeler.setMaxIdQualifierSize(int)— use thecayenne.max_id_qualifier_sizeproperty (Constants.MAX_ID_QUALIFIER_SIZE_PROPERTY).
-
Per CAY-2986 cgen now runs unconditionally. Previously it compared the DataMap file mtime against the mtime of the generated classes and skipped generation when the classes looked newer. That optimization saved very little (cgen is idempotent and fast) while regularly producing stale classes after project upgrades or when switching between machines and branches. Consequences:
- The
forceflag is now a deprecated no-op — its former behavior is the only behavior.
- The
-
Per CAY-2987,
PkGeneratoris now owned byDataNoderather than byDbAdapter. ADbAdapteris only the source of the default generator for its database. This change is entirely transparent unless you need to install a custom PkGenerator. You can do that via a custom injectedDefaultDataNodeFactory, an explicit call todataNode.setPkGenerator(..)or use a custom adapter.
-
Per CAY-2947 the
cayenne-commitlogartifact has been removed. Commit log support is now part of the corecayenneartifact — no extra dependency needed. Migrate as follows:- Remove the
cayenne-commitlogdependency from your build. - Replace
CommitLogModule.extend(binder).addListener(l)with:CoreModule.extend(binder).addCommitLogListener(l)
excludeFromTransaction()is nowexcludeCommitLogFromTransaction()onCoreModuleExtender.- Replace
@org.apache.cayenne.commitlog.CommitLogon entity classes with@org.apache.cayenne.annotation.CommitLog. - The
CommitLogListener,ChangeMap,ObjectChangeand related model classes remain in theorg.apache.cayenne.commitlogpackage (now part of the core artifact).
- Remove the
-
Per CAY-2935 Minimum required Java version for Apache Cayenne 5.0 is 21.
-
Per CAY-2937 the visual graph feature (entity layout diagrams) has been removed from CayenneModeler. Existing
.graph.xmlfiles will be automatically deleted and their references removed fromcayenne-project.xmlwhen a project is opened in the Modeler and upgraded to the newest format. -
Per CAY-2859
SelectByIdquery factory methods are redesigned with a bunch of old methods deprecated — update your calls accordingly. -
Per CAY-2917 joins are generated in a different order in the Select SQL. This should not affect any logic except if your code relies on the generated SQL in any way.
-
Per CAY-2924 the
org.apache.cayenne.map.eventpackage (mapping events and listener interfaces) was moved from the core to the CayenneModeler module — these events are not used at runtime. As part of this:DbEntity,ObjEntityandDataMapno longer implement the*Listenerinterfaces and no longer expose the internal event-consumer methods (dbEntityChanged,objEntityChanged,dbAttributeAdded,handleAttributeUpdate, etc.).- New public rename APIs replace the previous "set name + fire change event" pattern:
DataMap.renameDbEntity(DbEntity, String),DataMap.renameObjEntity(ObjEntity, String),DbEntity.renameAttribute(DbAttribute, String)andDbEntity.renameRelationship(DbRelationship, String). Prefer these oversetName(...)for renames, as they re-key the parent maps and update dependent references. DbAttribute.setPrimaryKey(boolean)andDbAttribute.setGenerated(boolean)no longer fire events; they update their parentDbEntity's cached collections via direct method calls, behavior-equivalent to before. If your application code subscribed to these mapping events at runtime, migrate to direct calls or to the Modeler.
-
Per CAY-2925 the
cayenne-modeler-maven-pluginwas removed. Launch CayenneModeler from the downloaded distribution instead. A CLI option also exists for all platform flavors:java -jar CayenneModeler.jar path/to/cayenne-project.xmlor on macOS:
open CayenneModeler.app --args path/to/cayenne-project.xml -
Per CAY-2955 the obsolete
QueryEngineabstraction (org.apache.cayenne.access.QueryEngine) has been removed.DataNodeis now used directly whereverQueryEnginewas previously referenced. So you must subclassDataNodeand overrideperformQueries()if you previously implemented a customQueryEngine.
-
Per CAY-2737 All code deprecated in Cayenne 4.1 and 4.2 was deleted — please review your code before upgrading. Most notable removals are
SelectQueryand these Cayenne modules:cayenne-dbcp2cayenne-jodacayenne-clientcayenne-client-jettycayenne-protostuffcayenne-rop-servercayenne-webcayenne-jgroupscayenne-jmscayenne-xmpp
-
Per CAY-2742 Minimum required Java version for Apache Cayenne is 11.
-
Per CAY-2747 Cayenne XML schemas are updated — update your projects by opening them in the Modeler or using the
cayenne-project-compatibilitymodule. -
Per CAY-2751 There is no more JNDI DataSource provided by Cayenne, nor password encoding capabilities. If you need these, provide your own custom DataSource.
-
Per CAY-2752 Code generation configuration has minor changes — review and update Maven, Gradle and Ant configs accordingly.
-
Per CAY-2772 Module extension is done differently. This may result in compile errors in some module extensions. If you encounter those, change how you configure the modules, following this general pattern (using
CacheInvalidationModuleas an example):CayenneRuntime.of(..) .addModule(b -> CacheInvalidationModule.extend(b).addHandler(MyHandler.class)) .build();
Two things to note: (1) a module-specific extender is created using an
extend(Binder)method of the module, and (2) an extender does not produce aModule— instead it adds services directly to theBinder. So it is usually invoked within a lambda that produces aModule, or within an appModule. -
Per CAY-2822
cayenne-servermodule is renamed tocayenne— update your build scripts accordingly:<dependency> <groupId>org.apache.cayenne</groupId> <artifactId>cayenne</artifactId> <version>{version}</version> </dependency>
-
Per CAY-2823
ServerRuntimeis deprecated. Useorg.apache.cayenne.runtime.CayenneRuntimeinstead. -
Per CAY-2824
CayenneServerModuleProviderwas renamed toCayenneRuntimeModuleProviderand moved to theorg.apache.cayenne.runtimepackage. If you are using the auto-loading mechanism for your custom modules, update yourMETA-INF/servicesreference accordingly. -
Per CAY-2825 Package
org.apache.cayenne.configuration.serverwas renamed toorg.apache.cayenne.configuration.runtime— fix your imports accordingly. -
Per CAY-2826
ServerModulerenamed toCoreModule. The new builder pattern combining both changes:CayenneRuntime runtime = CayenneRuntime.of() .addConfig("cayenne-project.xml") .module(b -> CoreModule.extend(b).setProperty("some_property", "some_value")) .build();
-
Per CAY-2828 The
serverprefix was removed from the names of runtime properties and named collections defined inorg.apache.cayenne.configuration.Constants. Update references in code and in any scripts that use them as system properties. -
Per CAY-2845
DataObjectinterface andBaseDataObjectclass were deprecated and all logic moved to thePersistentinterface andPersistentObjectclass. Regenerate model classes via the cgen tool in CayenneModeler or Maven/Gradle plugins.