From bb0443b244ca8611065d5d75da0b1340ad29d573 Mon Sep 17 00:00:00 2001 From: Georgios Andrianakis Date: Tue, 2 Jul 2024 14:36:17 +0300 Subject: [PATCH] Fix bytecode recording issue when default method is used as a getter See https://quarkusio.zulipchat.com/#narrow/stream/187038-dev/topic/Using.20default.20interface.20implementation.20in.20recordable.20class.3F/near/448577914 --- .../recording/BytecodeRecorderImpl.java | 13 +++++-- .../ControllerConfigurationBuildStep.java | 20 +++++++++++ .../def/ControllerConfigurationTest.java | 35 +++++++++++++++++++ .../runtime/def/ControllerConfiguration.java | 8 +++++ .../def/ControllerConfigurationProducer.java | 11 ++++++ .../def/ControllerConfigurationRecorder.java | 13 +++++++ .../def/QuarkusControllerConfiguration.java | 24 +++++++++++++ .../runtime/def/ResourceConfiguration.java | 19 ++++++++++ 8 files changed, 140 insertions(+), 3 deletions(-) create mode 100644 integration-tests/test-extension/extension/deployment/src/main/java/io/quarkus/extest/deployment/ControllerConfigurationBuildStep.java create mode 100644 integration-tests/test-extension/extension/deployment/src/test/java/io/quarkus/def/ControllerConfigurationTest.java create mode 100644 integration-tests/test-extension/extension/runtime/src/main/java/io/quarkus/extest/runtime/def/ControllerConfiguration.java create mode 100644 integration-tests/test-extension/extension/runtime/src/main/java/io/quarkus/extest/runtime/def/ControllerConfigurationProducer.java create mode 100644 integration-tests/test-extension/extension/runtime/src/main/java/io/quarkus/extest/runtime/def/ControllerConfigurationRecorder.java create mode 100644 integration-tests/test-extension/extension/runtime/src/main/java/io/quarkus/extest/runtime/def/QuarkusControllerConfiguration.java create mode 100644 integration-tests/test-extension/extension/runtime/src/main/java/io/quarkus/extest/runtime/def/ResourceConfiguration.java diff --git a/core/deployment/src/main/java/io/quarkus/deployment/recording/BytecodeRecorderImpl.java b/core/deployment/src/main/java/io/quarkus/deployment/recording/BytecodeRecorderImpl.java index 651d21b79eddc..91b33a0756886 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/recording/BytecodeRecorderImpl.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/recording/BytecodeRecorderImpl.java @@ -1235,9 +1235,16 @@ public void prepare(MethodContext context) { public void handle(MethodContext context, MethodCreator method, DeferredArrayStoreParameter out) { //get the collection - ResultHandle prop = method.invokeVirtualMethod( - MethodDescriptor.ofMethod(i.getReadMethod()), - context.loadDeferred(out)); + ResultHandle prop; + if (i.getReadMethod().isDefault()) { + prop = method.invokeInterfaceMethod( + MethodDescriptor.ofMethod(i.getReadMethod()), + context.loadDeferred(out)); + } else { + prop = method.invokeVirtualMethod( + MethodDescriptor.ofMethod(i.getReadMethod()), + context.loadDeferred(out)); + } for (DeferredParameter i : params) { //add the parameter //TODO: this is not guarded against large collections, probably not an issue in practice diff --git a/integration-tests/test-extension/extension/deployment/src/main/java/io/quarkus/extest/deployment/ControllerConfigurationBuildStep.java b/integration-tests/test-extension/extension/deployment/src/main/java/io/quarkus/extest/deployment/ControllerConfigurationBuildStep.java new file mode 100644 index 0000000000000..8e89f1256de0b --- /dev/null +++ b/integration-tests/test-extension/extension/deployment/src/main/java/io/quarkus/extest/deployment/ControllerConfigurationBuildStep.java @@ -0,0 +1,20 @@ +package io.quarkus.extest.deployment; + +import io.quarkus.arc.deployment.AdditionalBeanBuildItem; +import io.quarkus.deployment.annotations.BuildProducer; +import io.quarkus.deployment.annotations.BuildStep; +import io.quarkus.deployment.annotations.ExecutionTime; +import io.quarkus.deployment.annotations.Record; +import io.quarkus.extest.runtime.def.ControllerConfigurationProducer; +import io.quarkus.extest.runtime.def.ControllerConfigurationRecorder; +import io.quarkus.extest.runtime.def.QuarkusControllerConfiguration; + +public class ControllerConfigurationBuildStep { + + @BuildStep + @Record(ExecutionTime.RUNTIME_INIT) + public void record(ControllerConfigurationRecorder recorder, BuildProducer producer) { + producer.produce(AdditionalBeanBuildItem.builder().addBeanClasses(ControllerConfigurationProducer.class).build()); + recorder.setControllerConfiguration(new QuarkusControllerConfiguration("test1", "test2")); + } +} diff --git a/integration-tests/test-extension/extension/deployment/src/test/java/io/quarkus/def/ControllerConfigurationTest.java b/integration-tests/test-extension/extension/deployment/src/test/java/io/quarkus/def/ControllerConfigurationTest.java new file mode 100644 index 0000000000000..8538a8d2c859d --- /dev/null +++ b/integration-tests/test-extension/extension/deployment/src/test/java/io/quarkus/def/ControllerConfigurationTest.java @@ -0,0 +1,35 @@ +package io.quarkus.def; + +import static org.assertj.core.api.Assertions.assertThat; + +import jakarta.inject.Inject; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.extest.runtime.def.ControllerConfiguration; +import io.quarkus.extest.runtime.def.QuarkusControllerConfiguration; +import io.quarkus.test.QuarkusUnitTest; + +public class ControllerConfigurationTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .withEmptyApplication(); + + @Inject + ControllerConfiguration controllerConfiguration; + + @Test + public void test() { + assertThat(controllerConfiguration).isInstanceOfSatisfying(QuarkusControllerConfiguration.class, + quarkusControllerConfiguration -> { + assertThat(quarkusControllerConfiguration.getName()).isEqualTo("test1"); + assertThat(quarkusControllerConfiguration.getResourceTypeName()).isEqualTo("test2"); + assertThat(controllerConfiguration.getNamespaces()).containsOnly("foo", "bar"); + assertThat(controllerConfiguration.getInformerListLimit()).isEmpty(); + }); + + } + +} diff --git a/integration-tests/test-extension/extension/runtime/src/main/java/io/quarkus/extest/runtime/def/ControllerConfiguration.java b/integration-tests/test-extension/extension/runtime/src/main/java/io/quarkus/extest/runtime/def/ControllerConfiguration.java new file mode 100644 index 0000000000000..3c95427b9c1b5 --- /dev/null +++ b/integration-tests/test-extension/extension/runtime/src/main/java/io/quarkus/extest/runtime/def/ControllerConfiguration.java @@ -0,0 +1,8 @@ +package io.quarkus.extest.runtime.def; + +public interface ControllerConfiguration extends ResourceConfiguration { + + default String getName() { + return "name"; + } +} diff --git a/integration-tests/test-extension/extension/runtime/src/main/java/io/quarkus/extest/runtime/def/ControllerConfigurationProducer.java b/integration-tests/test-extension/extension/runtime/src/main/java/io/quarkus/extest/runtime/def/ControllerConfigurationProducer.java new file mode 100644 index 0000000000000..4cf319b5c24c8 --- /dev/null +++ b/integration-tests/test-extension/extension/runtime/src/main/java/io/quarkus/extest/runtime/def/ControllerConfigurationProducer.java @@ -0,0 +1,11 @@ +package io.quarkus.extest.runtime.def; + +import jakarta.inject.Singleton; + +public class ControllerConfigurationProducer { + + @Singleton + public ControllerConfiguration produce() { + return ControllerConfigurationRecorder.controllerConfiguration; + } +} diff --git a/integration-tests/test-extension/extension/runtime/src/main/java/io/quarkus/extest/runtime/def/ControllerConfigurationRecorder.java b/integration-tests/test-extension/extension/runtime/src/main/java/io/quarkus/extest/runtime/def/ControllerConfigurationRecorder.java new file mode 100644 index 0000000000000..00b9ce1e760e2 --- /dev/null +++ b/integration-tests/test-extension/extension/runtime/src/main/java/io/quarkus/extest/runtime/def/ControllerConfigurationRecorder.java @@ -0,0 +1,13 @@ +package io.quarkus.extest.runtime.def; + +import io.quarkus.runtime.annotations.Recorder; + +@Recorder +public class ControllerConfigurationRecorder { + + public static volatile ControllerConfiguration controllerConfiguration; + + public void setControllerConfiguration(QuarkusControllerConfiguration controllerConfiguration) { + ControllerConfigurationRecorder.controllerConfiguration = controllerConfiguration; + } +} diff --git a/integration-tests/test-extension/extension/runtime/src/main/java/io/quarkus/extest/runtime/def/QuarkusControllerConfiguration.java b/integration-tests/test-extension/extension/runtime/src/main/java/io/quarkus/extest/runtime/def/QuarkusControllerConfiguration.java new file mode 100644 index 0000000000000..55eb7689b14bc --- /dev/null +++ b/integration-tests/test-extension/extension/runtime/src/main/java/io/quarkus/extest/runtime/def/QuarkusControllerConfiguration.java @@ -0,0 +1,24 @@ +package io.quarkus.extest.runtime.def; + +import io.quarkus.runtime.annotations.RecordableConstructor; + +public class QuarkusControllerConfiguration implements ControllerConfiguration { + + private final String name; + private final String resourceTypeName; + + @RecordableConstructor + public QuarkusControllerConfiguration(String name, String resourceTypeName) { + this.name = name; + this.resourceTypeName = resourceTypeName; + } + + @Override + public String getName() { + return name; + } + + public String getResourceTypeName() { + return resourceTypeName; + } +} diff --git a/integration-tests/test-extension/extension/runtime/src/main/java/io/quarkus/extest/runtime/def/ResourceConfiguration.java b/integration-tests/test-extension/extension/runtime/src/main/java/io/quarkus/extest/runtime/def/ResourceConfiguration.java new file mode 100644 index 0000000000000..8244e21e124e1 --- /dev/null +++ b/integration-tests/test-extension/extension/runtime/src/main/java/io/quarkus/extest/runtime/def/ResourceConfiguration.java @@ -0,0 +1,19 @@ +package io.quarkus.extest.runtime.def; + +import java.util.HashSet; +import java.util.Optional; +import java.util.Set; + +public interface ResourceConfiguration { + + default Set getNamespaces() { + HashSet set = new HashSet<>(); + set.add("foo"); + set.add("bar"); + return set; + } + + default Optional getInformerListLimit() { + return Optional.empty(); + } +}