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 bestAt 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-onewas 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 derivedException in thread "AWT-EventQueue-0" java.lang.OutOfMemoryError: Java heap spaceat 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): @MappedSuperclasspublic 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 ofwhich 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 tothem (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 bidirectionalsCMEmail: Client, ContactMechType, ContactMechPurposeType CMTelecom: Client, ContactMechType, ContactMechPurposeType CMAddress: Client, ContactMechType, ContactMechPurposeType - In the above 3, Client and ContactMechType references are via inheritance of ContactMechTypeContactMechType: 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 thesebackpointers 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!
smime.p7s
Description: S/MIME cryptographic signature
