From ff7bd6f69953af7a89a740e11f8a4057bcaba743 Mon Sep 17 00:00:00 2001 From: Martin Kouba Date: Fri, 1 Sep 2023 09:14:01 +0200 Subject: [PATCH] ArC: fix decorators and interface default methods - fixes #35664 (cherry picked from commit ada6761763bd9dcc0d814327d66a8d9e35e78bac) --- .../io/quarkus/arc/processor/Methods.java | 2 +- .../arc/processor/SubclassGenerator.java | 26 +++----- .../DecoratorDefaultMethodTest.java | 59 +++++++++++++++++++ 3 files changed, 68 insertions(+), 19 deletions(-) create mode 100644 independent-projects/arc/tests/src/test/java/io/quarkus/arc/test/decorators/DecoratorDefaultMethodTest.java 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 d48294834bc68..a5290ed4c1ce9 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 @@ -140,7 +140,7 @@ private static boolean skipForClientProxy(MethodInfo method, boolean transformUn } static boolean skipForDelegateSubclass(MethodInfo method) { - if (Modifier.isStatic(method.flags()) || method.isSynthetic() || isDefault(method)) { + if (Modifier.isStatic(method.flags()) || method.isSynthetic()) { return true; } if (IGNORED_METHODS.contains(method.name())) { diff --git a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/SubclassGenerator.java b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/SubclassGenerator.java index 126e917a878b8..f665300bc4444 100644 --- a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/SubclassGenerator.java +++ b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/SubclassGenerator.java @@ -637,13 +637,10 @@ private void processDecorator(DecoratorInfo decorator, BeanInfo bean, Type provi } List constructorParameterTypes = new ArrayList<>(); - // Fields and constructor - FieldCreator subclassField = null; - if (decoratedMethods.size() != nextDecoratorsValues.size()) { - subclassField = delegateSubclass.getFieldCreator("subclass", subclass.getClassName()) - .setModifiers(ACC_PRIVATE | ACC_FINAL); - constructorParameterTypes.add(subclass.getClassName()); - } + // Holds a reference to the subclass of the decorated bean + FieldCreator subclassField = delegateSubclass.getFieldCreator("subclass", subclass.getClassName()) + .setModifiers(ACC_PRIVATE | ACC_FINAL); + constructorParameterTypes.add(subclass.getClassName()); Map nextDecoratorToField = new HashMap<>(); for (DecoratorInfo nextDecorator : decoratorParameters) { FieldCreator nextDecoratorField = delegateSubclass @@ -653,6 +650,7 @@ private void processDecorator(DecoratorInfo decorator, BeanInfo bean, Type provi nextDecoratorToField.put(nextDecorator, nextDecoratorField.getFieldDescriptor()); } + // Constructor MethodCreator constructor = delegateSubclass.getMethodCreator(Methods.INIT, "V", constructorParameterTypes.toArray(new String[0])); int param = 0; @@ -664,10 +662,8 @@ private void processDecorator(DecoratorInfo decorator, BeanInfo bean, Type provi constructor.getThis()); } // Set fields - if (subclassField != null) { - constructor.writeInstanceField( - subclassField.getFieldDescriptor(), constructor.getThis(), constructor.getMethodParam(param++)); - } + constructor.writeInstanceField( + subclassField.getFieldDescriptor(), constructor.getThis(), constructor.getMethodParam(param++)); for (FieldDescriptor field : nextDecoratorToField.values()) { constructor.writeInstanceField( field, constructor.getThis(), constructor.getMethodParam(param++)); @@ -700,10 +696,6 @@ private void processDecorator(DecoratorInfo decorator, BeanInfo bean, Type provi for (MethodKey m : methods) { MethodInfo method = m.method; - if (Methods.skipForDelegateSubclass(method)) { - continue; - } - MethodDescriptor methodDescriptor = MethodDescriptor.of(method); MethodCreator forward = delegateSubclass.getMethodCreator(methodDescriptor); // Exceptions @@ -818,9 +810,7 @@ && isDecorated(decoratedMethodDescriptors, methodDescriptor, resolvedMethodDescr // Create new delegate subclass instance and set the DecoratorDelegateProvider to satisfy the delegate IP ResultHandle[] paramHandles = new ResultHandle[constructorParameterTypes.size()]; int paramIdx = 0; - if (subclassField != null) { - paramHandles[paramIdx++] = subclassConstructor.getThis(); - } + paramHandles[paramIdx++] = subclassConstructor.getThis(); for (DecoratorInfo decoratorParameter : decoratorParameters) { ResultHandle decoratorHandle = decoratorToResultHandle.get(decoratorParameter.getIdentifier()); if (decoratorHandle == null) { diff --git a/independent-projects/arc/tests/src/test/java/io/quarkus/arc/test/decorators/DecoratorDefaultMethodTest.java b/independent-projects/arc/tests/src/test/java/io/quarkus/arc/test/decorators/DecoratorDefaultMethodTest.java new file mode 100644 index 0000000000000..ca072e9ae26cd --- /dev/null +++ b/independent-projects/arc/tests/src/test/java/io/quarkus/arc/test/decorators/DecoratorDefaultMethodTest.java @@ -0,0 +1,59 @@ +package io.quarkus.arc.test.decorators; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import jakarta.annotation.Priority; +import jakarta.decorator.Decorator; +import jakarta.decorator.Delegate; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.util.TypeLiteral; +import jakarta.inject.Inject; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.arc.Arc; +import io.quarkus.arc.test.ArcTestContainer; + +public class DecoratorDefaultMethodTest { + @RegisterExtension + public ArcTestContainer container = new ArcTestContainer(Converter.class, ToLengthConverter.class, + NoopConverterDecorator.class); + + @SuppressWarnings("serial") + @Test + public void testDecoration() { + Converter converter = Arc.container().instance(new TypeLiteral>() { + }).get(); + assertEquals(5, converter.convert("Hola!")); + } + + interface Converter { + default int convert(T value) { + return Integer.MAX_VALUE; + } + } + + @ApplicationScoped + static class ToLengthConverter implements Converter { + @Override + public int convert(String value) { + return value.length(); + } + } + + @Priority(1) + @Decorator + static class NoopConverterDecorator implements Converter { + + @Inject + @Delegate + Converter delegate; + + @Override + public int convert(String value) { + return delegate.convert(value); + } + } + +}