Hi Craig, I posted the original issue Iain mentioned in his first post and have opened a JIRA (https://issues.apache.org/jira/browse/OPENJPA-524) with a test case attached to it that reproduces the problem.
Hope this helps. Amit -----Original Message----- From: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED] Sent: Thursday, March 27, 2008 7:04 PM To: [email protected] Cc: [EMAIL PROTECTED] Subject: Re: PCEnhancer and MappedSuperclass problem??? Hi Iain, If you could file a JIRA with a (very) small test case attached showing this problem, it will be easier to have some enterprising community member take a closer look. And we can put the test case into the regression suite. From examination, I can't tell where the problem is. Thanks, Craig On Mar 26, 2008, at 8:04 PM, iain wrote: > FWIW, if I remove the inheritance of the MappedSuperclass, the > enhancer has no trouble with my application and things operate as > they should. This seems to indicate that there is a problem with > enhancing inheritance heirarchies, and certainly looks to have > something to do with cycle detection, but I don't know the OpenJPA > code so that is speculation at best > > At this stage, I'd recommend steering clear of inheritance... > > Cheers, Iain > > iain wrote: >> Last month another user posted the following message to the mailing >> list but no-one >> was able to help: >> >> http://mail-archives.apache.org/mod_mbox/openjpa-users/200802.mbox/ajax/ [EMAIL PROTECTED] >> >> I'm posting a follow-up because I'm experiencing the same symptom >> with openjpa-1.0.2. >> >> My scenario is a little different to the previous post, and I'll >> try to summarise here. >> If I need to post more detail, just let me know. There is something >> strange happening here if >> you can make it through to the end where I describe a "work-around" >> to the out-of-memory condition. >> >> First, here is the tail-end of the trace when I startup my >> application. >> I'll reproduce the comment in the OpenJPA code for >> MetaDataRepository.processBuffer - it sounds relevant: >> >> // continually pop a metadata and process it until we run >> out; note >> // that each processing call might place more metas in the >> buffer as >> // one class tries to access metadata for another; also note >> that the >> // buffer orders itself from least to most derived >> >> >> Exception in thread "AWT-EventQueue-0" java.lang.OutOfMemoryError: >> Java heap space >> at java.util.ArrayList.ensureCapacity(ArrayList.java:169) >> at java.util.ArrayList.add(ArrayList.java:351) >> at >> org >> .apache >> .openjpa >> .meta.MetaDataRepository.processBuffer(MetaDataRepository.java:676) >> at >> org >> .apache >> .openjpa >> .meta.MetaDataRepository.resolveMeta(MetaDataRepository.java:575) >> at >> org >> .apache >> .openjpa.meta.MetaDataRepository.resolve(MetaDataRepository.java:500) >> at >> org >> .apache >> .openjpa >> .meta.MetaDataRepository.getMetaData(MetaDataRepository.java:302) >> at >> org.apache.openjpa.enhance.PCEnhancer.<init>(PCEnhancer.java:241) >> at >> org.apache.openjpa.enhance.PCEnhancer.<init>(PCEnhancer.java:212) >> at >> org.apache.openjpa.enhance.PCEnhancer.<init>(PCEnhancer.java:182) >> at >> org >> .apache >> .openjpa >> .enhance >> .ManagedClassSubclasser >> .prepareUnenhancedClasses(ManagedClassSubclasser.java:119) >> at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) >> at >> sun >> .reflect >> .NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) >> at >> sun >> .reflect >> .DelegatingMethodAccessorImpl >> .invoke(DelegatingMethodAccessorImpl.java:25) >> at java.lang.reflect.Method.invoke(Method.java:585) >> at >> org >> .apache >> .openjpa >> .kernel >> .AbstractBrokerFactory >> .loadPersistentTypes(AbstractBrokerFactory.java:297) >> at >> org >> .apache >> .openjpa >> .kernel.AbstractBrokerFactory.newBroker(AbstractBrokerFactory.java: >> 199) >> at >> org >> .apache >> .openjpa >> .kernel >> .DelegatingBrokerFactory.newBroker(DelegatingBrokerFactory.java:142) >> at >> org >> .apache >> .openjpa >> .persistence >> .EntityManagerFactoryImpl >> .createEntityManager(EntityManagerFactoryImpl.java:192) >> at >> org >> .apache >> .openjpa >> .persistence >> .EntityManagerFactoryImpl >> .createEntityManager(EntityManagerFactoryImpl.java:145) >> at >> org >> .apache >> .openjpa >> .persistence >> .EntityManagerFactoryImpl >> .createEntityManager(EntityManagerFactoryImpl.java:56) >> at >> au >> .com.crabhill.hydrogeoreports.ORMHelper.openSession(ORMHelper.java: >> 38) >> at >> au >> .com >> .crabhill >> .hydrogeoreports.ClientModel.reloadClients(ClientModel.java:206) >> at >> au.com.crabhill.hydrogeoreports.ClientModel.<init>(ClientModel.java: >> 31) >> at >> au >> .com >> .crabhill >> .hydrogeoreports >> .HydrogeoReportsView.<init>(HydrogeoReportsView.java:69) >> at >> au >> .com >> .crabhill >> .hydrogeoreports.HydrogeoReportsApp.startup(HydrogeoReportsApp.java: >> 19) >> at org.jdesktop.application.Application >> $1.run(Application.java:171) >> at >> java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:209) >> at java.awt.EventQueue.dispatchEvent(EventQueue.java:461) >> at >> java >> .awt >> .EventDispatchThread >> .pumpOneEventForHierarchy(EventDispatchThread.java:242) >> at >> java >> .awt >> .EventDispatchThread >> .pumpEventsForHierarchy(EventDispatchThread.java:163) >> at >> java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:157) >> at >> java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:149) >> >> OK, so I seem to have the PCEnhancer thrashing about trying to work >> out my class metadata, >> so here are the relevant bits (at least I hope the relevant bits): >> >> @MappedSuperclass >> public abstract class ContactMech extends AbstractBean implements >> Serializable { >> // @Id field omitted for brevity >> >> @ManyToOne(cascade = {CascadeType.MERGE, CascadeType.REFRESH}) >> @ForeignKey >> @JoinColumn(name = "client_id", referencedColumnName = >> "client_id", nullable=false) >> protected Client clientId; >> // This is a bidirectional parent-child mapping and the parent >> class (Client) >> // includes the required 'mappedBy' attribute in the corresponding >> // @OneToMany >> >> @ManyToOne(cascade = {CascadeType.MERGE, CascadeType.REFRESH}) >> @ForeignKey >> @JoinColumn(name = "contact_mech_type_id", referencedColumnName = >> "type_id", nullable=false) >> protected ContactMechType contactMechTypeId; >> // This is a unidirectional mapping, so no 'mappedBy' in TypeClass >> ... >> } >> >> @Entity >> @Table(name = "client") >> public class Client implements Serializable { >> // @Id field omitted for brevity >> >> // See below for the owning side of these bidirectional >> relationships... >> @OneToMany(fetch = FetchType.LAZY, cascade = {CascadeType.MERGE, >> CascadeType.REMOVE, CascadeType.REFRESH}, mappedBy = "clientId") >> @OrderBy("emailAddress ASC") >> private List<CMEmail> emails; >> @OneToMany(fetch = FetchType.LAZY, cascade = >> {CascadeType.MERGE, CascadeType.REMOVE, CascadeType.REFRESH}, >> mappedBy = "clientId") >> @OrderBy("areaCode ASC, phoneNum ASC") >> private List<CMTelecom> telecoms; >> @OneToMany(fetch = FetchType.LAZY, cascade = >> {CascadeType.MERGE, CascadeType.REMOVE, CascadeType.REFRESH}, >> mappedBy = "clientId") >> private List<CMAddress> addresses; >> ... >> } >> Note in the following there is a self-referencing mapping >> (implementing a type hierarchy). >> @Entity >> @Table(name = "contact_mech_type") >> public class ContactMechType implements Serializable { >> @Id >> @Column(name = "type_id", nullable = false) >> private String typeId; >> @ManyToOne(fetch = FetchType.EAGER) >> @ForeignKey >> @JoinColumn(name = "parent_type_id", referencedColumnName = >> "type_id", nullable = true) >> private ContactMechType parentType; >> // This is the inverse of the above >> @OneToMany(fetch = FetchType.EAGER, mappedBy = "parentType") >> private List<ContactMechType> subTypes; >> ... >> } >> >> Then I have three (3) subclasses of ContactMech which add an extra >> few fields, one of >> which is a JoinTable mapping: >> >> @Entity >> @Table(name = "email") >> // Do I need the following if I don't plan to inherit from THIS >> class. Obviously I inherit from the MappedSuperclass above, >> // but not sure what effect the @Inheritance annotation has on this >> class. >> @Inheritance(strategy=InheritanceType.TABLE_PER_CLASS) >> public class CMEmail extends ContactMech implements Serializable { >> // Simple @Column fields ommitted for brevity >> >> // More on this one in a minute @ManyToMany(fetch = >> FetchType.EAGER) >> @JoinTable( >> name = "email_purpose", joinColumns = >> [EMAIL PROTECTED](name = "contact_mech_id", referencedColumnName = >> "contact_mech_id")}, >> inverseJoinColumns = [EMAIL PROTECTED](name = "purpose_type_id", >> referencedColumnName = "purpose_id")} >> ) >> private List<ContactMechPurposeType> purposes; >> ... >> } >> >> @Entity >> @Table(name = "telecom") >> @Inheritance(strategy=InheritanceType.TABLE_PER_CLASS) >> public class CMTelecom extends ContactMech implements Serializable { >> >> // As above, but we use a different JoinTable... >> @ManyToMany(fetch = FetchType.EAGER) >> @JoinTable( >> name = "telecom_purpose", joinColumns = >> [EMAIL PROTECTED](name = "contact_mech_id", referencedColumnName = >> "contact_mech_id")}, >> inverseJoinColumns = [EMAIL PROTECTED](name = "purpose_type_id", >> referencedColumnName = "purpose_id")} >> ) >> private List<ContactMechPurposeType> purposes; >> ... >> } >> >> @Entity >> @Table(name = "address") >> @Inheritance(strategy=InheritanceType.TABLE_PER_CLASS) >> public class CMAddress extends ContactMech implements Serializable { >> >> // Ditto @ManyToMany(fetch = FetchType.EAGER) >> @JoinTable( >> name = "address_purpose", joinColumns = >> [EMAIL PROTECTED](name = "contact_mech_id", referencedColumnName = >> "contact_mech_id")}, >> inverseJoinColumns = [EMAIL PROTECTED](name = "purpose_type_id", >> referencedColumnName = "purpose_id")} >> ) >> private List<ContactMechPurposeType> purposes; >> ... >> } >> >> Last but not least... >> >> @Entity >> @Table(name = "contact_mech_purpose_type") >> public class ContactMechPurposeType implements Serializable { >> // Omitted @Id field and various @Column fields for brevity >> >> @ManyToOne >> @ForeignKey >> @JoinColumn(name = "type_id", referencedColumnName = "type_id", >> nullable=false) >> private ContactMechType typeId; >> ... >> } >> >> What concerns me about my class network is circular references and >> what PCEnhancer is doing to >> them (given the comment I pasted from the OpenJPA source, above). >> >> To summarise, here's the reference table for all the classes above >> (and which classes they references): >> >> Client: CMEmail, CMTelecom, CMAddress >> - these references are all backpointers in bidirectionals >> CMEmail: Client, ContactMechType, >> ContactMechPurposeType >> CMTelecom: Client, ContactMechType, >> ContactMechPurposeType >> CMAddress: Client, ContactMechType, >> ContactMechPurposeType >> - In the above 3, Client and ContactMechType references are via >> inheritance of ContactMechType >> ContactMechType: ContactMechType (self-reference) >> ContactMechPurposeType: ContactMechType >> >> NOW FOR THE WIERD BIT... >> >> If I change my Client class (above) to temporarily "disable" any >> one of the mappings 'emails', >> 'addresses', 'telecoms', by tagging the field as @Transient instead >> of a backpointer to the >> bidirectional mapping, this makes the mapping unidirectional at the >> other end, obviously. >> >> When I do this, I don't get the PCEnhancer memory-slurp problem, >> and the application runs!?!?! >> (except for the bits that rely on the disable field). Note I only >> have to disable ONE of these >> backpointers for things get past the memory slurp. >> >> Help!!! >> >> And thanks for your patience if got this far... >> >> Cheers, Iain >> >> >> > > > > -- > No virus found in this outgoing message. > Checked by AVG. Version: 7.5.519 / Virus Database: 269.22.0 - > Release Date: 24/03/2008 12:00 AM > Craig Russell Architect, Sun Java Enterprise System http://java.sun.com/products/jdo 408 276-5638 mailto:[EMAIL PROTECTED] P.S. A good JDO? O, Gasp!
