Thanks John! This all makes sense. 

My hope was that for a "vanilla" project the delta would be just CayenneRuntime 
(name and package), DataNode and, possibly, thread-locals. But in a deeply 
customized stack (own ObjectContext, DbAdapter, etc.) it is a much bigger 
effort :-/

Claude seems to be able to guess all the renaming though from a single prompt. 
I just went through Bootique, Agrest and LinkMove upgrades, and other than the 
issue that I mention below, it did all the shuffling with zero human 
involvement.

The fallout on my end was related to the removal of EJBQLQuery. Ugly as it was, 
there's no more "delete with expression qualifier" functionality anywhere and 
LinkMove "delete all" task relied on it. So I had to vibecode a placeholder via 
non-public translator API. Will need to fill this gap in 6.0 by adding a 
"delete" option to the object query.

Andrus


> On Nov 3, 2026, at 10:55 AM, John Huss <[email protected]> wrote:
> 
> Thanks for asking! I don't want to bellyache - I get paid to do this stuff,
> so these are not terrible problems. But users should expect this upgrade to
> require some real investment from them - it's not a drop-in at all,
> especially due to the DataSource/Node changes which will hit everyone. A
> lot of the rest depends on how deeply you customize the stack. Since you
> asked I'll list the things I encountered. I'm not saying these are bad
> changes, just that this is certainly a major release. I can imagine some
> users beginning to upgrade and then stopping because of all the problems.
> It's not a slam-dunk. I'm basically the sole maintainer of 7 different
> server applications that all use a single shared version of cayenne, so
> when I upgrade I have to upgrade them all.
> 
> Things moved to different packages - IDE can find all these if the package
> was the only change; but often the class name changed too.
> Replacing ServerRuntime with CayenneRuntime - not hard, but of little value
> to users
> Replace BaseContext with DataContext - not hard, but of little value to
> users
> Rename ServerRuntime.builder to CayenneRuntime.of - not hard, but of little
> value to users
> Renaming of all AST* classes (not automatic) - The new names are definitely
> better, but this was annoying for little value returned
> Replace PersistentObjectList with ToManyList - not hard, but of little
> value to users
> 
> Entity object hierarchy - replace BaseDataObject with PersistentObject,
> etc. Changes break Jackson JSON mixins due to new hierarchy.
> My custom DataDomain subclass wasn't important enough to keep due to API
> changes (not automatic)
> API changes to DefaultSelectTranslator (not automatic)
> Custom ObjectContext subclass was difficult to install now - there are not
> great extension points for this use case. I had to modify the cayenne
> source to make this easier to extend without a ton of duplication.
> Custom JdbcAdapter - changes to Constant names in the constructor (not
> automatic), API changes like using NativeColumnType.
> Removal of DbAdapterFactory requires new way to install custom DbAdapter
> and PkGenerator
> Removal of DataNode and DataSourceFactory changes the way a DB connection
> is established - lots of work needed to runtime creation and
> binding/injection - removed extension points. Since the data source was set
> up using properties (strings) and it was harder to verify everything was
> correct. I've not been a fan of the binding/injection because it isn't
> discoverable. As a user I have seemingly no way of knowing what extension
> points are available and how to use them. The pro-tip is to read the source
> for CoreModule.java but that's not a great answer, and I don't know if that
> is even exhaustive.
> Removal of thread bound runtime without a built-in replacement. This is
> probably the hardest to address for users. I ended up just re-introducing
> the same concept almost exactly. In Java 25, this can be better with
> ScopedValue, but sadly I'm not on 25 yet. Thread-bound object context
> remains, but is deprecated - I'll wait and do that one later I guess.
> 
> The silver lining is that LLMs help a lot with this. You can provide them
> with the cayenne source code to refer to and they can rock a lot of this
> stuff. And the carrot/prize is that you get much improved performance! I'm
> still +1.
> 
> 
> 
> On Mon, Nov 2, 2026 at 4:28 PM Andrus Adamchik <[email protected]> wrote:
> 
>> 
>>> On Nov 2, 2026, at 3:32 PM, John Huss <[email protected]> wrote:
>>> 
>>> I will say that upgrading to this release requires a LOT of effort. There
>>> are SO many breaking changes. I get that this is a major version update,
>>> and I am totally thrilled with the performance improvements. But golly,
>>> this is a huge effort. It is very fortunate that we have LLMs now to help
>>> with the transition, but this is still a rough process. I hope the amount
>>> of breaking changes is going to slow down.
>> 
>> Hi John,
>> 
>> Thanks for sharing your experience. This is important, as soon others will
>> start upgrading. Before I go on a rant, a question :) Can you describe your
>> upgrade experience? What you needed to change and what was the hardest to
>> deal with? What else can we add to UPGRADE.md to make things easier?
>> 
>> 
>> Now my thoughts on the rate of change... Years ago we've noticed how
>> adding even a smallest new feature is insanely hard due to how many edge
>> cases needed to be handled. This is why we still don't have horizontal
>> inheritance. The amount of tech debt that accumulated over two decades is
>> staggering. So the product stagnated and got confusing. Just some examples:
>> 
>> 1. Depending on how you count, there are between 15 and 23 Query
>> subclasses in 4.2! How do you explain this to users? And how do you support
>> all of those runtime paths?
>> 2. User-facing APIs from different moments in history (DataContext has
>> older methods that are not in ObjectContext; query methods are different
>> between fluent queries and the context)
>> 3. Three different event models (callbacks, snapshot events, filters)
>> 4. Four independent cache subsystems
>> 
>> LLMs presented a unique chance to finally get unstuck, drive towards a
>> consistent mental model that can be communicated to users and meaningfully
>> improve the product. But it did (does) require what essentially amounts to
>> an ongoing open-heart surgery that we never dared to do before.
>> 
>> I understand that 90% of our users have extensive existing code bases, so
>> we are creating extra pain. While the core behavior is unchanged (I am
>> trying to keep all the faulting contracts and such) and the model upgrade
>> is done automatically, there are dozens of API changes across the board.
>> More so if people built extensions based on (formally public, but outside
>> ObjectContext / Query) APIs. Those things will be broken and will need to
>> be redesigned as they cannot be preserved in a meaningful way.
>> 
>> So I am constantly asking myself if we got carried away too much and when
>> we should stop. From what I see now, at least 6.0 is going to be another
>> breaking release (BTW it is down to just 4 essential Queries already :)).
>> Hopefully we deal with all mapping and Query restructuring there and later
>> work on things like caches quietly without user disruption.
>> 
>> Andrus
>> 
>> 
>> 
>> 
>> 
>> 

Reply via email to