diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/internal/BytecodeProviderInitiator.java b/hibernate-core/src/main/java/org/hibernate/bytecode/internal/BytecodeProviderInitiator.java index 94776f6533..9b055d6a92 100644 --- a/hibernate-core/src/main/java/org/hibernate/bytecode/internal/BytecodeProviderInitiator.java +++ b/hibernate-core/src/main/java/org/hibernate/bytecode/internal/BytecodeProviderInitiator.java @@ -8,13 +8,23 @@ package org.hibernate.bytecode.internal; import java.util.Map; +import org.hibernate.Internal; import org.hibernate.boot.registry.StandardServiceInitiator; import org.hibernate.bytecode.spi.BytecodeProvider; -import org.hibernate.cfg.Environment; +import org.hibernate.internal.CoreMessageLogger; +import org.hibernate.internal.util.config.ConfigurationHelper; import org.hibernate.service.spi.ServiceRegistryImplementor; +import org.jboss.logging.Logger; + +import static org.hibernate.cfg.AvailableSettings.BYTECODE_PROVIDER; + public final class BytecodeProviderInitiator implements StandardServiceInitiator { + public static final String BYTECODE_PROVIDER_NAME_BYTEBUDDY = "bytebuddy"; + public static final String BYTECODE_PROVIDER_NAME_NONE = "none"; + public static final String BYTECODE_PROVIDER_NAME_DEFAULT = BYTECODE_PROVIDER_NAME_BYTEBUDDY; + /** * Singleton access */ @@ -22,9 +32,8 @@ public final class BytecodeProviderInitiator implements StandardServiceInitiator @Override public BytecodeProvider initiateService(Map configurationValues, ServiceRegistryImplementor registry) { - // TODO in 6 this will no longer use Environment, which is configured via global environment variables, - // but move to a component which can be reconfigured differently in each registry. - return Environment.getBytecodeProvider(); + String provider = ConfigurationHelper.getString( BYTECODE_PROVIDER, configurationValues, BYTECODE_PROVIDER_NAME_DEFAULT ); + return buildBytecodeProvider( provider ); } @Override @@ -32,4 +41,35 @@ public final class BytecodeProviderInitiator implements StandardServiceInitiator return BytecodeProvider.class; } + @Internal + public static BytecodeProvider buildDefaultBytecodeProvider() { + return buildBytecodeProvider( BYTECODE_PROVIDER_NAME_BYTEBUDDY ); + } + + @Internal + public static BytecodeProvider buildBytecodeProvider(String providerName) { + + CoreMessageLogger LOG = Logger.getMessageLogger( CoreMessageLogger.class, BytecodeProviderInitiator.class.getName() ); + LOG.bytecodeProvider( providerName ); + + if ( BYTECODE_PROVIDER_NAME_NONE.equals( providerName ) ) { + return new org.hibernate.bytecode.internal.none.BytecodeProviderImpl(); + } + if ( BYTECODE_PROVIDER_NAME_BYTEBUDDY.equals( providerName ) ) { + return new org.hibernate.bytecode.internal.bytebuddy.BytecodeProviderImpl(); + } + + // There is no need to support plugging in a custom BytecodeProvider via FQCN + // as it's possible to plug a custom BytecodeProviderInitiator into the bootstrap. + // + // This also allows integrators to inject a BytecodeProvider instance which has some + // state: particularly useful to inject proxy definitions which have been prepared in + // advance. + // See also https://hibernate.atlassian.net/browse/HHH-13804 and how this was solved in + // Quarkus. + + LOG.unknownBytecodeProvider( providerName, BYTECODE_PROVIDER_NAME_DEFAULT ); + return new org.hibernate.bytecode.internal.bytebuddy.BytecodeProviderImpl(); + } + } diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java b/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java index ba65d182a9..4c21b0c7c1 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java @@ -1533,7 +1533,7 @@ public interface AvailableSettings { String CHECK_NULLABILITY = "hibernate.check_nullability"; /** - * Selects a bytecode enhancment library. + * Selects a bytecode enhancement library. *

* At present only bytebuddy is supported, bytebuddy being the default since version 5.3. */ diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/Environment.java b/hibernate-core/src/main/java/org/hibernate/cfg/Environment.java index f45d69ba84..a47f69ba02 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/Environment.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/Environment.java @@ -13,6 +13,7 @@ import java.util.Properties; import org.hibernate.HibernateException; import org.hibernate.Internal; import org.hibernate.Version; +import org.hibernate.bytecode.internal.BytecodeProviderInitiator; import org.hibernate.bytecode.spi.BytecodeProvider; import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.util.ConfigHelper; @@ -35,8 +36,8 @@ import static org.hibernate.internal.log.DeprecationLogger.DEPRECATION_LOGGER; * always determined by the {@code Environment} properties in {@link #getProperties()}. * *

- * The only system-level properties are {@value #USE_REFLECTION_OPTIMIZER} and - * {@value #BYTECODE_PROVIDER}. + * The only system-level property is {@value #USE_REFLECTION_OPTIMIZER}, + * and it's deprecated. *

* {@code Environment} properties are populated by calling {@link System#getProperties()} * and then from a resource named {@code /hibernate.properties}, if it exists. System @@ -141,7 +142,6 @@ import static org.hibernate.internal.log.DeprecationLogger.DEPRECATION_LOGGER; public final class Environment implements AvailableSettings { private static final CoreMessageLogger LOG = Logger.getMessageLogger( CoreMessageLogger.class, Environment.class.getName()); - private static final BytecodeProvider BYTECODE_PROVIDER_INSTANCE; private static final boolean ENABLE_REFLECTION_OPTIMIZER; private static final Properties GLOBAL_PROPERTIES; @@ -193,8 +193,6 @@ public final class Environment implements AvailableSettings { else { DEPRECATION_LOGGER.deprecatedSettingForRemoval( USE_REFLECTION_OPTIMIZER, "true" ); } - - BYTECODE_PROVIDER_INSTANCE = buildBytecodeProvider( GLOBAL_PROPERTIES ); } /** @@ -203,12 +201,11 @@ public final class Environment implements AvailableSettings { * @return True if reflection optimization should be used; false otherwise. * * @see #USE_REFLECTION_OPTIMIZER - * @see #getBytecodeProvider() * @see BytecodeProvider#getReflectionOptimizer * * @deprecated Deprecated to indicate that the method will be moved to * {@link org.hibernate.boot.spi.SessionFactoryOptions} / - * {@link org.hibernate.boot.SessionFactoryBuilder} - probably in 6.0. + * {@link org.hibernate.boot.SessionFactoryBuilder}. * See HHH-12194 and * HHH-12193 for details */ @@ -217,23 +214,11 @@ public final class Environment implements AvailableSettings { return ENABLE_REFLECTION_OPTIMIZER; } - /** - * @deprecated Deprecated to indicate that the method will be moved to - * {@link org.hibernate.boot.spi.SessionFactoryOptions} / - * {@link org.hibernate.boot.SessionFactoryBuilder} - probably in 6.0. - * See HHH-12194 and - * HHH-12193 for details - */ - @Deprecated - public static BytecodeProvider getBytecodeProvider() { - return BYTECODE_PROVIDER_INSTANCE; - } - /** * Disallow instantiation */ private Environment() { - throw new UnsupportedOperationException(); + //not to be constructed } /** @@ -246,36 +231,36 @@ public final class Environment implements AvailableSettings { return copy; } + /** + * @deprecated Replaced by {@code org.hibernate.bytecode.internal.BytecodeProviderInitiator#BYTECODE_PROVIDER_NAME_BYTEBUDDY}, + * however note that that's an internal contract: a different BytecodeProvider Initiator might ignore these constants + * or interpret them differently. + */ + @Deprecated(forRemoval = true) public static final String BYTECODE_PROVIDER_NAME_BYTEBUDDY = "bytebuddy"; - public static final String BYTECODE_PROVIDER_NAME_NONE = "none"; - public static final String BYTECODE_PROVIDER_NAME_DEFAULT = BYTECODE_PROVIDER_NAME_BYTEBUDDY; + /** + * @deprecated Replaced by {@code org.hibernate.bytecode.internal.BytecodeProviderInitiator#BYTECODE_PROVIDER_NAME_NONE}, + * however note that that's an internal contract: a different BytecodeProvider Initiator might ignore these constants + * or interpret them differently. + */ + @Deprecated(forRemoval = true) + public static final String BYTECODE_PROVIDER_NAME_NONE = "none"; + + /** + * @deprecated Replaced by {@code org.hibernate.bytecode.internal.BytecodeProviderInitiator#BYTECODE_PROVIDER_NAME_DEFAULT} + * however note that that's an internal contract: a different BytecodeProvider Initiator might apply a different default. + */ + @Deprecated(forRemoval = true) + public static final String BYTECODE_PROVIDER_NAME_DEFAULT = BytecodeProviderInitiator.BYTECODE_PROVIDER_NAME_BYTEBUDDY; + + /** + * @deprecated this will be removed; retrieval of the BytecodeProvider should be performed via the {@link org.hibernate.service.ServiceRegistry}. + */ + @Deprecated(forRemoval = true) public static BytecodeProvider buildBytecodeProvider(Properties properties) { String provider = ConfigurationHelper.getString( BYTECODE_PROVIDER, properties, BYTECODE_PROVIDER_NAME_DEFAULT ); - return buildBytecodeProvider( provider ); + return BytecodeProviderInitiator.buildBytecodeProvider( provider ); } - private static BytecodeProvider buildBytecodeProvider(String providerName) { - if ( BYTECODE_PROVIDER_NAME_NONE.equals( providerName ) ) { - return new org.hibernate.bytecode.internal.none.BytecodeProviderImpl(); - } - if ( BYTECODE_PROVIDER_NAME_BYTEBUDDY.equals( providerName ) ) { - return new org.hibernate.bytecode.internal.bytebuddy.BytecodeProviderImpl(); - } - - LOG.bytecodeProvider( providerName ); - - // there is no need to support plugging in a custom BytecodeProvider via FQCN: - // - the static helper methods on this class are deprecated - // - it's possible to plug a custom BytecodeProvider directly into the ServiceRegistry - // - // This also allows integrators to inject a BytecodeProvider instance which has some - // state; particularly useful to inject proxy definitions which have been prepared in - // advance. - // See also https://hibernate.atlassian.net/browse/HHH-13804 and how this was solved in - // Quarkus. - - LOG.unknownBytecodeProvider( providerName, BYTECODE_PROVIDER_NAME_DEFAULT ); - return new org.hibernate.bytecode.internal.bytebuddy.BytecodeProviderImpl(); - } } diff --git a/hibernate-core/src/main/java/org/hibernate/internal/CoreMessageLogger.java b/hibernate-core/src/main/java/org/hibernate/internal/CoreMessageLogger.java index f12f0a4d7d..2b65a8c460 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/CoreMessageLogger.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/CoreMessageLogger.java @@ -1290,7 +1290,7 @@ public interface CoreMessageLogger extends BasicLogger { void unexpectedRowCounts(); @LogMessage(level = WARN) - @Message(value = "unrecognized bytecode provider [%s], using [%s] by default", id = 382) + @Message(value = "Unrecognized bytecode provider [%s]; using the default implementation [%s]", id = 382) void unknownBytecodeProvider(String providerName, String defaultProvider); @LogMessage(level = WARN) diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/internal/enhance/EnhancingClassTransformerImpl.java b/hibernate-core/src/main/java/org/hibernate/jpa/internal/enhance/EnhancingClassTransformerImpl.java index 5143dce082..0cd5f1996b 100644 --- a/hibernate-core/src/main/java/org/hibernate/jpa/internal/enhance/EnhancingClassTransformerImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/jpa/internal/enhance/EnhancingClassTransformerImpl.java @@ -7,10 +7,13 @@ package org.hibernate.jpa.internal.enhance; import java.security.ProtectionDomain; +import java.util.Objects; import org.hibernate.bytecode.enhance.spi.EnhancementContext; import org.hibernate.bytecode.enhance.spi.EnhancementContextWrapper; import org.hibernate.bytecode.enhance.spi.Enhancer; +import org.hibernate.bytecode.internal.BytecodeProviderInitiator; +import org.hibernate.bytecode.spi.BytecodeProvider; import org.hibernate.bytecode.spi.ClassTransformer; import org.hibernate.cfg.Environment; @@ -23,9 +26,12 @@ import jakarta.persistence.spi.TransformerException; public class EnhancingClassTransformerImpl implements ClassTransformer { private final EnhancementContext enhancementContext; + private final BytecodeProvider bytecodeProvider; public EnhancingClassTransformerImpl(EnhancementContext enhancementContext) { + Objects.requireNonNull( enhancementContext ); this.enhancementContext = enhancementContext; + this.bytecodeProvider = BytecodeProviderInitiator.buildDefaultBytecodeProvider(); } @Override @@ -41,12 +47,15 @@ public class EnhancingClassTransformerImpl implements ClassTransformer { // It also assumed that all calls come from the same class loader, which is fair, but this makes it more robust. try { - Enhancer enhancer = Environment.getBytecodeProvider().getEnhancer( new EnhancementContextWrapper( enhancementContext, loader ) ); + Enhancer enhancer = bytecodeProvider.getEnhancer( new EnhancementContextWrapper( enhancementContext, loader ) ); return enhancer.enhance( className, classfileBuffer ); } catch (final Exception e) { throw new TransformerException( "Error performing enhancement of " + className, e ); } + finally { + bytecodeProvider.resetCaches(); + } } } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/EmbeddableRepresentationStrategyPojo.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/EmbeddableRepresentationStrategyPojo.java index f306f70cbc..89753fcff7 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/EmbeddableRepresentationStrategyPojo.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/EmbeddableRepresentationStrategyPojo.java @@ -13,13 +13,12 @@ import java.util.function.Supplier; import org.hibernate.HibernateException; import org.hibernate.boot.registry.selector.spi.StrategySelector; +import org.hibernate.bytecode.spi.BytecodeProvider; import org.hibernate.bytecode.spi.ProxyFactoryFactory; import org.hibernate.bytecode.spi.ReflectionOptimizer; import org.hibernate.cfg.Environment; -import org.hibernate.engine.config.spi.ConfigurationService; import org.hibernate.internal.util.ReflectHelper; import org.hibernate.internal.util.StringHelper; -import org.hibernate.internal.util.config.ConfigurationHelper; import org.hibernate.mapping.Backref; import org.hibernate.mapping.Component; import org.hibernate.mapping.IndexBackref; @@ -33,6 +32,7 @@ import org.hibernate.property.access.internal.PropertyAccessStrategyIndexBackRef import org.hibernate.property.access.spi.BuiltInPropertyAccessStrategies; import org.hibernate.property.access.spi.PropertyAccess; import org.hibernate.property.access.spi.PropertyAccessStrategy; +import org.hibernate.service.ServiceRegistry; import org.hibernate.type.descriptor.java.JavaType; import org.hibernate.type.descriptor.java.spi.JavaTypeRegistry; import org.hibernate.type.internal.CompositeUserTypeJavaTypeWrapper; @@ -187,8 +187,9 @@ public class EmbeddableRepresentationStrategyPojo extends AbstractEmbeddableRepr propertyAccessMap.put( property.getName(), getPropertyAccesses()[i] ); i++; } + final BytecodeProvider bytecodeProvider = creationContext.getServiceRegistry().getService( BytecodeProvider.class ); - return Environment.getBytecodeProvider().getReflectionOptimizer( + return bytecodeProvider.getReflectionOptimizer( bootDescriptor.getComponentClass(), propertyAccessMap ); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/EntityRepresentationStrategyPojoStandard.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/EntityRepresentationStrategyPojoStandard.java index 4e479ed48e..8f90a387e4 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/EntityRepresentationStrategyPojoStandard.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/EntityRepresentationStrategyPojoStandard.java @@ -20,7 +20,6 @@ import org.hibernate.bytecode.spi.ReflectionOptimizer; import org.hibernate.bytecode.spi.ReflectionOptimizer.InstantiationOptimizer; import org.hibernate.cfg.Environment; import org.hibernate.classic.Lifecycle; -import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.internal.CoreLogging; import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.util.ReflectHelper; @@ -140,8 +139,7 @@ public class EntityRepresentationStrategyPojoStandard implements EntityRepresent identifierPropertyAccess = makePropertyAccess( identifierProperty ); } -// final BytecodeProvider bytecodeProvider = creationContext.getBootstrapContext().getBytecodeProvider(); - final BytecodeProvider bytecodeProvider = Environment.getBytecodeProvider(); + final BytecodeProvider bytecodeProvider = creationContext.getBootstrapContext().getServiceRegistry().getService( BytecodeProvider.class ); final EntityMetamodel entityMetamodel = runtimeDescriptor.getEntityMetamodel(); ProxyFactory proxyFactory = null; diff --git a/hibernate-core/src/main/java/org/hibernate/proxy/AbstractLazyInitializer.java b/hibernate-core/src/main/java/org/hibernate/proxy/AbstractLazyInitializer.java index 65a3d8af15..0a7ca1aedd 100644 --- a/hibernate-core/src/main/java/org/hibernate/proxy/AbstractLazyInitializer.java +++ b/hibernate-core/src/main/java/org/hibernate/proxy/AbstractLazyInitializer.java @@ -265,15 +265,16 @@ public abstract class AbstractLazyInitializer implements LazyInitializer { /** * Initialize internal state based on the currently attached session, * in order to be ready to load data even after the proxy is detached from the session. - * - * This method only has any effect if - * {@link SessionFactoryOptions#isInitializeLazyStateOutsideTransactionsEnabled()} is {@code true}. */ protected void prepareForPossibleLoadingOutsideTransaction() { if ( session != null ) { allowLoadOutsideTransaction = session.getFactory().getSessionFactoryOptions().isInitializeLazyStateOutsideTransactionsEnabled(); - if ( allowLoadOutsideTransaction && sessionFactoryUuid == null ) { + if ( sessionFactoryUuid == null ) { + //we're going to need the UUID even if we the SessionFactory configuration doesn't + // allow any operations on it, as we need it to match deserialized objects with + // the originating SessionFactory: at very least it's useful to actually get + // such configuration, so to know if such operation isn't allowed or configured otherwise. sessionFactoryUuid = session.getFactory().getUuid(); } } diff --git a/hibernate-core/src/main/java/org/hibernate/proxy/AbstractSerializableProxy.java b/hibernate-core/src/main/java/org/hibernate/proxy/AbstractSerializableProxy.java index 2c41a96fe9..ece5c8673e 100644 --- a/hibernate-core/src/main/java/org/hibernate/proxy/AbstractSerializableProxy.java +++ b/hibernate-core/src/main/java/org/hibernate/proxy/AbstractSerializableProxy.java @@ -17,7 +17,7 @@ public abstract class AbstractSerializableProxy implements Serializable { private final String entityName; private final Object id; private final Boolean readOnly; - private final String sessionFactoryUuid; + protected final String sessionFactoryUuid; private final boolean allowLoadOutsideTransaction; protected AbstractSerializableProxy( diff --git a/hibernate-core/src/main/java/org/hibernate/proxy/pojo/bytebuddy/SerializableProxy.java b/hibernate-core/src/main/java/org/hibernate/proxy/pojo/bytebuddy/SerializableProxy.java index 1f85d35e7b..98a3c57ba3 100644 --- a/hibernate-core/src/main/java/org/hibernate/proxy/pojo/bytebuddy/SerializableProxy.java +++ b/hibernate-core/src/main/java/org/hibernate/proxy/pojo/bytebuddy/SerializableProxy.java @@ -6,12 +6,13 @@ */ package org.hibernate.proxy.pojo.bytebuddy; -import java.io.Serializable; import java.lang.reflect.Method; +import java.util.Objects; import org.hibernate.bytecode.internal.bytebuddy.BytecodeProviderImpl; import org.hibernate.bytecode.spi.BytecodeProvider; -import org.hibernate.cfg.Environment; +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.internal.SessionFactoryRegistry; import org.hibernate.proxy.AbstractSerializableProxy; import org.hibernate.proxy.HibernateProxy; import org.hibernate.type.CompositeType; @@ -109,13 +110,32 @@ public final class SerializableProxy extends AbstractSerializableProxy { } private Object readResolve() { - BytecodeProvider bytecodeProvider = Environment.getBytecodeProvider(); - if ( !( bytecodeProvider instanceof BytecodeProviderImpl ) ) { - throw new IllegalStateException( "The bytecode provider is not ByteBuddy, unable to deserialize a ByteBuddy proxy." ); - } - - HibernateProxy proxy = ( (BytecodeProviderImpl) bytecodeProvider ).getByteBuddyProxyHelper().deserializeProxy( this ); + final SessionFactoryImplementor sessionFactory = retrieveMatchingSessionFactory( this.sessionFactoryUuid ); + BytecodeProviderImpl byteBuddyBytecodeProvider = retrieveByteBuddyBytecodeProvider( sessionFactory ); + HibernateProxy proxy = byteBuddyBytecodeProvider.getByteBuddyProxyHelper().deserializeProxy( this ); afterDeserialization( (ByteBuddyInterceptor) proxy.getHibernateLazyInitializer() ); return proxy; } + + private static SessionFactoryImplementor retrieveMatchingSessionFactory(final String sessionFactoryUuid) { + Objects.requireNonNull( sessionFactoryUuid ); + final SessionFactoryImplementor sessionFactory = SessionFactoryRegistry.INSTANCE.getSessionFactory( sessionFactoryUuid ); + if ( sessionFactory != null ) { + return sessionFactory; + } + else { + throw new IllegalStateException( "Could not identify any active SessionFactory having UUID " + sessionFactoryUuid ); + } + } + + private static BytecodeProviderImpl retrieveByteBuddyBytecodeProvider(final SessionFactoryImplementor sessionFactory) { + final BytecodeProvider bytecodeProvider = sessionFactory.getServiceRegistry().getService( BytecodeProvider.class ); + if ( bytecodeProvider instanceof BytecodeProviderImpl ) { + return (BytecodeProviderImpl) bytecodeProvider; + } + else { + throw new IllegalStateException( "Unable to deserialize a SerializableProxy proxy: the bytecode provider is not ByteBuddy." ); + } + } + } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/ReflectionOptimizerTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/ReflectionOptimizerTest.java index 5b7d8bc14e..52a8611bb2 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/ReflectionOptimizerTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/ReflectionOptimizerTest.java @@ -6,14 +6,17 @@ */ package org.hibernate.orm.test.bytecode; +import static org.hibernate.bytecode.internal.BytecodeProviderInitiator.buildDefaultBytecodeProvider; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import org.hibernate.bytecode.spi.BytecodeProvider; import org.hibernate.bytecode.spi.ReflectionOptimizer; -import org.hibernate.cfg.Environment; + import org.hibernate.testing.TestForIssue; import org.hibernate.testing.junit4.BaseUnitTestCase; +import org.junit.AfterClass; +import org.junit.BeforeClass; import org.junit.Test; /** @@ -21,9 +24,23 @@ import org.junit.Test; */ public class ReflectionOptimizerTest extends BaseUnitTestCase { + private static BytecodeProvider provider; + + @BeforeClass + public static void initBytecodeProvider() { + provider = buildDefaultBytecodeProvider(); + } + + @AfterClass + public static void clearBytecodeProvider() { + if ( provider != null ) { + provider.resetCaches(); + provider = null; + } + } + @Test public void testReflectionOptimization() { - BytecodeProvider provider = Environment.getBytecodeProvider(); ReflectionOptimizer optimizer = provider.getReflectionOptimizer( Bean.class, BeanReflectionHelper.getGetterNames(), @@ -47,18 +64,16 @@ public class ReflectionOptimizerTest extends BaseUnitTestCase { @Test @TestForIssue(jiraKey = "HHH-12584") public void testAbstractClass() { - BytecodeProvider provider = Environment.getBytecodeProvider(); ReflectionOptimizer reflectionOptimizer = provider.getReflectionOptimizer( AbstractClass.class, new String[]{ "getProperty" }, - new String[]{ "setProperty" }, new Class[]{ String.class } ); + new String[]{ "setProperty" }, new Class[]{ String.class } ); assertNotNull( reflectionOptimizer ); } @Test @TestForIssue(jiraKey = "HHH-12584") public void testInterface() { - BytecodeProvider provider = Environment.getBytecodeProvider(); ReflectionOptimizer reflectionOptimizer = provider.getReflectionOptimizer( Interface.class, new String[]{ "getProperty" }, - new String[]{ "setProperty" }, new Class[]{ String.class } ); + new String[]{ "setProperty" }, new Class[]{ String.class } ); assertNotNull( reflectionOptimizer ); } @@ -88,4 +103,5 @@ public class ReflectionOptimizerTest extends BaseUnitTestCase { void setProperty(String property); } + } diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/bytecode/enhancement/BytecodeEnhancerRunner.java b/hibernate-testing/src/main/java/org/hibernate/testing/bytecode/enhancement/BytecodeEnhancerRunner.java index af5626531d..dfdd5218d8 100644 --- a/hibernate-testing/src/main/java/org/hibernate/testing/bytecode/enhancement/BytecodeEnhancerRunner.java +++ b/hibernate-testing/src/main/java/org/hibernate/testing/bytecode/enhancement/BytecodeEnhancerRunner.java @@ -32,6 +32,8 @@ import org.junit.runners.Suite; import org.junit.runners.model.InitializationError; import org.junit.runners.model.RunnerBuilder; +import static org.hibernate.bytecode.internal.BytecodeProviderInitiator.buildDefaultBytecodeProvider; + /** * @author Luis Barreiro */ @@ -182,7 +184,7 @@ public class BytecodeEnhancerRunner extends Suite { EnhancementContext enhancerContext, List selectors) { return new EnhancingClassLoader( - Environment.getBytecodeProvider().getEnhancer( enhancerContext ), + buildDefaultBytecodeProvider().getEnhancer( enhancerContext ), selectors ); } diff --git a/tooling/hibernate-ant/src/main/java/org/hibernate/tool/enhance/EnhancementTask.java b/tooling/hibernate-ant/src/main/java/org/hibernate/tool/enhance/EnhancementTask.java index e5269a0a17..161da368a0 100644 --- a/tooling/hibernate-ant/src/main/java/org/hibernate/tool/enhance/EnhancementTask.java +++ b/tooling/hibernate-ant/src/main/java/org/hibernate/tool/enhance/EnhancementTask.java @@ -14,6 +14,8 @@ import org.hibernate.bytecode.enhance.spi.EnhancementContext; import org.hibernate.bytecode.enhance.spi.Enhancer; import org.hibernate.bytecode.enhance.spi.UnloadedClass; import org.hibernate.bytecode.enhance.spi.UnloadedField; +import org.hibernate.bytecode.internal.BytecodeProviderInitiator; +import org.hibernate.bytecode.spi.BytecodeProvider; import org.hibernate.cfg.Environment; import java.io.ByteArrayOutputStream; @@ -30,6 +32,8 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import static org.hibernate.bytecode.internal.BytecodeProviderInitiator.buildDefaultBytecodeProvider; + /** * Ant task for performing build-time enhancement of entity objects. * @@ -162,16 +166,21 @@ public class EnhancementTask extends Task { log( "Extended enhancement is enabled. Classes other than entities may be modified. You should consider access the entities using getter/setter methods and disable this property. Use at your own risk.", Project.MSG_WARN ); } - Enhancer enhancer = Environment.getBytecodeProvider().getEnhancer( enhancementContext ); + final BytecodeProvider bytecodeProvider = buildDefaultBytecodeProvider(); + try { + Enhancer enhancer = bytecodeProvider.getEnhancer( enhancementContext ); + for ( File file : sourceSet ) { + byte[] enhancedBytecode = doEnhancement( file, enhancer ); + if ( enhancedBytecode == null ) { + continue; + } + writeOutEnhancedClass( enhancedBytecode, file ); - for ( File file : sourceSet ) { - byte[] enhancedBytecode = doEnhancement( file, enhancer ); - if ( enhancedBytecode == null ) { - continue; + log( "Successfully enhanced class [" + file + "]", Project.MSG_INFO ); } - writeOutEnhancedClass( enhancedBytecode, file ); - - log( "Successfully enhanced class [" + file + "]", Project.MSG_INFO ); + } + finally { + bytecodeProvider.resetCaches(); } } diff --git a/tooling/hibernate-enhance-maven-plugin/src/main/java/org/hibernate/orm/tooling/maven/MavenEnhancePlugin.java b/tooling/hibernate-enhance-maven-plugin/src/main/java/org/hibernate/orm/tooling/maven/MavenEnhancePlugin.java index 86e20d08ff..baed59b893 100644 --- a/tooling/hibernate-enhance-maven-plugin/src/main/java/org/hibernate/orm/tooling/maven/MavenEnhancePlugin.java +++ b/tooling/hibernate-enhance-maven-plugin/src/main/java/org/hibernate/orm/tooling/maven/MavenEnhancePlugin.java @@ -38,10 +38,12 @@ import org.hibernate.bytecode.enhance.spi.EnhancementContext; import org.hibernate.bytecode.enhance.spi.Enhancer; import org.hibernate.bytecode.enhance.spi.UnloadedClass; import org.hibernate.bytecode.enhance.spi.UnloadedField; -import org.hibernate.cfg.Environment; +import org.hibernate.bytecode.spi.BytecodeProvider; import org.sonatype.plexus.build.incremental.BuildContext; +import static org.hibernate.bytecode.internal.BytecodeProviderInitiator.buildDefaultBytecodeProvider; + /** * This plugin will enhance Entity objects. * @@ -153,21 +155,28 @@ public class MavenEnhancePlugin extends AbstractMojo { log.warn( "Extended enhancement is enabled. Classes other than entities may be modified. You should consider access the entities using getter/setter methods and disable this property. Use at your own risk." ); } - final Enhancer enhancer = Environment.getBytecodeProvider().getEnhancer( enhancementContext ); + //TODO allow the Maven plugin to configure the bytecode enhancer? + final BytecodeProvider bytecodeProvider = buildDefaultBytecodeProvider(); + try { + final Enhancer enhancer = bytecodeProvider.getEnhancer( enhancementContext ); - for ( File file : sourceSet ) { + for ( File file : sourceSet ) { - final byte[] enhancedBytecode = doEnhancement( file, enhancer ); + final byte[] enhancedBytecode = doEnhancement( file, enhancer ); - if ( enhancedBytecode == null ) { - continue; - } - - writeOutEnhancedClass( enhancedBytecode, file ); - if ( log.isDebugEnabled() ) { - log.debug( "Successfully enhanced class [" + file + "]" ); + if ( enhancedBytecode == null ) { + continue; + } + + writeOutEnhancedClass( enhancedBytecode, file ); + if ( log.isDebugEnabled() ) { + log.debug( "Successfully enhanced class [" + file + "]" ); + } } } + finally { + bytecodeProvider.resetCaches(); + } } private ClassLoader toClassLoader(List runtimeClasspath) throws MojoExecutionException { diff --git a/tooling/hibernate-gradle-plugin/src/main/java/org/hibernate/orm/tooling/gradle/enhance/EnhancementHelper.java b/tooling/hibernate-gradle-plugin/src/main/java/org/hibernate/orm/tooling/gradle/enhance/EnhancementHelper.java index e36f9a4398..c25735433b 100644 --- a/tooling/hibernate-gradle-plugin/src/main/java/org/hibernate/orm/tooling/gradle/enhance/EnhancementHelper.java +++ b/tooling/hibernate-gradle-plugin/src/main/java/org/hibernate/orm/tooling/gradle/enhance/EnhancementHelper.java @@ -25,6 +25,7 @@ import org.hibernate.bytecode.enhance.spi.UnloadedField; import org.hibernate.cfg.Environment; import org.hibernate.orm.tooling.gradle.HibernateOrmSpec; +import static org.hibernate.bytecode.internal.BytecodeProviderInitiator.buildDefaultBytecodeProvider; import static org.hibernate.orm.tooling.gradle.Helper.determineClassName; /** @@ -130,8 +131,8 @@ public class EnhancementHelper { } }; - //noinspection deprecation - return Environment.getBytecodeProvider().getEnhancer( enhancementContext ); + //TODO allow the Gradle plugin to configure the bytecode enhancer? + return buildDefaultBytecodeProvider().getEnhancer( enhancementContext ); } private static void writeOutEnhancedClass(byte[] enhancedBytecode, File file, Logger logger) {