diff --git a/bom/application/pom.xml b/bom/application/pom.xml
index 3d5fd38ce4b824..e658793f81f75f 100644
--- a/bom/application/pom.xml
+++ b/bom/application/pom.xml
@@ -101,7 +101,7 @@
bytebuddy.version (just below), hibernate-orm.version-for-documentation (in docs/pom.xml)
and both hibernate-orm.version and antlr.version in build-parent/pom.xml
WARNING again for diffs that don't provide enough context: when updating, see above -->
- 6.5.0.Final
+ 6.5.1-bb5
1.14.12
6.0.6.Final
2.3.0.Final
diff --git a/extensions/hibernate-orm/deployment/src/main/java/io/quarkus/hibernate/orm/deployment/HibernateEntityEnhancer.java b/extensions/hibernate-orm/deployment/src/main/java/io/quarkus/hibernate/orm/deployment/HibernateEntityEnhancer.java
index 89d9dfdad455cb..3f24029883aba3 100644
--- a/extensions/hibernate-orm/deployment/src/main/java/io/quarkus/hibernate/orm/deployment/HibernateEntityEnhancer.java
+++ b/extensions/hibernate-orm/deployment/src/main/java/io/quarkus/hibernate/orm/deployment/HibernateEntityEnhancer.java
@@ -2,10 +2,11 @@
import java.util.function.BiFunction;
-import org.hibernate.bytecode.enhance.spi.DefaultEnhancementContext;
+import org.hibernate.bytecode.enhance.internal.bytebuddy.CoreTypePool;
+import org.hibernate.bytecode.enhance.internal.bytebuddy.EnhancerClassLocator;
+import org.hibernate.bytecode.enhance.internal.bytebuddy.ModelTypePool;
import org.hibernate.bytecode.enhance.spi.Enhancer;
-import org.hibernate.bytecode.enhance.spi.UnloadedField;
-import org.hibernate.bytecode.spi.BytecodeProvider;
+import org.hibernate.bytecode.internal.bytebuddy.BytecodeProviderImpl;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
@@ -13,6 +14,8 @@
import io.quarkus.deployment.QuarkusClassVisitor;
import io.quarkus.deployment.QuarkusClassWriter;
import io.quarkus.gizmo.Gizmo;
+import io.quarkus.hibernate.orm.deployment.integration.QuarkusClassFileLocator;
+import io.quarkus.hibernate.orm.deployment.integration.QuarkusEnhancementContext;
import net.bytebuddy.ClassFileVersion;
/**
@@ -29,44 +32,31 @@
*/
public final class HibernateEntityEnhancer implements BiFunction {
- private static final BytecodeProvider PROVIDER = new org.hibernate.bytecode.internal.bytebuddy.BytecodeProviderImpl(
+ private static final BytecodeProviderImpl PROVIDER = new org.hibernate.bytecode.internal.bytebuddy.BytecodeProviderImpl(
ClassFileVersion.JAVA_V11);
+ private static final CoreTypePool CORE_POOL = new CoreTypePool("jakarta.", "java.", "org.hibernate.");
+
+ private final EnhancerHolder enhancerHolder = new EnhancerHolder();
@Override
public ClassVisitor apply(String className, ClassVisitor outputClassVisitor) {
- return new HibernateEnhancingClassVisitor(className, outputClassVisitor);
+ return new HibernateEnhancingClassVisitor(className, outputClassVisitor, enhancerHolder);
}
private static class HibernateEnhancingClassVisitor extends QuarkusClassVisitor {
private final String className;
private final ClassVisitor outputClassVisitor;
- private final Enhancer enhancer;
+ private final EnhancerHolder enhancerHolder;
- public HibernateEnhancingClassVisitor(String className, ClassVisitor outputClassVisitor) {
+ public HibernateEnhancingClassVisitor(String className, ClassVisitor outputClassVisitor,
+ EnhancerHolder enhancerHolder) {
//Careful: the ASM API version needs to match the ASM version of Gizmo, not the one from Byte Buddy.
//Most often these match - but occasionally they will diverge which is acceptable as Byte Buddy is shading ASM.
super(Gizmo.ASM_API_VERSION, new QuarkusClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS));
this.className = className;
this.outputClassVisitor = outputClassVisitor;
- //note that as getLoadingClassLoader is resolved immediately this can't be created until transform time
-
- DefaultEnhancementContext enhancementContext = new DefaultEnhancementContext() {
-
- @Override
- public boolean doBiDirectionalAssociationManagement(final UnloadedField field) {
- //Don't enable automatic association management as it's often too surprising.
- //Also, there's several cases in which its semantics are of unspecified,
- //such as what should happen when dealing with ordered collections.
- return false;
- }
-
- @Override
- public ClassLoader getLoadingClassLoader() {
- return Thread.currentThread().getContextClassLoader();
- }
- };
- this.enhancer = PROVIDER.getEnhancer(enhancementContext);
+ this.enhancerHolder = enhancerHolder;
}
@Override
@@ -83,21 +73,36 @@ public void visitEnd() {
}
private byte[] hibernateEnhancement(final String className, final byte[] originalBytes) {
- final byte[] enhanced = enhancer.enhance(className, originalBytes);
+ final byte[] enhanced = enhancerHolder.getEnhancer().enhance(className, originalBytes);
return enhanced == null ? originalBytes : enhanced;
}
}
public byte[] enhance(String className, byte[] bytes) {
- DefaultEnhancementContext enhancementContext = new DefaultEnhancementContext() {
- @Override
- public ClassLoader getLoadingClassLoader() {
- return Thread.currentThread().getContextClassLoader();
- }
+ return enhancerHolder.getEnhancer().enhance(className, bytes);
+ }
- };
- Enhancer enhancer = PROVIDER.getEnhancer(enhancementContext);
- return enhancer.enhance(className, bytes);
+ private static class EnhancerHolder {
+
+ private volatile Enhancer actualEnhancer;
+
+ public Enhancer getEnhancer() {
+ //Lazily initialized for multiple reasons:
+ //1)it's expensive: try to skip it if we can; this is actually not unlikely to happen as the transformation is cacheable.
+ //2)We want the Advice loaders of the Hibernate ORM implementation to be initialized within the scope in which we
+ //have the transformation classloader installed in the thread's context.
+ if (actualEnhancer == null) {
+ synchronized (this) {
+ if (actualEnhancer == null) {
+ EnhancerClassLocator modelPool = ModelTypePool.buildModelTypePool(QuarkusClassFileLocator.INSTANCE,
+ CORE_POOL);
+ actualEnhancer = PROVIDER.getEnhancer(QuarkusEnhancementContext.INSTANCE, modelPool);
+ }
+ }
+ }
+ return actualEnhancer;
+ }
}
+
}
diff --git a/extensions/hibernate-orm/deployment/src/main/java/io/quarkus/hibernate/orm/deployment/integration/QuarkusClassFileLocator.java b/extensions/hibernate-orm/deployment/src/main/java/io/quarkus/hibernate/orm/deployment/integration/QuarkusClassFileLocator.java
new file mode 100644
index 00000000000000..78b3c7a0b3f705
--- /dev/null
+++ b/extensions/hibernate-orm/deployment/src/main/java/io/quarkus/hibernate/orm/deployment/integration/QuarkusClassFileLocator.java
@@ -0,0 +1,37 @@
+package io.quarkus.hibernate.orm.deployment.integration;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import net.bytebuddy.dynamic.ClassFileLocator;
+import net.bytebuddy.utility.StreamDrainer;
+
+public final class QuarkusClassFileLocator implements ClassFileLocator {
+
+ public static final QuarkusClassFileLocator INSTANCE = new QuarkusClassFileLocator();
+
+ private QuarkusClassFileLocator() {
+ //do not invoke, use INSTANCE
+ }
+
+ @Override
+ public Resolution locate(final String name) throws IOException {
+ final ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
+ InputStream inputStream = classLoader.getResourceAsStream(name.replace('.', '/') + CLASS_FILE_EXTENSION);
+ if (inputStream != null) {
+ try {
+ return new Resolution.Explicit(StreamDrainer.DEFAULT.drain(inputStream));
+ } finally {
+ inputStream.close();
+ }
+ } else {
+ return new Resolution.Illegal(name);
+ }
+ }
+
+ @Override
+ public void close() {
+ //nothing to do
+ }
+
+}
diff --git a/extensions/hibernate-orm/deployment/src/main/java/io/quarkus/hibernate/orm/deployment/integration/QuarkusEnhancementContext.java b/extensions/hibernate-orm/deployment/src/main/java/io/quarkus/hibernate/orm/deployment/integration/QuarkusEnhancementContext.java
new file mode 100644
index 00000000000000..12e55fa54e55d0
--- /dev/null
+++ b/extensions/hibernate-orm/deployment/src/main/java/io/quarkus/hibernate/orm/deployment/integration/QuarkusEnhancementContext.java
@@ -0,0 +1,28 @@
+package io.quarkus.hibernate.orm.deployment.integration;
+
+import org.hibernate.bytecode.enhance.spi.DefaultEnhancementContext;
+import org.hibernate.bytecode.enhance.spi.UnloadedField;
+
+public final class QuarkusEnhancementContext extends DefaultEnhancementContext {
+
+ public static final QuarkusEnhancementContext INSTANCE = new QuarkusEnhancementContext();
+
+ private QuarkusEnhancementContext() {
+ //do not invoke, use INSTANCE
+ }
+
+ @Override
+ public boolean doBiDirectionalAssociationManagement(final UnloadedField field) {
+ //Don't enable automatic association management as it's often too surprising.
+ //Also, there's several cases in which its semantics are of unspecified,
+ //such as what should happen when dealing with ordered collections.
+ return false;
+ }
+
+ @Override
+ public ClassLoader getLoadingClassLoader() {
+ //This shouldn't matter, see: QuarkusClassFileLocator
+ return Thread.currentThread().getContextClassLoader();
+ }
+
+}