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 453407f38c4b..e35bac133693 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 @@ -6,6 +6,8 @@ */ package org.hibernate.bytecode.enhance.spi; +import org.hibernate.bytecode.spi.BytecodeProvider; + import jakarta.persistence.metamodel.Type; import org.hibernate.Incubating; @@ -158,4 +160,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 df5d7801e2da..474f0be1f2db 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/BytecodeSettings.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/BytecodeSettings.java @@ -28,6 +28,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 c089097949a0..ff2cbe9d3cf4 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 @@ -57,6 +57,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.cfg.Environment; @@ -128,6 +129,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; @@ -443,6 +445,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 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 @@ -483,6 +490,10 @@ public boolean doExtendedEnhancement(UnloadedClass classDescriptor) { 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 77383de47070..079e34570de0 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 @@ -37,7 +37,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