From dccaadc0f274f30c5f8f605c1717082a49343c36 Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Wed, 15 Jan 2025 10:02:52 +0000 Subject: [PATCH] HHH-19050 Allow configuration of EntityManagerFactoryBuilderImpl to override the BytecodeProvider instance --- .../bytecode/enhance/spi/EnhancementContext.java | 13 +++++++++++++ .../java/org/hibernate/cfg/BytecodeSettings.java | 11 +++++++++++ .../internal/EntityManagerFactoryBuilderImpl.java | 12 ++++++++++++ .../enhance/EnhancingClassTransformerImpl.java | 3 ++- 4 files changed, 38 insertions(+), 1 deletion(-) diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/spi/EnhancementContext.java b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/spi/EnhancementContext.java index 97bef960b263..81b605533446 100644 --- a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/spi/EnhancementContext.java +++ b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/spi/EnhancementContext.java @@ -4,6 +4,8 @@ */ package org.hibernate.bytecode.enhance.spi; +import org.hibernate.bytecode.spi.BytecodeProvider; + import jakarta.persistence.metamodel.Type; import org.hibernate.Incubating; @@ -156,4 +158,15 @@ public interface EnhancementContext { default UnsupportedEnhancementStrategy getUnsupportedEnhancementStrategy() { return UnsupportedEnhancementStrategy.SKIP; } + + /** + * Allows to force the use of a specific instance of BytecodeProvider to perform the enhancement. + * @return When returning {code null} the default implementation will be used. Only return a different instance if + * you need to override the default implementation. + */ + @Incubating + default BytecodeProvider getBytecodeProvider() { + return null; + } + } diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/BytecodeSettings.java b/hibernate-core/src/main/java/org/hibernate/cfg/BytecodeSettings.java index a7dee97a68e8..50ee94c10564 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/BytecodeSettings.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/BytecodeSettings.java @@ -26,6 +26,17 @@ public interface BytecodeSettings { @Deprecated( forRemoval = true ) String BYTECODE_PROVIDER = "hibernate.bytecode.provider"; + /** + * This is similar to the now deprecated legacy property {@code hibernate.bytecode.provider} except + * it's used specifically to pass an existing instance of a {@link org.hibernate.bytecode.spi.BytecodeProvider}; + * this happens to also allow to override the implementation, but is primarily intended to allow reusing a + * specific instance; this could be useful when the implementation benefits from internal caches. + * When not set, Hibernate will create its default implementation. + * + * @settingDefault {@code null} + */ + String BYTECODE_PROVIDER_INSTANCE = "hibernate.enhancer.bytecodeprovider.instance"; + /** * Enable association management feature in runtime bytecode enhancement * diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/boot/internal/EntityManagerFactoryBuilderImpl.java b/hibernate-core/src/main/java/org/hibernate/jpa/boot/internal/EntityManagerFactoryBuilderImpl.java index 38df0e659d45..70f281ad7e02 100644 --- a/hibernate-core/src/main/java/org/hibernate/jpa/boot/internal/EntityManagerFactoryBuilderImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/jpa/boot/internal/EntityManagerFactoryBuilderImpl.java @@ -52,6 +52,7 @@ import org.hibernate.bytecode.enhance.spi.EnhancementException; import org.hibernate.bytecode.enhance.spi.UnloadedClass; import org.hibernate.bytecode.enhance.spi.UnloadedField; +import org.hibernate.bytecode.spi.BytecodeProvider; import org.hibernate.bytecode.spi.ClassTransformer; import org.hibernate.cfg.AvailableSettings; import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider; @@ -113,6 +114,7 @@ import static org.hibernate.cfg.AvailableSettings.TRANSACTION_COORDINATOR_STRATEGY; import static org.hibernate.cfg.AvailableSettings.URL; import static org.hibernate.cfg.AvailableSettings.USER; +import static org.hibernate.cfg.BytecodeSettings.BYTECODE_PROVIDER_INSTANCE; import static org.hibernate.cfg.BytecodeSettings.ENHANCER_ENABLE_ASSOCIATION_MANAGEMENT; import static org.hibernate.cfg.BytecodeSettings.ENHANCER_ENABLE_DIRTY_TRACKING; import static org.hibernate.cfg.BytecodeSettings.ENHANCER_ENABLE_LAZY_INITIALIZATION; @@ -422,6 +424,11 @@ protected EnhancementContext getEnhancementContext( final boolean dirtyTrackingEnabled, final boolean lazyInitializationEnabled, final boolean associationManagementEnabled ) { + final Object propValue = configurationValues.get( BYTECODE_PROVIDER_INSTANCE ); + if ( propValue != null && ( ! ( propValue instanceof BytecodeProvider ) ) ) { + throw new PersistenceException( "Property " + BYTECODE_PROVIDER_INSTANCE + " was set to '" + propValue + "', which is not compatible with the expected type " + BytecodeProvider.class ); + } + final BytecodeProvider overriddenBytecodeProvider = (BytecodeProvider) propValue; return new DefaultEnhancementContext() { @Override @@ -461,6 +468,11 @@ public boolean doExtendedEnhancement(UnloadedClass classDescriptor) { // doesn't make any sense to have extended enhancement enabled at runtime. we only enhance entities anyway. return false; } + + @Override + public BytecodeProvider getBytecodeProvider() { + return overriddenBytecodeProvider; + } }; } 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 7e1200a1be7a..2fb3bc527bf9 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 @@ -35,7 +35,8 @@ public class EnhancingClassTransformerImpl implements ClassTransformer { public EnhancingClassTransformerImpl(EnhancementContext enhancementContext) { Objects.requireNonNull( enhancementContext ); this.enhancementContext = enhancementContext; - this.bytecodeProvider = BytecodeProviderInitiator.buildDefaultBytecodeProvider(); + final BytecodeProvider overriddenProvider = enhancementContext.getBytecodeProvider(); + this.bytecodeProvider = overriddenProvider == null ? BytecodeProviderInitiator.buildDefaultBytecodeProvider() : overriddenProvider; } @Override