From 62cd6384e2afa58ee7b2f8d6c452f15e0ac05223 Mon Sep 17 00:00:00 2001 From: Emily Wang Date: Mon, 26 Sep 2022 20:20:21 +0000 Subject: [PATCH 1/4] Update annotations to use classes and parameters instead of strings --- .../SpringAutoConfigClassComposer.java | 79 +++++++++++++++---- .../SpringAutoConfigClassComposerTest.java | 9 ++- 2 files changed, 69 insertions(+), 19 deletions(-) diff --git a/src/main/java/com/google/api/generator/spring/composer/SpringAutoConfigClassComposer.java b/src/main/java/com/google/api/generator/spring/composer/SpringAutoConfigClassComposer.java index fe33bbdfb9..d673b8525c 100644 --- a/src/main/java/com/google/api/generator/spring/composer/SpringAutoConfigClassComposer.java +++ b/src/main/java/com/google/api/generator/spring/composer/SpringAutoConfigClassComposer.java @@ -32,9 +32,11 @@ import com.google.api.generator.engine.ast.MethodDefinition; import com.google.api.generator.engine.ast.MethodInvocationExpr; import com.google.api.generator.engine.ast.NewObjectExpr; +import com.google.api.generator.engine.ast.PrimitiveValue; import com.google.api.generator.engine.ast.RelationalOperationExpr; import com.google.api.generator.engine.ast.ScopeNode; import com.google.api.generator.engine.ast.Statement; +import com.google.api.generator.engine.ast.StringObjectValue; import com.google.api.generator.engine.ast.ThisObjectValue; import com.google.api.generator.engine.ast.TypeNode; import com.google.api.generator.engine.ast.ValueExpr; @@ -401,37 +403,84 @@ private static List createClassAnnotations( // @ConditionalOnProperty(value = "spring.cloud.gcp.language.enabled", matchIfMissing = true) // @EnableConfigurationProperties(LanguageProperties.class) - // TODO: AnnotationNode description only accepts String for now. need to extend to params - // and classes. + AssignmentExpr valueStringAssignmentExpr = + AssignmentExpr.builder() + .setVariableExpr( + VariableExpr.withVariable( + Variable.builder().setName("value").setType(TypeNode.STRING).build())) + .setValueExpr( + ValueExpr.withValue( + StringObjectValue.withValue( + Utils.springPropertyPrefix(libName, service.name()) + ".enabled"))) + .build(); + AssignmentExpr matchIfMissingAssignmentExpr = + AssignmentExpr.builder() + .setVariableExpr( + VariableExpr.withVariable( + Variable.builder().setName("matchIfMissing").setType(TypeNode.BOOLEAN).build())) + .setValueExpr( + ValueExpr.withValue( + PrimitiveValue.builder().setValue("false").setType(TypeNode.BOOLEAN).build())) + .build(); AnnotationNode conditionalOnPropertyNode = AnnotationNode.builder() .setType(types.get("ConditionalOnProperty")) - .setDescription( - "value = \"" - + Utils.springPropertyPrefix(libName, service.name()) - + ".enabled\", matchIfMissing = false") + .addDescription(valueStringAssignmentExpr) + .addDescription(matchIfMissingAssignmentExpr) + .build(); + + TypeNode clazzType = + TypeNode.withReference( + VaporReference.builder() + .setName(ClassNames.getServiceClientClassName(service)) + .setPakkage(service.pakkage()) + .build()); + VariableExpr conditionalOnClassVariableExpr = + VariableExpr.builder() + .setVariable(Variable.builder().setType(TypeNode.CLASS_OBJECT).setName("class").build()) + .setStaticReferenceType(clazzType) .build(); AnnotationNode conditionalOnClassNode = AnnotationNode.builder() .setType(types.get("ConditionalOnClass")) - .setDescription( - "value = " - + ClassNames.getServiceClientClassName(service) - + ".class") // TODO: change after annotation feature merged. need to produce - // XXX.class + .setDescription(conditionalOnClassVariableExpr) + .build(); + + AssignmentExpr proxyBeanMethodsAssignmentExpr = + AssignmentExpr.builder() + .setVariableExpr( + VariableExpr.withVariable( + Variable.builder() + .setName("proxyBeanMethods") + .setType(TypeNode.BOOLEAN) + .build())) + .setValueExpr( + ValueExpr.withValue( + PrimitiveValue.builder().setValue("false").setType(TypeNode.BOOLEAN).build())) .build(); AnnotationNode configurationNode = AnnotationNode.builder() .setType(types.get("Configuration")) - .setDescription("proxyBeanMethods = false") // TODO: change to parameters + .addDescription(proxyBeanMethodsAssignmentExpr) + .build(); + + TypeNode propertiesClazzType = + TypeNode.withReference( + VaporReference.builder() + .setName(types.get(service.name() + "Properties").reference().name()) + .setPakkage(service.pakkage()) + .build()); + VariableExpr propertiesClassVariableExpr = + VariableExpr.builder() + .setVariable(Variable.builder().setType(TypeNode.CLASS_OBJECT).setName("class").build()) + .setStaticReferenceType(propertiesClazzType) .build(); AnnotationNode enableConfigurationPropertiesNode = AnnotationNode.builder() .setType(types.get("EnableConfigurationProperties")) - .setDescription( - types.get(service.name() + "Properties").reference().name() - + ".Class") // TODO: change to parameters + .setDescription(propertiesClassVariableExpr) .build(); + return Arrays.asList( AnnotationNode.builder() .setType(STATIC_TYPES.get("Generated")) diff --git a/src/test/java/com/google/api/generator/spring/SpringAutoConfigClassComposerTest.java b/src/test/java/com/google/api/generator/spring/SpringAutoConfigClassComposerTest.java index d31a8e4b03..65b89cbd02 100644 --- a/src/test/java/com/google/api/generator/spring/SpringAutoConfigClassComposerTest.java +++ b/src/test/java/com/google/api/generator/spring/SpringAutoConfigClassComposerTest.java @@ -151,11 +151,12 @@ public void generatePropertiesTest() { + "import org.springframework.context.annotation.Configuration;\n" + "\n" + "@Generated(\"by gapic-generator-java\")\n" - + "@Configuration(\"proxyBeanMethods = false\")\n" - + "@ConditionalOnClass(\"value = EchoClient.class\")\n" + + "@Configuration(proxyBeanMethods = false)\n" + + "@ConditionalOnClass(EchoClient.class)\n" + "@ConditionalOnProperty(\n" - + " \"value = \\\"spring.cloud.gcp.autoconfig.showcase.echo.enabled\\\", matchIfMissing = false\")\n" - + "@EnableConfigurationProperties(\"EchoSpringProperties.Class\")\n" + + " value = \"spring.cloud.gcp.autoconfig.showcase.echo.enabled\",\n" + + " matchIfMissing = false)\n" + + "@EnableConfigurationProperties(EchoSpringProperties.class)\n" + "public class EchoSpringAutoConfiguration {\n" + " private final EchoSpringProperties clientProperties;\n" + " private static final ImmutableMap RETRY_PARAM_DEFINITIONS;\n" From 3efc65740bba623c0c735cc16d9246c600f8c3cb Mon Sep 17 00:00:00 2001 From: Emily Wang Date: Wed, 28 Sep 2022 17:32:10 +0000 Subject: [PATCH 2/4] Add qualifier annotations on variables --- .../SpringAutoConfigClassComposer.java | 33 +++++++++++++++++-- .../SpringAutoConfigClassComposerTest.java | 5 +-- 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/google/api/generator/spring/composer/SpringAutoConfigClassComposer.java b/src/main/java/com/google/api/generator/spring/composer/SpringAutoConfigClassComposer.java index d673b8525c..0525da4732 100644 --- a/src/main/java/com/google/api/generator/spring/composer/SpringAutoConfigClassComposer.java +++ b/src/main/java/com/google/api/generator/spring/composer/SpringAutoConfigClassComposer.java @@ -945,14 +945,35 @@ private static MethodDefinition createClientBeanMethod( String methodName = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_CAMEL, service.name()) + "Client"; + String transportChannelProviderName = "default" + service.name() + "TransportChannelProvider"; + String credentialsProviderName = "googleCredentials"; + return MethodDefinition.builder() .setName(methodName) .setScope(ScopeNode.PUBLIC) .setReturnType(types.get("ServiceClient")) .setArguments( Arrays.asList( - credentialsProviderVariableExpr.toBuilder().setIsDecl(true).build(), - transportChannelProviderVariableExpr.toBuilder().setIsDecl(true).build())) + credentialsProviderVariableExpr + .toBuilder() + .setIsDecl(true) + .setAnnotations( + Arrays.asList( + AnnotationNode.builder() + .setType(types.get("Qualifier")) + .setDescription(credentialsProviderName) + .build())) + .build(), + transportChannelProviderVariableExpr + .toBuilder() + .setIsDecl(true) + .setAnnotations( + Arrays.asList( + AnnotationNode.builder() + .setType(types.get("Qualifier")) + .setDescription(transportChannelProviderName) + .build())) + .build())) .setAnnotations( Arrays.asList( AnnotationNode.withType(types.get("Bean")), @@ -1101,6 +1122,13 @@ private static Map createDynamicTypes(Service service, String .setPakkage("org.springframework.boot.autoconfigure.condition") .build()); + TypeNode qualifier = + TypeNode.withReference( + VaporReference.builder() + .setName("Qualifier") + .setPakkage("org.springframework.beans.factory.annotation") + .build()); + typeMap.put("CredentialsProvider", credentialsProvider); typeMap.put(service.name() + "Properties", clientProperties); typeMap.put(service.name() + "AutoConfig", clientAutoconfig); @@ -1116,6 +1144,7 @@ private static Map createDynamicTypes(Service service, String typeMap.put("ConditionalOnMissingBean", conditionalOnMissingBean); typeMap.put("ConditionalOnProperty", conditionalOnProperty); typeMap.put("ConditionalOnClass", conditionalOnClass); + typeMap.put("Qualifier", qualifier); return typeMap; } diff --git a/src/test/java/com/google/api/generator/spring/SpringAutoConfigClassComposerTest.java b/src/test/java/com/google/api/generator/spring/SpringAutoConfigClassComposerTest.java index 65b89cbd02..5bcb0aed64 100644 --- a/src/test/java/com/google/api/generator/spring/SpringAutoConfigClassComposerTest.java +++ b/src/test/java/com/google/api/generator/spring/SpringAutoConfigClassComposerTest.java @@ -189,8 +189,9 @@ public void generatePropertiesTest() { + " @Bean\n" + " @ConditionalOnMissingBean\n" + " public EchoClient echoClient(\n" - + " CredentialsProvider credentialsProvider,\n" - + " TransportChannelProvider defaultTransportChannelProvider)\n" + + " @Qualifier(\"googleCredentials\") CredentialsProvider credentialsProvider,\n" + + " @Qualifier(\"defaultEchoTransportChannelProvider\")\n" + + " TransportChannelProvider defaultTransportChannelProvider)\n" + " throws IOException {\n" + " EchoSettings.Builder clientSettingsBuilder =\n" + " EchoSettings.newBuilder()\n" From 93c17652dd48aec404b0df42ddb02897fba087bb Mon Sep 17 00:00:00 2001 From: Emily Wang Date: Wed, 28 Sep 2022 18:16:17 +0000 Subject: [PATCH 3/4] Reuse types that are already defined --- .../SpringAutoConfigClassComposer.java | 36 +++++++------------ 1 file changed, 12 insertions(+), 24 deletions(-) diff --git a/src/main/java/com/google/api/generator/spring/composer/SpringAutoConfigClassComposer.java b/src/main/java/com/google/api/generator/spring/composer/SpringAutoConfigClassComposer.java index 0525da4732..447c6eda66 100644 --- a/src/main/java/com/google/api/generator/spring/composer/SpringAutoConfigClassComposer.java +++ b/src/main/java/com/google/api/generator/spring/composer/SpringAutoConfigClassComposer.java @@ -429,21 +429,15 @@ private static List createClassAnnotations( .addDescription(matchIfMissingAssignmentExpr) .build(); - TypeNode clazzType = - TypeNode.withReference( - VaporReference.builder() - .setName(ClassNames.getServiceClientClassName(service)) - .setPakkage(service.pakkage()) - .build()); - VariableExpr conditionalOnClassVariableExpr = - VariableExpr.builder() - .setVariable(Variable.builder().setType(TypeNode.CLASS_OBJECT).setName("class").build()) - .setStaticReferenceType(clazzType) - .build(); AnnotationNode conditionalOnClassNode = AnnotationNode.builder() .setType(types.get("ConditionalOnClass")) - .setDescription(conditionalOnClassVariableExpr) + .setDescription( + VariableExpr.builder() + .setVariable( + Variable.builder().setType(TypeNode.CLASS_OBJECT).setName("class").build()) + .setStaticReferenceType(types.get("ServiceClient")) + .build()) .build(); AssignmentExpr proxyBeanMethodsAssignmentExpr = @@ -464,21 +458,15 @@ private static List createClassAnnotations( .addDescription(proxyBeanMethodsAssignmentExpr) .build(); - TypeNode propertiesClazzType = - TypeNode.withReference( - VaporReference.builder() - .setName(types.get(service.name() + "Properties").reference().name()) - .setPakkage(service.pakkage()) - .build()); - VariableExpr propertiesClassVariableExpr = - VariableExpr.builder() - .setVariable(Variable.builder().setType(TypeNode.CLASS_OBJECT).setName("class").build()) - .setStaticReferenceType(propertiesClazzType) - .build(); AnnotationNode enableConfigurationPropertiesNode = AnnotationNode.builder() .setType(types.get("EnableConfigurationProperties")) - .setDescription(propertiesClassVariableExpr) + .setDescription( + VariableExpr.builder() + .setVariable( + Variable.builder().setType(TypeNode.CLASS_OBJECT).setName("class").build()) + .setStaticReferenceType(types.get(service.name() + "Properties")) + .build()) .build(); return Arrays.asList( From 82699cb12fe9714c247755a352b0d566e7e97aae Mon Sep 17 00:00:00 2001 From: Emily Wang Date: Wed, 28 Sep 2022 19:46:53 +0000 Subject: [PATCH 4/4] Add member variable annotation to credentials property --- .../SpringPropertiesClassComposer.java | 27 ++++++++++++++----- .../SpringAutoConfigClassComposerTest.java | 2 ++ 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/google/api/generator/spring/composer/SpringPropertiesClassComposer.java b/src/main/java/com/google/api/generator/spring/composer/SpringPropertiesClassComposer.java index 35f30a40a6..ad28f3fde3 100644 --- a/src/main/java/com/google/api/generator/spring/composer/SpringPropertiesClassComposer.java +++ b/src/main/java/com/google/api/generator/spring/composer/SpringPropertiesClassComposer.java @@ -92,12 +92,17 @@ public GapicClass generate(GapicContext context, Service service) { } private static ExprStatement createMemberVarStatement( - String varName, TypeNode varType, boolean isFinal, Expr defaultVal) { + String varName, + TypeNode varType, + boolean isFinal, + Expr defaultVal, + List annotationNodes) { Variable memberVar = Variable.builder().setName(varName).setType(varType).build(); VariableExpr memberVarExpr = VariableExpr.builder() .setVariable(memberVar) .setScope(ScopeNode.PRIVATE) + .setAnnotations(annotationNodes == null ? Collections.emptyList() : annotationNodes) .setIsDecl(true) .setIsFinal(isFinal) .build(); @@ -133,22 +138,30 @@ private static List createMemberVariables( .map(x -> ValueExpr.withValue(StringObjectValue.withValue(x))) .collect(Collectors.toList())) .build(); - // TODO: credentials field needs annotation. + // Note that the annotations are set on the VariableExpr rather than the ExprStatement. + // The single annotation works fine here, + // but multiple annotations would be written to the same line + List credentialsAnnotations = + Arrays.asList(AnnotationNode.withType(types.get("NestedConfigurationProperty"))); ExprStatement credentialsStatement = createMemberVarStatement( - "credentials", types.get("Credentials"), true, defaultCredentialScopes); + "credentials", + types.get("Credentials"), + true, + defaultCredentialScopes, + credentialsAnnotations); // private String quotaProjectId; ExprStatement quotaProjectIdVarStatement = - createMemberVarStatement("quotaProjectId", TypeNode.STRING, false, null); + createMemberVarStatement("quotaProjectId", TypeNode.STRING, false, null, null); // private Integer executorThreadCount; ExprStatement executorThreadCountVarStatement = - createMemberVarStatement("executorThreadCount", TypeNode.INT_OBJECT, false, null); + createMemberVarStatement("executorThreadCount", TypeNode.INT_OBJECT, false, null, null); // private boolean useRest = false; ExprStatement useRestVarStatement = - createMemberVarStatement("useRest", TypeNode.BOOLEAN, false, null); + createMemberVarStatement("useRest", TypeNode.BOOLEAN, false, null, null); // // private static final ImmutableMap RETRY_PARAM_DEFINITIONS; @@ -170,7 +183,7 @@ private static List createMemberVariables( } String propertyName = Joiner.on("").join(methodAndPropertyName); ExprStatement retrySettingsStatement = - createMemberVarStatement(propertyName, propertyType, false, null); + createMemberVarStatement(propertyName, propertyType, false, null, null); getterAndSetter.add(retrySettingsStatement); return getterAndSetter; }, diff --git a/src/test/java/com/google/api/generator/spring/SpringAutoConfigClassComposerTest.java b/src/test/java/com/google/api/generator/spring/SpringAutoConfigClassComposerTest.java index 5bcb0aed64..7a6cb81766 100644 --- a/src/test/java/com/google/api/generator/spring/SpringAutoConfigClassComposerTest.java +++ b/src/test/java/com/google/api/generator/spring/SpringAutoConfigClassComposerTest.java @@ -304,8 +304,10 @@ public void generatePropertiesTest() { + "\n" + "@ConfigurationProperties(\"spring.cloud.gcp.autoconfig.showcase.echo\")\n" + "public class EchoSpringProperties implements CredentialsSupplier {\n" + + " @NestedConfigurationProperty\n" + " private final Credentials credentials =\n" + " new Credentials(\"https://www.googleapis.com/auth/cloud-platform\");\n" + + "\n" + " private String quotaProjectId;\n" + " private Integer executorThreadCount;\n" + " private boolean useRest;\n"