3 Replies Latest reply on Jul 10, 2006 12:33 AM by gavin.king

    @PreUpdate not being called on Seam @Entity

    robjellinghaus

      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

        • 1. Re: @PreUpdate not being called on Seam @Entity
          robjellinghaus

          Arrgh, sorry about that. I fundamentally misunderstood how this works. Now I know about @EntityListeners and I will build a proper listener class and so forth. SEARCH BEFORE POSTING :-(

          Cheers,
          Rob

          • 2. Re: @PreUpdate not being called on Seam @Entity
            robjellinghaus

            Actually, it looks like I *didn't* misunderstand how this works. A Hibernate forum post mentions that the EJB3 lifecycle callbacks only work if you're using EntityManager, i.e. an embedded EJB3 container. Which I'm not -- I'm using the microcontainer-based Hibernate example for my configuration.

            Anyone know offhand? Is it true that if I'm using the Tomcat / microcontainer / no-EJB3 configuration, that EJB3 lifecycle callbacks (e.g. @PreUpdate) won't be called? If so, does this mean that @EntityListeners won't work either without going to an embeddedEjb configuration?

            And in general, is there any reason to prefer the microcontainer config (a la the Seam Hibernate example) to the embeddedEjb config (a la the blog example)? Seems like the microcontainer style might be strictly less useful...?

            Thanks....
            Cheers,
            Rob

            • 3. Re: @PreUpdate not being called on Seam @Entity
              gavin.king

              Emmanuel doesn't monitor this list. Ask in HEM or EJB3 forums.