Hi everyone,
I’m using Hibernate 4.3.10 for in my migration project and I have been running into a strange problem. I use custom load listeners. The strange thing is that during runtime of my test, I can see that the listeners are being added to the eventlistenerregistry initially (replacing the default listener), but once I run my test the default listeners are being used, causing my tests to fail.
My custom EventListenerRegistryImpl:
public class AutofetchEventListenerRegistryImpl extends EventListenerRegistryImpl {
private ExtentManager em;
public AutofetchEventListenerRegistryImpl(ExtentManager em) {
super();
this.em = em;
}
@Override
public <T> void setListeners(EventType<T> type, T... listeners) {
setExtentManager(listeners, em);
super.setListeners(type, listeners);
}
private <T> void setExtentManager(T[] listeners, ExtentManager em) {
for (Object listener : listeners) {
if (listener instanceof AutofetchInitializeCollectionListener) {
((AutofetchInitializeCollectionListener) listener).setExtentManager(em);
}
if (listener instanceof AutofetchLoadListener) {
((AutofetchLoadListener) listener).setExtentManager(em);
}
}
}
}
My custom integrator:
@Override
public void integrate(Configuration configuration, SessionFactoryImplementor sessionFactory,
SessionFactoryServiceRegistry serviceRegistry) {
// EventListenerRegistry eventListenerRegistry = serviceRegistry.getService(AutofetchEventListenerRegistryImpl.class);
//eventListenerRegistry.getEventListenerGroup(EventType.LOAD).appendListener(new AutofetchLoadListener(extentManager));
EventListenerRegistry eventListenerRegistry = ((SessionFactoryImpl) sessionFactory).getServiceRegistry()
.getService(AutofetchEventListenerRegistryImpl.class);
eventListenerRegistry.setListeners(EventType.LOAD, new AutofetchLoadListener(extentManager));
eventListenerRegistry.setListeners(EventType.INIT_COLLECTION,
new AutofetchInitializeCollectionListener(extentManager));
eventListenerRegistry.addDuplicationStrategy(new DuplicationStrategy());
}
My custom listener:
public class AutofetchLoadListener extends DefaultLoadEventListener {
private static final Log log = LogFactory
.getLog(AutofetchLoadListener.class);
private ExtentManager extentManager;
/**
* Default constructor.
* setEm(ExtentManager) must be called before this listener is used
* This constructor exists so that this listener can be instantiated from
* the configuration file.
*/
public AutofetchLoadListener() {
// empty constructor
}
public AutofetchLoadListener(ExtentManager em) {
super();
if (em == null) {
throw new NullPointerException("Extent manager may not be null.");
}
this.extentManager = em;
}
@Override
protected Object loadFromDatasource(LoadEvent event,
EntityPersister entityPersister, EntityKey entityKey,
LoadType loadType) throws HibernateException {
String classname = entityPersister.getEntityName();
if (log.isDebugEnabled()) {
log.debug("Entity id: " + event.getEntityId());
}
List<Path> prefetchPaths = extentManager.getPrefetchPaths(classname);
Object result = null;
if (!prefetchPaths.isEmpty()) {
result = getResult(prefetchPaths, classname, event.getEntityId(),
event.getLockMode(), event.getSession());
if (result instanceof HibernateProxy) {
HibernateProxy proxy = (HibernateProxy) result;
if (proxy.getHibernateLazyInitializer().isUninitialized()) {
throw new IllegalStateException("proxy uninitialized");
}
result = proxy.getHibernateLazyInitializer()
.getImplementation();
}
} else {
result = super.loadFromDatasource(event, entityPersister,
entityKey, loadType);
}
extentManager.markAsRoot(result, classname);
return result;
}
public static Object getResult(List<Path> prefetchPaths, String classname,
Serializable id, LockMode lm, Session sess) {
StringBuilder queryStr = new StringBuilder();
queryStr.append("from " + classname + " entity");
Map<Path, String> pathAliases = new HashMap<Path, String>();
int aliasCnt = 0;
pathAliases.put(new Path(), "entity");
// Assumes prefetchPaths is ordered such larger paths
// appear after smaller ones.
// Also assumes all prefixes of a path are present except the
// empty prefix.
for (Path p : prefetchPaths) {
String oldAlias = pathAliases.get(p.removeLastTraversal());
String newAlias = "af" + (aliasCnt++);
String lastField = p.traversals().get(p.size() - 1);
pathAliases.put(p, newAlias);
queryStr.append(" left outer join fetch ");
queryStr.append(oldAlias + "." + lastField + " " + newAlias);
}
queryStr.append(" where entity.id = :id");
if (log.isDebugEnabled()) {
log.debug("Query: " + queryStr);
}
Query q = sess.createQuery(queryStr.toString());
q.setLockMode("entity", lm);
q.setFlushMode(FlushMode.MANUAL);
q.setParameter("id", id);
long startTimeMillis = System.currentTimeMillis();
Object o = q.uniqueResult();
if (log.isDebugEnabled()) {
log.debug("Query execution time: " +
(System.currentTimeMillis() - startTimeMillis));
}
return o;
}
public void setExtentManager(ExtentManager em) {
this.extentManager = em;
}
}
How I set up my tests:
@Before
public void setUp() {
try {
em = new ExtentManager();
org.hibernate.boot.registry.BootstrapServiceRegistry bootstrapRegistry = new org.hibernate.boot.registry.BootstrapServiceRegistryBuilder()
.with(new AutofetchEventListenerIntegrator(em)).build();
ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder(bootstrapRegistry)
.addService(EventListenerRegistry.class, new AutofetchEventListenerRegistryImpl(em)).build();
AutofetchConfiguration cfg = new AutofetchConfiguration();
sf = cfg.buildSessionFactory(serviceRegistry, em);
SchemaExport se = new SchemaExport(cfg);
se.create(false, true);
} catch (Throwable ex) {
System.err.println("Initial SessionFactory creation failed." + ex);
throw new ExceptionInInitializerError(ex);
}
}
When I get the custom service, I get the following message in the console:
EventListenerRegistry eventListenerRegistry = ((SessionFactoryImpl) sessionFactory).getServiceRegistry()
.getService(AutofetchEventListenerRegistryImpl.class);
WARN HHH000450: Encountered request for Service by non-primary service role [org.autofetch.hibernate.AutofetchEventListenerRegistryImpl -> org.hibernate.event.service.spi.EventListenerRegistry]; please update usage
The problem is that while running the tests, the AutofetchLoadListener is not being used, instead it is the DefaultListener. Does anyone have an idea what could be wrong here?
Thanks.