Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Apache Cayenne 4.0 —What It Is All About

DZone's Guide to

Apache Cayenne 4.0 —What It Is All About

Whether you are just trying Cayenne or are an existing user, there’s lots of cool stuff in to check out in 4.0

· Java Zone ·
Free Resource

Download Microservices for Java Developers: A hands-on introduction to frameworks and containers. Brought to you in partnership with Red Hat.

Didn’t have much time for writing lately. Still felt the topic of Apache Cayenne 4.0 is important enough to say a few words, even though this is coming to you months after the final release. So here is a belated overview of the release scope and its significance. Enjoy!

As you may know, Cayenne is a Java ORM, i.e. an intermediary between your Java objects and the database, that keeps object and relational worlds in sync and lets you run queries and persist data. The current stable version of Cayenne is 4.0 and it was released in August 2018.

This iteration took almost four years of active development. Around 400 task tracker items were opened, dealt with, closed, and released on this branch per the official announcement. In this post, let me initially focus on the few most consequential new features: database-first flow and the new property/query API. In the end, I will provide a high-level list of all new features.

The new CayenneModeler app

Database-First Flow

Mapping flow is arguably the most tedious part of any ORM project. You constantly need to keep in sync three “models” — (1) DB schema, (2) OR mapping, and (3) Java classes — which is rarely fun. You can either do it all manually (yikes!) or pick which one of the three is the “primary” model and do your best to update the other two via some automated process. It appears that the majority of Java developers prefer their Java classes to be the “primary” model. This is totally not surprising, as this results in the most comfortable experience for … well, Java developers.

While I am a Java developer myself, I generally hold an opposing view on the priorities here. In most environments, the database you create is as much a standalone product as is your Java app. To repeat, the database is important on its own, and neither your Java class structures nor even your OR model can adequately describe all the richness of the DB schema. And don’t even get me started on mapping the legacy schemas.

This observation points at the “DB-first” as a natural choice, which may happen like this:

  1. Update the DB via an external migrations framework, like Liquibase
  2. Sync OR model from DB
  3. Do some minimal re-mapping in the OR layer (as the DB schema doesn’t always map to a clean object model by default)
  4. Generate classes out of the OR model

Until 4.0 this flow would get stuck at step #2 (sync OR model from DB), as the Cayenne “reverse-engineering” feature wouldn’t produce idempotent results on multiple runs and would conflict with step #3 (user customization of the model). In 4.0, it “just works”, so you should probably rethink your ORM flow and give the “DB first” option a closer look. The details are described in Cayenne documentation, but let me provide a quick overview. Here is what you need to do for the four steps above:

1 . (Outside of Cayenne scope). Integrate your favorite SQL migrations framework in your project and then track each DB change using whatever tools it provides. E.g. you may use Liquibase (I use Bootique, so my migrations are packaged as small standalone runnable apps via bootique-liquibase).

2 . Setup cayenne-maven-plugin (assuming you use Maven, there’s support for Gradle and Ant as well):

<plugin>
    <groupId>org.apache.cayenne.plugins</groupId>
    <artifactId>cayenne-maven-plugin</artifactId>
    <configuration>
        <map>src/main/resources/my.map.xml</map>
        <dataSource>
            <driver>com.mysql.jdbc.Driver</driver>
            <url>jdbc:mysql://127.0.0.1/</url>
            <username>root</username>
            <password>${env.DB_PASSWORD}</password>
        </dataSource>
        <dbImport>
            <stripFromTableNames>^abc_</stripFromTableNames>
            <catalog>
                <name>mydb</name>
                <includeTable>abc_.*</includeTable>
            </catalog>
        </dbImport>
    </configuration>
</plugin>


And then, run a “cdbimport” Maven task from your IDE or command line:

“cdbimport” in IntelliJ IDEA

3. Use CayenneModeler GUI to change anything in your object layer that wasn’t “cdbimported” to your liking.

4. Runcgen task, that is also available in cayenne-maven-plugin.

To summarize, 4.0 brings automation to the ORM process without restricting what you can do with your model. Here, I should also mention that in Cayenne 4.1 you will no longer need to use the build script for cdbimport. The import flow will be fully integrated into CayenneModeler GUI.

Modern Cayenne Expressions and Queries

The second topic I’d like to discuss is the Expression and Query API, the bread-and-butter tool for any DB work.

Cayenne was always big on source code generation (as opposed to invasive bytecode enhancement). While previously Cayenne would insert String property names in your generated classes, now each persistent class will have the following static Property object generated for each one of its properties:

public static final Property<String> EMAIL =
    Property.create(“email”, String.class);


And this allows us to build Expressions in a way that is compiler-checked and type-safe:

Expression e1 = EMAIL.eq("root@example.org");
Expression e2 = ADDRESS.dot(Address.CITY).eq(“New York”);


Expressions are used within Queries. And, the later is also significantly redone. While the older queries where all JavaBean-style, the new API is fluent and easy to both write and read. Also, it is type-safe.

List<Person> people = ObjectSelect
    .query(Person.class)
    .where(EMAIL.eq("root@example.org"))
    .select(context);


There is a number of useful queries in addition to ObjectSelect. For example, here is a query that selects a single object by ID:

Person p = SelectById.query(Person.class, 29).selectOne(context);


The Laundry List

And finally, here is a more or less complete list of all the new things you will find in Cayenne 4.0:

Expressions and Queries

  • Generated “property” objects serving as expression builders
  • Fluent, type-safe Query API and a whole slew of new query classes using this style
  • Object queries with aggregate and scalar functions, individual columns select
  • Query result iteration API, iterating over items and batches of items

Configuration and Runtime

  •  ServerRuntime builder to simplify stack customization
  • Simplified project structure ( DataMap-only projects that are connected to their DataSource in runtime)
  • Auto-loadable DI modules
  • DI service decorators
  • DI collections type-safety and control over element ordering
  • Transaction control API

DevTools

  • Fresh CayenneModeler with a fully redesigned look and improved UX
  • Gradle plugins for common ORM workflow tasks, on par with Maven/Ant toolset
  • Practical Database-first flow with Maven, Gradle, and Ant

Integrations and Various Cool Features

  • cayenne-crypto — column-level DB encryption.
  • cayenne-commitlog — tracking of commit changes.
  • cayenne-jcache — bridging Cayenne cache with JCache, which is a Java standard
  • OSGI integration
  • javax.time support (as well as Joda-Time for legacy apps)

Conclusion

Whether you are just trying Cayenne or are an existing user, there’s lots of cool stuff in 4.0 that will make your ORM modeling and coding much easier. Also watch for the upcoming 4.1 (hopefully, it's going Beta this year). It has its own exciting enhancements in performance and GUI. Thanks for reading!

Download Building Reactive Microservices in Java: Asynchronous and Event-Based Application Design. Brought to you in partnership with Red Hat

Topics:
object relational mapping ,java ,apache cayenne ,apache cayenne 4.0 ,orm ,jvm ,api ,query ,orm modeling

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}