| We have an application that was using the following successfully: Hibernate 5.0.10.FINAL Weld 2.3.5.FINAL Java 8u101 PostgreSQL 9.5.2 In this application we use Weld CDI to manage the EntityManager reference. There is one spot where we gain access to the underlying Hibernate Session by calling EntityManager.unwrap(Session.class) in order to call Session.setDefaultReadOnly(true). It looks something like: public abstract class AbstractDao<E, K extends Serializable> implements Dao<E, K> { ... @Inject protected EntityManager em; ... public E find(....) { ... if (readOnly) { em.unwrap(Session.class).setDefaultReadOnly(true); } ... } We attempted to upgrade to Hibernate 5.2.1.FINAL with no other changes, this results in the call to em.unwrap(Session.class) to now fail with a ClassCastException: java.lang.ClassCastException: org.jboss.weldx.persistence.EntityManager$1473582185$Proxy$_$$_WeldClientProxy cannot be cast to org.hibernate.Session This appears to be a result of SessionImpl now directly implementing javax.persistence.EntityManager and returning itself (i.e. "this"), from the unwrap method, from 5.2.1.FINAL version of SessionImpl.java: @Override @SuppressWarnings("unchecked") public <T> T unwrap(Class<T> clazz) { checkOpen(); if ( Session.class.isAssignableFrom( clazz ) ) { --> return (T) this; } if ( SessionImplementor.class.isAssignableFrom( clazz ) ) { return (T) this; } if ( SharedSessionContractImplementor.class.isAssignableFrom( clazz ) ) { return (T) this; } if ( EntityManager.class.isAssignableFrom( clazz ) ) { return (T) this; } throw new PersistenceException( "Hibernate cannot unwrap " + clazz ); } The SessionImpl.unwrap method returns the correct value, however there appears to be a negative interaction with Weld, in Weld's ProxyMethodHandler.java: /* (non-Javadoc)
- @see javassist.util.proxy.MethodHandler#invoke(java.lang.Object, java.lang.reflect.Method, java.lang.reflect.Method, java.lang.Object[])
*/ public Object invoke(Object self, Method thisMethod, Method proceed, Object[] args) throws Throwable { if (thisMethod == null)
Unknown macro: { BeanLogger.LOG.methodHandlerProcessingReturningBeanInstance(self.getClass()); if (beanInstance == null) { throw BeanLogger.LOG.beanInstanceNotSetOnProxy(getBean()); } return beanInstance.getInstance(); } BeanLogger.LOG.methodHandlerProcessingCall(thisMethod, self.getClass()); if (thisMethod.getDeclaringClass().equals(TargetInstanceProxy.class)) { if (beanInstance == null) { throw BeanLogger.LOG.beanInstanceNotSetOnProxy(getBean()); } if (thisMethod.getName().equals("getTargetInstance")) { return beanInstance.getInstance(); } else if (thisMethod.getName().equals("getTargetClass")) { return beanInstance.getInstanceType(); } else { return null; } }
else if (thisMethod.getName().equals("_initMH")) { BeanLogger.LOG.settingNewMethodHandler(args[0], self.getClass()); return new ProxyMethodHandler(contextId, new TargetBeanInstance(args[0]), getBean()); } else
Unknown macro: { if (beanInstance == null) { throw BeanLogger.LOG.beanInstanceNotSetOnProxy(getBean()); } Object instance = beanInstance.getInstance(); Object result = beanInstance.invoke(instance, thisMethod, args); // if the method returns this and the return type matches the proxy type, return the proxy instead // to prevent the bean instance escaping---> if (result != null && result == instance && (thisMethod.getReturnType().isAssignableFrom(self.getClass()))) { return self; } return result; }
}
Weld detects that the object returned from calling SessionImpl.unwrap is the object wrapped in the Weld client proxy and returns the Weld client proxy rather than a direct reference to the SessionImpl object. Unfortunately the Weld client proxy object only implements the EntityManager interface, not all interfaces that SessionImpl implements which includes Session. I'm not sure if this is a Hibernate bug or a Weld bug or a combination of both. |