HHH-13851 Rework initialization of ProxyFactoryFactory, allow some code reuse from SPI

(cherry picked from commit 0964b881f7)
This commit is contained in:
Sanne Grinovero 2020-02-05 14:31:59 +00:00 committed by gbadner
parent 9fc4f5b8e7
commit 8d73884cbf
2 changed files with 125 additions and 70 deletions

View File

@ -0,0 +1,115 @@
/*
* 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>.
*/
package org.hibernate.proxy.pojo;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Iterator;
import java.util.Set;
import org.hibernate.MappingException;
import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.ReflectHelper;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.Property;
import org.hibernate.mapping.Subclass;
import org.hibernate.property.access.spi.Getter;
import org.hibernate.property.access.spi.Setter;
import org.hibernate.proxy.HibernateProxy;
import org.hibernate.tuple.entity.PojoEntityTuplizer;
/**
* Most of this code was originally an internal detail of {@link PojoEntityTuplizer},
* then extracted to make it easier for integrators to initialize a custom
* {@link org.hibernate.proxy.ProxyFactory}.
*/
public final class ProxyFactoryHelper {
private static final CoreMessageLogger LOG = CoreLogging.messageLogger( ProxyFactoryHelper.class );
private ProxyFactoryHelper() {
//not meant to be instantiated
}
public static Set<Class> extractProxyInterfaces(final PersistentClass persistentClass, final String entityName) {
/*
* We need to preserve the order of the interfaces they were put into the set, since javassist will choose the
* first one's class-loader to construct the proxy class with. This is also the reason why HibernateProxy.class
* should be the last one in the order (on JBossAS7 its class-loader will be org.hibernate module's class-
* loader, which will not see the classes inside deployed apps. See HHH-3078
*/
final Set<Class> proxyInterfaces = new java.util.LinkedHashSet<Class>();
final Class mappedClass = persistentClass.getMappedClass();
final Class proxyInterface = persistentClass.getProxyInterface();
if ( proxyInterface != null && !mappedClass.equals( proxyInterface ) ) {
if ( !proxyInterface.isInterface() ) {
throw new MappingException(
"proxy must be either an interface, or the class itself: " + entityName
);
}
proxyInterfaces.add( proxyInterface );
}
if ( mappedClass.isInterface() ) {
proxyInterfaces.add( mappedClass );
}
Iterator<Subclass> subclasses = persistentClass.getSubclassIterator();
while ( subclasses.hasNext() ) {
final Subclass subclass = subclasses.next();
final Class subclassProxy = subclass.getProxyInterface();
final Class subclassClass = subclass.getMappedClass();
if ( subclassProxy != null && !subclassClass.equals( subclassProxy ) ) {
if ( !subclassProxy.isInterface() ) {
throw new MappingException(
"proxy must be either an interface, or the class itself: " + subclass.getEntityName()
);
}
proxyInterfaces.add( subclassProxy );
}
}
proxyInterfaces.add( HibernateProxy.class );
return proxyInterfaces;
}
public static void validateProxyability(final PersistentClass persistentClass) {
Iterator properties = persistentClass.getPropertyIterator();
Class clazz = persistentClass.getMappedClass();
while ( properties.hasNext() ) {
Property property = (Property) properties.next();
Method method = property.getGetter( clazz ).getMethod();
if ( method != null && Modifier.isFinal( method.getModifiers() ) ) {
LOG.gettersOfLazyClassesCannotBeFinal( persistentClass.getEntityName(), property.getName() );
}
method = property.getSetter( clazz ).getMethod();
if ( method != null && Modifier.isFinal( method.getModifiers() ) ) {
LOG.settersOfLazyClassesCannotBeFinal( persistentClass.getEntityName(), property.getName() );
}
}
}
public static Method extractProxySetIdentifierMethod(final Setter idSetter, final Class proxyInterface) {
Method idSetterMethod = idSetter == null ? null : idSetter.getMethod();
Method proxySetIdentifierMethod = idSetterMethod == null || proxyInterface == null ?
null :
ReflectHelper.getMethod( proxyInterface, idSetterMethod );
return proxySetIdentifierMethod;
}
public static Method extractProxyGetIdentifierMethod(final Getter idGetter, final Class proxyInterface) {
Method idGetterMethod = idGetter == null ? null : idGetter.getMethod();
Method proxyGetIdentifierMethod = idGetterMethod == null || proxyInterface == null ?
null :
ReflectHelper.getMethod( proxyInterface, idGetterMethod );
return proxyGetIdentifierMethod;
}
}

View File

@ -7,15 +7,12 @@
package org.hibernate.tuple.entity;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import org.hibernate.EntityMode;
import org.hibernate.EntityNameResolver;
import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.bytecode.enhance.spi.interceptor.BytecodeLazyAttributeInterceptor;
import org.hibernate.bytecode.enhance.spi.interceptor.EnhancementAsProxyLazinessInterceptor;
import org.hibernate.bytecode.spi.ReflectionOptimizer;
@ -27,14 +24,12 @@ import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.ReflectHelper;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.Property;
import org.hibernate.mapping.Subclass;
import org.hibernate.property.access.spi.Getter;
import org.hibernate.property.access.spi.Setter;
import org.hibernate.proxy.HibernateProxy;
import org.hibernate.proxy.ProxyFactory;
import org.hibernate.proxy.pojo.ProxyFactoryHelper;
import org.hibernate.tuple.Instantiator;
import org.hibernate.type.CompositeType;
@ -92,76 +87,21 @@ public class PojoEntityTuplizer extends AbstractEntityTuplizer {
protected ProxyFactory buildProxyFactory(PersistentClass persistentClass, Getter idGetter, Setter idSetter) {
// determine the id getter and setter methods from the proxy interface (if any)
// determine all interfaces needed by the resulting proxy
/*
* We need to preserve the order of the interfaces they were put into the set, since javassist will choose the
* first one's class-loader to construct the proxy class with. This is also the reason why HibernateProxy.class
* should be the last one in the order (on JBossAS7 its class-loader will be org.hibernate module's class-
* loader, which will not see the classes inside deployed apps. See HHH-3078
*/
Set<Class> proxyInterfaces = new java.util.LinkedHashSet<Class>();
final String entityName = getEntityName();
final Class mappedClass = persistentClass.getMappedClass();
final Class proxyInterface = persistentClass.getProxyInterface();
Class mappedClass = persistentClass.getMappedClass();
Class proxyInterface = persistentClass.getProxyInterface();
final Set<Class> proxyInterfaces = ProxyFactoryHelper.extractProxyInterfaces( persistentClass, entityName );
if ( proxyInterface != null && !mappedClass.equals( proxyInterface ) ) {
if ( !proxyInterface.isInterface() ) {
throw new MappingException(
"proxy must be either an interface, or the class itself: " + getEntityName()
);
}
proxyInterfaces.add( proxyInterface );
}
ProxyFactoryHelper.validateProxyability( persistentClass );
if ( mappedClass.isInterface() ) {
proxyInterfaces.add( mappedClass );
}
Iterator<Subclass> subclasses = persistentClass.getSubclassIterator();
while ( subclasses.hasNext() ) {
final Subclass subclass = subclasses.next();
final Class subclassProxy = subclass.getProxyInterface();
final Class subclassClass = subclass.getMappedClass();
if ( subclassProxy != null && !subclassClass.equals( subclassProxy ) ) {
if ( !subclassProxy.isInterface() ) {
throw new MappingException(
"proxy must be either an interface, or the class itself: " + subclass.getEntityName()
);
}
proxyInterfaces.add( subclassProxy );
}
}
proxyInterfaces.add( HibernateProxy.class );
Iterator properties = persistentClass.getPropertyIterator();
Class clazz = persistentClass.getMappedClass();
while ( properties.hasNext() ) {
Property property = (Property) properties.next();
Method method = property.getGetter( clazz ).getMethod();
if ( method != null && Modifier.isFinal( method.getModifiers() ) ) {
LOG.gettersOfLazyClassesCannotBeFinal( persistentClass.getEntityName(), property.getName() );
}
method = property.getSetter( clazz ).getMethod();
if ( method != null && Modifier.isFinal( method.getModifiers() ) ) {
LOG.settersOfLazyClassesCannotBeFinal( persistentClass.getEntityName(), property.getName() );
}
}
Method idGetterMethod = idGetter == null ? null : idGetter.getMethod();
Method idSetterMethod = idSetter == null ? null : idSetter.getMethod();
Method proxyGetIdentifierMethod = idGetterMethod == null || proxyInterface == null ?
null :
ReflectHelper.getMethod( proxyInterface, idGetterMethod );
Method proxySetIdentifierMethod = idSetterMethod == null || proxyInterface == null ?
null :
ReflectHelper.getMethod( proxyInterface, idSetterMethod );
Method proxyGetIdentifierMethod = ProxyFactoryHelper.extractProxyGetIdentifierMethod( idGetter, proxyInterface );
Method proxySetIdentifierMethod = ProxyFactoryHelper.extractProxySetIdentifierMethod( idSetter, proxyInterface );
ProxyFactory pf = buildProxyFactoryInternal( persistentClass, idGetter, idSetter );
try {
pf.postInstantiate(
getEntityName(),
entityName,
mappedClass,
proxyInterfaces,
proxyGetIdentifierMethod,
@ -172,7 +112,7 @@ public class PojoEntityTuplizer extends AbstractEntityTuplizer {
);
}
catch (HibernateException he) {
LOG.unableToCreateProxyFactory( getEntityName(), he );
LOG.unableToCreateProxyFactory( entityName, he );
pf = null;
}
return pf;