|
42 | 42 | import com.google.api.generator.engine.ast.MethodDefinition;
|
43 | 43 | import com.google.api.generator.engine.ast.MethodInvocationExpr;
|
44 | 44 | import com.google.api.generator.engine.ast.NewObjectExpr;
|
| 45 | +import com.google.api.generator.engine.ast.Reference; |
45 | 46 | import com.google.api.generator.engine.ast.ReferenceConstructorExpr;
|
46 | 47 | import com.google.api.generator.engine.ast.RelationalOperationExpr;
|
47 | 48 | import com.google.api.generator.engine.ast.ScopeNode;
|
|
58 | 59 | import com.google.api.generator.gapic.composer.comment.StubCommentComposer;
|
59 | 60 | import com.google.api.generator.gapic.composer.store.TypeStore;
|
60 | 61 | import com.google.api.generator.gapic.composer.utils.PackageChecker;
|
| 62 | +import com.google.api.generator.gapic.model.Field; |
61 | 63 | import com.google.api.generator.gapic.model.GapicClass;
|
62 | 64 | import com.google.api.generator.gapic.model.GapicClass.Kind;
|
63 | 65 | import com.google.api.generator.gapic.model.GapicContext;
|
|
70 | 72 | import com.google.api.generator.gapic.model.Transport;
|
71 | 73 | import com.google.api.generator.gapic.utils.JavaStyle;
|
72 | 74 | import com.google.api.pathtemplate.PathTemplate;
|
| 75 | +import com.google.common.annotations.VisibleForTesting; |
73 | 76 | import com.google.common.base.Preconditions;
|
74 | 77 | import com.google.common.base.Splitter;
|
| 78 | +import com.google.common.base.Strings; |
75 | 79 | import com.google.common.collect.ImmutableList;
|
76 | 80 | import com.google.common.collect.ImmutableMap;
|
77 | 81 | import com.google.longrunning.Operation;
|
|
84 | 88 | import java.util.List;
|
85 | 89 | import java.util.Map;
|
86 | 90 | import java.util.Optional;
|
| 91 | +import java.util.UUID; |
87 | 92 | import java.util.concurrent.TimeUnit;
|
88 | 93 | import java.util.function.BiFunction;
|
89 | 94 | import java.util.function.Function;
|
| 95 | +import java.util.function.Predicate; |
90 | 96 | import java.util.stream.Collectors;
|
91 | 97 | import javax.annotation.Generated;
|
92 | 98 | import javax.annotation.Nullable;
|
@@ -136,6 +142,7 @@ private static TypeStore createStaticTypes() {
|
136 | 142 | OperationCallable.class,
|
137 | 143 | OperationSnapshot.class,
|
138 | 144 | RequestParamsExtractor.class,
|
| 145 | + UUID.class, |
139 | 146 | ServerStreamingCallable.class,
|
140 | 147 | TimeUnit.class,
|
141 | 148 | TypeRegistry.class,
|
@@ -277,7 +284,8 @@ protected Expr createTransportSettingsInitExpr(
|
277 | 284 | Method method,
|
278 | 285 | VariableExpr transportSettingsVarExpr,
|
279 | 286 | VariableExpr methodDescriptorVarExpr,
|
280 |
| - List<Statement> classStatements) { |
| 287 | + List<Statement> classStatements, |
| 288 | + ImmutableMap<String, Message> messageTypes) { |
281 | 289 | MethodInvocationExpr callSettingsBuilderExpr =
|
282 | 290 | MethodInvocationExpr.builder()
|
283 | 291 | .setStaticReferenceType(getTransportContext().transportCallSettingsType())
|
@@ -318,6 +326,15 @@ protected Expr createTransportSettingsInitExpr(
|
318 | 326 | .build();
|
319 | 327 | }
|
320 | 328 |
|
| 329 | + if (method.hasAutoPopulatedFields() && shouldGenerateRequestMutator(method, messageTypes)) { |
| 330 | + callSettingsBuilderExpr = |
| 331 | + MethodInvocationExpr.builder() |
| 332 | + .setExprReferenceExpr(callSettingsBuilderExpr) |
| 333 | + .setMethodName("setRequestMutator") |
| 334 | + .setArguments(createRequestMutatorClassInstance(method, messageTypes)) |
| 335 | + .build(); |
| 336 | + } |
| 337 | + |
321 | 338 | callSettingsBuilderExpr =
|
322 | 339 | MethodInvocationExpr.builder()
|
323 | 340 | .setExprReferenceExpr(callSettingsBuilderExpr)
|
@@ -760,7 +777,8 @@ protected List<MethodDefinition> createConstructorMethods(
|
760 | 777 | javaStyleMethodNameToTransportSettingsVarExprs.get(
|
761 | 778 | JavaStyle.toLowerCamelCase(m.name())),
|
762 | 779 | protoMethodNameToDescriptorVarExprs.get(m.name()),
|
763 |
| - classStatements)) |
| 780 | + classStatements, |
| 781 | + context.messages())) |
764 | 782 | .collect(Collectors.toList()));
|
765 | 783 | secondCtorStatements.addAll(
|
766 | 784 | secondCtorExprs.stream().map(ExprStatement::withExpr).collect(Collectors.toList()));
|
@@ -1233,12 +1251,197 @@ protected TypeNode getTransportOperationsStubType(Service service) {
|
1233 | 1251 | return transportOpeationsStubType;
|
1234 | 1252 | }
|
1235 | 1253 |
|
| 1254 | + protected static LambdaExpr createRequestMutatorClassInstance( |
| 1255 | + Method method, ImmutableMap<String, Message> messageTypes) { |
| 1256 | + List<Statement> bodyStatements = new ArrayList<>(); |
| 1257 | + VariableExpr requestVarExpr = createRequestVarExpr(method); |
| 1258 | + |
| 1259 | + Reference requestBuilderRef = |
| 1260 | + VaporReference.builder() |
| 1261 | + .setEnclosingClassNames(method.inputType().reference().name()) |
| 1262 | + .setName("Builder") |
| 1263 | + .setPakkage(method.inputType().reference().pakkage()) |
| 1264 | + .build(); |
| 1265 | + |
| 1266 | + TypeNode requestBuilderType = TypeNode.withReference(requestBuilderRef); |
| 1267 | + |
| 1268 | + VariableExpr requestBuilderVarExpr = |
| 1269 | + VariableExpr.builder() |
| 1270 | + .setVariable( |
| 1271 | + Variable.builder().setName("requestBuilder").setType(requestBuilderType).build()) |
| 1272 | + .setIsDecl(true) |
| 1273 | + .build(); |
| 1274 | + |
| 1275 | + MethodInvocationExpr setRequestBuilderInvocationExpr = |
| 1276 | + MethodInvocationExpr.builder() |
| 1277 | + .setExprReferenceExpr(requestVarExpr) |
| 1278 | + .setMethodName("toBuilder") |
| 1279 | + .setReturnType(requestBuilderType) |
| 1280 | + .build(); |
| 1281 | + |
| 1282 | + Expr requestBuilderExpr = |
| 1283 | + AssignmentExpr.builder() |
| 1284 | + .setVariableExpr(requestBuilderVarExpr) |
| 1285 | + .setValueExpr(setRequestBuilderInvocationExpr) |
| 1286 | + .build(); |
| 1287 | + |
| 1288 | + bodyStatements.add(ExprStatement.withExpr(requestBuilderExpr)); |
| 1289 | + |
| 1290 | + VariableExpr returnBuilderVarExpr = |
| 1291 | + VariableExpr.builder() |
| 1292 | + .setVariable( |
| 1293 | + Variable.builder().setName("requestBuilder").setType(requestBuilderType).build()) |
| 1294 | + .setIsDecl(false) |
| 1295 | + .build(); |
| 1296 | + |
| 1297 | + MethodInvocationExpr.Builder returnExpr = |
| 1298 | + MethodInvocationExpr.builder() |
| 1299 | + .setExprReferenceExpr(returnBuilderVarExpr) |
| 1300 | + .setMethodName("build"); |
| 1301 | + |
| 1302 | + createRequestMutatorBody(method, messageTypes, bodyStatements, returnBuilderVarExpr); |
| 1303 | + |
| 1304 | + return LambdaExpr.builder() |
| 1305 | + .setArguments(requestVarExpr.toBuilder().setIsDecl(true).build()) |
| 1306 | + .setBody(bodyStatements) |
| 1307 | + .setReturnExpr(returnExpr.build()) |
| 1308 | + .build(); |
| 1309 | + } |
| 1310 | + |
| 1311 | + @VisibleForTesting |
| 1312 | + static List<Statement> createRequestMutatorBody( |
| 1313 | + Method method, |
| 1314 | + ImmutableMap<String, Message> messageTypes, |
| 1315 | + List<Statement> bodyStatements, |
| 1316 | + VariableExpr returnBuilderVarExpr) { |
| 1317 | + |
| 1318 | + Message methodRequestMessage = messageTypes.get(method.inputType().reference().fullName()); |
| 1319 | + method.autoPopulatedFields().stream() |
| 1320 | + // Map each field name to its corresponding Field object, if present |
| 1321 | + .map( |
| 1322 | + fieldName -> |
| 1323 | + methodRequestMessage.fields().stream() |
| 1324 | + .filter(field -> field.name().equals(fieldName)) |
| 1325 | + .findFirst()) |
| 1326 | + .filter(Optional::isPresent) // Keep only the existing Fields |
| 1327 | + .map(Optional::get) // Extract the Field from the Optional |
| 1328 | + .filter(Field::canBeAutoPopulated) // Filter fields that can be autopopulated |
| 1329 | + .forEach( |
| 1330 | + matchedField -> { |
| 1331 | + // Create statements for each autopopulated Field |
| 1332 | + bodyStatements.add( |
| 1333 | + createAutoPopulatedRequestStatement( |
| 1334 | + method, matchedField.name(), returnBuilderVarExpr)); |
| 1335 | + }); |
| 1336 | + return bodyStatements; |
| 1337 | + } |
| 1338 | + |
| 1339 | + @VisibleForTesting |
| 1340 | + static Statement createAutoPopulatedRequestStatement( |
| 1341 | + Method method, String fieldName, VariableExpr returnBuilderVarExpr) { |
| 1342 | + |
| 1343 | + VariableExpr requestVarExpr = createRequestVarExpr(method); |
| 1344 | + |
| 1345 | + // Expected expression: request.getRequestId() |
| 1346 | + MethodInvocationExpr getAutoPopulatedFieldInvocationExpr = |
| 1347 | + MethodInvocationExpr.builder() |
| 1348 | + .setExprReferenceExpr(requestVarExpr) |
| 1349 | + .setMethodName(String.format("get%s", JavaStyle.toUpperCamelCase(fieldName))) |
| 1350 | + .setReturnType(TypeNode.STRING) |
| 1351 | + .build(); |
| 1352 | + |
| 1353 | + VariableExpr stringsVar = |
| 1354 | + VariableExpr.withVariable( |
| 1355 | + Variable.builder() |
| 1356 | + .setType(TypeNode.withReference(ConcreteReference.withClazz(Strings.class))) |
| 1357 | + .setName("Strings") |
| 1358 | + .build()); |
| 1359 | + |
| 1360 | + // Expected expression: Strings.isNullOrEmpty(request.getRequestId()) |
| 1361 | + MethodInvocationExpr isNullOrEmptyFieldInvocationExpr = |
| 1362 | + MethodInvocationExpr.builder() |
| 1363 | + .setExprReferenceExpr(stringsVar) |
| 1364 | + .setMethodName("isNullOrEmpty") |
| 1365 | + .setReturnType(TypeNode.BOOLEAN) |
| 1366 | + .setArguments(getAutoPopulatedFieldInvocationExpr) |
| 1367 | + .build(); |
| 1368 | + |
| 1369 | + // Note: Currently, autopopulation is only for UUID. |
| 1370 | + VariableExpr uuidVarExpr = |
| 1371 | + VariableExpr.withVariable( |
| 1372 | + Variable.builder() |
| 1373 | + .setType( |
| 1374 | + TypeNode.withReference( |
| 1375 | + ConcreteReference.builder().setClazz(UUID.class).build())) |
| 1376 | + .setName("UUID") |
| 1377 | + .build()); |
| 1378 | + |
| 1379 | + // Expected expression: UUID.randomUUID() |
| 1380 | + MethodInvocationExpr autoPopulatedFieldsArgsHelper = |
| 1381 | + MethodInvocationExpr.builder() |
| 1382 | + .setExprReferenceExpr(uuidVarExpr) |
| 1383 | + .setMethodName("randomUUID") |
| 1384 | + .setReturnType( |
| 1385 | + TypeNode.withReference(ConcreteReference.builder().setClazz(UUID.class).build())) |
| 1386 | + .build(); |
| 1387 | + |
| 1388 | + // Expected expression: UUID.randomUUID().toString() |
| 1389 | + MethodInvocationExpr autoPopulatedFieldsArgsToString = |
| 1390 | + MethodInvocationExpr.builder() |
| 1391 | + .setExprReferenceExpr(autoPopulatedFieldsArgsHelper) |
| 1392 | + .setMethodName("toString") |
| 1393 | + .setReturnType(TypeNode.STRING) |
| 1394 | + .build(); |
| 1395 | + |
| 1396 | + // Expected expression: requestBuilder().setField(UUID.randomUUID().toString()) |
| 1397 | + MethodInvocationExpr setAutoPopulatedFieldInvocationExpr = |
| 1398 | + MethodInvocationExpr.builder() |
| 1399 | + .setArguments(autoPopulatedFieldsArgsToString) |
| 1400 | + .setExprReferenceExpr(returnBuilderVarExpr) |
| 1401 | + .setMethodName(String.format("set%s", JavaStyle.toUpperCamelCase(fieldName))) |
| 1402 | + .setReturnType(method.inputType()) |
| 1403 | + .build(); |
| 1404 | + |
| 1405 | + return IfStatement.builder() |
| 1406 | + .setConditionExpr(isNullOrEmptyFieldInvocationExpr) |
| 1407 | + .setBody(Arrays.asList(ExprStatement.withExpr(setAutoPopulatedFieldInvocationExpr))) |
| 1408 | + .build(); |
| 1409 | + } |
| 1410 | + |
| 1411 | + /** |
| 1412 | + * The Request Mutator should only be generated if the field exists in the Message and is properly |
| 1413 | + * configured in the Message(see {@link Field#canBeAutoPopulated()}) |
| 1414 | + */ |
| 1415 | + @VisibleForTesting |
| 1416 | + static Boolean shouldGenerateRequestMutator( |
| 1417 | + Method method, ImmutableMap<String, Message> messageTypes) { |
| 1418 | + if (method.inputType().reference() == null |
| 1419 | + || method.inputType().reference().fullName() == null) { |
| 1420 | + return false; |
| 1421 | + } |
| 1422 | + String methodRequestName = method.inputType().reference().fullName(); |
| 1423 | + |
| 1424 | + Message methodRequestMessage = messageTypes.get(methodRequestName); |
| 1425 | + if (methodRequestMessage == null || methodRequestMessage.fields() == null) { |
| 1426 | + return false; |
| 1427 | + } |
| 1428 | + return method.autoPopulatedFields().stream().anyMatch(shouldAutoPopulate(methodRequestMessage)); |
| 1429 | + } |
| 1430 | + |
| 1431 | + /** |
| 1432 | + * The field has to exist in the Message and properly configured in the Message(see {@link |
| 1433 | + * Field#canBeAutoPopulated()}) |
| 1434 | + */ |
| 1435 | + private static Predicate<String> shouldAutoPopulate(Message methodRequestMessage) { |
| 1436 | + return fieldName -> |
| 1437 | + methodRequestMessage.fields().stream() |
| 1438 | + .anyMatch(field -> field.name().equals(fieldName) && field.canBeAutoPopulated()); |
| 1439 | + } |
| 1440 | + |
1236 | 1441 | protected LambdaExpr createRequestParamsExtractorClassInstance(
|
1237 | 1442 | Method method, List<Statement> classStatements) {
|
1238 | 1443 | List<Statement> bodyStatements = new ArrayList<>();
|
1239 |
| - VariableExpr requestVarExpr = |
1240 |
| - VariableExpr.withVariable( |
1241 |
| - Variable.builder().setType(method.inputType()).setName("request").build()); |
| 1444 | + VariableExpr requestVarExpr = createRequestVarExpr(method); |
1242 | 1445 | TypeNode returnType =
|
1243 | 1446 | TypeNode.withReference(
|
1244 | 1447 | ConcreteReference.builder()
|
@@ -1499,4 +1702,9 @@ private MethodInvocationExpr createRequestFieldGetterExpr(
|
1499 | 1702 | }
|
1500 | 1703 | return requestFieldGetterExprBuilder.build();
|
1501 | 1704 | }
|
| 1705 | + |
| 1706 | + private static VariableExpr createRequestVarExpr(Method method) { |
| 1707 | + return VariableExpr.withVariable( |
| 1708 | + Variable.builder().setType(method.inputType()).setName("request").build()); |
| 1709 | + } |
1502 | 1710 | }
|
0 commit comments