3 Replies Latest reply on Jul 10, 2006 12:33 AM by Gavin King

    @PreUpdate not being called on Seam @Entity

    Rob Jellinghaus Novice

      OK, so this is probably another Hibernate issue, but still. I'm building my Seam app from the Seam Hibernate example under Tomcat alone (microcontainer, yada yada). I'm trying to declare a @PreUpdate method to protect certain objects from updates (by throwing an exception and killing the session). But my method is never called.

      Code:

      @Entity
      @Inheritance(strategy=InheritanceType.JOINED)
      public class RepObject {
      ...
       private Changeset replicatedChangeset;
      
       /**
       * The changeset in which this object was created. Null for head objects; set for all
       * versioned copies.
       */
       @ManyToOne
       public Changeset getReplicatedChangeset ()
       {
       return replicatedChangeset;
       }
      ...
       @PreUpdate
       private void checkUpdate () {
       log.debug("Calling checkUpdate on " + this + "...");
       if (replicatedChangeset != null) {
       throw new IllegalStateException("Can't update snapshotted object " + this);
       }
       }

      The idea is that a RepObject can be copied, and the copy has a non-null "Changeset". The copy then should never ever be updated again. Basically I want it to be "dynamically immutable" (I wish there was a way to flag a particular object as immutable at the Hibernate level, but the best I can do is blow up if you change it and then try to flush).

      The test is this. (BlogPostImpl is of course a subclass of RepObject.)
      database.enableFilter("priorVersion").setParameter("version", last.getId());
       List<BlogPostImpl> priorBlogPosts = database.createQuery("from BlogPostImpl").list();
      
       try {
       BlogPost prior1 = priorBlogPosts.get(0);
       prior1.setTitle("changedTitle");
      
       // this should call the @PreUpdate on RepObject, which should blow up here
       // ... but doesn't! and I can't even see where the @PreUpdate gets read!
       database.flush();
      
       // assert false; // plan to die if we get this far; should get exception from the flush
       } catch (Exception e) {
       // you should never do this, so we don't attempt to support any sort of recovery!
       log.info("Got expected exception from attempted snapshot update", e);
       }

      But my @PreUpdate method is never called, no exception gets thrown, and I hit the "assert false". And I can see in the log output that the flush *is* causing a single update:
      DEBUG 06-07 08:49:12,353 (Log4JLogger.java:debug:84) -Flushed: 0 insertions, 1 updates, 0 deletions to 4 objects
      ... DEBUG 06-07 08:49:12,393 (Log4JLogger.java:debug:84) -update RepObject set version=?, replicatedChangeset_id=?, replicatedKey=? where id=? and version=?
      ... DEBUG 06-07 08:49:12,433 (Log4JLogger.java:debug:84) -update BlogPostImpl set content=?, title=? where repobject_id=?


      In digging through hibernate-annotations source, I can't see where AnnotationBinder ever looks at the Entity methods to see which of them are flagged with EJB3 callbacks! I would like to trace through the code that sets up the callbacks on this Entity, but I can't find it to trace through!

      What am I missing? Can anyone confirm or disconfirm that EJB3 persistence lifecycle annotations actually work with Seam @Entities? I will also post this in the Hibernate EJB3 forum....
      Cheers,
      Rob