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



--
Internal Virus Database is out-of-date.
Checked by AVG. Version: 7.5.519 / Virus Database: 269.21.7 - Release Date: 8/03/2008 12:00 AM

Reply via email to