From 307ce71d68711b83967f735f650bcba470b12c2a Mon Sep 17 00:00:00 2001 From: prodriguezdefino Date: Wed, 6 Jul 2022 18:22:05 -0700 Subject: [PATCH 1/8] adding support for maps and array of maps to BQ when using StorageWrites --- .../bigquery/BeamRowToStorageApiProto.java | 88 +++++++++++++++++-- .../sdk/io/gcp/bigquery/BigQueryUtils.java | 2 +- 2 files changed, 84 insertions(+), 6 deletions(-) diff --git a/sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/bigquery/BeamRowToStorageApiProto.java b/sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/bigquery/BeamRowToStorageApiProto.java index 816cbe9d6caf..78da3cab2ccd 100644 --- a/sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/bigquery/BeamRowToStorageApiProto.java +++ b/sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/bigquery/BeamRowToStorageApiProto.java @@ -38,6 +38,7 @@ import java.util.function.BiFunction; import java.util.function.Function; import java.util.stream.Collectors; +import java.util.stream.Stream; import java.util.stream.StreamSupport; import javax.annotation.Nullable; import org.apache.beam.sdk.schemas.Schema; @@ -185,6 +186,19 @@ static DescriptorProto descriptorSchemaFromBeamSchema(Schema schema) { return descriptorBuilder.build(); } + static DescriptorProto mapDescriptorSchemaFromBeamSchema( + FieldDescriptorProto.Builder keyFieldDescriptor, + FieldDescriptorProto.Builder valueFieldDescriptor, + List nestedTypes) { + DescriptorProto.Builder descriptorBuilder = DescriptorProto.newBuilder(); + // Create a unique name for the descriptor ('-' characters cannot be used). + descriptorBuilder.setName("D" + UUID.randomUUID().toString().replace("-", "_")); + descriptorBuilder.addField(keyFieldDescriptor); + descriptorBuilder.addField(valueFieldDescriptor); + nestedTypes.forEach(descriptorBuilder::addNestedType); + return descriptorBuilder.build(); + } + private static FieldDescriptorProto.Builder fieldDescriptorFromBeamField( Field field, int fieldNumber, List nestedTypes) { FieldDescriptorProto.Builder fieldDescriptorBuilder = FieldDescriptorProto.newBuilder(); @@ -226,7 +240,25 @@ private static FieldDescriptorProto.Builder fieldDescriptorFromBeamField( fieldDescriptorBuilder = fieldDescriptorBuilder.setType(type); break; case MAP: - throw new RuntimeException("Map types not supported by BigQuery."); + @Nullable FieldType keyType = field.getType().getMapKeyType(); + @Nullable FieldType valueType = field.getType().getMapValueType(); + if (keyType == null || valueType == null) { + throw new RuntimeException("Unexpected null element type!"); + } + + List nestedTypesMap = Lists.newArrayList(); + + DescriptorProto nestedMap = + mapDescriptorSchemaFromBeamSchema( + fieldDescriptorFromBeamField(Field.of("key", keyType), 1, nestedTypesMap), + fieldDescriptorFromBeamField(Field.of("value", valueType), 2, nestedTypesMap), + nestedTypesMap); + + nestedTypes.add(nestedMap); + fieldDescriptorBuilder = + fieldDescriptorBuilder.setType(Type.TYPE_MESSAGE).setTypeName(nestedMap.getName()); + + return fieldDescriptorBuilder.setLabel(Label.LABEL_REPEATED); default: @Nullable Type primitiveType = PRIMITIVE_TYPES.get(field.getType().getTypeName()); if (primitiveType == null) { @@ -249,6 +281,8 @@ private static Object messageValueFromRowValue( if (value == null) { if (fieldDescriptor.isOptional()) { return null; + } else if (fieldDescriptor.isRepeated()) { + return Lists.newArrayList(); } else { throw new IllegalArgumentException( "Received null value for non-nullable field " + fieldDescriptor.getName()); @@ -268,9 +302,18 @@ private static Object toProtoValue( if (arrayElementType == null) { throw new RuntimeException("Unexpected null element type!"); } - return list.stream() - .map(v -> toProtoValue(fieldDescriptor, arrayElementType, v)) - .collect(Collectors.toList()); + Boolean shouldFlatMap = + arrayElementType.getTypeName().isCollectionType() + || arrayElementType.getTypeName().isMapType() + ? true + : false; + + Stream valueStream = + list.stream().map(v -> toProtoValue(fieldDescriptor, arrayElementType, v)); + + if (shouldFlatMap) valueStream = valueStream.flatMap(vs -> ((List) vs).stream()); + + return valueStream.collect(Collectors.toList()); case ITERABLE: Iterable iterable = (Iterable) value; @Nullable FieldType iterableElementType = beamFieldType.getCollectionElementType(); @@ -281,12 +324,47 @@ private static Object toProtoValue( .map(v -> toProtoValue(fieldDescriptor, iterableElementType, v)) .collect(Collectors.toList()); case MAP: - throw new RuntimeException("Map types not supported by BigQuery."); + Map map = (Map) value; + @Nullable FieldType keyType = beamFieldType.getMapKeyType(); + @Nullable FieldType valueType = beamFieldType.getMapValueType(); + if (keyType == null || valueType == null) { + throw new RuntimeException("Unexpected null element type!"); + } + + return map.entrySet().stream() + .map( + (Map.Entry entry) -> + mapEntryToProtoValue( + fieldDescriptor.getMessageType(), keyType, valueType, entry)) + .collect(Collectors.toList()); default: return scalarToProtoValue(beamFieldType, value); } } + static Object mapEntryToProtoValue( + Descriptor descriptor, + FieldType keyFieldType, + FieldType valueFieldType, + Map.Entry entryValue) { + + DynamicMessage.Builder builder = DynamicMessage.newBuilder(descriptor); + FieldDescriptor keyFieldDescriptor = + Preconditions.checkNotNull(descriptor.findFieldByName("key")); + @Nullable Object key = toProtoValue(keyFieldDescriptor, keyFieldType, entryValue.getKey()); + if (key != null) { + builder.setField(keyFieldDescriptor, key); + } + FieldDescriptor valueFieldDescriptor = + Preconditions.checkNotNull(descriptor.findFieldByName("value")); + @Nullable + Object value = toProtoValue(valueFieldDescriptor, valueFieldType, entryValue.getValue()); + if (value != null) { + builder.setField(valueFieldDescriptor, value); + } + return builder.build(); + } + @VisibleForTesting static Object scalarToProtoValue(FieldType beamFieldType, Object value) { if (beamFieldType.getTypeName() == TypeName.LOGICAL_TYPE) { diff --git a/sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/bigquery/BigQueryUtils.java b/sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/bigquery/BigQueryUtils.java index 256d6786ecdf..cef2246e8719 100644 --- a/sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/bigquery/BigQueryUtils.java +++ b/sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/bigquery/BigQueryUtils.java @@ -394,7 +394,7 @@ private static List toTableFieldSchema(Schema schema) { } if (type.getTypeName().isCollectionType()) { type = Preconditions.checkArgumentNotNull(type.getCollectionElementType()); - if (type.getTypeName().isCollectionType() || type.getTypeName().isMapType()) { + if (type.getTypeName().isCollectionType() && !type.getTypeName().isMapType()) { throw new IllegalArgumentException("Array of collection is not supported in BigQuery."); } field.setMode(Mode.REPEATED.toString()); From 10aa27a46986a8a5173144c378436964c568e8d3 Mon Sep 17 00:00:00 2001 From: pablo rodriguez defino Date: Wed, 12 Oct 2022 14:52:45 -0700 Subject: [PATCH 2/8] adding tests for new functionality --- .../BeamRowToStorageApiProtoTest.java | 28 +++++++++++++++++-- .../io/gcp/bigquery/BigQueryUtilsTest.java | 12 ++++++++ 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/sdks/java/io/google-cloud-platform/src/test/java/org/apache/beam/sdk/io/gcp/bigquery/BeamRowToStorageApiProtoTest.java b/sdks/java/io/google-cloud-platform/src/test/java/org/apache/beam/sdk/io/gcp/bigquery/BeamRowToStorageApiProtoTest.java index 854058a81f35..08e794a7d338 100644 --- a/sdks/java/io/google-cloud-platform/src/test/java/org/apache/beam/sdk/io/gcp/bigquery/BeamRowToStorageApiProtoTest.java +++ b/sdks/java/io/google-cloud-platform/src/test/java/org/apache/beam/sdk/io/gcp/bigquery/BeamRowToStorageApiProtoTest.java @@ -18,6 +18,7 @@ package org.apache.beam.sdk.io.gcp.bigquery; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; import com.google.protobuf.ByteString; import com.google.protobuf.DescriptorProtos.DescriptorProto; @@ -33,7 +34,9 @@ import java.time.LocalDateTime; import java.time.LocalTime; import java.util.Map; +import java.util.function.Supplier; import java.util.stream.Collectors; +import java.util.stream.Stream; import org.apache.beam.sdk.schemas.Schema; import org.apache.beam.sdk.schemas.Schema.Field; import org.apache.beam.sdk.schemas.Schema.FieldType; @@ -273,12 +276,14 @@ public class BeamRowToStorageApiProtoTest { .addField("nested", FieldType.row(BASE_SCHEMA).withNullable(true)) .addField("nestedArray", FieldType.array(FieldType.row(BASE_SCHEMA))) .addField("nestedIterable", FieldType.iterable(FieldType.row(BASE_SCHEMA))) + .addField("nestedMap", FieldType.map(FieldType.STRING, FieldType.row(BASE_SCHEMA))) .build(); private static final Row NESTED_ROW = Row.withSchema(NESTED_SCHEMA) .withFieldValue("nested", BASE_ROW) .withFieldValue("nestedArray", ImmutableList.of(BASE_ROW, BASE_ROW)) .withFieldValue("nestedIterable", ImmutableList.of(BASE_ROW, BASE_ROW)) + .withFieldValue("nestedMap", ImmutableMap.of("key1", BASE_ROW, "key2", BASE_ROW)) .build(); @Test @@ -334,12 +339,12 @@ public void testNestedFromSchema() { .collect( Collectors.toMap(FieldDescriptorProto::getName, FieldDescriptorProto::getLabel)); - assertEquals(3, types.size()); + assertEquals(4, types.size()); Map nestedTypes = descriptor.getNestedTypeList().stream() .collect(Collectors.toMap(DescriptorProto::getName, Functions.identity())); - assertEquals(3, nestedTypes.size()); + assertEquals(4, nestedTypes.size()); assertEquals(Type.TYPE_MESSAGE, types.get("nested")); assertEquals(Label.LABEL_OPTIONAL, typeLabels.get("nested")); String nestedTypeName1 = typeNames.get("nested"); @@ -366,6 +371,23 @@ public void testNestedFromSchema() { .collect( Collectors.toMap(FieldDescriptorProto::getName, FieldDescriptorProto::getType)); assertEquals(expectedBaseTypes, nestedTypes3); + + assertEquals(Type.TYPE_MESSAGE, types.get("nestedmap")); + assertEquals(Label.LABEL_REPEATED, typeLabels.get("nestedmap")); + String nestedTypeName4 = typeNames.get("nestedmap"); + // expects 2 fields in the nested map, key and value + assertEquals(2, nestedTypes.get(nestedTypeName4).getFieldList().size()); + Supplier> stream = + () -> nestedTypes.get(nestedTypeName4).getFieldList().stream(); + assertTrue(stream.get().anyMatch(fdp -> fdp.getName().equals("key"))); + assertTrue(stream.get().anyMatch(fdp -> fdp.getName().equals("value"))); + + Map nestedTypes4 = + nestedTypes.get(nestedTypeName4).getNestedTypeList().stream() + .flatMap(vdesc -> vdesc.getFieldList().stream()) + .collect( + Collectors.toMap(FieldDescriptorProto::getName, FieldDescriptorProto::getType)); + assertEquals(expectedBaseTypes, nestedTypes4); } private void assertBaseRecord(DynamicMessage msg) { @@ -380,7 +402,7 @@ private void assertBaseRecord(DynamicMessage msg) { public void testMessageFromTableRow() throws Exception { Descriptor descriptor = BeamRowToStorageApiProto.getDescriptorFromSchema(NESTED_SCHEMA); DynamicMessage msg = BeamRowToStorageApiProto.messageFromBeamRow(descriptor, NESTED_ROW); - assertEquals(3, msg.getAllFields().size()); + assertEquals(4, msg.getAllFields().size()); Map fieldDescriptors = descriptor.getFields().stream() diff --git a/sdks/java/io/google-cloud-platform/src/test/java/org/apache/beam/sdk/io/gcp/bigquery/BigQueryUtilsTest.java b/sdks/java/io/google-cloud-platform/src/test/java/org/apache/beam/sdk/io/gcp/bigquery/BigQueryUtilsTest.java index b832a9b3612e..116ce5e09b3f 100644 --- a/sdks/java/io/google-cloud-platform/src/test/java/org/apache/beam/sdk/io/gcp/bigquery/BigQueryUtilsTest.java +++ b/sdks/java/io/google-cloud-platform/src/test/java/org/apache/beam/sdk/io/gcp/bigquery/BigQueryUtilsTest.java @@ -592,6 +592,18 @@ public void testToTableSchema_map() { assertThat(field.getMode(), equalTo(Mode.REPEATED.toString())); assertThat(field.getFields(), containsInAnyOrder(MAP_KEY, MAP_VALUE)); } + + @Test + public void testToTableSchema_map_array() { + TableSchema schema = toTableSchema(MAP_ARRAY_TYPE); + + assertThat(schema.getFields().size(), equalTo(1)); + TableFieldSchema field = schema.getFields().get(0); + assertThat(field.getName(), equalTo("map")); + assertThat(field.getType(), equalTo(StandardSQLTypeName.STRUCT.toString())); + assertThat(field.getMode(), equalTo(Mode.REPEATED.toString())); + assertThat(field.getFields(), containsInAnyOrder(MAP_KEY, MAP_VALUE)); + } @Test public void testToTableRow_flat() { From 7c41beefb732da4103688a8bd261ca4ce940f71e Mon Sep 17 00:00:00 2001 From: pablo rodriguez defino Date: Wed, 12 Oct 2022 14:58:09 -0700 Subject: [PATCH 3/8] spotless apply --- .../org/apache/beam/sdk/io/gcp/bigquery/BigQueryUtilsTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdks/java/io/google-cloud-platform/src/test/java/org/apache/beam/sdk/io/gcp/bigquery/BigQueryUtilsTest.java b/sdks/java/io/google-cloud-platform/src/test/java/org/apache/beam/sdk/io/gcp/bigquery/BigQueryUtilsTest.java index 116ce5e09b3f..c4cee76ed3f2 100644 --- a/sdks/java/io/google-cloud-platform/src/test/java/org/apache/beam/sdk/io/gcp/bigquery/BigQueryUtilsTest.java +++ b/sdks/java/io/google-cloud-platform/src/test/java/org/apache/beam/sdk/io/gcp/bigquery/BigQueryUtilsTest.java @@ -592,7 +592,7 @@ public void testToTableSchema_map() { assertThat(field.getMode(), equalTo(Mode.REPEATED.toString())); assertThat(field.getFields(), containsInAnyOrder(MAP_KEY, MAP_VALUE)); } - + @Test public void testToTableSchema_map_array() { TableSchema schema = toTableSchema(MAP_ARRAY_TYPE); From c9e22d6af26ca7bf99f0a8fdf567fc0b6e1ae5d3 Mon Sep 17 00:00:00 2001 From: pablo rodriguez defino Date: Mon, 31 Oct 2022 10:23:53 -0700 Subject: [PATCH 4/8] fixes checkstyle error --- .../beam/sdk/io/gcp/bigquery/BeamRowToStorageApiProto.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/bigquery/BeamRowToStorageApiProto.java b/sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/bigquery/BeamRowToStorageApiProto.java index 78da3cab2ccd..75dff750f35e 100644 --- a/sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/bigquery/BeamRowToStorageApiProto.java +++ b/sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/bigquery/BeamRowToStorageApiProto.java @@ -311,7 +311,9 @@ private static Object toProtoValue( Stream valueStream = list.stream().map(v -> toProtoValue(fieldDescriptor, arrayElementType, v)); - if (shouldFlatMap) valueStream = valueStream.flatMap(vs -> ((List) vs).stream()); + if (shouldFlatMap) { + valueStream = valueStream.flatMap(vs -> ((List) vs).stream()); + } return valueStream.collect(Collectors.toList()); case ITERABLE: From 7cf633bd716e3031cf7cd5149ab6a252dbc1b9fa Mon Sep 17 00:00:00 2001 From: Pablo Rodriguez Defino Date: Wed, 30 Nov 2022 15:39:29 -0800 Subject: [PATCH 5/8] spotless apply --- .../sdk/io/gcp/bigquery/BeamRowToStorageApiProto.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/bigquery/BeamRowToStorageApiProto.java b/sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/bigquery/BeamRowToStorageApiProto.java index 269d153da0bb..40a49bec7abd 100644 --- a/sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/bigquery/BeamRowToStorageApiProto.java +++ b/sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/bigquery/BeamRowToStorageApiProto.java @@ -208,10 +208,12 @@ private static TableFieldSchema fieldDescriptorFromBeamField(Field field) { throw new RuntimeException("Unexpected null element type!"); } - builder = builder.setType(TableFieldSchema.Type.STRUCT) - .addFields(fieldDescriptorFromBeamField(Field.of("key", keyType))) - .addFields(fieldDescriptorFromBeamField(Field.of("value", valueType))) - .setMode(TableFieldSchema.Mode.REPEATED); + builder = + builder + .setType(TableFieldSchema.Type.STRUCT) + .addFields(fieldDescriptorFromBeamField(Field.of("key", keyType))) + .addFields(fieldDescriptorFromBeamField(Field.of("value", valueType))) + .setMode(TableFieldSchema.Mode.REPEATED); break; default: @Nullable From 5e450e9b30afa35b9898528b71e50b1a0cb557ef Mon Sep 17 00:00:00 2001 From: Pablo Rodriguez Defino Date: Thu, 1 Dec 2022 09:40:20 -0800 Subject: [PATCH 6/8] addressing comments --- .../sdk/io/gcp/bigquery/BeamRowToStorageApiProto.java | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/bigquery/BeamRowToStorageApiProto.java b/sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/bigquery/BeamRowToStorageApiProto.java index 40a49bec7abd..9615981daf01 100644 --- a/sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/bigquery/BeamRowToStorageApiProto.java +++ b/sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/bigquery/BeamRowToStorageApiProto.java @@ -27,6 +27,7 @@ import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.function.BiFunction; @@ -47,7 +48,6 @@ import org.apache.beam.vendor.guava.v26_0_jre.com.google.common.base.Functions; import org.apache.beam.vendor.guava.v26_0_jre.com.google.common.base.Preconditions; import org.apache.beam.vendor.guava.v26_0_jre.com.google.common.collect.ImmutableMap; -import org.apache.beam.vendor.guava.v26_0_jre.com.google.common.collect.Lists; import org.apache.beam.vendor.guava.v26_0_jre.com.google.common.primitives.Bytes; import org.joda.time.ReadableInstant; @@ -244,7 +244,7 @@ private static Object messageValueFromRowValue( if (fieldDescriptor.isOptional()) { return null; } else if (fieldDescriptor.isRepeated()) { - return Lists.newArrayList(); + return Collections.emptyList(); } else { throw new IllegalArgumentException( "Received null value for non-nullable field " + fieldDescriptor.getName()); @@ -265,10 +265,8 @@ private static Object toProtoValue( throw new RuntimeException("Unexpected null element type!"); } Boolean shouldFlatMap = - arrayElementType.getTypeName().isCollectionType() - || arrayElementType.getTypeName().isMapType() - ? true - : false; + arrayElementType.getTypeName().isCollectionType() + || arrayElementType.getTypeName().isMapType(); Stream valueStream = list.stream().map(v -> toProtoValue(fieldDescriptor, arrayElementType, v)); @@ -311,7 +309,6 @@ static Object mapEntryToProtoValue( FieldType keyFieldType, FieldType valueFieldType, Map.Entry entryValue) { - DynamicMessage.Builder builder = DynamicMessage.newBuilder(descriptor); FieldDescriptor keyFieldDescriptor = Preconditions.checkNotNull(descriptor.findFieldByName("key")); From 5f588e52c13a743e0c4f5bf09121ca3a54e3fffe Mon Sep 17 00:00:00 2001 From: pablo rodriguez defino Date: Thu, 1 Dec 2022 10:27:17 -0800 Subject: [PATCH 7/8] fixing spotless expected format --- .../beam/sdk/io/gcp/bigquery/BeamRowToStorageApiProto.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/bigquery/BeamRowToStorageApiProto.java b/sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/bigquery/BeamRowToStorageApiProto.java index 9615981daf01..a5d438bf56a5 100644 --- a/sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/bigquery/BeamRowToStorageApiProto.java +++ b/sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/bigquery/BeamRowToStorageApiProto.java @@ -265,7 +265,7 @@ private static Object toProtoValue( throw new RuntimeException("Unexpected null element type!"); } Boolean shouldFlatMap = - arrayElementType.getTypeName().isCollectionType() + arrayElementType.getTypeName().isCollectionType() || arrayElementType.getTypeName().isMapType(); Stream valueStream = From cda4069fbc86b692c30537482199afdfc6ce7a67 Mon Sep 17 00:00:00 2001 From: Pablo Rodriguez Defino Date: Mon, 30 Jan 2023 16:46:24 -0800 Subject: [PATCH 8/8] ran spotless apply --- .../beam/sdk/io/gcp/bigquery/BeamRowToStorageApiProto.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/bigquery/BeamRowToStorageApiProto.java b/sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/bigquery/BeamRowToStorageApiProto.java index 360ae6ddef90..034b3bd179d6 100644 --- a/sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/bigquery/BeamRowToStorageApiProto.java +++ b/sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/bigquery/BeamRowToStorageApiProto.java @@ -28,8 +28,8 @@ import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; -import java.util.Collections; import java.time.temporal.ChronoUnit; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.function.BiFunction;