From 05c51e555a0b1e043a5a86dc5cffb0d096e327a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Mon, 20 Sep 2021 16:47:32 +0200 Subject: [PATCH] HHH-14828 Remove final modifier from enhanced fields We need to remove the final modifier if we want to address the possibility of that field being lazy. --- .../PersistentAttributeTransformer.java | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/PersistentAttributeTransformer.java b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/PersistentAttributeTransformer.java index 02eb26f25b8c..287ce6b793e4 100644 --- a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/PersistentAttributeTransformer.java +++ b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/PersistentAttributeTransformer.java @@ -6,6 +6,7 @@ */ package org.hibernate.bytecode.enhance.internal.bytebuddy; +import static net.bytebuddy.matcher.ElementMatchers.anyOf; import static net.bytebuddy.matcher.ElementMatchers.nameStartsWith; import static net.bytebuddy.matcher.ElementMatchers.not; @@ -25,8 +26,10 @@ import net.bytebuddy.asm.Advice; import net.bytebuddy.asm.AsmVisitorWrapper; +import net.bytebuddy.asm.ModifierAdjustment; import net.bytebuddy.description.field.FieldDescription; import net.bytebuddy.description.method.MethodDescription; +import net.bytebuddy.description.modifier.ModifierContributor; import net.bytebuddy.description.modifier.Visibility; import net.bytebuddy.description.type.TypeDefinition; import net.bytebuddy.description.type.TypeDescription; @@ -47,6 +50,22 @@ final class PersistentAttributeTransformer implements AsmVisitorWrapper.ForDecla private static final CoreMessageLogger log = CoreLogging.messageLogger( PersistentAttributeTransformer.class ); private static final Junction NOT_HIBERNATE_GENERATED = not( nameStartsWith( "$$_hibernate_" ) ); + private static final ModifierContributor.ForField REMOVE_FINAL_MODIFIER = new ModifierContributor.ForField() { + @Override + public int getMask() { + return EMPTY_MASK; // Do not add any modifier + } + + @Override + public int getRange() { + return Opcodes.ACC_FINAL; // Remove the "final" modifier + } + + @Override + public boolean isDefault() { + return false; + } + }; private final TypeDescription managedCtClass; @@ -185,6 +204,16 @@ DynamicType.Builder applyTo(DynamicType.Builder builder) { boolean compositeOwner = false; builder = builder.visit( new AsmVisitorWrapper.ForDeclaredMethods().invokable( NOT_HIBERNATE_GENERATED, this ) ); + // Remove the final modifier from all enhanced fields, because: + // 1. We sometimes need to write to final fields when they are lazy. + // 2. Those fields are already written to by Hibernate ORM through reflection anyway. + // 3. The compiler already makes sure that final fields are not written to from the user's source code. + List enhancedFieldsAsDefined = new ArrayList<>(); + for ( AnnotatedFieldDescription f : enhancedFields ) { + enhancedFieldsAsDefined.add( f.asDefined() ); + } + builder = builder.visit( new ModifierAdjustment().withFieldModifiers( anyOf( enhancedFieldsAsDefined ), + REMOVE_FINAL_MODIFIER ) ); for ( AnnotatedFieldDescription enhancedField : enhancedFields ) { builder = builder .defineMethod(