From 52f73dda82fbb287488f5ca4022a664c9bdbfefc Mon Sep 17 00:00:00 2001 From: Stuart Douglas Date: Mon, 7 Feb 2022 11:25:18 +1100 Subject: [PATCH] Also remove final from parent classes Fixes #23282 --- .../FinalMethodRemoveFlagTest.java | 61 +++++++++++++++++++ .../arc/processor/ClientProxyGenerator.java | 11 ++-- .../io/quarkus/arc/processor/Methods.java | 7 ++- 3 files changed, 71 insertions(+), 8 deletions(-) create mode 100644 extensions/arc/deployment/src/test/java/io/quarkus/arc/test/unproxyable/FinalMethodRemoveFlagTest.java diff --git a/extensions/arc/deployment/src/test/java/io/quarkus/arc/test/unproxyable/FinalMethodRemoveFlagTest.java b/extensions/arc/deployment/src/test/java/io/quarkus/arc/test/unproxyable/FinalMethodRemoveFlagTest.java new file mode 100644 index 0000000000000..99ca1f42faefa --- /dev/null +++ b/extensions/arc/deployment/src/test/java/io/quarkus/arc/test/unproxyable/FinalMethodRemoveFlagTest.java @@ -0,0 +1,61 @@ +package io.quarkus.arc.test.unproxyable; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import javax.annotation.PostConstruct; +import javax.enterprise.context.ApplicationScoped; +import javax.inject.Inject; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.test.QuarkusUnitTest; + +public class FinalMethodRemoveFlagTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .withApplicationRoot((jar) -> jar + .addClasses(FinalMethodRemoveFlagTest.class, MyBean.class, MyParent.class)); + + @Inject + MyBean bean; + + @Test + public void testFinalFlagWasRemoved() { + assertEquals("ok", bean.ping()); + assertEquals("parent", bean.parentPing()); + } + + // The final flag should normally result in deployment exception + @ApplicationScoped + public static class MyBean extends MyParent { + + private String foo; + + final String ping() { + return foo; + } + + @PostConstruct + void init() { + foo = "ok"; + } + + } + + public static class MyParent { + + private String parent; + + final String parentPing() { + return parent; + } + + @PostConstruct + void parentInit() { + parent = "parent"; + } + + } +} diff --git a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/ClientProxyGenerator.java b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/ClientProxyGenerator.java index 5500c9c499165..b1a4d165f5429 100644 --- a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/ClientProxyGenerator.java +++ b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/ClientProxyGenerator.java @@ -24,7 +24,6 @@ import java.util.Collection; import java.util.Collections; import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -320,14 +319,16 @@ Collection getDelegatingMethods(BeanInfo bean, Consumer methodsFromWhichToRemoveFinal = new HashSet<>(); + Map> methodsFromWhichToRemoveFinal = new HashMap<>(); ClassInfo classInfo = bean.getTarget().get().asClass(); Methods.addDelegatingMethods(index, classInfo, methods, methodsFromWhichToRemoveFinal, transformUnproxyableClasses); if (!methodsFromWhichToRemoveFinal.isEmpty()) { - String className = classInfo.name().toString(); - bytecodeTransformerConsumer.accept(new BytecodeTransformer(className, - new Methods.RemoveFinalFromMethod(className, methodsFromWhichToRemoveFinal))); + for (Map.Entry> entry : methodsFromWhichToRemoveFinal.entrySet()) { + String className = entry.getKey(); + bytecodeTransformerConsumer.accept(new BytecodeTransformer(className, + new Methods.RemoveFinalFromMethod(className, entry.getValue()))); + } } } else if (bean.isProducerMethod()) { MethodInfo producerMethod = bean.getTarget().get().asMethod(); diff --git a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/Methods.java b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/Methods.java index f2e4453b34338..1eae51aac6626 100644 --- a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/Methods.java +++ b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/Methods.java @@ -69,7 +69,7 @@ static boolean isBridge(MethodInfo method) { } static void addDelegatingMethods(IndexView index, ClassInfo classInfo, Map methods, - Set methodsFromWhichToRemoveFinal, boolean transformUnproxyableClasses) { + Map> methodsFromWhichToRemoveFinal, boolean transformUnproxyableClasses) { if (classInfo != null) { // First methods declared on the class for (MethodInfo method : classInfo.methods()) { @@ -110,7 +110,7 @@ static void addDelegatingMethods(IndexView index, ClassInfo classInfo, Map methodsFromWhichToRemoveFinal) { + Map> methodsFromWhichToRemoveFinal) { if (Modifier.isStatic(method.flags()) || Modifier.isPrivate(method.flags())) { return true; } @@ -125,7 +125,8 @@ private static boolean skipForClientProxy(MethodInfo method, boolean transformUn String className = method.declaringClass().name().toString(); if (!className.startsWith("java.")) { if (transformUnproxyableClasses && (methodsFromWhichToRemoveFinal != null)) { - methodsFromWhichToRemoveFinal.add(NameAndDescriptor.fromMethodInfo(method)); + methodsFromWhichToRemoveFinal.computeIfAbsent(className, (k) -> new HashSet<>()) + .add(NameAndDescriptor.fromMethodInfo(method)); return false; }