как добавить entity listener программируемый в Hibernate JPA


Я использую spring, hibernate, jpa2. 1. следующим образом:

@Entity
@EntityListeners(DemoListener.class)
public class Demo {

    @Id
    private Long id;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }
}

public class DemoListener {

    @PersistenceContext
    private EntityManager entityManager;

    @PrePersist
    public void prePersist(Demo demo){

    }
}

Пример хорошо работает, когда я хочу добавить больше слушателя, я должен изменить сущность Demo, но Demo находится в другом jar, я не хочу использовать конфигурацию XML, есть ли какой-то способ, как это:

...addListener(Demo.class, new DemoListener());
...addListener(Demo.class, new OtherDemoListener());
1 3

1 ответ:

База на hibernate-orm docs и Hibernate-tutorials:

/**
 * @param <T> one of {@link EventType#baseListenerInterface()}
 * @see org.hibernate.event.service.spi.EventListenerRegistry
 */
public interface JpaEventListenerRegistry<T> {

    /**
     * add listener for entity class
     *
     * @param entityClass can't be null
     * @param listener    can't be null
     */
    void addListener(Class<?> entityClass, T listener);
}



public class JpaEventListenerRegistryImpl implements JpaEventListenerRegistry<Object> {

    private Logger logger = LoggerFactory.getLogger(getClass());

    private EventListenerRegistry eventListenerRegistry;
    private Map<EventType, JpaEventListenerRegistry> listeners = new HashMap<EventType, JpaEventListenerRegistry>();

    public JpaEventListenerRegistryImpl(EventListenerRegistry eventListenerRegistry) {
        this.eventListenerRegistry = eventListenerRegistry;
        initDefault();
    }

    private void initDefault() {
        listeners.put(EventType.PRE_INSERT, new DomainPreInsertEventListener());
        listeners.put(EventType.POST_INSERT, new DomainPostInsertEventListener());
        for (Map.Entry<EventType, JpaEventListenerRegistry> entry : listeners.entrySet()) {
            eventListenerRegistry.appendListeners(entry.getKey(), entry.getValue());
        }
    }

    @SuppressWarnings("unchecked")
    public void addListener(Class<?> entityClass, Object listener) {
        logger.info("add listener {} for entity {}", listener, entityClass.getName());
        for (EventType eventType : EventType.values()) {
            Class<?> listenerInterface = eventType.baseListenerInterface();
            if (listenerInterface.isAssignableFrom(listener.getClass())) {
                JpaEventListenerRegistry registry = listeners.get(eventType);
                if (registry == null) {
                    logger.warn("the event type {} for listener {} is not supported", eventType, listener);
                } else {
                    registry.addListener(entityClass, listener);
                }
            }
        }
    }

    public static class Abstract<T> implements JpaEventListenerRegistry<T> {

        private Logger logger = LoggerFactory.getLogger(getClass());
        private Map<Class<?>, List<T>> listeners = new HashMap<Class<?>, List<T>>();

        public void addListener(Class<?> entityClass, T listener) {
            logger.info("add listener {} for entity {}", listener, entityClass.getName());
            List<T> listeners = this.listeners.get(entityClass);
            if (listeners == null) {
                listeners = new ArrayList<T>();
                this.listeners.put(entityClass, listeners);
            }
            listeners.add(listener);
        }

        List<T> findListener(Class<?> entityClass) {
            for (Map.Entry<Class<?>, List<T>> entry : listeners.entrySet()) {
                if (entry.getKey().isAssignableFrom(entityClass)) {
                    return entry.getValue();
                }
            }
            return null;
        }

    }


    public static class DomainPreInsertEventListener extends Abstract<PreInsertEventListener> implements PreInsertEventListener {

        public boolean onPreInsert(PreInsertEvent event) {
            return onPreInsert(event, findListener(event.getEntity().getClass()));
        }

        private boolean onPreInsert(PreInsertEvent event, List<PreInsertEventListener> listeners) {
            if (listeners == null) return false;
            for (PreInsertEventListener listener : listeners) {
                if (listener.onPreInsert(event)) return true;
            }
            return false;
        }
    }

    public static class DomainPostInsertEventListener extends Abstract<PostInsertEventListener> implements PostInsertEventListener {

        public void onPostInsert(PostInsertEvent event) {
            onPostInsert(event, findListener(event.getEntity().getClass()));
        }

        private void onPostInsert(PostInsertEvent event, List<PostInsertEventListener> listeners) {
            if (listeners == null) return;
            for (PostInsertEventListener listener : listeners) {
                listener.onPostInsert(event);
            }
        }


        public boolean requiresPostCommitHanding(EntityPersister persister) {
            return false;
        }
    }
}


public class EntityManagerIllustrationTest extends TestCase {
    private EntityManagerFactory entityManagerFactory;

    @Override
    protected void setUp() throws Exception {
        // like discussed with regards to SessionFactory, an EntityManagerFactory is set up once for an application
        //      IMPORTANT: notice how the name here matches the name we gave the persistence-unit in persistence.xml!
        entityManagerFactory = Persistence.createEntityManagerFactory("org.hibernate.tutorial.jpa");

        SessionFactoryImplementor sessionFactory = entityManagerFactory.unwrap(SessionFactoryImplementor.class);
        EventListenerRegistry eventListenerRegistry = sessionFactory.getServiceRegistry().getService(EventListenerRegistry.class);
        JpaEventListenerRegistryImpl jpaEventListenerRegistry = new JpaEventListenerRegistryImpl(eventListenerRegistry);
        jpaEventListenerRegistry.addListener(EventListener.class, new JpaEventListener());
    }

    private static class JpaEventListener implements PreInsertEventListener, PostInsertEventListener {
        public boolean onPreInsert(PreInsertEvent event) {
            Event entity = (Event) event.getEntity();
            System.out.println("onPreInsert:" + entity);
            return false;
        }

        public void onPostInsert(PostInsertEvent event) {
            Event entity = (Event) event.getEntity();
            System.out.println("onPostInsert:" + entity);
        }

        public boolean requiresPostCommitHanding(EntityPersister persister) {
            return false;
        }
    }

    @Override
    protected void tearDown() throws Exception {
        entityManagerFactory.close();
    }

    public void testBasicUsage() {
        // create a couple of events...
        EntityManager entityManager = entityManagerFactory.createEntityManager();
        entityManager.getTransaction().begin();
        entityManager.persist(new Event("Our very first event!", new Date()));
//        entityManager.persist(new Event("A follow up event", new Date()));
        entityManager.getTransaction().commit();
        entityManager.close();

        // now lets pull events from the database and list them
        entityManager = entityManagerFactory.createEntityManager();
        entityManager.getTransaction().begin();
        List<Event> result = entityManager.createQuery("from Event", Event.class).getResultList();
        for (Event event : result) {
            System.out.println("Event (" + event.getDate() + ") : " + event.getTitle());
        }
        entityManager.getTransaction().commit();
        entityManager.close();
    }


}