From e3214647498496e5f51e66a5d8f5e082528f2757 Mon Sep 17 00:00:00 2001 From: Hemant Vyas Date: Sat, 18 Nov 2023 17:48:16 +0530 Subject: [PATCH] feat: Allow annotation GrpcClient for target type 'annotation' Add testcases with usage of GrpcClientWrapper meta-annotation. --- .../boot/grpc/client/inject/GrpcClient.java | 2 +- .../inject/GrpcClientMetaAnnotationTest.java | 200 ++++++++++++++++++ .../metaannotation/GrpcClientWrapper.java | 51 +++++ 3 files changed, 252 insertions(+), 1 deletion(-) create mode 100644 tests/src/test/java/net/devh/boot/grpc/test/inject/GrpcClientMetaAnnotationTest.java create mode 100644 tests/src/test/java/net/devh/boot/grpc/test/inject/metaannotation/GrpcClientWrapper.java diff --git a/grpc-client-spring-boot-autoconfigure/src/main/java/net/devh/boot/grpc/client/inject/GrpcClient.java b/grpc-client-spring-boot-autoconfigure/src/main/java/net/devh/boot/grpc/client/inject/GrpcClient.java index d81d922dc..145da8e0e 100644 --- a/grpc-client-spring-boot-autoconfigure/src/main/java/net/devh/boot/grpc/client/inject/GrpcClient.java +++ b/grpc-client-spring-boot-autoconfigure/src/main/java/net/devh/boot/grpc/client/inject/GrpcClient.java @@ -65,7 +65,7 @@ * * @see GrpcClientBean Add as bean to the {@link ApplicationContext}. */ -@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER}) +@Target({ElementType.ANNOTATION_TYPE, ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER}) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited diff --git a/tests/src/test/java/net/devh/boot/grpc/test/inject/GrpcClientMetaAnnotationTest.java b/tests/src/test/java/net/devh/boot/grpc/test/inject/GrpcClientMetaAnnotationTest.java new file mode 100644 index 000000000..3822ff98b --- /dev/null +++ b/tests/src/test/java/net/devh/boot/grpc/test/inject/GrpcClientMetaAnnotationTest.java @@ -0,0 +1,200 @@ +/* + * Copyright (c) 2016-2021 The gRPC-Spring Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.devh.boot.grpc.test.inject; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.lang.reflect.Field; + +import javax.annotation.PostConstruct; + +import org.junit.jupiter.api.Test; +import org.opentest4j.AssertionFailedError; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.TestConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; + +import io.grpc.stub.AbstractStub; +import net.devh.boot.grpc.client.stubfactory.StandardJavaGrpcStubFactory; +import net.devh.boot.grpc.client.stubfactory.StubFactory; +import net.devh.boot.grpc.test.config.BaseAutoConfiguration; +import net.devh.boot.grpc.test.config.InProcessConfiguration; +import net.devh.boot.grpc.test.config.ServiceConfiguration; +import net.devh.boot.grpc.test.inject.CustomGrpc.ConstructorAccessibleStub; +import net.devh.boot.grpc.test.inject.CustomGrpc.CustomAccessibleStub; +import net.devh.boot.grpc.test.inject.CustomGrpc.FactoryMethodAccessibleStub; +import net.devh.boot.grpc.test.inject.GrpcClientInjectionTest.TestConfig; +import net.devh.boot.grpc.test.inject.metaannotation.GrpcClientWrapper; +import net.devh.boot.grpc.test.proto.TestServiceGrpc.TestServiceBlockingStub; +import net.devh.boot.grpc.test.proto.TestServiceGrpc.TestServiceFutureStub; +import net.devh.boot.grpc.test.proto.TestServiceGrpc.TestServiceStub; + +/** + * A test checking that the client injection works. + * + * @author Hemant Vyas (v313hemant@gmail.com) + */ +@SpringBootTest +@SpringJUnitConfig(classes = {TestConfig.class, InProcessConfiguration.class, + ServiceConfiguration.class, + BaseAutoConfiguration.class}) +@DirtiesContext +class GrpcClientMetaAnnotationTest { + + @GrpcClientWrapper(value = "test", extraParamString = "testExtraParamString", extraParamBoolean = true) + TestServiceStub stub; + @GrpcClientWrapper(value = "test", extraParamString = "testExtraParamString", extraParamBoolean = true) + TestServiceBlockingStub blockingStub; + @GrpcClientWrapper(value = "test", extraParamString = "testExtraParamString", extraParamBoolean = true) + TestServiceFutureStub futureStub; + @GrpcClientWrapper(value = "test", extraParamString = "testExtraParamString", extraParamBoolean = true) + ConstructorAccessibleStub constructorStub; + @GrpcClientWrapper(value = "test", extraParamString = "testExtraParamString", extraParamBoolean = true) + FactoryMethodAccessibleStub factoryMethodStub; + @GrpcClientWrapper(value = "test", extraParamString = "testExtraParamString", extraParamBoolean = true) + CustomAccessibleStub customStub; + + TestServiceStub stubSetted; + TestServiceBlockingStub blockingStubSetted; + TestServiceFutureStub futureStubSetted; + ConstructorAccessibleStub constructorStubSetted; + FactoryMethodAccessibleStub factoryMethodStubSetted; + CustomAccessibleStub customStubSetted; + + @PostConstruct + public void init() { + // Test injection + assertNotNull(this.stub, "stub"); + assertNotNull(this.blockingStub, "blockingStub"); + assertNotNull(this.futureStub, "futureStub"); + assertNotNull(this.constructorStub, "constructorStub"); + assertNotNull(this.factoryMethodStub, "factoryMethodStub"); + assertNotNull(this.customStub, "customStub"); + + assertAnnotationExtraParams("testExtraParamString", true); + } + + @GrpcClientWrapper(value = "test", extraParamString = "testExtraParamString", extraParamBoolean = true) + void inject(final TestServiceStub stub) { + assertNotNull(stub, "stub"); + this.stubSetted = stub; + } + + @GrpcClientWrapper(value = "test", extraParamString = "testExtraParamString", extraParamBoolean = true) + void inject(final TestServiceBlockingStub stub) { + assertNotNull(stub, "stub"); + this.blockingStubSetted = stub; + } + + @GrpcClientWrapper(value = "test", extraParamString = "testExtraParamString", extraParamBoolean = true) + void inject(final TestServiceFutureStub stub) { + assertNotNull(stub, "stub"); + this.futureStubSetted = stub; + } + + @GrpcClientWrapper(value = "test", extraParamString = "testExtraParamString", extraParamBoolean = true) + void inject(final ConstructorAccessibleStub stub) { + assertNotNull(stub, "stub"); + this.constructorStubSetted = stub; + } + + @GrpcClientWrapper(value = "test", extraParamString = "testExtraParamString", extraParamBoolean = true) + void inject(final FactoryMethodAccessibleStub stub) { + assertNotNull(stub, "stub"); + this.factoryMethodStubSetted = stub; + } + + @GrpcClientWrapper(value = "test", extraParamString = "testExtraParamString", extraParamBoolean = true) + void inject(final CustomAccessibleStub stub) { + assertNotNull(stub, "stub"); + this.customStubSetted = stub; + } + + @Test + void testAllSet() { + // Field injection + assertNotNull(this.stub, "stub"); + assertNotNull(this.blockingStub, "blockingStub"); + assertNotNull(this.futureStub, "futureStub"); + assertNotNull(this.constructorStub, "constructorStub"); + assertNotNull(this.factoryMethodStub, "factoryMethodStub"); + assertNotNull(this.customStub, "customStub"); + // Setter injection + assertNotNull(this.stubSetted, "stubSetted"); + assertNotNull(this.blockingStubSetted, "blockingStubSetted"); + assertNotNull(this.futureStubSetted, "futureStubSetted"); + assertNotNull(this.constructorStubSetted, "constructorStubSetted"); + assertNotNull(this.factoryMethodStubSetted, "factoryMethodStubSetted"); + assertNotNull(this.customStubSetted, "customStubSetted"); + } + + @Test + void AnnotationExtraParamsNegativeTest() { + + AssertionFailedError exceptionA = assertThrows( + AssertionFailedError.class, + () -> assertAnnotationExtraParams("INCORRECT_VALUE", true), + "failed"); + + AssertionFailedError exceptionB = assertThrows( + AssertionFailedError.class, + () -> assertAnnotationExtraParams("testExtraParamString", false), + "failed"); + + assertNotNull(exceptionA); + assertNotNull(exceptionB); + } + + private void assertAnnotationExtraParams(String extraParamStringValue, + boolean extraParamBooleanValue) { + final Field[] fields = this.getClass().getDeclaredFields(); + for (final Field field : fields) { + if (field.isAnnotationPresent(GrpcClientWrapper.class)) { + final GrpcClientWrapper annotation = field.getAnnotation(GrpcClientWrapper.class); + assertEquals(extraParamStringValue, annotation.extraParamString()); + assertEquals(extraParamBooleanValue, annotation.extraParamBoolean()); + } + } + } + + @TestConfiguration + public static class TestConfig { + + @Bean + StubFactory customStubFactory() { + return new StandardJavaGrpcStubFactory() { + + @Override + public boolean isApplicable(final Class> stubType) { + return CustomStub.class.isAssignableFrom(stubType); + } + + @Override + protected String getFactoryMethodName() { + return "custom"; + } + + }; + } + + } + +} diff --git a/tests/src/test/java/net/devh/boot/grpc/test/inject/metaannotation/GrpcClientWrapper.java b/tests/src/test/java/net/devh/boot/grpc/test/inject/metaannotation/GrpcClientWrapper.java new file mode 100644 index 000000000..5aa2bea4f --- /dev/null +++ b/tests/src/test/java/net/devh/boot/grpc/test/inject/metaannotation/GrpcClientWrapper.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2016-2023 The gRPC-Spring Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.devh.boot.grpc.test.inject.metaannotation; + + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.springframework.core.annotation.AliasFor; + +import io.grpc.ClientInterceptor; +import net.devh.boot.grpc.client.inject.GrpcClient; + +@GrpcClient(value = "") +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.FIELD, ElementType.METHOD}) +public @interface GrpcClientWrapper { + + @AliasFor(annotation = GrpcClient.class, attribute = "value") + String value(); + + @AliasFor(annotation = GrpcClient.class, attribute = "interceptors") + Class[] interceptors() default {}; + + @AliasFor(annotation = GrpcClient.class, attribute = "interceptorNames") + String[] interceptorNames() default {}; + + @AliasFor(annotation = GrpcClient.class, attribute = "sortInterceptors") + boolean sortInterceptors() default false; + + String extraParamString(); + + boolean extraParamBoolean() default false; + +}