Iain, Can you expand on this? On Wed, Mar 26, 2008 at 10:04 PM, iain <[EMAIL PROTECTED]> wrote:
> FWIW, if I remove the inheritance of the MappedSuperclass, the enhancer > has no trouble with my application and things operate as they should. What exactly are you referring to when you say that you "remove the inheritance"? Removing the @Inheritance annotation? Or, actually removing the "extends" clauses? Although, if it's the latter, then how does your application work as it should? You have provided a lot of good information for this problem. I'm just trying to figure out what exactly you changed to get this to "work". Thanks, Kevin > 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 > >
