From 285877db097dded2d988e9882240c83c7f9c3df4 Mon Sep 17 00:00:00 2001 From: Victor Chudnovsky Date: Fri, 13 Dec 2024 08:28:43 -0800 Subject: [PATCH] fix: handle type:object with format:google.protobuf.Any (#138) We were not handling the Discovery equivalent of proto `repeated Any`, which shows up in Discovery docs as an `array` of `object` with `format:google.protobuf.Any`. This fixes that, and adds a test. Note that because we only allow `google.protobuf.Any` when it's nested inside `....error.details`, the test case for this has more structure than other test cases for the `format` field. --- .../discotoproto3converter/disco/Schema.java | 4 +++ .../proto3/DocumentToProtoConverter.java | 11 +++++--- .../v1small/compute.any-format.proto.baseline | 27 ++++++++++++++----- .../v1small/compute.v1small.any-format.json | 24 ++++++++++++++++- 4 files changed, 55 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/google/cloud/discotoproto3converter/disco/Schema.java b/src/main/java/com/google/cloud/discotoproto3converter/disco/Schema.java index 53ae274..90513fb 100644 --- a/src/main/java/com/google/cloud/discotoproto3converter/disco/Schema.java +++ b/src/main/java/com/google/cloud/discotoproto3converter/disco/Schema.java @@ -275,6 +275,10 @@ public enum Format { this.text = text; } + public String toString() { + return this.text; + } + /** * @param text the JSON text of the format. * @return the enum representing the raw JSON format. diff --git a/src/main/java/com/google/cloud/discotoproto3converter/proto3/DocumentToProtoConverter.java b/src/main/java/com/google/cloud/discotoproto3converter/proto3/DocumentToProtoConverter.java index 7050a8c..84ae398 100644 --- a/src/main/java/com/google/cloud/discotoproto3converter/proto3/DocumentToProtoConverter.java +++ b/src/main/java/com/google/cloud/discotoproto3converter/proto3/DocumentToProtoConverter.java @@ -553,8 +553,8 @@ private Field schemaToField(Schema sch, boolean optional, String debugPreviousPa default: throw new IllegalStateException( String.format( - "unexpected 'format' value ('%s') when processing ANY type in schema %s", - sch.format().toString(), debugCurrentPath)); + "unexpected 'format' value (%s:'%s') when processing ANY type in schema %s", + sch.format().name(), sch.format().toString(), debugCurrentPath)); } break; case ARRAY: @@ -631,6 +631,9 @@ private Field schemaToField(Schema sch, boolean optional, String debugPreviousPa // `additionalProperties' in the schema further specifies the JSON format, but // "google.protobuf.Struct" is enough for specifying the proto message field type. break; + case ANY: + valueType = Message.PRIMITIVES.get("google.protobuf.Any"); + break; case EMPTY: if (sch.additionalProperties() != null) { repeated = true; @@ -643,8 +646,8 @@ private Field schemaToField(Schema sch, boolean optional, String debugPreviousPa default: throw new IllegalStateException( String.format( - "unexpected 'format' value ('%s') when processing OBJECT type in schema %s", - sch.format().toString(), debugCurrentPath)); + "unexpected 'format' value (%s:'%s') when processing OBJECT type in schema %s", + sch.format().name(), sch.format().toString(), debugCurrentPath)); } break; case STRING: diff --git a/src/test/resources/google/cloud/compute/v1small/compute.any-format.proto.baseline b/src/test/resources/google/cloud/compute/v1small/compute.any-format.proto.baseline index 9ec5a99..c3de50e 100644 --- a/src/test/resources/google/cloud/compute/v1small/compute.any-format.proto.baseline +++ b/src/test/resources/google/cloud/compute/v1small/compute.any-format.proto.baseline @@ -185,6 +185,9 @@ message Address { // This is a field to test that we can create a map whose values are google.protobuf.Value. map metadata_map_value = 453356478; + // This is a field to test we can create a repeated google.protobuf.Any + optional MetadataRepeatedAny metadata_repeated_any = 122515127; + // This is a field to test that we can create google.protobuf.Struct. optional google.protobuf.Struct metadata_struct = 224324325; @@ -354,10 +357,9 @@ message DeleteAddressRequest { } -// [Output Only] If errors are generated during processing of the operation, this field will be populated. +// message Error { - // [Output Only] The array of errors encountered while processing this operation. - repeated Errors errors = 315977579; + repeated google.protobuf.Any details = 483979842; } @@ -448,6 +450,12 @@ message ListAddressesRequest { } +// This is a field to test we can create a repeated google.protobuf.Any +message MetadataRepeatedAny { + optional Error error = 96784904; + +} + // Represents an Operation resource. // // Google Compute Engine has three Operation resources: @@ -488,9 +496,6 @@ message Operation { // [Output Only] The time that this operation was completed. This value is in RFC3339 text format. optional string end_time = 114938801; - // [Output Only] If errors are generated during processing of the operation, this field will be populated. - optional Error error = 96784904; - // [Output Only] If the operation fails, this field contains the HTTP error message that was returned, such as NOT FOUND. optional string http_error_message = 202521945 [(google.cloud.operation_field) = ERROR_MESSAGE]; @@ -509,6 +514,9 @@ message Operation { // [Output Only] Name of the operation. optional string name = 3373707 [(google.cloud.operation_field) = NAME]; + // [Output Only] If errors are generated during processing of the operation, this field will be populated. + optional OperationError operation_error = 124395824; + // [Output Only] The type of operation, such as insert, update, or delete, and so on. optional string operation_type = 177650450; @@ -550,6 +558,13 @@ message Operation { } +// [Output Only] If errors are generated during processing of the operation, this field will be populated. +message OperationError { + // [Output Only] The array of errors encountered while processing this operation. + repeated Errors errors = 315977579; + +} + // message SetCommonInstanceMetadataOperationMetadata { // [Output Only] The client operation id. diff --git a/src/test/resources/google/cloud/compute/v1small/compute.v1small.any-format.json b/src/test/resources/google/cloud/compute/v1small/compute.v1small.any-format.json index bbf6d49..da6c4ae 100644 --- a/src/test/resources/google/cloud/compute/v1small/compute.v1small.any-format.json +++ b/src/test/resources/google/cloud/compute/v1small/compute.v1small.any-format.json @@ -112,7 +112,7 @@ "type": "string", "description": "[Output Only] The time that this operation was completed. This value is in RFC3339 text format." }, - "error": { + "operationError": { "type": "object", "description": "[Output Only] If errors are generated during processing of the operation, this field will be populated.", "properties": { @@ -514,6 +514,28 @@ } } }, + "metadataRepeatedAny": { + "type": "object", + "description": "This is a field to test we can create a repeated google.protobuf.Any", + "properties": { + "error": { + "type": "object", + "properties": { + "details": { + "type": "array", + "items": { + "format": "google.protobuf.Any", + "type": "object", + "additionalProperties": { + "type": "any", + "description": "Properties of the object. Contains field @type with type URL." + } + } + } + } + } + } + }, "networkTier": { "type": "string", "description": "This signifies the networking tier used for configuring this address and can only take the following values: PREMIUM or STANDARD. Global forwarding rules can only be Premium Tier. Regional forwarding rules can be either Premium or Standard Tier. Standard Tier addresses applied to regional forwarding rules can be used with any external load balancer. Regional forwarding rules in Premium Tier can only be used with a network load balancer.\n\nIf this field is not specified, it is assumed to be PREMIUM.",