Why envers was blowing up

We’re experiencing an issue when we try to use envers to version a persistent object that holds a set of other persistent objects, when we’re using Spring’s JTA transaction manager.  (It doesn’t happen when we use hibernate local transactions using Spring’s HibernateTransactionManager.)  The commit of a one-to-many relationship (a Product and a Product Set), blows up with a weird error.

I had made a little test project with a greeting and a greeting set, to try to duplicate the issue apart from all the domain code.  I was not able to duplicate the issue — my greeting and greeting set committed fine, and the versioning records were created normally.

My test was set up like this:


    /**
     * This test commits an empty greeting set, then commits a new greeting to the set.      * The envers versioning works. 
     */
    @Test
    public void testSimpleCreate() {
        final String greeting = "Hola";
        assertNull(greetingDao.findByGreeting(greeting));

        final String setName = "Saludos";
        GreetingSetPO greetingSet = new GreetingSetPO();
        greetingSet.setName(setName);
        greetingSetDao.create(greetingSet);

        GreetingPO greetingPO = new GreetingPO();
        greetingPO.setGreeting(greeting);
        greetingPO.setGreetingSet(greetingSetDao.findByName(setName));
        Long greetingId = greetingDao.create(greetingPO);

        GreetingPO greetingId2 = greetingDao.findByGreeting(greeting);
        assertEquals(greetingId, greetingId2.getId());
    }

Notice that I’m committing the (empty) greeting set, then pointing the greeting to it and committing the greeting — two create() calls.

Today I talked with the domain guy and found out that the domain code is doing it a little differently:


    /**
     * This test creates a transient greeting set and a transient greeting, points them to each other, and then commits the
     * set-with-the-greeting-in-it. This blows up.
     */
    @Test
    public void testComplexCreate() {
        final String greeting = "Quid est nomen tibi?";
        final String setName = "Latin greetings";
        assertNull(greetingSetDao.findByName(setName));
        assertNull(greetingDao.findByGreeting(greeting));

        GreetingSetPO greetingSetPO = new GreetingSetPO();
        greetingSetPO.setName(setName);

        GreetingPO greetingPO = new GreetingPO();
        greetingPO.setGreeting(greeting);

        // Point the GreetingPO to its GreetingSetPO and vice versa
        greetingPO.setGreetingSet(greetingSetPO);

        Set<GreetingPO> greetings = new HashSet<GreetingPO>();
        greetings.add(greetingPO);
        greetingSetPO.setMembers(greetings);

        greetingSetDao.create(greetingSetPO);

        assertNotNull(greetingSetDao.findByName(setName));
        assertNotNull(greetingDao.findByGreeting(greeting));
    }

Notice that this time, instead of committing the empty greeting set, we create the greeting set and greeting, point them to each other, then commit the set-with-the-greeting-in-it.

This blows up just like the domain code. Yeah!

So now my questions are:

  1. Should this single-create() version work?
  2. If not, why does it work when we’re using Hibernate local transactions?

Update: I’ve posted my question to the envers forum.

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.