HHH-12384 Introduce new hibernate.bytecode.enforce_legacy_proxy_classnames configuration property

This commit is contained in:
Sanne Grinovero 2018-04-17 12:15:40 +01:00
parent 1f7457133c
commit 432d3a29fa
7 changed files with 88 additions and 4 deletions

View File

@ -401,6 +401,9 @@ The https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibern
`*hibernate.bytecode.use_reflection_optimizer*` (e.g. `true` or `false` (default value)):: `*hibernate.bytecode.use_reflection_optimizer*` (e.g. `true` or `false` (default value))::
Should we use reflection optimization? The reflection optimizer implements the https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibernate/bytecode/spi/ReflectionOptimizer.html[`ReflectionOptimizer`] interface and improves entity instantiation and property getter/setter calls. Should we use reflection optimization? The reflection optimizer implements the https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibernate/bytecode/spi/ReflectionOptimizer.html[`ReflectionOptimizer`] interface and improves entity instantiation and property getter/setter calls.
`*hibernate.bytecode.enforce_legacy_proxy_classnames*` (e.g. `true` or `false` (default value))::
Some other libraries, such as Spring, used to depend on a specific naming pattern used for proxy classes generated at runtime. Set this to `true` to have proxy class names conform to the old pattern.
[[configurations-query]] [[configurations-query]]
=== Query settings === Query settings

View File

@ -13,18 +13,22 @@ import java.util.Set;
import org.hibernate.AssertionFailure; import org.hibernate.AssertionFailure;
import org.hibernate.HibernateException; import org.hibernate.HibernateException;
import org.hibernate.bytecode.spi.BasicProxyFactory; import org.hibernate.bytecode.spi.BasicProxyFactory;
import org.hibernate.cfg.Environment;
import org.hibernate.proxy.ProxyConfiguration; import org.hibernate.proxy.ProxyConfiguration;
import net.bytebuddy.NamingStrategy;
import net.bytebuddy.description.modifier.Visibility; import net.bytebuddy.description.modifier.Visibility;
import net.bytebuddy.implementation.FieldAccessor; import net.bytebuddy.implementation.FieldAccessor;
import net.bytebuddy.implementation.MethodDelegation; import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.implementation.auxiliary.AuxiliaryType;
import net.bytebuddy.implementation.bytecode.assign.Assigner; import net.bytebuddy.implementation.bytecode.assign.Assigner;
import net.bytebuddy.matcher.ElementMatchers; import net.bytebuddy.matcher.ElementMatchers;
public class BasicProxyFactoryImpl implements BasicProxyFactory { public class BasicProxyFactoryImpl implements BasicProxyFactory {
private static final Class[] NO_INTERFACES = new Class[0]; private static final Class[] NO_INTERFACES = new Class[0];
private static final NamingStrategy PROXY_NAMING = Environment.useLegacyProxyClassnames() ?
new NamingStrategy.SuffixingRandom( "HibernateBasicProxy$" ) :
new NamingStrategy.SuffixingRandom( "HibernateBasicProxy" );
private final Class proxyClass; private final Class proxyClass;
@ -42,7 +46,7 @@ public class BasicProxyFactoryImpl implements BasicProxyFactory {
} }
this.proxyClass = bytebuddy.getCurrentyByteBuddy() this.proxyClass = bytebuddy.getCurrentyByteBuddy()
.with( new AuxiliaryType.NamingStrategy.SuffixingRandom( "HibernateBasicProxy" ) ) .with( PROXY_NAMING )
.subclass( superClass == null ? Object.class : superClass ) .subclass( superClass == null ? Object.class : superClass )
.implement( interfaces == null ? NO_INTERFACES : interfaces ) .implement( interfaces == null ? NO_INTERFACES : interfaces )
.defineField( ProxyConfiguration.INTERCEPTOR_FIELD_NAME, ProxyConfiguration.Interceptor.class, Visibility.PRIVATE ) .defineField( ProxyConfiguration.INTERCEPTOR_FIELD_NAME, ProxyConfiguration.Interceptor.class, Visibility.PRIVATE )

View File

@ -851,6 +851,15 @@ public interface AvailableSettings extends org.hibernate.jpa.AvailableSettings {
*/ */
String USE_REFLECTION_OPTIMIZER = "hibernate.bytecode.use_reflection_optimizer"; String USE_REFLECTION_OPTIMIZER = "hibernate.bytecode.use_reflection_optimizer";
/**
* Configure the global BytecodeProvider implementation to generate class names matching the
* existing naming patterns.
* It is not a good idea to rely on a classname to check if a class is an Hibernate proxy,
* yet some frameworks are currently relying on this.
* This option is disabled by default and will log a deprecation warning when enabled.
*/
String ENFORCE_LEGACY_PROXY_CLASSNAMES = "hibernate.bytecode.enforce_legacy_proxy_classnames";
/** /**
* The classname of the HQL query parser factory * The classname of the HQL query parser factory
*/ */

View File

@ -17,6 +17,7 @@ import org.hibernate.Version;
import org.hibernate.bytecode.spi.BytecodeProvider; import org.hibernate.bytecode.spi.BytecodeProvider;
import org.hibernate.engine.jdbc.connections.internal.ConnectionProviderInitiator; import org.hibernate.engine.jdbc.connections.internal.ConnectionProviderInitiator;
import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.log.UnsupportedLogger;
import org.hibernate.internal.util.ConfigHelper; import org.hibernate.internal.util.ConfigHelper;
import org.hibernate.internal.util.config.ConfigurationHelper; import org.hibernate.internal.util.config.ConfigurationHelper;
@ -155,6 +156,7 @@ public final class Environment implements AvailableSettings {
private static final BytecodeProvider BYTECODE_PROVIDER_INSTANCE; private static final BytecodeProvider BYTECODE_PROVIDER_INSTANCE;
private static final boolean ENABLE_BINARY_STREAMS; private static final boolean ENABLE_BINARY_STREAMS;
private static final boolean ENABLE_REFLECTION_OPTIMIZER; private static final boolean ENABLE_REFLECTION_OPTIMIZER;
private static final boolean ENABLE_LEGACY_PROXY_CLASSNAMES;
private static final Properties GLOBAL_PROPERTIES; private static final Properties GLOBAL_PROPERTIES;
@ -235,6 +237,12 @@ public final class Environment implements AvailableSettings {
LOG.usingReflectionOptimizer(); LOG.usingReflectionOptimizer();
} }
ENABLE_LEGACY_PROXY_CLASSNAMES = ConfigurationHelper.getBoolean( ENFORCE_LEGACY_PROXY_CLASSNAMES, GLOBAL_PROPERTIES );
if ( ENABLE_LEGACY_PROXY_CLASSNAMES ) {
final UnsupportedLogger unsupportedLogger = Logger.getMessageLogger( UnsupportedLogger.class, Environment.class.getName() );
unsupportedLogger.usingLegacyClassnamesForProxies();
}
BYTECODE_PROVIDER_INSTANCE = buildBytecodeProvider( GLOBAL_PROPERTIES ); BYTECODE_PROVIDER_INSTANCE = buildBytecodeProvider( GLOBAL_PROPERTIES );
} }
@ -299,6 +307,15 @@ public final class Environment implements AvailableSettings {
return BYTECODE_PROVIDER_INSTANCE; return BYTECODE_PROVIDER_INSTANCE;
} }
/**
* @return True if global option org.hibernate.cfg.AvailableSettings#ENFORCE_LEGACY_PROXY_CLASSNAMES was enabled
* @deprecated This option will be removed soon and should not be relied on.
*/
@Deprecated
public static boolean useLegacyProxyClassnames() {
return ENABLE_LEGACY_PROXY_CLASSNAMES;
}
/** /**
* Disallow instantiation * Disallow instantiation
*/ */

View File

@ -43,6 +43,7 @@ import org.jboss.logging.annotations.Cause;
import org.jboss.logging.annotations.LogMessage; import org.jboss.logging.annotations.LogMessage;
import org.jboss.logging.annotations.Message; import org.jboss.logging.annotations.Message;
import org.jboss.logging.annotations.MessageLogger; import org.jboss.logging.annotations.MessageLogger;
import org.jboss.logging.annotations.ValidIdRange;
import static org.jboss.logging.Logger.Level.DEBUG; import static org.jboss.logging.Logger.Level.DEBUG;
import static org.jboss.logging.Logger.Level.ERROR; import static org.jboss.logging.Logger.Level.ERROR;
@ -56,6 +57,7 @@ import static org.jboss.logging.Logger.Level.WARN;
* New messages must be added after the last message defined to ensure message codes are unique. * New messages must be added after the last message defined to ensure message codes are unique.
*/ */
@MessageLogger(projectCode = "HHH") @MessageLogger(projectCode = "HHH")
@ValidIdRange( min = 1, max = 10000 )
public interface CoreMessageLogger extends BasicLogger { public interface CoreMessageLogger extends BasicLogger {
@LogMessage(level = WARN) @LogMessage(level = WARN)
@ -1804,4 +1806,5 @@ public interface CoreMessageLogger extends BasicLogger {
@Message(value = "The query: [%s] attempts to update an immutable entity: %s", @Message(value = "The query: [%s] attempts to update an immutable entity: %s",
id = 487) id = 487)
void immutableEntityUpdateQuery(String sourceQuery, String querySpaces); void immutableEntityUpdateQuery(String sourceQuery, String querySpaces);
} }

View File

@ -0,0 +1,37 @@
/*
* 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.internal.log;
import org.hibernate.cfg.AvailableSettings;
import org.jboss.logging.annotations.LogMessage;
import org.jboss.logging.annotations.Message;
import org.jboss.logging.annotations.MessageLogger;
import org.jboss.logging.annotations.ValidIdRange;
import static org.jboss.logging.Logger.Level.WARN;
/**
* Class to consolidate logging about usage of features which should
* never be used.
* Such features might have been introduced for practical reasons so
* that people who really know what they want can use them, with the
* understanding that they should find a better alternative.
*
* @author Sanne Grinovero
*/
@MessageLogger( projectCode = "HHH" )
@ValidIdRange( min = 90002001, max = 90003000 )
public interface UnsupportedLogger {
@LogMessage(level = WARN)
@Message(value = "Global configuration option '" + AvailableSettings.ENFORCE_LEGACY_PROXY_CLASSNAMES + "' was enabled. " +
"Generated proxies will use backwards compatible classnames. This option is unsupported and will be removed.",
id = 90002001)
void usingLegacyClassnamesForProxies();
}

View File

@ -16,6 +16,7 @@ import java.util.Set;
import org.hibernate.HibernateException; import org.hibernate.HibernateException;
import org.hibernate.bytecode.internal.bytebuddy.ByteBuddyState; import org.hibernate.bytecode.internal.bytebuddy.ByteBuddyState;
import org.hibernate.cfg.Environment;
import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.ReflectHelper; import org.hibernate.internal.util.ReflectHelper;
@ -34,11 +35,21 @@ import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.implementation.SuperMethodCall; import net.bytebuddy.implementation.SuperMethodCall;
import net.bytebuddy.implementation.bytecode.assign.Assigner; import net.bytebuddy.implementation.bytecode.assign.Assigner;
import static net.bytebuddy.matcher.ElementMatchers.isFinalizer;
import static net.bytebuddy.matcher.ElementMatchers.isSynthetic;
import static net.bytebuddy.matcher.ElementMatchers.isVirtual;
import static net.bytebuddy.matcher.ElementMatchers.nameStartsWith;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static net.bytebuddy.matcher.ElementMatchers.not;
import static net.bytebuddy.matcher.ElementMatchers.returns;
import static org.hibernate.internal.CoreLogging.messageLogger; import static org.hibernate.internal.CoreLogging.messageLogger;
import static net.bytebuddy.matcher.ElementMatchers.*;
public class ByteBuddyProxyFactory implements ProxyFactory, Serializable { public class ByteBuddyProxyFactory implements ProxyFactory, Serializable {
private static final CoreMessageLogger LOG = messageLogger( ByteBuddyProxyFactory.class ); private static final CoreMessageLogger LOG = messageLogger( ByteBuddyProxyFactory.class );
private static final NamingStrategy PROXY_NAMING = Environment.useLegacyProxyClassnames() ?
new NamingStrategy.SuffixingRandom( "HibernateProxy$" ) :
new NamingStrategy.SuffixingRandom( "HibernateProxy" );
private Class persistentClass; private Class persistentClass;
private String entityName; private String entityName;
@ -91,7 +102,7 @@ public class ByteBuddyProxyFactory implements ProxyFactory, Serializable {
return cacheForProxies.findOrInsert( persistentClass.getClassLoader(), new TypeCache.SimpleKey(key), () -> return cacheForProxies.findOrInsert( persistentClass.getClassLoader(), new TypeCache.SimpleKey(key), () ->
ByteBuddyState.getStaticByteBuddyInstance() ByteBuddyState.getStaticByteBuddyInstance()
.ignore( isSynthetic().and( named( "getMetaClass" ).and( returns( td -> "groovy.lang.MetaClass".equals( td.getName() ) ) ) ) ) .ignore( isSynthetic().and( named( "getMetaClass" ).and( returns( td -> "groovy.lang.MetaClass".equals( td.getName() ) ) ) ) )
.with( new NamingStrategy.SuffixingRandom( "HibernateProxy" ) ) .with( PROXY_NAMING )
.subclass( interfaces.length == 1 ? persistentClass : Object.class, ConstructorStrategy.Default.IMITATE_SUPER_CLASS_OPENING ) .subclass( interfaces.length == 1 ? persistentClass : Object.class, ConstructorStrategy.Default.IMITATE_SUPER_CLASS_OPENING )
.implement( (Type[]) interfaces ) .implement( (Type[]) interfaces )
.method( isVirtual().and( not( isFinalizer() ) ) ) .method( isVirtual().and( not( isFinalizer() ) ) )