0

I am trying to register an Integrator in Hibernate 5.0.3 to trigger a particular EventListener. I am modifying one of the examples supplied in the Hibernate Getting Started Guide. The original jUnit Test Class that works well is the following:

    package org.hibernate.tutorial.annotations;

    import java.util.Date;
    import java.util.List;

    import org.hibernate.Session;
    import org.hibernate.SessionFactory;
    import org.hibernate.boot.MetadataSources;
    import org.hibernate.boot.registry.BootstrapServiceRegistry;
    import org.hibernate.boot.registry.BootstrapServiceRegistryBuilder;
    import org.hibernate.boot.registry.StandardServiceRegistry;
    import org.hibernate.boot.registry.StandardServiceRegistryBuilder;

    import junit.framework.TestCase;

    /**
     * Illustrates the use of Hibernate native APIs.  The code here is unchanged from the {@code basic} example, the
     * only difference being the use of annotations to supply the metadata instead of Hibernate mapping files.
     *
     * @author Steve Ebersole
     */
    public class AnnotationsIllustrationTest extends TestCase {
        private SessionFactory sessionFactory;

        @Override
        protected void setUp() throws Exception {
            // A SessionFactory is set up once for an application!          
            final StandardServiceRegistry registry = new StandardServiceRegistryBuilder()
                    .configure() // configures settings from hibernate.cfg.xml
                    .build();
            try {
                sessionFactory = new MetadataSources( registry ).buildMetadata().buildSessionFactory();
            }
            catch (Exception e) {
                // The registry would be destroyed by the SessionFactory, but we had trouble building the SessionFactory
                // so destroy it manually.
                StandardServiceRegistryBuilder.destroy( registry );
            }
        }

        @Override
        protected void tearDown() throws Exception {
            if ( sessionFactory != null ) {
                sessionFactory.close();
            }
        }

        @SuppressWarnings({ "unchecked" })
        public void testBasicUsage() {
            // create a couple of events...
            Session session = sessionFactory.openSession();
            session.beginTransaction();
            session.save( new Event( "Our very first event!", new Date() ) );
            session.save( new Event( "A follow up event", new Date() ) );
            session.getTransaction().commit();
            session.close();

            // now lets pull events from the database and list them
            session = sessionFactory.openSession();
            session.beginTransaction();
            List result = session.createQuery( "from Event" ).list();
            for ( Event event : (List<Event>) result ) {
                System.out.println( "Event (" + event.getDate() + ") : " + event.getTitle() );
            }
            session.getTransaction().commit();
            session.close();
        }
    }

Now I just modify the setUp() method like this:

@Override
    protected void setUp() throws Exception {
        // A SessionFactory is set up once for an application!
        BootstrapServiceRegistry bootstrapServiceRegistry = new BootstrapServiceRegistryBuilder().applyIntegrator(new MyEventListenerIntegrator()).build();

        try {
            sessionFactory = new MetadataSources( bootstrapServiceRegistry ).buildMetadata().buildSessionFactory();
        }
        catch (Exception e) {
            // The registry would be destroyed by the SessionFactory, but we had trouble building the SessionFactory
            // so destroy it manually.
            StandardServiceRegistryBuilder.destroy( bootstrapServiceRegistry );
        }
    }

When I execute the test case I get the following error:

java.lang.ClassCastException: org.hibernate.boot.registry.internal.BootstrapServiceRegistryImpl cannot be cast to org.hibernate.boot.registry.internal.StandardServiceRegistryImpl

This is my Integrator class (but I don't think this is the problem because the setUp() method also fails when I don't apply the Integrator to the BootstrapServiceRegistryBuilder):

package org.hibernate.tutorial.annotations;

import org.hibernate.boot.Metadata;
import org.hibernate.cfg.Configuration;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.event.service.spi.EventListenerRegistry;
import org.hibernate.event.spi.EventType;
import org.hibernate.integrator.spi.Integrator;
import org.hibernate.service.spi.SessionFactoryServiceRegistry;

public class MyEventListenerIntegrator implements Integrator {

    public void integrate(
            Configuration configuration,
            SessionFactoryImplementor sessionFactory,
            SessionFactoryServiceRegistry serviceRegistry) {
        // As you might expect, an EventListenerRegistry is the thing with which event listeners are registered  It is a
        // service so we look it up using the service registry
        final EventListenerRegistry eventListenerRegistry = serviceRegistry.getService( EventListenerRegistry.class );

        //     3) This form adds the specified listener(s) to the end of the listener chain
        eventListenerRegistry.appendListeners( EventType.LOAD, new LoadListenerExample() );
    }

    @Override
    public void disintegrate(SessionFactoryImplementor arg0, SessionFactoryServiceRegistry arg1) {
        // TODO Auto-generated method stub

    }

    @Override
    public void integrate(Metadata arg0, SessionFactoryImplementor arg1, SessionFactoryServiceRegistry arg2) {
        // TODO Auto-generated method stub

    }
}

And finally my hibernate.cfg.xml:

<?xml version='1.0' encoding='utf-8'?>
<!--
  ~ Hibernate, Relational Persistence for Idiomatic Java
  ~
  ~ License: GNU Lesser General Public License (LGPL), version 2.1 or later.
  ~ See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
  -->
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">

<hibernate-configuration>

    <session-factory>

        <!-- Database connection settings -->
        <property name="connection.driver_class">org.h2.Driver</property>
        <property name="connection.url">jdbc:h2:mem:db1;DB_CLOSE_DELAY=-1;MVCC=TRUE</property>
        <property name="connection.username">sa</property>
        <property name="connection.password"></property>

        <!-- JDBC connection pool (use the built-in) -->
        <property name="connection.pool_size">1</property>

        <!-- SQL dialect -->
        <property name="dialect">org.hibernate.dialect.H2Dialect</property>

        <!-- Disable the second-level cache  -->
        <property name="cache.provider_class">org.hibernate.cache.internal.NoCacheProvider</property>

        <!-- Echo all executed SQL to stdout -->
        <property name="show_sql">true</property>

        <!-- Drop and re-create the database schema on startup -->
        <property name="hbm2ddl.auto">create</property>

        <!-- Names the annotated entity class -->
        <mapping class="org.hibernate.tutorial.annotations.Event"/>

    </session-factory>

</hibernate-configuration>

Thank you very much for your help.

rocotocloc
  • 418
  • 6
  • 19
  • You did not leave the stacktrace so hard to be certain, but I'd assume the problem is with your line `StandardServiceRegistryBuilder.destroy( bootstrapServiceRegistry )`. You are trying to use the StandardServiceRegistryBuilder to close a BootstrapServiceRegistry which is a type mismatch. – Steve Ebersole Nov 13 '15 at 14:37
  • The problematic line is: `sessionFactory = new MetadataSources( bootstrapServiceRegistry ).buildMetadata().buildSessionFactory();`. The stacktrace is `org.eclipse.debug.core.DebugException: com.sun.jdi.ClassNotLoadedException: Type has not been loaded occurred while retrieving component type of array.` and the cause of the exception is `org.hibernate.HibernateException: Access to DialectResolutionInfo cannot be null when 'hibernate.dialect' not set`. I guess it's because I was not indicating the hibernate.cfg.xml file anywhere. Also you're right about the `destroy` method. – rocotocloc Nov 20 '15 at 11:07

1 Answers1

3

Ok, solved:

    @Override
protected void setUp() throws Exception {
    // A SessionFactory is set up once for an application!
    BootstrapServiceRegistry bootstrapServiceRegistry = new BootstrapServiceRegistryBuilder().applyIntegrator(new MyEventListenerIntegrator()).build();

    final StandardServiceRegistry registry = new StandardServiceRegistryBuilder(bootstrapServiceRegistry)
            .configure() // configures settings from hibernate.cfg.xml
            .build();
    try {
        sessionFactory = new MetadataSources( registry  ).buildMetadata().buildSessionFactory();
    }
    catch (Exception e) {
        // The registry would be destroyed by the SessionFactory, but we had trouble building the SessionFactory
        // so destroy it manually.
        StandardServiceRegistryBuilder.destroy( registry  );
    }
}
rocotocloc
  • 418
  • 6
  • 19
  • 1
    Wanted to mention another option which is to use Java's service discovery mechanism (http://docs.oracle.com/javase/7/docs/api/java/util/ServiceLoader.html) which Hibernate supports for discovery of Integrators and other extension points. – Steve Ebersole Nov 13 '15 at 14:35
  • Thanks for your help, I'll give it a try. – rocotocloc Nov 20 '15 at 11:13