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!

Attachment: smime.p7s
Description: S/MIME cryptographic signature

Reply via email to