From b55c59d29be093beee3ce24740fbccc592a86840 Mon Sep 17 00:00:00 2001 From: Matej Novotny Date: Fri, 15 Nov 2019 15:14:54 +0100 Subject: [PATCH] Arc - support static producer methods. --- .../quarkus/arc/processor/BeanGenerator.java | 72 +++++++++----- .../StaticMethodProducerTest.java | 98 +++++++++++++++++++ 2 files changed, 146 insertions(+), 24 deletions(-) create mode 100644 independent-projects/arc/tests/src/test/java/io/quarkus/arc/test/producer/staticProducers/StaticMethodProducerTest.java diff --git a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanGenerator.java b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanGenerator.java index 8a638e6ad3716..6a1ab91a75642 100644 --- a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanGenerator.java +++ b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanGenerator.java @@ -1119,25 +1119,31 @@ protected void implementCreate(ClassOutput classOutput, ClassCreator beanCreator create.returnValue(instanceHandle); } else if (bean.isProducerMethod()) { + MethodInfo producerMethod = bean.getTarget().get().asMethod(); instanceHandle = create.createVariable(DescriptorUtils.extToInt(providerTypeName)); // instance = declaringProviderSupplier.get().get(new CreationalContextImpl<>()).produce() + ResultHandle ctxHandle = create.newInstance( + MethodDescriptor.ofConstructor(CreationalContextImpl.class, Contextual.class), create.getThis()); + ResultHandle declaringProviderInstanceHandle; ResultHandle declaringProviderSupplierHandle = create.readInstanceField( FieldDescriptor.of(beanCreator.getClassName(), FIELD_NAME_DECLARING_PROVIDER_SUPPLIER, Supplier.class.getName()), create.getThis()); ResultHandle declaringProviderHandle = create.invokeInterfaceMethod( MethodDescriptors.SUPPLIER_GET, declaringProviderSupplierHandle); - ResultHandle ctxHandle = create.newInstance( - MethodDescriptor.ofConstructor(CreationalContextImpl.class, Contextual.class), create.getThis()); - ResultHandle declaringProviderInstanceHandle = create.invokeInterfaceMethod( - MethodDescriptors.INJECTABLE_REF_PROVIDER_GET, declaringProviderHandle, - ctxHandle); - - if (bean.getDeclaringBean().getScope().isNormal()) { - // We need to unwrap the client proxy + if (Modifier.isStatic(producerMethod.flags())) { + // for static producers, we don't need to resolve this this handle + declaringProviderInstanceHandle = create.loadNull(); + } else { declaringProviderInstanceHandle = create.invokeInterfaceMethod( - MethodDescriptors.CLIENT_PROXY_GET_CONTEXTUAL_INSTANCE, - declaringProviderInstanceHandle); + MethodDescriptors.INJECTABLE_REF_PROVIDER_GET, declaringProviderHandle, + ctxHandle); + if (bean.getDeclaringBean().getScope().isNormal()) { + // We need to unwrap the client proxy + declaringProviderInstanceHandle = create.invokeInterfaceMethod( + MethodDescriptors.CLIENT_PROXY_GET_CONTEXTUAL_INSTANCE, + declaringProviderInstanceHandle); + } } List injectionPoints = bean.getAllInjectionPoints(); @@ -1156,7 +1162,6 @@ protected void implementCreate(ClassOutput classOutput, ClassCreator beanCreator referenceHandles[paramIdx++] = referenceHandle; } - MethodInfo producerMethod = bean.getTarget().get().asMethod(); if (Modifier.isPrivate(producerMethod.flags())) { privateMembers.add(isApplicationClass, String.format("Producer method %s#%s()", producerMethod.declaringClass().name(), producerMethod.name())); @@ -1171,10 +1176,18 @@ protected void implementCreate(ClassOutput classOutput, ClassCreator beanCreator create.assign(instanceHandle, create.invokeStaticMethod(MethodDescriptors.REFLECTIONS_INVOKE_METHOD, create.loadClass(producerMethod.declaringClass().name().toString()), create.load(producerMethod.name()), paramTypesArray, - declaringProviderInstanceHandle, argsArray)); + declaringProviderInstanceHandle, + argsArray)); } else { - create.assign(instanceHandle, create.invokeVirtualMethod(MethodDescriptor.of(producerMethod), - declaringProviderInstanceHandle, referenceHandles)); + ResultHandle invokeMethodHandle; + if (Modifier.isStatic(producerMethod.flags())) { + invokeMethodHandle = create.invokeStaticMethod(MethodDescriptor.of(producerMethod), + referenceHandles); + } else { + invokeMethodHandle = create.invokeVirtualMethod(MethodDescriptor.of(producerMethod), + declaringProviderInstanceHandle, referenceHandles); + } + create.assign(instanceHandle, invokeMethodHandle); } if (bean.getScope().isNormal()) { @@ -1205,15 +1218,20 @@ protected void implementCreate(ClassOutput classOutput, ClassCreator beanCreator MethodDescriptors.SUPPLIER_GET, declaringProviderSupplierHandle); ResultHandle ctxHandle = create.newInstance( MethodDescriptor.ofConstructor(CreationalContextImpl.class, Contextual.class), create.getThis()); - ResultHandle declaringProviderInstanceHandle = create.invokeInterfaceMethod( - MethodDescriptors.INJECTABLE_REF_PROVIDER_GET, declaringProviderHandle, - ctxHandle); - - if (bean.getDeclaringBean().getScope().isNormal()) { - // We need to unwrap the client proxy + ResultHandle declaringProviderInstanceHandle; + if (Modifier.isStatic(producerField.flags())) { + declaringProviderInstanceHandle = create.loadNull(); + } else { declaringProviderInstanceHandle = create.invokeInterfaceMethod( - MethodDescriptors.CLIENT_PROXY_GET_CONTEXTUAL_INSTANCE, - declaringProviderInstanceHandle); + MethodDescriptors.INJECTABLE_REF_PROVIDER_GET, declaringProviderHandle, + ctxHandle); + + if (bean.getDeclaringBean().getScope().isNormal()) { + // We need to unwrap the client proxy + declaringProviderInstanceHandle = create.invokeInterfaceMethod( + MethodDescriptors.CLIENT_PROXY_GET_CONTEXTUAL_INSTANCE, + declaringProviderInstanceHandle); + } } if (Modifier.isPrivate(producerField.flags())) { @@ -1224,8 +1242,14 @@ protected void implementCreate(ClassOutput classOutput, ClassCreator beanCreator create.loadClass(producerField.declaringClass().name().toString()), create.load(producerField.name()), declaringProviderInstanceHandle)); } else { - create.assign(instanceHandle, - create.readInstanceField(FieldDescriptor.of(producerField), declaringProviderInstanceHandle)); + ResultHandle readFieldHandle; + if (Modifier.isStatic(producerField.flags())) { + readFieldHandle = create.readStaticField(FieldDescriptor.of(producerField)); + } else { + readFieldHandle = create.readInstanceField(FieldDescriptor.of(producerField), + declaringProviderInstanceHandle); + } + create.assign(instanceHandle, readFieldHandle); } if (bean.getScope().isNormal()) { diff --git a/independent-projects/arc/tests/src/test/java/io/quarkus/arc/test/producer/staticProducers/StaticMethodProducerTest.java b/independent-projects/arc/tests/src/test/java/io/quarkus/arc/test/producer/staticProducers/StaticMethodProducerTest.java new file mode 100644 index 0000000000000..ce753b6bdcf88 --- /dev/null +++ b/independent-projects/arc/tests/src/test/java/io/quarkus/arc/test/producer/staticProducers/StaticMethodProducerTest.java @@ -0,0 +1,98 @@ +package io.quarkus.arc.test.producer.staticProducers; + +import io.quarkus.arc.Arc; +import io.quarkus.arc.InstanceHandle; +import io.quarkus.arc.test.ArcTestContainer; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import javax.enterprise.inject.Produces; +import javax.enterprise.util.AnnotationLiteral; +import javax.inject.Qualifier; +import javax.inject.Singleton; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +/** + * Tests static method/field producers + */ +public class StaticMethodProducerTest { + + @RegisterExtension + public ArcTestContainer container = new ArcTestContainer(StaticMethodProducerTest.class, SomeProducer.class, + MyQualifier.class); + + @Test + public void testStaticProducers() { + // method producers + InstanceHandle stringMethod = Arc.container().instance(String.class); + Assertions.assertTrue(stringMethod.isAvailable()); + Assertions.assertEquals("foo", stringMethod.get()); + InstanceHandle longMethod = Arc.container().instance(Long.class); + Assertions.assertTrue(longMethod.isAvailable()); + Assertions.assertEquals(2L, longMethod.get()); + InstanceHandle doubleMethod = Arc.container().instance(Double.class); + Assertions.assertTrue(doubleMethod.isAvailable()); + Assertions.assertEquals(2.1, doubleMethod.get()); + + // field producers + InstanceHandle stringField = Arc.container().instance(String.class, MyQualifier.Literal.INSTANCE); + Assertions.assertTrue(stringField.isAvailable()); + Assertions.assertEquals("foo", stringField.get()); + InstanceHandle longField = Arc.container().instance(Long.class, MyQualifier.Literal.INSTANCE); + Assertions.assertTrue(longField.isAvailable()); + Assertions.assertEquals(2L, longField.get()); + InstanceHandle doubleField = Arc.container().instance(Double.class, MyQualifier.Literal.INSTANCE); + Assertions.assertTrue(doubleField.isAvailable()); + Assertions.assertEquals(2.1, doubleField.get()); + } + + @Singleton + static class SomeProducer { + + static Long LONG = 2l; + static String STRING = "foo"; + static Double DOUBLE = 2.1; + + @Produces + private static Long produceLong() { + return LONG; + } + + @Produces + static String produceString() { + return STRING; + } + + @Produces + public static Double produceDouble() { + return DOUBLE; + } + + @Produces + @MyQualifier + private static Long longField = LONG; + + @Produces + @MyQualifier + static String stringField = STRING; + + @Produces + @MyQualifier + public static Double doubleField = DOUBLE; + } + + @Qualifier + @Retention(RetentionPolicy.RUNTIME) + @Target(value = { ElementType.TYPE, ElementType.FIELD, ElementType.METHOD }) + static @interface MyQualifier { + public final static class Literal extends AnnotationLiteral implements MyQualifier { + + public static final Literal INSTANCE = new Literal(); + private static final long serialVersionUID = 1L; + + } + } +}