blob: 71ef667168f5a6f016d1702056f12b568c2e8a15 [file] [log] [blame]
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.3">
<link rel="apple-touch-icon" sizes="180x180" href="/img/favicon/apple-touch-icon-04cb17e028.png">
<link rel="icon" type="image/png" sizes="32x32" href="/img/favicon/favicon-32x32-12431ee8eb.png">
<link rel="icon" type="image/png" sizes="16x16" href="/img/favicon/favicon-16x16-4f316e4d55.png">
<link rel="manifest" href="/img/favicon/manifest-65e6aaa49e.json">
<link rel="mask-icon" href="/img/favicon/safari-pinned-tab-558c1991b1.svg" color="#dc5656">
<link rel="shortcut icon" href="/img/favicon/favicon-6cef91375b.ico">
<meta name="msapplication-TileColor" content="#ffffff">
<meta name="msapplication-TileImage" content="/img/favicon/mstile-144x144-34e7696278.png">
<meta name="msapplication-config" content="/img/favicon/browserconfig-82ff158058.xml">
<meta name="theme-color" content="#ffffff">
<link rel="stylesheet" href="https://cayenne.apache.org/css/styles-9ee2e6e330.css"/>
<script src="https://cayenne.apache.org/js/bundle-c0e6356367.js"></script>
<title>Guide to 4.0 Features &middot; Apache Cayenne</title>
</head>
<body data-spy="scroll" data-target=".toc-side" class="cd-head">
<header class="page-header">
<nav id="topbar" class="bg-dark" aria-label="breadcrumb" role="navigation">
<ul class="breadcrumb breadcrumb-sm breadcrumb-dark container mb-0">
<li class="breadcrumb-item dropdown">
<a class="dropdown-toggle text-nowrap pr-1" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<img class="mw-15px mr-1" src="/img/feather-641aa69d09.svg" />Apache Software Foundation</a>
<div class="dropdown-menu rounded-0" aria-labelledby="navbarDropdown">
<a class="dropdown-item" href="https://www.apache.org">Apache Homepage</a>
<a class="dropdown-item" href="https://www.apache.org/licenses/">License</a>
<a class="dropdown-item" href="https://www.apache.org/foundation/sponsorship.html">Sponsorship</a>
<a class="dropdown-item" href="https://www.apache.org/foundation/thanks.html">Thanks</a>
<a class="dropdown-item" href="https://www.apache.org/security/">Security</a>
<a class="dropdown-item" href="https://privacy.apache.org/policies/privacy-policy-public.html">Privacy</a>
<a class="ml-1 mt-1 acevent" data-format="wide" data-mode="dark" data-width="120"></a>
</div>
</li>
</ul>
</nav>
<nav class="navbar navbar-expand-lg navbar-dark bg-primary">
<div class="container">
<a class="navbar-brand" href="https://cayenne.apache.org/">
<img src="/img/logo_mono_full-d7a19eef61.svg" alt="Apache Cayenne" />
</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#mainMenu" aria-controls="mainMenu" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="mainMenu">
<ul class="navbar-nav mt-3 mt-lg-0 mr-auto">
<li class="nav-item">
<a class="nav-link" href="/download/">DOWNLOAD</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/docs/4.2/getting-started-guide/">DOCUMENTATION</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/about/support/">SUPPORT</a>
</li>
</ul>
<ul class="navbar-nav flex-row justify-content-center mt-2 mt-lg-0 mb-2 mb-lg-0 " id="social-links-menu">
<li class="nav-item d-flex">
<a class="nav-link d-flex justify-content-center align-items-center" href="https://github.com/apache/cayenne">
<img src="/img/icon_octocat_stars-c24dac94b8.svg" alt="GitHub" />
</a>
</li>
<li class="nav-item d-flex">
<a class="nav-link d-flex justify-content-center align-items-center" href="https://twitter.com/ApacheCayenne">
<img src="/img/icon_twitter-220a129d14.svg" alt="Twitter" />
</a>
</li>
</ul>
</div>
</div>
</nav>
</header>
<main>
<div class="cd-top-sidebar bb">
<div class="container">
<div class="row no-gutters">
<div class="col-12 col-lg-4 col-xl-3 br cd-sidebar1">
<ul class="nav" role="tablist">
<li class="nav-item dropdown mw-100">
<a class="nav-link dropdown-toggle text-truncate" data-toggle="dropdown" href="#" role="button" aria-haspopup="true" aria-expanded="false">
Cayenne Version 4.0
</a>
<div class="dropdown-menu">
<a class="dropdown-item" href="/docs/5.0/cayenne-guide/">Version 5.0 (Alpha)</a><a class="dropdown-item" href="/docs/4.2/getting-started-guide/">Version 4.2 (Stable)</a><a class="dropdown-item" href="/docs/4.1/getting-started-guide/">Version 4.1 (Stable)</a><a class="dropdown-item" href="/docs/4.0/getting-started-guide/">Version 4.0 (Aging)</a><a class="dropdown-item" href="/docs/3.1/getting-started-guide/">Version 3.1 (Legacy)</a>
</div>
</li>
</ul>
</div>
<div class="col-12 col-lg-8 col-xl-9"> </div>
</div>
</div>
</div>
<div class="container">
<div class="row no-gutters ">
<div class="col-12 col-lg-4 col-xl-3 br py-2 bg-gray-100 cd-sidebar">
<div class="tab-content" id="cd-docs-nav">
<div class="cd-toc-item">
<a class="cd-toc-link" href="/docs/4.0/getting-started-guide/">Getting Started</a>
</div>
<div class="cd-toc-item">
<a class="cd-toc-link" href="/docs/4.0/cayenne-guide/">Cayenne Guide</a>
</div>
<div class="cd-toc-item">
<a class="cd-toc-link" href="/docs/4.0/getting-started-rop/">Getting Started ROP</a>
</div>
<div class="cd-toc-item">
<span class="cd-toc-link active">Upgrade Guide</span><div id="toc" class="toc toc-side">
<div id="toctitle">
Table of Contents
</div>
<ul class="sectlevel1 nav">
<li><a href="#guide-to-4-0-features" class="nav-link">1. Guide to 4.0 Features</a>
<ul class="sectlevel2 nav">
<li><a href="#java-version" class="nav-link">1.1. Java Version</a></li>
<li><a href="#cayenne-configuration" class="nav-link">1.2. Cayenne Configuration</a></li>
<li><a href="#framework-api" class="nav-link">1.3. Framework API</a></li>
<li><a href="#cayennemodeler" class="nav-link">1.4. CayenneModeler</a></li>
<li><a href="#build-tools" class="nav-link">1.5. Build Tools</a></li>
</ul> </li>
</ul>
</div>
</div>
<div class="cd-toc-item">
<a class="cd-toc-link" href="/docs/4.0/api/">JavaDoc</a></div>
</div>
</div>
<div class="col-12 col-lg-8 col-xl-9 py-3 pl-lg-5 cd-content">
<article>
<header>
<h1>Guide to 4.0 Features</h1>
</header>
<section>
<div class="sect1">
<h2 id="guide-to-4-0-features"><a class="anchor" href="#guide-to-4-0-features"></a>1. Guide to 4.0 Features</h2>
<div class="sectionbody">
<div class="paragraph">
<p>This guide highlights the new features and changes introduced in Apache Cayenne 4.0. For a full list of changes consult RELEASE-NOTES.txt included in Cayenne download. For release-specific upgrade instructions check UPGRADE.txt.</p>
</div>
<div class="sect2">
<h3 id="java-version"><a class="anchor" href="#java-version"></a>1.1. Java Version</h3>
<div class="paragraph">
<p>Minimum required JDK version is 1.7 or newer. Cayenne 4.0 is fully tested with Java 1.7, 1.8.</p>
</div>
<div class="paragraph">
<p>The examples below often use Java 8 syntax. But those same examples should work without lambdas just as well.</p>
</div>
</div>
<div class="sect2">
<h3 id="cayenne-configuration"><a class="anchor" href="#cayenne-configuration"></a>1.2. Cayenne Configuration</h3>
<div class="sect3">
<h4 id="serverruntimebuilder"><a class="anchor" href="#serverruntimebuilder"></a>ServerRuntimeBuilder</h4>
<div class="paragraph">
<p>Cayenne 3.1 introduced dependency injection and ServerRuntime. 4.0 provides a very convenient utility to create a custom runtime with various extensions. This reduces the code needed to integrate Cayenne in your environment to just a few lines and no boilerplate. E.g.:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">ServerRuntime runtime = ServerRuntime.builder("myproject")
.addConfigs("cayenne-project1.xml", "cayenne-project2.xml")
.addModule(binder -&gt; binder.bind(JdbcEventLogger.class).toInstance(myLogger))
.dataSource(myDataSource)
.build();</code></pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="mapping-free-serverruntime"><a class="anchor" href="#mapping-free-serverruntime"></a>Mapping-free ServerRuntime</h4>
<div class="paragraph">
<p>ServerRuntime can now be started without any ORM mapping at all. This is useful in situations when Cayenne is used as a stack to execute raw SQL, in unit tests, etc.</p>
</div>
</div>
<div class="sect3">
<h4 id="di-container-decorators"><a class="anchor" href="#di-container-decorators"></a>DI Container Decorators</h4>
<div class="paragraph">
<p>In addition to overriding services in DI container, Cayenne now allows to supply decorators. True to the "smallest-footprint" DI philosophy, decorator approach is very simple and does not require proxies or class enhancement. Just implement the decorated interface and provide a constructor that takes a delegate instance being decorated:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">public class MyInterfaceDecorator implements MyInterface {
private MyInterface delegate;
public MockInterface1_Decorator3(@Inject MyInterface delegate) {
this.delegate = delegate;
}
@Override
public String getName() {
return "&lt;" + delegate.getName() + "&gt;";
}
}
Module module = binder -&gt;
binder.decorate(MyInterface.class).before(MyInterfaceDecorator.class);</code></pre>
</div>
</div>
</div>
</div>
<div class="sect2">
<h3 id="framework-api"><a class="anchor" href="#framework-api"></a>1.3. Framework API</h3>
<div class="sect3">
<h4 id="fluent-query-api"><a class="anchor" href="#fluent-query-api"></a>Fluent Query API</h4>
<div class="paragraph">
<p>Fluent Query API is one of the most exciting new features in Cayenne 4.0. This syntax is "chainable" so you can write query assembly and execution code on one line. The most useful fluent queries are <code>ObjectSelect</code>, <code>SQLSelect</code> and <code>SelectById</code>:</p>
</div>
<div class="sect4">
<h5 id="objectselect"><a class="anchor" href="#objectselect"></a>ObjectSelect</h5>
<div class="paragraph">
<p>A "chainable" analog of SelectQuery.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">Artist a = ObjectSelect
.query(Artist.class)
.where(Artist.ARTIST_NAME.eq("Picasso"))
.selectOne(context);</code></pre>
</div>
</div>
</div>
<div class="sect4">
<h5 id="columnselect"><a class="anchor" href="#columnselect"></a>ColumnSelect</h5>
<div class="paragraph">
<p>This query allows you directly access individual properties of Objects and use functions (including aggregate) via type-safe API.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">List&lt;String&gt; names = ObjectSelect
.columnQuery(Artist.class, Artist.ARTIST_NAME)
.where(Artist.ARTIST_NAME.length().gt(6))
.select(context);</code></pre>
</div>
</div>
</div>
<div class="sect4">
<h5 id="sqlselect"><a class="anchor" href="#sqlselect"></a>SQLSelect</h5>
<div class="paragraph">
<p>A "chainable" analog of <code>SQLTemplate</code> used specifically to run selecting raw SQL:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">List&lt;Long&gt; ids = SQLSelect
.scalarQuery(Long.class, "SELECT ARTIST_ID FROM ARTIST ORDER BY ARTIST_ID")
.select(context);</code></pre>
</div>
</div>
</div>
<div class="sect4">
<h5 id="selectbyid"><a class="anchor" href="#selectbyid"></a>SelectById</h5>
<div class="paragraph">
<p>There’s really no good analog of <code>SelectById</code> in Cayenne prior to 4.0. Previously available <code>ObjectIdQuery</code> didn’t support half of the features of <code>SelectById</code> (e.g. caching consistent with other queries, prefetches, etc.) :</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">Artist a = SelectById
.query(Artist.class, 3)
.useLocalCache("g1")
.selectOne(context)</code></pre>
</div>
</div>
</div>
</div>
<div class="sect3">
<h4 id="objectcontext"><a class="anchor" href="#objectcontext"></a>ObjectContext</h4>
<div class="sect4">
<h5 id="callback-based-object-iterator"><a class="anchor" href="#callback-based-object-iterator"></a>Callback-based Object Iterator</h5>
<div class="paragraph">
<p>ObjectContext now features a simpler way to iterate over large result sets, based on callback interface that can be implemented with a lambda:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">SelectQuery&lt;Artist&gt; q = new SelectQuery&lt;Artist&gt;(Artist.class);
context.iterate(q, (Artist a) -&gt; {
// do something with the object...
...
});</code></pre>
</div>
</div>
</div>
</div>
<div class="sect3">
<h4 id="generics-in-expressions-and-queries"><a class="anchor" href="#generics-in-expressions-and-queries"></a>Generics in Expressions and Queries</h4>
<div class="paragraph">
<p>We finished the work of "genericizing" Cayenne APIs started in 3.1. Now all APIs dealing with persistent objects (Expressions, Queries, ObjectContext, etc.) support generics of Persistent object type or attribute property type.</p>
</div>
</div>
<div class="sect3">
<h4 id="property-api"><a class="anchor" href="#property-api"></a>Property API</h4>
<div class="paragraph">
<p>Persistent superclasses (_MyEntity) now contain a set of static <code>Property&lt;T&gt;</code> variables generated from the model. These metadata objects make possible to create type-safe Expressions and other query parts.</p>
</div>
</div>
<div class="sect3">
<h4 id="positional-parameter-bindings"><a class="anchor" href="#positional-parameter-bindings"></a>Positional Parameter Bindings</h4>
<div class="paragraph">
<p>Expressions and <code>SQLTemplate</code> traditionally supported binding of parameters by name as a map. Cayenne 4.0 introduces a very easy form of positional bindings. It works with the same named template format, only parameters are bound by position, left-to-right. Here we showing a more complex example with the same parameter name being used more than once in the query:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">// two distinct names, 3 positional parameters.
// "price" is set to 23, "maxPrice" - to 50
Expression e = ExpressionFactory.exp(
"price = $price or averagePrice = $price and maxPrice = $maxPrice", 23, 50);</code></pre>
</div>
</div>
<div class="paragraph">
<p>This API is supported in Expressions, SQLTemplate as well as new SQLSelect and can be used interchangeably with named parameters with a single template flavor.</p>
</div>
</div>
<div class="sect3">
<h4 id="improved-transaction-api"><a class="anchor" href="#improved-transaction-api"></a>Improved Transaction API</h4>
<div class="paragraph">
<p>Transaction factory is now setup via DI (instead of being configured in the Modeler). There’s a utility method on ServerRuntime to perform multiple operations as one transaction:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">runtime.performInTransaction(() -&gt; {
// ... do some changes
context.commitChanges();
// ... do more changes
context.commitChanges();
return true;
});</code></pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="transparent-database-cryptography-with-cayenne-crypto-module"><a class="anchor" href="#transparent-database-cryptography-with-cayenne-crypto-module"></a>Transparent Database Cryptography with "cayenne-crypto" Module</h4>
<div class="paragraph">
<p>Cayenne includes a new module called "cayenne-crypto" that enables transparent cryptography for designated data columns. This is a pretty cool feature that allows to enable encryption/decryption of your sensitive data pretty much declaratively using your regular DB storage. Encrypted values can be stored in (VAR)BINARY and (VAR)CHAR columns. Currently "cayenne-crypto" supports AES/CBC/PKCS5Padding encryption (though other cyphers can be added). It also supports encrypted data compression. Here is an example of building a crypto DI module that can be added to ServerRuntime:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">Module cryptoExtensions = CryptoModule.extend()
.keyStore("file:///mykeystore", "keystorepassword".toCharArray(), "keyalias")
.compress()
.module();</code></pre>
</div>
</div>
</div>
</div>
<div class="sect2">
<h3 id="cayennemodeler"><a class="anchor" href="#cayennemodeler"></a>1.4. CayenneModeler</h3>
<div class="sect3">
<h4 id="improved-ui"><a class="anchor" href="#improved-ui"></a>Improved UI</h4>
<div class="paragraph">
<p>CayenneModeler features a number of UI improvements. Attributes and relationships are now edited in the same view (no need to switch between the tabs). Project tree allows to easily filter elements by type and quickly collapse the tree.</p>
</div>
</div>
<div class="sect3">
<h4 id="dropped-support-for-mapping-listeners"><a class="anchor" href="#dropped-support-for-mapping-listeners"></a>Dropped Support for Mapping Listeners</h4>
<div class="paragraph">
<p>Managing listeners in the DataMap XML model is counterproductive and confusing, so support for listeners was removed from both the XML and the Modeler. If you previously had listeners mapped in the model, annotate their callback methods, and perform listener registration in the code:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">runtime.getDataDomain().addListener(myListener);</code></pre>
</div>
</div>
<div class="paragraph">
<p>or via DI:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">Module module = binder -&gt; ServerModule.contributeDomainListeners(myListener);</code></pre>
</div>
</div>
<div class="paragraph">
<p>Entity callbacks on the other hand are managed in the Modeler as before.</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="build-tools"><a class="anchor" href="#build-tools"></a>1.5. Build Tools</h3>
<div class="sect3">
<h4 id="cdbimport"><a class="anchor" href="#cdbimport"></a>cdbimport</h4>
<div class="paragraph">
<p><code>cdbimport</code> has evolved from an experiment to a full-featured production tool that significantly reduces (and sometimes eliminates) the need for manual maintenance of the DataMaps in CayenneModeler. Two improvements made this possible. First, smart merge algorithm will ensure that custom changes to the model are not overridden on subsequent runs of "cdbimport". Second, the mechanism for specifing DB reverse-engineering parameters, such as name filtering, is made much more powerful with many new options. E.g. we started supporting filters by catalogs and schemas, table name filters can be added per catalog/schema or at the top level, etc.</p>
</div>
</div>
<div class="sect3">
<h4 id="cgen"><a class="anchor" href="#cgen"></a>cgen</h4>
<div class="paragraph">
<p>As was mentioned above, <code>cgen</code> now includes <code>Property&lt;T&gt;</code> static variables for expression building. It is also made smarter about its defaults for "destDir" and "superPkg".</p>
</div>
</div>
<div class="sect3">
<h4 id="gradle-plugin"><a class="anchor" href="#gradle-plugin"></a>Gradle Plugin</h4>
<div class="paragraph">
<p>Cayenne now provides it’s own Gradle Plugin that allows you easily integrate <code>cdbimport</code> and <code>cgen</code> tools into your build process. Here is example of it’s usage:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-Groovy Groovy" data-lang="Groovy">buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath group: 'org.apache.cayenne.plugins', name: 'cayenne-gradle-plugin', version: '4.0'
}
}
apply plugin: 'org.apache.cayenne'
cayenne.defaultDataMap 'datamap.map.xml'
dependencies {
compile cayenne.dependency('server')
compile cayenne.dependency('java8')
}</code></pre>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
<footer>
<div class="row">
<div class="col-6 col-md-3 text-center text-md-left">
&nbsp;
</div>
<div class="col-18 col-md-9 text-center text-md-right">
</div>
</div>
</footer>
</article>
<img referrerpolicy="no-referrer-when-downgrade" src="https://static.scarf.sh/a.png?x-pxid=5c836e39-be6b-4a21-a946-a97b5b69f172" />
</div>
</div>
</div>
</main>
<footer class="bg-dark">
<div class="footer-nav container text-center text-lg-left pb-3">
<div class="row pt-5 pb-3">
<div class="col-sm-6 col-lg-3">
<h4>About</h4>
<ul class="list-unstyled">
<li>
<a href="/why-cayenne.html">Why Cayenne?</a>
</li>
<li>
<a href="/download/">Download</a>
</li>
<li>
<a href="/success-stories.html">Success Stories</a>
</li>
<li>
<a href="/about/support/">Support</a>
</li>
</ul>
</div>
<div class="col-sm-6 col-lg-3">
<h4>Documentation</h4>
<ul class="list-unstyled">
<li>
<a href="/docs/4.0/getting-started-guide/">Getting Started (4.0)</a>
</li>
<li>
<a href="/docs/4.1/getting-started-guide/">Getting Started (4.1)</a>
</li>
<li>
<a href="/docs/4.2/getting-started-guide/">Getting Started (4.2)</a>
</li>
<li>
<a href="/docs/4.0/cayenne-guide/">Cayenne Guide (4.0)</a>
</li>
<li>
<a href="/docs/4.1/cayenne-guide/">Cayenne Guide (4.1)</a>
</li>
<li>
<a href="/docs/4.2/cayenne-guide/">Cayenne Guide (4.2)</a>
</li>
<li>
<a href="/docs/4.1/getting-started-db-first/">Database First tutorial (4.1)</a>
</li>
<li>
<a href="/docs/4.2/getting-started-db-first/">Database First tutorial (4.2)</a>
</li>
<li>
<a href="/legacy/legacy-docs/">Legacy Documentation</a>
</li>
</ul>
</div>
<div class="col-sm-6 col-lg-3">
<h4>Collaboration</h4>
<ul class="list-unstyled">
<li>
<a href="https://issues.apache.org/jira/browse/CAY">Bug/Feature Tracker</a>
</li>
<li>
<a href="/mailing-lists.html">Mailing Lists</a>
</li>
<li>
<a href="/dev/code-repository.html">Code Repository</a>
</li>
<li>
<a href="/dev/">Developer Guide</a>
</li>
<li>
<a href="/how-can-i-help.html">How can I help?</a>
</li>
<li>
<a href="/contributors.html">Contributors</a>
</li>
<li>
<a href="/thanks.html">Thanks</a>
</li>
</ul>
</div>
<div class="col-sm-6 col-lg-3">
<h4>News</h4>
<ul class="list-multiline-items list-unstyled mb-0">
<li>
<time datetime="2023-05-25 18:00:00 &#43;0300 &#43;0300" class="xsmall d-block">May 25, 2023</time>
<a href="/2023/05/cayenne-42-final-released/">Cayenne 4.2 Final Released</a>
</li>
<li>
<time datetime="2023-03-02 12:00:00 &#43;0300 &#43;0300" class="xsmall d-block">Mar 02, 2023</time>
<a href="/2023/03/cayenne-403-released/">Cayenne 4.0.3 Released</a>
</li>
<li>
<time datetime="2022-12-05 12:00:00 &#43;0300 &#43;0300" class="xsmall d-block">Dec 05, 2022</time>
<a href="/2022/12/cayenne-42rc2-released/">Cayenne 4.2 Release Candidate 2 Released</a>
</li>
</ul>
<a class="btn-link text-uppercase xsmall" href="https://cayenne.apache.org/news">
More news
<i class="fa fa-lg fa-long-arrow-right" aria-hidden="true"></i>
</a>
</div>
</div>
<hr class="mt-0 mb-3" />
<p class="copy xsmall text-center mw-75 mx-auto mb-0">
Copyright © 2001-2024 Apache Software Foundation. Apache Cayenne, Cayenne, Apache, the Apache feather logo, and the Apache Cayenne project logo are trademarks of The Apache Software Foundation.
<a href="https://privacy.apache.org/policies/privacy-policy-public.html">Privacy policy</a>.
<img class="d-block mx-auto mt-2" src="/img/logo_mono-3302daa3cf.svg" alt="Apache Cayenne" />
</p>
</div>
</footer>
</body>
</html>