Hi Jon,
I noticed there is a pre-update listener on the mapped superclass. Does it
ever get called? Is it just the pre-persist that never executes?
Cheers,
Guy
----- Original Message -----
From: "Jon Miller" <jemiller_at_uchicago.edu>
To: <persistence_at_glassfish.dev.java.net>
Sent: Monday, January 08, 2007 1:00 PM
Subject: Re: PrePersist method not being called
> Thanks Tom. Yeah, I have all the classes listed there now. It still isn't
> working though. I just tried a simpler test with the PrePersist method in
> the top level class and it worked. I'll have to look into it further...
>
> Thanks for the info on weaving. I recently read about that. So far I just
> been doing without it. I figure once I get further along I may need to
> enable it if performance is an issue. One thing that I'm wondering about
> the agent is: is it possible to somehow enable the agent programatically
> in the program itself, or, does it have to be passed as a command-line
> argument? I'm using TopLink with Tomcat and not using an EJB application
> server. I like the idea of being able to deploy the web app self-contained
> without having to make changes to the web server configuration such as
> passing command-line arguments to the JVM.
>
> Jon
>
> ----- Original Message -----
> From: "Tom Ware" <tom.ware_at_oracle.com>
> To: <persistence_at_glassfish.dev.java.net>
> Sent: Monday, January 08, 2007 8:28 AM
> Subject: Re: PrePersist method not being called
>
>
>> Hi Jon,
>>
>> Are you still seeing the problem now that you have listed AuditObject in
>> your persistence.xml?
>>
>> In Java SE, the JPA specification says that portable applications must
>> list the classes that will be used in the persistence.xml either with
>> <class> element, by referring to them in a file referenced by a
>> <mapping-file> element, or by placing them in a file referenced by a
>> <jar-file> element. As a result, in Java SE depending on how your
>> persistence.xml looks, we may not automatically discover your classes.
>>
>> In some Java SE Environments TopLink Essentials will be able to
>> auto-discover if you use the <exclude-unlisted-classes> element in your
>> persistence.xml and set it to false.
>>
>> FYI: You have asked a couple of questions about the javaagent, so I'll
>> give you an idea what the purpose of the agent is. In TopLink
>> Essentials, we use the javaagent to dynamically weave classes that have
>> OneToOne or ManyToOne mappings with FetchType LAZY. The weaving allows
>> us to actually retrieve the elements referenced by those mappings in a
>> LAZY manner. For those that do not wish to use the agent (or cannot use
>> it), there is also the option of using a preprocessing step for this
>> weaving. If you are interested in that step, take a look at the section
>> of the following document entitled, "Static Weaving Using the StaticWeave
>> Class on the Command Line":
>>
>> http://www.oracle.com/technology/products/ias/toplink/jpa/resources/toplink-jpa-extensions.html#LazyLoading
>>
>> -Tom
>>
>> Jon Miller wrote:
>>
>>>I thought I found what might have been the problem on my side. I wasn't
>>>listing AuditObject in my persistence.xml. Initially, I was thinking that
>>>you only would have to list the subclasses that you are using directly
>>>and that it would automatically add in the superclasses for you. I found
>>>out that this doesn't appear to be the case though (at least in
>>>standalone mode). Another thing worth mentioning is that the AuditObject
>>>class is in a different jar file. I'm not sure if that would make a
>>>difference or not. There's only one persistence.xml, but, the classes are
>>>split between two jar files.
>>>
>>>Jon
>>>
>>>----- Original Message -----
>>>From: "Jon Miller" <jemiller_at_uchicago.edu>
>>>To: <persistence_at_glassfish.dev.java.net>
>>>Sent: Friday, January 05, 2007 6:13 PM
>>>Subject: Re: PrePersist method not being called
>>>
>>>
>>>
>>>>OK, I tested it and it works with Hibernate, but, I receive the
>>>>following error with TopLink. The prePersist method is supposed to be
>>>>called which sets the lastWriteTime field. This isn't happening, so,
>>>>it's causing an exception since that field is NOT NULL.
>>>>
>>>> [junit] Caused by: Exception [TOPLINK-4002] (Oracle TopLink
>>>> Essentials - 9.1 (Build b30)): oracle.toplink.essentials
>>>>.exceptions.DatabaseException
>>>> [junit] Internal Exception: java.sql.SQLException:
>>>> [SKATE\SQLEXPRESS]Cannot insert the value NULL into column 'LastW
>>>>riteTime', table 'Schedules.dbo.Person'; column does not allow nulls.
>>>>INSERT fails.Error Code: 515
>>>> [junit] Call:INSERT INTO Person (Department, CreationUserName,
>>>> FirstName, LastName, LastWriteTime, Name, LastWriteUs
>>>>erName, MiddleName, TelephoneNumber, Title, CreationTime, Curriculum,
>>>>Address, UserName, EmailAddress, Organization, Cla
>>>>ss) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
>>>> [junit] bind => [null, null, Jonathan, Miller, null, Jonathan
>>>> Eric Miller, null, Eric, null, null, null, null, n
>>>>ull, jemiller, null, null, Schedules.Persistence.Entity.User]
>>>>
>>>>Jon
>>>>
>>>>----- Original Message -----
>>>>From: "Jon Miller" <jemiller_at_uchicago.edu>
>>>>To: <persistence_at_glassfish.dev.java.net>
>>>>Sent: Friday, January 05, 2007 5:47 PM
>>>>Subject: Re: PrePersist method not being called
>>>>
>>>>
>>>>
>>>>>OK, I tested it with V2 build 30. It still isn't getting called. I'm
>>>>>not using the agent at present. Would that matter? I'm wondering if the
>>>>>problem is that the PrePersist method is in a MappedSuperclass? I think
>>>>>that's a valid thing to do though. I think the Javadocs mention it if I
>>>>>remember correctly. I'm going to test it again with Hibernate, just to
>>>>>make sure I'm not doing something else wrong and that it does indeed
>>>>>work with Hibernate and not TopLink.
>>>>>
>>>>>Jon
>>>>>
>>>>>----- Original Message -----
>>>>>From: "Tom Ware" <tom.ware_at_oracle.com>
>>>>>To: <persistence_at_glassfish.dev.java.net>
>>>>>Sent: Thursday, January 04, 2007 2:10 PM
>>>>>Subject: Re: PrePersist method not being called
>>>>>
>>>>>
>>>>>
>>>>>>Hi Jon,
>>>>>>
>>>>>> Do you see the same behavior on the latest builds of TopLink
>>>>>> essentials (e.g. V2 build 30)? There have been quite a lot of
>>>>>> changes since the end of August (060830).
>>>>>>
>>>>>> You can get the latest version at:
>>>>>>
>>>>>>https://glassfish.dev.java.net/downloads/persistence/JavaPersistence.html
>>>>>>
>>>>>>-Tom
>>>>>>
>>>>>>Jon Miller wrote:
>>>>>>
>>>>>>
>>>>>>>Hi all,
>>>>>>>
>>>>>>>I'm using the version of Toplink Essentials that comes with NetBeans
>>>>>>>5.5. I have a class which defines a PrePersist method
>>>>>>>(AuditObject.prePersist()) which sets some values in an object
>>>>>>>(namely a timestamp which is a NOT NULL value). I'm finding that this
>>>>>>>method isn't being called when I attempt to persist an Item object
>>>>>>>(subclass of AuditObject). It works fine if I use Hibernate's
>>>>>>>implementation of JPA. Does anyone know what I might be doing wrong
>>>>>>>or if this is a known issue? So far I haven't been using the
>>>>>>>javaagent. However, I just tried it with the agent to see if that
>>>>>>>might be the problem, but, it didn't make a difference. The following
>>>>>>>is the exception that I'm receiving.
>>>>>>>
>>>>>>>Exception [TOPLINK-4002] (Oracle TopLink Essentials - 2006.8 (Build
>>>>>>>060830)): oracle.toplink.essentials.exceptions.DatabaseException
>>>>>>>Internal Exception: java.sql.SQLException: [SKATE\SQLEXPRESS]Cannot
>>>>>>>insert the value NULL into column 'LastWriteTime', table
>>>>>>>'ReservationsDev.dbo.Item'; column does not allow nulls. INSERT
>>>>>>>fails.Error Code: 515
>>>>>>>Call:INSERT INTO Item (Name, CreationUserName, Description,
>>>>>>>LastWriteUserName, LastWriteTime, CreationTime) VALUES (?, ?, ?, ?,
>>>>>>>?, ?)
>>>>>>> bind => [testSaveItem Wed Jan 03 14:43:08 CST 2007, null,
>>>>>>> Description, null, null, null]
>>>>>>>Query:InsertObjectQuery([id = null, name = "testSaveItem Wed Jan 03
>>>>>>>14:43:08 CST 2007", description = "Description"])
>>>>>>>javax.persistence.RollbackException: Exception [TOPLINK-4002] (Oracle
>>>>>>>TopLink Essentials - 2006.8 (Build 060830)):
>>>>>>>oracle.toplink.essentials.exceptions.DatabaseException
>>>>>>>Internal Exception: java.sql.SQLException: [SKATE\SQLEXPRESS]Cannot
>>>>>>>insert the value NULL into column 'LastWriteTime', table
>>>>>>>'ReservationsDev.dbo.Item'; column does not allow nulls. INSERT
>>>>>>>fails.Error Code: 515
>>>>>>>Call:INSERT INTO Item (Name, CreationUserName, Description,
>>>>>>>LastWriteUserName, LastWriteTime, CreationTime) VALUES (?, ?, ?, ?,
>>>>>>>?, ?)
>>>>>>> bind => [testSaveItem Wed Jan 03 14:43:08 CST 2007, null,
>>>>>>> Description, null, null, null]
>>>>>>>Query:InsertObjectQuery([id = null, name = "testSaveItem Wed Jan 03
>>>>>>>14:43:08 CST 2007", description = "Description"])
>>>>>>> at
>>>>>>> oracle.toplink.essentials.internal.ejb.cmp3.transaction.base.EntityTransactionImpl.commit(EntityTransactionImpl.java:109)
>>>>>>> at
>>>>>>> oracle.toplink.essentials.internal.ejb.cmp3.transaction.EntityTransactionImpl.commit(EntityTransactionImpl.java:45)
>>>>>>> at
>>>>>>> edu.uchicago.at.reservations.ReservationsService.saveItem(ReservationsService.java:254)
>>>>>>> at
>>>>>>> edu.uchicago.at.reservations.ReservationsServiceTest.testSaveGetAndRemoveItem(ReservationsServiceTest.java:44)
>>>>>>>Caused by: Exception [TOPLINK-4002] (Oracle TopLink Essentials -
>>>>>>>2006.8 (Build 060830)):
>>>>>>>oracle.toplink.essentials.exceptions.DatabaseException
>>>>>>>Internal Exception: java.sql.SQLException: [SKATE\SQLEXPRESS]Cannot
>>>>>>>insert the value NULL into column 'LastWriteTime', table
>>>>>>>'ReservationsDev.dbo.Item'; column does not allow nulls. INSERT
>>>>>>>fails.Error Code: 515
>>>>>>>Call:INSERT INTO Item (Name, CreationUserName, Description,
>>>>>>>LastWriteUserName, LastWriteTime, CreationTime) VALUES (?, ?, ?, ?,
>>>>>>>?, ?)
>>>>>>> bind => [testSaveItem Wed Jan 03 14:43:08 CST 2007, null,
>>>>>>> Description, null, null, null]
>>>>>>>Query:InsertObjectQuery([id = null, name = "testSaveItem Wed Jan 03
>>>>>>>14:43:08 CST 2007", description = "Description"])
>>>>>>> at
>>>>>>> oracle.toplink.essentials.exceptions.DatabaseException.sqlException(DatabaseException.java:295)
>>>>>>> at
>>>>>>> oracle.toplink.essentials.internal.databaseaccess.DatabaseAccessor.executeDirectNoSelect(DatabaseAccessor.java:639)
>>>>>>> at
>>>>>>> oracle.toplink.essentials.internal.databaseaccess.DatabaseAccessor.executeNoSelect(DatabaseAccessor.java:688)
>>>>>>> at
>>>>>>> oracle.toplink.essentials.internal.databaseaccess.DatabaseAccessor.basicExecuteCall(DatabaseAccessor.java:477)
>>>>>>> at
>>>>>>> oracle.toplink.essentials.internal.databaseaccess.DatabaseAccessor.executeCall(DatabaseAccessor.java:437)
>>>>>>> at
>>>>>>> oracle.toplink.essentials.internal.sessions.AbstractSession.executeCall(AbstractSession.java:675)
>>>>>>> at
>>>>>>> oracle.toplink.essentials.internal.queryframework.DatasourceCallQueryMechanism.executeCall(DatasourceCallQueryMechanism.java:213)
>>>>>>> at
>>>>>>> oracle.toplink.essentials.internal.queryframework.DatasourceCallQueryMechanism.executeCall(DatasourceCallQueryMechanism.java:199)
>>>>>>> at
>>>>>>> oracle.toplink.essentials.internal.queryframework.DatasourceCallQueryMechanism.insertObject(DatasourceCallQueryMechanism.java:331)
>>>>>>> at
>>>>>>> oracle.toplink.essentials.internal.queryframework.StatementQueryMechanism.insertObject(StatementQueryMechanism.java:176)
>>>>>>> at
>>>>>>> oracle.toplink.essentials.internal.queryframework.StatementQueryMechanism.insertObject(StatementQueryMechanism.java:190)
>>>>>>> at
>>>>>>> oracle.toplink.essentials.internal.queryframework.DatabaseQueryMechanism.insertObjectForWrite(DatabaseQueryMechanism.java:457)
>>>>>>> at
>>>>>>> oracle.toplink.essentials.queryframework.InsertObjectQuery.executeCommit(InsertObjectQuery.java:74)
>>>>>>> at
>>>>>>> oracle.toplink.essentials.internal.queryframework.DatabaseQueryMechanism.performUserDefinedWrite(DatabaseQueryMechanism.java:635)
>>>>>>> at
>>>>>>> oracle.toplink.essentials.internal.queryframework.DatabaseQueryMechanism.performUserDefinedInsert(DatabaseQueryMechanism.java:599)
>>>>>>> at
>>>>>>> oracle.toplink.essentials.internal.queryframework.DatabaseQueryMechanism.insertObjectForWriteWithChangeSet(DatabaseQueryMechanism.java:495)
>>>>>>> at
>>>>>>> oracle.toplink.essentials.queryframework.WriteObjectQuery.executeCommitWithChangeSet(WriteObjectQuery.java:130)
>>>>>>> at
>>>>>>> oracle.toplink.essentials.internal.queryframework.DatabaseQueryMechanism.executeWriteWithChangeSet(DatabaseQueryMechanism.java:283)
>>>>>>> at
>>>>>>> oracle.toplink.essentials.queryframework.WriteObjectQuery.executeDatabaseQuery(WriteObjectQuery.java:67)
>>>>>>> at
>>>>>>> oracle.toplink.essentials.queryframework.DatabaseQuery.execute(DatabaseQuery.java:609)
>>>>>>> at
>>>>>>> oracle.toplink.essentials.queryframework.DatabaseQuery.executeInUnitOfWork(DatabaseQuery.java:536)
>>>>>>> at
>>>>>>> oracle.toplink.essentials.queryframework.ObjectLevelModifyQuery.executeInUnitOfWorkObjectLevelModifyQuery(ObjectLevelModifyQuery.java:123)
>>>>>>> at
>>>>>>> oracle.toplink.essentials.queryframework.ObjectLevelModifyQuery.executeInUnitOfWork(ObjectLevelModifyQuery.java:95)
>>>>>>> at
>>>>>>> oracle.toplink.essentials.internal.sessions.UnitOfWorkImpl.internalExecuteQuery(UnitOfWorkImpl.java:2218)
>>>>>>> at
>>>>>>> oracle.toplink.essentials.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:937)
>>>>>>> at
>>>>>>> oracle.toplink.essentials.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:894)
>>>>>>> at
>>>>>>> oracle.toplink.essentials.internal.sessions.CommitManager.commitNewObjectsForClassWithChangeSet(CommitManager.java:254)
>>>>>>> at
>>>>>>> oracle.toplink.essentials.internal.sessions.CommitManager.commitAllObjectsWithChangeSet(CommitManager.java:175)
>>>>>>> at
>>>>>>> oracle.toplink.essentials.internal.sessions.AbstractSession.writeAllObjectsWithChangeSet(AbstractSession.java:2638)
>>>>>>> at
>>>>>>> oracle.toplink.essentials.internal.sessions.UnitOfWorkImpl.commitToDatabase(UnitOfWorkImpl.java:1030)
>>>>>>> at
>>>>>>> oracle.toplink.essentials.internal.ejb.cmp3.base.RepeatableWriteUnitOfWork.commitToDatabase(RepeatableWriteUnitOfWork.java:357)
>>>>>>> at
>>>>>>> oracle.toplink.essentials.internal.sessions.UnitOfWorkImpl.commitToDatabaseWithChangeSet(UnitOfWorkImpl.java:1112)
>>>>>>> at
>>>>>>> oracle.toplink.essentials.internal.ejb.cmp3.base.RepeatableWriteUnitOfWork.commitRootUnitOfWork(RepeatableWriteUnitOfWork.java:82)
>>>>>>> at
>>>>>>> oracle.toplink.essentials.internal.sessions.UnitOfWorkImpl.commitAndResume(UnitOfWorkImpl.java:842)
>>>>>>> at
>>>>>>> oracle.toplink.essentials.internal.ejb.cmp3.transaction.base.EntityTransactionImpl.commit(EntityTransactionImpl.java:90)
>>>>>>> ... 18 more
>>>>>>>Caused by: java.sql.SQLException: [SKATE\SQLEXPRESS]Cannot insert the
>>>>>>>value NULL into column 'LastWriteTime', table
>>>>>>>'ReservationsDev.dbo.Item'; column does not allow nulls. INSERT
>>>>>>>fails.
>>>>>>> at com.inet.tds.a.a(Unknown Source)
>>>>>>> at com.inet.tds.c.new(Unknown Source)
>>>>>>> at com.inet.tds.c.executeUpdate(Unknown Source)
>>>>>>> at
>>>>>>> oracle.toplink.essentials.internal.databaseaccess.DatabaseAccessor.executeDirectNoSelect(DatabaseAccessor.java:632)
>>>>>>> ... 51 more
>>>>>>>
>>>>>>>// AuditObject.java
>>>>>>>package edu.uchicago.at.common.persistence.entity;
>>>>>>>
>>>>>>>import java.io.Serializable;
>>>>>>>import java.util.Date;
>>>>>>>import java.util.logging.Logger;
>>>>>>>import javax.persistence.Column;
>>>>>>>import javax.persistence.MappedSuperclass;
>>>>>>>import javax.persistence.PrePersist;
>>>>>>>import javax.persistence.PreUpdate;
>>>>>>>import javax.persistence.Temporal;
>>>>>>>import javax.persistence.TemporalType;
>>>>>>>
>>>>>>>@MappedSuperclass
>>>>>>>public abstract class AuditObject implements Serializable {
>>>>>>> private Date creationTime;
>>>>>>> private String creationUserName;
>>>>>>> private Date lastWriteTime;
>>>>>>> private String lastWriteUserName;
>>>>>>> private static Logger logger = Logger.getLogger(
>>>>>>> AuditObject.class.getName());
>>>>>>>
>>>>>>> @Column(name="CreationTime", nullable=false)
>>>>>>> @Temporal(TemporalType.TIMESTAMP)
>>>>>>> public Date getCreationTime() {
>>>>>>> return creationTime;
>>>>>>> }
>>>>>>>
>>>>>>> public void setCreationTime(Date creationTime) {
>>>>>>> this.creationTime = creationTime;
>>>>>>> }
>>>>>>>
>>>>>>> @Column(name="CreationUserName", columnDefinition="nvarchar(255)")
>>>>>>> public String getCreationUserName() {
>>>>>>> return creationUserName;
>>>>>>> }
>>>>>>>
>>>>>>> public void setCreationUserName(String creationUserName) {
>>>>>>> this.creationUserName = creationUserName;
>>>>>>> }
>>>>>>>
>>>>>>> @Column(name="LastWriteTime", nullable=false)
>>>>>>> @Temporal(TemporalType.TIMESTAMP)
>>>>>>> public Date getLastWriteTime() {
>>>>>>> return lastWriteTime;
>>>>>>> }
>>>>>>>
>>>>>>> public void setLastWriteTime(Date lastWriteTime) {
>>>>>>> this.lastWriteTime = lastWriteTime;
>>>>>>> }
>>>>>>>
>>>>>>> @Column(name="LastWriteUserName",
>>>>>>> columnDefinition="nvarchar(255)")
>>>>>>> public String getLastWriteUserName() {
>>>>>>> return lastWriteUserName;
>>>>>>> }
>>>>>>>
>>>>>>> public void setLastWriteUserName(String lastWriteUserName) {
>>>>>>> this.lastWriteUserName = lastWriteUserName;
>>>>>>> }
>>>>>>>
>>>>>>> @PrePersist
>>>>>>> public void prePersist() {
>>>>>>> Date d = new Date();
>>>>>>> setCreationTime(d);
>>>>>>> setLastWriteTime(d);
>>>>>>> }
>>>>>>>
>>>>>>> @PreUpdate
>>>>>>> public void preUpdate() {
>>>>>>> Date d = new Date();
>>>>>>> setLastWriteTime(d);
>>>>>>> }
>>>>>>>}
>>>>>>>
>>>>>>>// Item.java
>>>>>>>package edu.uchicago.at.reservations.persistence.entity;
>>>>>>>
>>>>>>>import edu.uchicago.at.common.persistence.entity.AuditObject;
>>>>>>>import java.util.ArrayList;
>>>>>>>import java.util.Collection;
>>>>>>>import javax.persistence.Column;
>>>>>>>import javax.persistence.Entity;
>>>>>>>import javax.persistence.GeneratedValue;
>>>>>>>import javax.persistence.GenerationType;
>>>>>>>import javax.persistence.Id;
>>>>>>>import javax.persistence.JoinColumn;
>>>>>>>import javax.persistence.JoinTable;
>>>>>>>import javax.persistence.ManyToMany;
>>>>>>>import javax.persistence.Table;
>>>>>>>
>>>>>>>@Entity
>>>>>>>@Table(name="Item")
>>>>>>>public class Item extends AuditObject {
>>>>>>> private String description;
>>>>>>> private Integer id;
>>>>>>> private String name;
>>>>>>> private Collection<Reservation> reservations = new
>>>>>>> ArrayList<Reservation>();
>>>>>>> private Collection<Item> subItems = new ArrayList<Item>();
>>>>>>> private Collection<Item> superItems = new ArrayList<Item>();
>>>>>>>
>>>>>>> public Item() {
>>>>>>> }
>>>>>>>
>>>>>>> public Item(String name) {
>>>>>>> setName(name);
>>>>>>> }
>>>>>>>
>>>>>>> public boolean contains(Item item) {
>>>>>>> for(Item i : subItems) {
>>>>>>> if (i.id == item.id) {
>>>>>>> return true;
>>>>>>> }
>>>>>>> if (i.contains(item)) {
>>>>>>> return true;
>>>>>>> }
>>>>>>> }
>>>>>>> return false;
>>>>>>> }
>>>>>>>
>>>>>>> @Column(name="Description", columnDefinition="nvarchar(max)")
>>>>>>> public String getDescription() {
>>>>>>> return description;
>>>>>>> }
>>>>>>>
>>>>>>> public void setDescription(String description) {
>>>>>>> this.description = description;
>>>>>>> }
>>>>>>>
>>>>>>> @Id
>>>>>>> @GeneratedValue(strategy = GenerationType.IDENTITY)
>>>>>>> @Column(name="Id")
>>>>>>> public Integer getId() {
>>>>>>> return id;
>>>>>>> }
>>>>>>>
>>>>>>> public void setId(Integer id) {
>>>>>>> this.id = id;
>>>>>>> }
>>>>>>>
>>>>>>> @Column(name="Name", columnDefinition="nvarchar(255)")
>>>>>>> public String getName() {
>>>>>>> return name;
>>>>>>> }
>>>>>>>
>>>>>>> public void setName(String name) {
>>>>>>> this.name = name;
>>>>>>> }
>>>>>>>
>>>>>>> @ManyToMany(mappedBy="items")
>>>>>>> public Collection<Reservation> getReservations() {
>>>>>>> return reservations;
>>>>>>> }
>>>>>>>
>>>>>>> public void setReservations(Collection<Reservation> reservations)
>>>>>>> {
>>>>>>> this.reservations = reservations;
>>>>>>> }
>>>>>>>
>>>>>>> @ManyToMany
>>>>>>> @JoinTable(name="ItemItem",
>>>>>>> joinColumns={_at_JoinColumn(name="ItemId")},
>>>>>>> inverseJoinColumns={_at_JoinColumn(name="SubItemId")})
>>>>>>> public Collection<Item> getSubItems() {
>>>>>>> return subItems;
>>>>>>> }
>>>>>>>
>>>>>>> public void setSubItems(Collection<Item> subItems) {
>>>>>>> this.subItems = subItems;
>>>>>>> }
>>>>>>>
>>>>>>> @ManyToMany(mappedBy="subItems")
>>>>>>> public Collection<Item> getSuperItems() {
>>>>>>> return superItems;
>>>>>>> }
>>>>>>>
>>>>>>> public void setSuperItems(Collection<Item> superItems) {
>>>>>>> this.superItems = superItems;
>>>>>>> }
>>>>>>>
>>>>>>> public String toString() {
>>>>>>> StringBuilder sb = new StringBuilder();
>>>>>>> sb.append("[");
>>>>>>> sb.append(String.format("id = %d", id));
>>>>>>> sb.append(String.format(", name = \"%s\"", name));
>>>>>>> sb.append(String.format(", description = \"%s\"",
>>>>>>> description));
>>>>>>> sb.append("]");
>>>>>>> return sb.toString();
>>>>>>> }
>>>>>>>}
>>>>>>>
>>>>>>>Jon
>>>>>>>
>>>>>>>
>>
>