Skip to content

Commit ba039e9

Browse files
committed
feat: added poc for option c for compute lro error details
1 parent 5bd14bf commit ba039e9

6 files changed

Lines changed: 302 additions & 3 deletions

File tree

sdk-platform-java/gapic-generator-java/src/main/java/com/google/api/generator/engine/writer/JavaWriterVisitor.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -536,11 +536,27 @@ public void visit(ArithmeticOperationExpr arithmeticOperationExpr) {
536536

537537
@Override
538538
public void visit(UnaryOperationExpr unaryOperationExpr) {
539+
boolean needsParen = unaryOperationExpr.expr() instanceof InstanceofExpr
540+
|| unaryOperationExpr.expr() instanceof RelationalOperationExpr
541+
|| unaryOperationExpr.expr() instanceof LogicalOperationExpr;
542+
539543
if (unaryOperationExpr.operatorKind().isPrefixOperator()) {
540544
operator(unaryOperationExpr.operatorKind());
545+
if (needsParen) {
546+
leftParen();
547+
}
541548
unaryOperationExpr.expr().accept(this);
549+
if (needsParen) {
550+
rightParen();
551+
}
542552
} else {
553+
if (needsParen) {
554+
leftParen();
555+
}
543556
unaryOperationExpr.expr().accept(this);
557+
if (needsParen) {
558+
rightParen();
559+
}
544560
operator(unaryOperationExpr.operatorKind());
545561
}
546562
}

sdk-platform-java/gapic-generator-java/src/main/java/com/google/api/generator/gapic/composer/Composer.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import com.google.api.generator.gapic.composer.grpc.ServiceStubSettingsClassComposer;
2929
import com.google.api.generator.gapic.composer.grpcrest.HttpJsonServiceClientTestClassComposer;
3030
import com.google.api.generator.gapic.composer.resourcename.ResourceNameHelperClassComposer;
31+
import com.google.api.generator.gapic.composer.rest.ComputeLroErrorParserClassComposer;
3132
import com.google.api.generator.gapic.composer.rest.HttpJsonServiceCallableFactoryClassComposer;
3233
import com.google.api.generator.gapic.composer.rest.HttpJsonServiceStubClassComposer;
3334
import com.google.api.generator.gapic.model.GapicClass;
@@ -102,6 +103,10 @@ public static List<GapicClass> generateStubClasses(GapicContext context) {
102103
clazzes.add(
103104
HttpJsonServiceCallableFactoryClassComposer.instance().generate(context, s));
104105
clazzes.add(HttpJsonServiceStubClassComposer.instance().generate(context, s));
106+
if (s.pakkage().startsWith("com.google.cloud.compute.v1")) {
107+
clazzes.add(
108+
ComputeLroErrorParserClassComposer.instance().generate(context, s));
109+
}
105110
} else if (context.transport() == Transport.GRPC) {
106111
clazzes.add(ServiceStubClassComposer.instance().generate(context, s));
107112
clazzes.add(ServiceStubSettingsClassComposer.instance().generate(context, s));

sdk-platform-java/gapic-generator-java/src/main/java/com/google/api/generator/gapic/composer/common/RetrySettingsComposer.java

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,12 @@
3030
import com.google.api.generator.engine.ast.Expr;
3131
import com.google.api.generator.engine.ast.ExprStatement;
3232
import com.google.api.generator.engine.ast.MethodInvocationExpr;
33+
import com.google.api.generator.engine.ast.NewObjectExpr;
3334
import com.google.api.generator.engine.ast.PrimitiveValue;
3435
import com.google.api.generator.engine.ast.StringObjectValue;
3536
import com.google.api.generator.engine.ast.TypeNode;
3637
import com.google.api.generator.engine.ast.ValueExpr;
38+
import com.google.api.generator.engine.ast.VaporReference;
3739
import com.google.api.generator.engine.ast.Variable;
3840
import com.google.api.generator.engine.ast.VariableExpr;
3941
import com.google.api.generator.gapic.composer.store.TypeStore;
@@ -323,6 +325,21 @@ public static Expr createLroSettingsBuilderExpr(
323325
Variable.builder().setType(TypeNode.CLASS_OBJECT).setName("class").build())
324326
.setStaticReferenceType(t)
325327
.build();
328+
329+
List<Expr> createArgs = new ArrayList<>();
330+
createArgs.add(classFieldRefFn.apply(method.lro().responseType()));
331+
if (service.pakkage().startsWith("com.google.cloud.compute.v1") && operationResponseTransformer.reference().pakkage().equals("com.google.api.gax.httpjson")) {
332+
createArgs.add(
333+
NewObjectExpr.builder()
334+
.setType(
335+
TypeNode.withReference(
336+
VaporReference.builder()
337+
.setName("ComputeLroErrorParser")
338+
.setPakkage(service.pakkage() + ".stub")
339+
.build()))
340+
.build());
341+
}
342+
326343
builderSettingsExpr =
327344
MethodInvocationExpr.builder()
328345
.setExprReferenceExpr(builderSettingsExpr)
@@ -331,7 +348,7 @@ public static Expr createLroSettingsBuilderExpr(
331348
MethodInvocationExpr.builder()
332349
.setStaticReferenceType(operationResponseTransformer)
333350
.setMethodName("create")
334-
.setArguments(classFieldRefFn.apply(method.lro().responseType()))
351+
.setArguments(createArgs)
335352
.build())
336353
.build();
337354
builderSettingsExpr =
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
package com.google.api.generator.gapic.composer.rest;
2+
3+
import com.google.api.generator.engine.ast.AssignmentExpr;
4+
import com.google.api.generator.engine.ast.BlockStatement;
5+
import com.google.api.generator.engine.ast.CastExpr;
6+
import com.google.api.generator.engine.ast.ClassDefinition;
7+
import com.google.api.generator.engine.ast.ConcreteReference;
8+
import com.google.api.generator.engine.ast.Expr;
9+
import com.google.api.generator.engine.ast.ExprStatement;
10+
import com.google.api.generator.engine.ast.ForStatement;
11+
import com.google.api.generator.engine.ast.IfStatement;
12+
import com.google.api.generator.engine.ast.InstanceofExpr;
13+
import com.google.api.generator.engine.ast.LogicalOperationExpr;
14+
import com.google.api.generator.engine.ast.UnaryOperationExpr;
15+
import com.google.api.generator.engine.ast.MethodDefinition;
16+
import com.google.api.generator.engine.ast.MethodInvocationExpr;
17+
import com.google.api.generator.engine.ast.NewObjectExpr;
18+
import com.google.api.generator.engine.ast.PrimitiveValue;
19+
import com.google.api.generator.engine.ast.RelationalOperationExpr;
20+
import com.google.api.generator.engine.ast.ReturnExpr;
21+
import com.google.api.generator.engine.ast.ScopeNode;
22+
import com.google.api.generator.engine.ast.Statement;
23+
import com.google.api.generator.engine.ast.StringObjectValue;
24+
import com.google.api.generator.engine.ast.TypeNode;
25+
import com.google.api.generator.engine.ast.ValueExpr;
26+
import com.google.api.generator.engine.ast.VaporReference;
27+
import com.google.api.generator.engine.ast.Variable;
28+
import com.google.api.generator.engine.ast.VariableExpr;
29+
import com.google.api.generator.gapic.composer.comment.CommentComposer;
30+
import com.google.api.generator.gapic.model.GapicClass;
31+
import com.google.api.generator.gapic.model.GapicContext;
32+
import com.google.api.generator.gapic.model.Service;
33+
import java.util.ArrayList;
34+
import java.util.Arrays;
35+
import java.util.List;
36+
37+
public class ComputeLroErrorParserClassComposer {
38+
private static final ComputeLroErrorParserClassComposer INSTANCE = new ComputeLroErrorParserClassComposer();
39+
40+
public static ComputeLroErrorParserClassComposer instance() {
41+
return INSTANCE;
42+
}
43+
44+
public GapicClass generate(GapicContext context, Service service) {
45+
String pakkage = service.pakkage() + ".stub";
46+
TypeNode parserType = TypeNode.withReference(
47+
VaporReference.builder().setName("ComputeLroErrorParser").setPakkage(pakkage).build());
48+
49+
TypeNode httpJsonLroErrorParserType = TypeNode.withReference(
50+
ConcreteReference.withClazz(com.google.api.gax.httpjson.HttpJsonLroErrorParser.class));
51+
TypeNode errorDetailsType = TypeNode.withReference(
52+
ConcreteReference.withClazz(com.google.api.gax.rpc.ErrorDetails.class));
53+
TypeNode operationType = TypeNode.withReference(
54+
VaporReference.builder().setName("Operation").setPakkage(service.pakkage()).build());
55+
TypeNode errorsType = TypeNode.withReference(
56+
VaporReference.builder().setName("Errors").setPakkage(service.pakkage()).build());
57+
TypeNode errorInfoType = TypeNode.withReference(
58+
ConcreteReference.withClazz(com.google.rpc.ErrorInfo.class));
59+
TypeNode anyType = TypeNode.withReference(
60+
ConcreteReference.withClazz(com.google.protobuf.Any.class));
61+
TypeNode listAnyType = TypeNode.withReference(
62+
ConcreteReference.builder().setClazz(java.util.List.class).setGenerics(anyType.reference()).build());
63+
TypeNode arrayListAnyType = TypeNode.withReference(
64+
ConcreteReference.builder().setClazz(java.util.ArrayList.class).setGenerics(anyType.reference()).build());
65+
66+
VariableExpr responseVar = VariableExpr.withVariable(
67+
Variable.builder().setType(TypeNode.OBJECT).setName("response").build());
68+
VariableExpr operationVar = VariableExpr.withVariable(
69+
Variable.builder().setType(operationType).setName("operation").build());
70+
VariableExpr rawErrorMessagesVar = VariableExpr.withVariable(
71+
Variable.builder().setType(listAnyType).setName("rawErrorMessages").build());
72+
VariableExpr errorVar = VariableExpr.withVariable(
73+
Variable.builder().setType(errorsType).setName("error").build());
74+
VariableExpr errorInfoVar = VariableExpr.withVariable(
75+
Variable.builder().setType(errorInfoType).setName("errorInfo").build());
76+
VariableExpr sbVar = VariableExpr.withVariable(
77+
Variable.builder().setType(TypeNode.withReference(ConcreteReference.withClazz(StringBuilder.class))).setName("sb").build());
78+
79+
// parse() method
80+
List<Statement> parseBody = new ArrayList<>();
81+
parseBody.add(IfStatement.builder()
82+
.setConditionExpr(UnaryOperationExpr.logicalNotWithExpr(
83+
InstanceofExpr.builder().setExpr(responseVar).setCheckType(operationType).build()))
84+
.setBody(Arrays.asList(ExprStatement.withExpr(ReturnExpr.withExpr(ValueExpr.createNullExpr()))))
85+
.build());
86+
parseBody.add(ExprStatement.withExpr(AssignmentExpr.builder()
87+
.setVariableExpr(operationVar.toBuilder().setIsDecl(true).build())
88+
.setValueExpr(CastExpr.builder().setType(operationType).setExpr(responseVar).build())
89+
.build()));
90+
parseBody.add(IfStatement.builder()
91+
.setConditionExpr(UnaryOperationExpr.logicalNotWithExpr(
92+
MethodInvocationExpr.builder().setExprReferenceExpr(operationVar).setMethodName("hasError").setReturnType(TypeNode.BOOLEAN).build()))
93+
.setBody(Arrays.asList(ExprStatement.withExpr(ReturnExpr.withExpr(ValueExpr.createNullExpr()))))
94+
.build());
95+
parseBody.add(ExprStatement.withExpr(AssignmentExpr.builder()
96+
.setVariableExpr(rawErrorMessagesVar.toBuilder().setIsDecl(true).build())
97+
.setValueExpr(NewObjectExpr.builder().setType(arrayListAnyType).build())
98+
.build()));
99+
100+
Expr getErrorsListExpr = MethodInvocationExpr.builder()
101+
.setExprReferenceExpr(MethodInvocationExpr.builder().setExprReferenceExpr(operationVar).setMethodName("getError").build())
102+
.setMethodName("getErrorsList").build();
103+
104+
List<Statement> forBody = new ArrayList<>();
105+
Expr errorInfoBuilderExpr = MethodInvocationExpr.builder().setStaticReferenceType(errorInfoType).setMethodName("newBuilder").build();
106+
errorInfoBuilderExpr = MethodInvocationExpr.builder().setExprReferenceExpr(errorInfoBuilderExpr).setMethodName("setReason")
107+
.setArguments(MethodInvocationExpr.builder().setExprReferenceExpr(errorVar).setMethodName("getCode").setReturnType(TypeNode.STRING).build()).build();
108+
errorInfoBuilderExpr = MethodInvocationExpr.builder().setExprReferenceExpr(errorInfoBuilderExpr).setMethodName("setDomain")
109+
.setArguments(ValueExpr.withValue(StringObjectValue.withValue("googleapis.com"))).build();
110+
errorInfoBuilderExpr = MethodInvocationExpr.builder().setExprReferenceExpr(errorInfoBuilderExpr).setMethodName("putMetadata")
111+
.setArguments(ValueExpr.withValue(StringObjectValue.withValue("message")), MethodInvocationExpr.builder().setExprReferenceExpr(errorVar).setMethodName("getMessage").setReturnType(TypeNode.STRING).build()).build();
112+
errorInfoBuilderExpr = MethodInvocationExpr.builder().setExprReferenceExpr(errorInfoBuilderExpr).setMethodName("putMetadata")
113+
.setArguments(ValueExpr.withValue(StringObjectValue.withValue("location")), MethodInvocationExpr.builder().setExprReferenceExpr(errorVar).setMethodName("getLocation").setReturnType(TypeNode.STRING).build()).build();
114+
errorInfoBuilderExpr = MethodInvocationExpr.builder().setExprReferenceExpr(errorInfoBuilderExpr).setMethodName("build").setReturnType(errorInfoType).build();
115+
116+
forBody.add(ExprStatement.withExpr(AssignmentExpr.builder()
117+
.setVariableExpr(errorInfoVar.toBuilder().setIsDecl(true).build())
118+
.setValueExpr(errorInfoBuilderExpr)
119+
.build()));
120+
forBody.add(ExprStatement.withExpr(MethodInvocationExpr.builder()
121+
.setExprReferenceExpr(rawErrorMessagesVar).setMethodName("add")
122+
.setArguments(MethodInvocationExpr.builder().setStaticReferenceType(anyType).setMethodName("pack").setArguments(errorInfoVar).setReturnType(anyType).build())
123+
.build()));
124+
125+
parseBody.add(ForStatement.builder()
126+
.setLocalVariableExpr(errorVar.toBuilder().setIsDecl(true).build())
127+
.setCollectionExpr(getErrorsListExpr)
128+
.setBody(forBody)
129+
.build());
130+
131+
Expr parseReturnExpr = MethodInvocationExpr.builder()
132+
.setExprReferenceExpr(MethodInvocationExpr.builder()
133+
.setExprReferenceExpr(MethodInvocationExpr.builder().setStaticReferenceType(errorDetailsType).setMethodName("builder").build())
134+
.setMethodName("setRawErrorMessages").setArguments(rawErrorMessagesVar).build())
135+
.setMethodName("build").setReturnType(errorDetailsType).build();
136+
137+
MethodDefinition parseMethod = MethodDefinition.builder()
138+
.setAnnotations(Arrays.asList(com.google.api.generator.engine.ast.AnnotationNode.OVERRIDE))
139+
.setScope(ScopeNode.PUBLIC)
140+
.setReturnType(errorDetailsType)
141+
.setName("parse")
142+
.setArguments(responseVar.toBuilder().setIsDecl(true).build())
143+
.setBody(parseBody)
144+
.setReturnExpr(parseReturnExpr)
145+
.build();
146+
147+
// parseErrorMessage() method
148+
List<Statement> parseErrorBody = new ArrayList<>();
149+
parseErrorBody.add(IfStatement.builder()
150+
.setConditionExpr(UnaryOperationExpr.logicalNotWithExpr(
151+
InstanceofExpr.builder().setExpr(responseVar).setCheckType(operationType).build()))
152+
.setBody(Arrays.asList(ExprStatement.withExpr(ReturnExpr.withExpr(ValueExpr.createNullExpr()))))
153+
.build());
154+
parseErrorBody.add(ExprStatement.withExpr(AssignmentExpr.builder()
155+
.setVariableExpr(operationVar.toBuilder().setIsDecl(true).build())
156+
.setValueExpr(CastExpr.builder().setType(operationType).setExpr(responseVar).build())
157+
.build()));
158+
159+
Expr condition1 = UnaryOperationExpr.logicalNotWithExpr(MethodInvocationExpr.builder().setExprReferenceExpr(operationVar).setMethodName("hasError").setReturnType(TypeNode.BOOLEAN).build());
160+
Expr condition2 = RelationalOperationExpr.equalToWithExprs(
161+
MethodInvocationExpr.builder().setExprReferenceExpr(MethodInvocationExpr.builder().setExprReferenceExpr(operationVar).setMethodName("getError").build()).setMethodName("getErrorsCount").setReturnType(TypeNode.INT).build(),
162+
ValueExpr.withValue(PrimitiveValue.builder().setType(TypeNode.INT).setValue("0").build()));
163+
parseErrorBody.add(IfStatement.builder()
164+
.setConditionExpr(LogicalOperationExpr.logicalOrWithExprs(condition1, condition2))
165+
.setBody(Arrays.asList(ExprStatement.withExpr(ReturnExpr.withExpr(ValueExpr.createNullExpr()))))
166+
.build());
167+
168+
parseErrorBody.add(ExprStatement.withExpr(AssignmentExpr.builder()
169+
.setVariableExpr(sbVar.toBuilder().setIsDecl(true).build())
170+
.setValueExpr(NewObjectExpr.builder().setType(sbVar.type()).build())
171+
.build()));
172+
173+
List<Statement> forBody2 = new ArrayList<>();
174+
forBody2.add(IfStatement.builder()
175+
.setConditionExpr(RelationalOperationExpr.lessThanWithExprs(
176+
ValueExpr.withValue(PrimitiveValue.builder().setType(TypeNode.INT).setValue("0").build()),
177+
MethodInvocationExpr.builder().setExprReferenceExpr(sbVar).setMethodName("length").setReturnType(TypeNode.INT).build()))
178+
.setBody(Arrays.asList(ExprStatement.withExpr(MethodInvocationExpr.builder().setExprReferenceExpr(sbVar).setMethodName("append").setArguments(ValueExpr.withValue(StringObjectValue.withValue("; "))).build())))
179+
.build());
180+
181+
Expr appendExpr = MethodInvocationExpr.builder().setExprReferenceExpr(sbVar).setMethodName("append").setArguments(MethodInvocationExpr.builder().setExprReferenceExpr(errorVar).setMethodName("getCode").build()).build();
182+
appendExpr = MethodInvocationExpr.builder().setExprReferenceExpr(appendExpr).setMethodName("append").setArguments(ValueExpr.withValue(StringObjectValue.withValue(": "))).build();
183+
appendExpr = MethodInvocationExpr.builder().setExprReferenceExpr(appendExpr).setMethodName("append").setArguments(MethodInvocationExpr.builder().setExprReferenceExpr(errorVar).setMethodName("getMessage").build()).build();
184+
forBody2.add(ExprStatement.withExpr(appendExpr));
185+
186+
parseErrorBody.add(ForStatement.builder()
187+
.setLocalVariableExpr(errorVar.toBuilder().setIsDecl(true).build())
188+
.setCollectionExpr(getErrorsListExpr)
189+
.setBody(forBody2)
190+
.build());
191+
192+
Expr parseErrorReturnExpr = MethodInvocationExpr.builder().setExprReferenceExpr(sbVar).setMethodName("toString").setReturnType(TypeNode.STRING).build();
193+
194+
MethodDefinition parseErrorMethod = MethodDefinition.builder()
195+
.setAnnotations(Arrays.asList(com.google.api.generator.engine.ast.AnnotationNode.OVERRIDE))
196+
.setScope(ScopeNode.PUBLIC)
197+
.setReturnType(TypeNode.STRING)
198+
.setName("parseErrorMessage")
199+
.setArguments(responseVar.toBuilder().setIsDecl(true).build())
200+
.setBody(parseErrorBody)
201+
.setReturnExpr(parseErrorReturnExpr)
202+
.build();
203+
204+
ClassDefinition classDef = ClassDefinition.builder()
205+
.setFileHeader(CommentComposer.APACHE_LICENSE_COMMENT)
206+
.setPackageString(pakkage)
207+
.setName("ComputeLroErrorParser")
208+
.setScope(ScopeNode.PUBLIC)
209+
.setImplementsTypes(Arrays.asList(httpJsonLroErrorParserType))
210+
.setMethods(Arrays.asList(parseMethod, parseErrorMethod))
211+
.build();
212+
213+
return GapicClass.create(GapicClass.Kind.STUB, classDef);
214+
}
215+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package com.google.api.gax.httpjson;
2+
3+
import com.google.api.core.BetaApi;
4+
import com.google.api.gax.rpc.ErrorDetails;
5+
import org.jspecify.annotations.NullMarked;
6+
import org.jspecify.annotations.Nullable;
7+
8+
@NullMarked
9+
@BetaApi("The surface for custom LRO error parsing is not stable yet and may change.")
10+
public interface HttpJsonLroErrorParser {
11+
/** Parses custom LRO response object into standard ErrorDetails. */
12+
@Nullable
13+
ErrorDetails parse(Object response);
14+
15+
/** Concatenates custom LRO response errors into a single descriptive message. */
16+
@Nullable
17+
String parseErrorMessage(Object response);
18+
}

0 commit comments

Comments
 (0)