persistence@glassfish.java.net

Re: PrePersist method not being called

From: Tom Ware <tom.ware_at_oracle.com>
Date: Mon, 08 Jan 2007 09:28:53 -0500

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
>>>>>
>>>>>
>>>>>