You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@isis.apache.org by Kevin Meyer - KMZ <ke...@kmz.co.za> on 2011/12/11 17:32:02 UTC

Some help with supporting Cayenne

I have a bit of a problem.

As a first approximation, I'm trying to create a new Isis ObjectStore 
that uses Cayenne.

I've got to the stage where I've created the Cayenne mappers, etc,  
and am now trying to instantiate an instance of my test class..

But now I've discovered that Cayenne requires its supported POJOs to 
implement some Cayenne interfaces and explicitly casts the 
instantiated object to the Cayenne Persistent interface.

Problem is, this interface kills the Isis introspector - it eventually hits 
interface org.apache.cayenne.util.XMLSerializable, which has a List 
(Collection) parameter.

I have two options:
1) Somehow disable the Isis introspector from walking down the 
Cayenne Persistor interface, or
2) Do some byte-code magic that is somehow able to wrap the users 
domain class picked up by Isis into something which implements 
Persisted, and can be given to Cayenne to instantiate.

Option 2 requires me to somehow create a 1-to-1 mapping between 
user domain POJOs and runtime contructed classes that implement 
the Persisted interface, which Cayenne can instantiate, but that I can 
use to intercept Cayenne methods.

Is this possible? To create new classes, based on existing classes, 
that can be instantiated?


Regards,
Kevin



Re: Some help with supporting Cayenne

Posted by Mohammad Nour El-Din <no...@gmail.com>.
Hi...

On Sun, Dec 11, 2011 at 7:16 PM, Dan Haywood
<da...@haywood-associates.co.uk>wrote:

> On 11 December 2011 16:32, Kevin Meyer - KMZ <ke...@kmz.co.za> wrote:
>
> >
> > Problem is, this interface kills the Isis introspector - it eventually
> hits
> > interface org.apache.cayenne.util.XMLSerializable, which has a List
> > (Collection) parameter.
> >
> > I have two options:
> > 1) Somehow disable the Isis introspector from walking down the
> > Cayenne Persistor interface, or
> >
>
> I'd imagine this ought to be possible by writing a FacetFactory similar
> to RemoveJavaLangObjectMethodsFacetFactory
> or RemoveJavaLangComparableMethodsFacetFactory.  This would remove any of
> the methods in the provided type (ie the cayenne interface).
>
>
>
>
> > 2) Do some byte-code magic that is somehow able to wrap the users
> > domain class picked up by Isis into something which implements
> > Persisted, and can be given to Cayenne to instantiate.
> >
>
> This would be more elegant, but also more work.
>
> The CgLibClassProxyFactory (and Javassist equivalent) work by (on-the-fly)
> creating a subclass of the provided class.  I imagine that this subclass
> could implement the cayenne interface.
>
>
>
> >
> > Option 2 requires me to somehow create a 1-to-1 mapping between
> > user domain POJOs and runtime contructed classes that implement
> > the Persisted interface, which Cayenne can instantiate, but that I can
> > use to intercept Cayenne methods.
> >
> > Is this possible? To create new classes, based on existing classes,
> > that can be instantiated?
> >
> Yup, it's what we do...
>
>
> ~~~
> Just another thought; I know you have a distaste of the JPA annotations
> etc, but even so my JPA object store - currently mothballed because it has
> a dependency on the LGPL Hibernate library - might be easier to get fully
> working, probably by porting to OpenJPA [1].  My view, for what it's worth,
> is that JPA is more mainstream than Cayenne (and would help Isis grow its
> userbase if we had it as a supported object store....).
>
> I think that Mark is involved in OpenJPA - Mark, can you comment on how
> OpenJPA picks up its metadata: is it only annotations, or is it optionally
> XML, or even can it just infer some stuff?
>
> Cheers
> Dan
>
>
AFAIK, you can use both, and if it follows the same way of JEE deployment
descriptors XML can override annotations - Mark please correct me if I am
wrong :).


>
>
> [1] http://openjpa.apache.org/
>
>
>
> >
> > Regards,
> > Kevin
> >
> >
> >
>



-- 
Thanks
- Mohammad Nour
----
"Life is like riding a bicycle. To keep your balance you must keep moving"
- Albert Einstein

Re: Some help with supporting Cayenne

Posted by Kevin Meyer - KMZ <ke...@kmz.co.za>.
> >
> > I have two options:
> > 1) Somehow disable the Isis introspector from walking down the
> > Cayenne Persistor interface, or
> >
> 
> I'd imagine this ought to be possible by writing a FacetFactory similar
> to RemoveJavaLangObjectMethodsFacetFactory
> or RemoveJavaLangComparableMethodsFacetFactory.  This would remove any of
> the methods in the provided type (ie the cayenne interface).
> 

It was easy enough to install a FacetFactory that removed the 
offending class. In isis.properties:
isis.reflector.facets.include=isis.persistor.cayenne.installer.CayenneClassRemover

where:
public class CayenneClassRemover extends AbstractRemoveMethodsFacetFactory {
    public CayenneClassRemover() {
        super(CayenneDataObject.class);
    }
}

To solve a greater problem, I'd still like to know if CgLib (or others) can 
create new instantiable classes at runtime...

Regards,
Kevin


Re: Some help with supporting Cayenne

Posted by Dan Haywood <da...@haywood-associates.co.uk>.
On 12 December 2011 05:00, Kevin Meyer - KMZ <ke...@kmz.co.za> wrote:

>
> > I'd imagine this ought to be possible by writing a FacetFactory
> similar...
>
> This might also have been able to solve the earlier problems faced by
> Iain Flynn[1] earlier.
>

Indeed; oh well.



>
> >
> > The CgLibClassProxyFactory (and Javassist equivalent) work by
> (on-the-fly)
> > creating a subclass of the provided class.
>
> Do they operate on *instances* of the class (e.g. after New ), or on
> definitions of the class: If I have
> class Customer {
> }
>
> can I use CgLibClassProxyFactory to runtime create:
> class CgCustomer extends Customer implements Persistor {
> }
>
> so that Cayenne can call "newInstance" and create an instance of
> CgCustomer ?
>
>
They work on definitions of the class.

However, I think I gave you bad information there.  Was just digging into
the code, and the CgLibClassProxy is only used by the wrapping domain
container, which is part of the infrastructure for the JUnit test runner.

The class I should have cited is the CgLibObjectFactory (and its javassist
equivalent).  This implements ObjectFactory interface, and is accessible
directly from the PersistenceSession.

For example, CgLibObjectFactory has:

public class CglibObjectFactory extends ObjectFactoryAbstract {
    private ObjectResolveAndObjectChangedEnhancer classEnhancer;

    @Override
    public void open() {
        ...
        classEnhancer =
            new ObjectResolveAndObjectChangedEnhancer(objectResolver,
objectChanger, getSpecificationLoader());
    }

    @Override
    public <T> T doInstantiate(final Class<T> cls) throws
ObjectInstantiationException {
        return classEnhancer.newInstance(cls);
    }
}


where


public class ObjectResolveAndObjectChangedEnhancer extends
ObjectResolveAndObjectChangedEnhancerAbstract {
   ...
    public <T> T newInstance(final Class<T> cls) {
        final Enhancer enhancer = lookupOrCreateEnhancerFor(cls);
        return (T) enhancer.create();
    }

    private Enhancer lookupOrCreateEnhancerFor(final Class<?> cls) {
        Enhancer enhancer = enhancerByClass.get(cls);
        if (enhancer == null) {
            enhancer = new Enhancer();
            enhancer.setSuperclass(cls);
            enhancer.setInterfaces(ArrayUtils.combine(cls.getInterfaces(),
new Class<?>[] { CglibEnhanced.class }));
            enhancer.setCallback(callback);
            enhancerByClass.put(cls, enhancer);
        }
        return enhancer;
    }
}

That "setInterfaces" call is the one that's of interest to you.

~~~
In terms of implementation, you could either clone the entire
implementation and edit in isis.properties, or you could perhaps add some
new configuration keys, eg:

isis.persistor.object-factory=org.apache.isis.runtimes.dflt.bytecode.dflt.objectfactory.CglibObjectFactory
isis.persistor.object-factory.interfaces=org.apache.cayenne.foobar.SomePersistor





> > ~~~
> > Just another thought; I know you have a distaste of the JPA annotations
> > etc, but even so my JPA object store - currently mothballed because it
> has
> > a dependency on the LGPL Hibernate library - might be easier to get fully
> > working, probably by porting to OpenJPA [1].  My view, for what it's
> worth,
> > is that JPA is more mainstream than Cayenne (and would help Isis grow its
> > userbase if we had it as a supported object store....).
>
> The other option could be to provide a decorator / annotator service to
> automagically add annotations based on assumptions, similar to how
> the SQL objectstore creates automappers at the moment?
>

Maybe.  That might be trickier to do, though (it wouldn't be similar to
anything we've done thus far, at any rate).



>
> And what about JDO?
>

JDO is also fine with me; we have a JIRA ISIS-14 to do something in this
space.

HTH
Dan



>
> > I think that Mark is involved in OpenJPA - Mark, can you comment on how
> > OpenJPA picks up its metadata: is it only annotations, or is it
> optionally
> > XML, or even can it just infer some stuff?
> >
> > [1] http://openjpa.apache.org/
>
> [1] http://isis.markmail.org/message/z6ssovojrniuttkd
>
>

Re: Some help with supporting Cayenne

Posted by Kevin Meyer - KMZ <ke...@kmz.co.za>.
> > Problem is, this interface kills the Isis introspector - it eventually hits
> > interface org.apache.cayenne.util.XMLSerializable, which has a List
> > (Collection) parameter.
> >
> > I have two options:
> > 1) Somehow disable the Isis introspector from walking down the
> > Cayenne Persistor interface, or
> >
> 
> I'd imagine this ought to be possible by writing a FacetFactory similar
> to RemoveJavaLangObjectMethodsFacetFactory
> or RemoveJavaLangComparableMethodsFacetFactory.  This would remove any of
> the methods in the provided type (ie the cayenne interface).

This might also have been able to solve the earlier problems faced by 
Iain Flynn[1] earlier.

> > 2) Do some byte-code magic that is somehow able to wrap the users
> > domain class picked up by Isis into something which implements
> > Persisted, and can be given to Cayenne to instantiate.
> >
> 
> This would be more elegant, but also more work.
> 
> The CgLibClassProxyFactory (and Javassist equivalent) work by (on-the-fly)
> creating a subclass of the provided class.  I imagine that this subclass
> could implement the cayenne interface.

Do they operate on *instances* of the class (e.g. after New ), or on 
definitions of the class: If I have 
class Customer {
}

can I use CgLibClassProxyFactory to runtime create:
class CgCustomer extends Customer implements Persistor {
}

so that Cayenne can call "newInstance" and create an instance of 
CgCustomer ?

> ~~~
> Just another thought; I know you have a distaste of the JPA annotations
> etc, but even so my JPA object store - currently mothballed because it has
> a dependency on the LGPL Hibernate library - might be easier to get fully
> working, probably by porting to OpenJPA [1].  My view, for what it's worth,
> is that JPA is more mainstream than Cayenne (and would help Isis grow its
> userbase if we had it as a supported object store....).

The other option could be to provide a decorator / annotator service to 
automagically add annotations based on assumptions, similar to how 
the SQL objectstore creates automappers at the moment?

And what about JDO?
 
> I think that Mark is involved in OpenJPA - Mark, can you comment on how
> OpenJPA picks up its metadata: is it only annotations, or is it optionally
> XML, or even can it just infer some stuff?
> 
> [1] http://openjpa.apache.org/

[1] http://isis.markmail.org/message/z6ssovojrniuttkd


Re: Some help with supporting Cayenne

Posted by Dan Haywood <da...@haywood-associates.co.uk>.
On 11 December 2011 16:32, Kevin Meyer - KMZ <ke...@kmz.co.za> wrote:

>
> Problem is, this interface kills the Isis introspector - it eventually hits
> interface org.apache.cayenne.util.XMLSerializable, which has a List
> (Collection) parameter.
>
> I have two options:
> 1) Somehow disable the Isis introspector from walking down the
> Cayenne Persistor interface, or
>

I'd imagine this ought to be possible by writing a FacetFactory similar
to RemoveJavaLangObjectMethodsFacetFactory
or RemoveJavaLangComparableMethodsFacetFactory.  This would remove any of
the methods in the provided type (ie the cayenne interface).




> 2) Do some byte-code magic that is somehow able to wrap the users
> domain class picked up by Isis into something which implements
> Persisted, and can be given to Cayenne to instantiate.
>

This would be more elegant, but also more work.

The CgLibClassProxyFactory (and Javassist equivalent) work by (on-the-fly)
creating a subclass of the provided class.  I imagine that this subclass
could implement the cayenne interface.



>
> Option 2 requires me to somehow create a 1-to-1 mapping between
> user domain POJOs and runtime contructed classes that implement
> the Persisted interface, which Cayenne can instantiate, but that I can
> use to intercept Cayenne methods.
>
> Is this possible? To create new classes, based on existing classes,
> that can be instantiated?
>
Yup, it's what we do...


~~~
Just another thought; I know you have a distaste of the JPA annotations
etc, but even so my JPA object store - currently mothballed because it has
a dependency on the LGPL Hibernate library - might be easier to get fully
working, probably by porting to OpenJPA [1].  My view, for what it's worth,
is that JPA is more mainstream than Cayenne (and would help Isis grow its
userbase if we had it as a supported object store....).

I think that Mark is involved in OpenJPA - Mark, can you comment on how
OpenJPA picks up its metadata: is it only annotations, or is it optionally
XML, or even can it just infer some stuff?

Cheers
Dan



[1] http://openjpa.apache.org/



>
> Regards,
> Kevin
>
>
>