Hi Patrick,

I didn't get any attachment with your last email...  Anyway, I
understand your idea and I will look into it.

Thanks for the help!

Christian


On 7/13/07, Patrick Linskey <[EMAIL PROTECTED]> wrote:
Hmm. It looks like between how OpenJPA deals with Collection-typed
fields and the non-extensibility of EnumSet and its hierarchy, it's
not possible to use EnumSet fields currently. OpenJPA could be changed
to allow this, but it would not be trivial. (It wouldn't be that hard,
either. Just non-trivial.)

Meanwhile, I think that the only way to use EnumSet fields is to
create a separate holder class of your own that provides a means to
get its EnumSet. This would isolate OpenJPA from the fact that EnumSet
happens to implement Collection, even though it doesn't meet the
contract that we require of Collection. You would then mark that field
as @Persistent and provide an externalizer for it.

I created a test case + sample class hierarchy that demonstrates this
workaround. With this workaround, you would need to manually dirty the
delegating field when you change the contents of the EnumSet, or if
you mutate the holder's EnumSet field directly. To prevent this from
being an issue, my code example returns an unmodifiable view on the
set, so the only way to change the values is via the setter. I've
attached the core class to this email; I tried to create a JIRA case,
but my internet connection is really flaky today, and I was unable to
reach apache.org reliably.

-Patrick

On 7/13/07, Christian Defoy <[EMAIL PROTECTED]> wrote:
> I tried with the following annotations:
>     @Persistent
>     @Type( String.class )
>     @Externalizer( "Shape.typesToString" )
>     @Factory( "Shape.typesFromString" )
>     @Column( name="shape_types" )
>
> I also made an attempt without Externalizer and Factory and another
> one with ElementType instead of Type.  In every case, I get the same
> error message. :(
>
> Christian
>
> On 7/13/07, Patrick Linskey <[EMAIL PROTECTED]> wrote:
> > Hmm. You may also need to specify the type of the externalized value
> > for the field; I thought that this happened automatically.
> >
> > Try specifying @Type(String.class) on the field as well.
> >
> > -Patrick
> >
> > On 7/13/07, Christian Defoy <[EMAIL PROTECTED]> wrote:
> > > Hi Patrick,
> > >
> > > Thanks for the answer.  You guess correctly when you say that I want a
> > > stringified version of my EnumSet. :)
> > >
> > > I tried to simply mark it @Persistent instead of @PersistentCollection
> > > but I got a different error message:
> > >
> > >  org.apache.openjpa.util.MetaDataException: The type of field
> > > "Shape.types" isn't supported by declared persistence strategy
> > > "Persistent".  Please choose a different strategy.
> > >         at 
org.apache.openjpa.persistence.AnnotationPersistenceMetaDataParser.parsePersistent(AnnotationPersistenceMetaDataParser.java:1351)
> > >         at 
org.apache.openjpa.persistence.AnnotationPersistenceMetaDataParser.parseMemberAnnotations(AnnotationPersistenceMetaDataParser.java:952)
> > >         at 
org.apache.openjpa.persistence.AnnotationPersistenceMetaDataParser.parseClassAnnotations(AnnotationPersistenceMetaDataParser.java:599)
> > >         at 
org.apache.openjpa.persistence.AnnotationPersistenceMetaDataParser.parse(AnnotationPersistenceMetaDataParser.java:349)
> > >         at 
org.apache.openjpa.persistence.PersistenceMetaDataFactory.load(PersistenceMetaDataFactory.java:227)
> > >         at 
org.apache.openjpa.meta.MetaDataRepository.getMetaDataInternal(MetaDataRepository.java:421)
> > >         at 
org.apache.openjpa.meta.MetaDataRepository.getMetaData(MetaDataRepository.java:277)
> > >         at 
org.apache.openjpa.enhance.PCEnhancer.<init>(PCEnhancer.java:221)
> > >         at 
org.apache.openjpa.enhance.PCEnhancer.<init>(PCEnhancer.java:194)
> > >         at 
org.apache.openjpa.enhance.PCClassFileTransformer.transform(PCClassFileTransformer.java:127)
> > >         at 
sun.instrument.TransformerManager.transform(TransformerManager.java:122)
> > >         at 
sun.instrument.InstrumentationImpl.transform(InstrumentationImpl.java:155)
> > >         at java.lang.ClassLoader.defineClass1(Native Method)
> > >         at java.lang.ClassLoader.defineClass(ClassLoader.java:620)
> > >         at 
java.security.SecureClassLoader.defineClass(SecureClassLoader.java:124)
> > >         at java.net.URLClassLoader.defineClass(URLClassLoader.java:260)
> > >         at java.net.URLClassLoader.access$100(URLClassLoader.java:56)
> > >         at java.net.URLClassLoader$1.run(URLClassLoader.java:195)
> > >         at java.security.AccessController.doPrivileged(Native Method)
> > >         at java.net.URLClassLoader.findClass(URLClassLoader.java:188)
> > >         at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
> > >         at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:268)
> > >         at java.lang.ClassLoader.loadClass(ClassLoader.java:251)
> > >         at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:319)
> > >         at java.lang.Class.forName0(Native Method)
> > >         at java.lang.Class.forName(Class.java:242)
> > >         at 
org.apache.openjpa.meta.MetaDataRepository.classForName(MetaDataRepository.java:1234)
> > >         at 
org.apache.openjpa.meta.MetaDataRepository.loadPersistentTypes(MetaDataRepository.java:1222)
> > >         at 
org.apache.openjpa.kernel.AbstractBrokerFactory.loadPersistentTypes(AbstractBrokerFactory.java:240)
> > >         at 
org.apache.openjpa.kernel.AbstractBrokerFactory.newBroker(AbstractBrokerFactory.java:192)
> > >         at 
org.apache.openjpa.kernel.DelegatingBrokerFactory.newBroker(DelegatingBrokerFactory.java:142)
> > >         at 
org.apache.openjpa.persistence.EntityManagerFactoryImpl.createEntityManager(EntityManagerFactoryImpl.java:190)
> > >         at 
org.apache.openjpa.persistence.EntityManagerFactoryImpl.createEntityManager(EntityManagerFactoryImpl.java:143)
> > >         at 
org.apache.openjpa.persistence.EntityManagerFactoryImpl.createEntityManager(EntityManagerFactoryImpl.java:55)
> > >         at ShapeHelper.main(ShapeHelper.java:21)
> > >
> > > Could it be that I need to specify something in my persistence.xml or
> > > put annotations in my enum?  I tried a few variations but without
> > > success...
> > >
> > > Christian
> > >
> > > On 7/13/07, Patrick Linskey <[EMAIL PROTECTED]> wrote:
> > > > Hi,
> > > >
> > > > Externalizers and factories apply to the entire instance, not to the
> > > > innards of the collection. I think that you've got things in a bit of
> > > > a hybrid state right now.
> > > >
> > > > First, the problem is happening because EnumSet is an abstract type.
> > > > The only way to get EnumSet instances is by using the static methods
> > > > in the EnumSet class. Sadly, this is in stark contrast to the
> > > > contracts outlined in the Javadoc for java.util.Collection, and
> > > > OpenJPA requires compliance with some of those contracts. Put more
> > > > simply, OpenJPA does not natively support EnumSet at this time. IMO,
> > > > it would be worthwhile to add support for EnumSet (and EnumMap) at
> > > > some point. However, this might be difficult / limiting due to the
> > > > lack of extensibility of the EnumSet type and its subtypes.
> > > >
> > > > So, in terms of a solution: how do you want this data to be mapped to
> > > > the database? Are you looking to have a single column in a table that
> > > > contains the Stringified representation of the EnumSet, or are you
> > > > looking to have a join table with rows for each Stringified enum value
> > > > in the set? Given the method names in your externalizer and factory,
> > > > I'm going to assume the former.
> > > >
> > > > In this case, the field is not really a persistent collection from
> > > > OpenJPA's standpoint. You'll want to just mark it as @Persistent
> > > > instead of @PersistentCollection. Once you've done this, one of two
> > > > things will happen:
> > > >
> > > > 1. you will still get the second-class object problem
> > > >
> > > > or 2. it will work without an exception, but changes you make to the
> > > > collection will not be noticed. If you set the field to a new value,
> > > > the change will be detected, but mutations to the data structure
> > > > itself will not. Currently, there is no way around this -- you'll need
> > > > to explicitly dirty the field (OpenJPAEntityManager.dirty(o,
> > > > "nameOfEnumSetField")) when you mutate the record.
> > > >
> > > >
> > > > If you run into the first case, we'll need to change OpenJPA to allow
> > > > bypassing of proxy logic somehow.
> > > >
> > > > Also, we should probably allow field-by-field enabling of a
> > > > more-expensive dirty checking strategy so that you don't need to
> > > > manually mark the field as dirty.
> > > >
> > > > -Patrick
> > > >
> > > > On 7/13/07, Christian Defoy <[EMAIL PROTECTED]> wrote:
> > > > > Hello!
> > > > >
> > > > > Is there a way to persist an EnumSet easily with OpenJPA?  I tried
> > > > > with an externalizer:
> > > > >
> > > > >     @PersistentCollection
> > > > >     @Externalizer( "test.Shape.typesToString" )
> > > > >     @Factory( "test.Shape.typesFromString" )
> > > > >     @ElementType( String.class )
> > > > >     @Column( name="shape_types" )
> > > > >     private EnumSet<ShapeTypes> types;
> > > > >
> > > > > When I try to run this, I get the following error message, which makes
> > > > > me believe I am doing something wrong...
> > > > >
> > > > > Caused by: <0.9.7-incubating fatal general error>
> > > > > org.apache.openjpa.persistence.PersistenceException: Unable to create
> > > > > a second class object proxy for abstract type "class
> > > > > java.util.EnumSet".  You must use a concrete type or a recognized
> > > > > interface.
> > > > >         at 
org.apache.openjpa.util.ProxyManagerImpl.toProxyableCollectionType(ProxyManagerImpl.java:320)
> > > > >         at 
org.apache.openjpa.util.ProxyManagerImpl.newCollectionProxy(ProxyManagerImpl.java:191)
> > > > >         at 
org.apache.openjpa.kernel.StateManagerImpl.newFieldProxy(StateManagerImpl.java:1571)
> > > > >         at 
org.apache.openjpa.kernel.SingleFieldManager.proxy(SingleFieldManager.java:104)
> > > > >         at 
org.apache.openjpa.kernel.StateManagerImpl.proxyFields(StateManagerImpl.java:2624)
> > > > >         at 
org.apache.openjpa.kernel.PNonTransState.initialize(PNonTransState.java:44)
> > > > >         at 
org.apache.openjpa.kernel.StateManagerImpl.setPCState(StateManagerImpl.java:213)
> > > > >         at 
org.apache.openjpa.kernel.StateManagerImpl.commit(StateManagerImpl.java:919)
> > > > >         at 
org.apache.openjpa.kernel.BrokerImpl.endTransaction(BrokerImpl.java:2194)
> > > > >         ... 8 more
> > > > >
> > > > > Thanks in advance!
> > > > >
> > > > > Christian
> > > > >
> > > >
> > > >
> > > > --
> > > > Patrick Linskey
> > > > 202 669 5907
> > > >
> > >
> >
> >
> > --
> > Patrick Linskey
> > 202 669 5907
> >
>


--
Patrick Linskey
202 669 5907

Reply via email to