cayenne-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Kevin Menard <>
Subject Re: Cleaning up ROP
Date Wed, 07 Nov 2007 06:07:41 GMT
I just spent the better part of this evening trying to get something going.
Unfortunately, I'm stuck at the moment and it's getting pretty late (or
early) here.  So, I'm just posting what I tried and what my results were.
If anyone else wants to suggest something, great, if not, I'll prod at it
more when I can get some time.  I'll likely have to defer it and come up
with some workaround, because I need this portion of the app relying on the
fix done.

Anyway . . .

I took a really naïve approach to start because I just wanted to get
something going.

* Made CayenneDataObject extends PersistentObject
** Removed any code duplication

* Updated my data map to use the same class name for the server and client
classes for all obj entities.

* Modified the velocity template to combine both server and client class

* Static property name fields appear as before
* All client fields appear
* All methods perform an instanceof check on the context to choose the
appropriate code to call like so:

public BillingInfo getDefaultBillingInfo() {
        if (objectContext instanceof CayenneContext) {
            if(objectContext != null) {
                objectContext.prepareForAccess(this, "defaultBillingInfo",

            return (BillingInfo) defaultBillingInfo.getValue();
        else {
            return (BillingInfo)readProperty("defaultBillingInfo");


* Retrieving data from client fails during deep merge on toMany
relationships.  The read property is null causing most of the rest of the
method to fail.

* Adding NPE checks for the above gets me to a workable state, but the
generated class does not work as expected.  In particular, all the values
are in the map (like they should for a server) and all the fields are blank
(which should not be the case for the client).

My initial thoughts were that the failures were due to the above code
snippet failing to do the right thing if the context is null (is there a
better way to tell if we're executing on the client?).  But, the first
failure occurs well before any of those accessors are called.  So, I am a
bit at a loss.

Anyway, if Ari or someone else wants to help out with this, I'd certainly
welcome it.


On 10/27/07 1:01 PM, "Andrus Adamchik" <> wrote:

> Would be nice if we could make it work... IIRC back in the day when
> ROP was first implemented there were a number of limitations
> preventing DataContext and CayenneDataObject from being used on the
> client, mostly related to the fact that both had direct dependencies
> on the structure of the underlying stack (e.g. referencing DataDomain
> and DataNode). Now we are *mostly* free of those. So I'd be curious
> to try and use DataContext on the client.
> A few issues to pay attention to:
> * Serialization. Current client objects are more lightweight as they
> store their properties in Java fields, vs. a Map used by
> CayenneDataObject. So probably a custom serializer is needed.
> * While supporting a single class hierarchy is a good idea,
> preserving the ability for separate hierarchies is very important -
> users may not want to expose some server methods to the client, and
> generally may want to have two sets of objects with different behavior.
> In any event it is a good idea to reevaluate our options now.
> Andrus
> On Oct 27, 2007, at 7:20 PM, Kevin Menard wrote:
>> Hi all,
>> I've just gone back to work on a ROP application I have and am
>> again running
>> into the issue of having to duplicate code between the server model
>> subclasses and the client model subclasses.  I've got a way of working
>> around that, but I'm thinking this is probably best handled by
>> Cayenne.  In
>> particular, I really don't think that there should be two class
>> hierarchies
>> for what amounts to a boolean field (remote/not remote).
>> I think the generated superclass should perform the duty of calling
>> the
>> appropriate method for reading and writing properties.  I think
>> this would
>> advocate adding an isRemote() method to the ObjectContext interface
>> to avoid
>> having to do instanceof operations.
>> There would have to be some sort of unification between
>> PersistentObject and
>> CayenneDataObject as well.  My naïve guess is that the latter could
>> extend
>> the former, but I haven't investigated whether or not they are
>> compatible.
>> Does this sound like a reasonable approach?  If so, I'll probably
>> dig in on
>> that.
>> Thanks,
>> Kevin


View raw message