diff --git a/sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/spanner/MutationSizeEstimator.java b/sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/spanner/MutationSizeEstimator.java index 83fcf026cc1a..67d71148e16d 100644 --- a/sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/spanner/MutationSizeEstimator.java +++ b/sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/spanner/MutationSizeEstimator.java @@ -106,6 +106,8 @@ private static long estimatePrimitiveValue(Value v) { switch (v.getType().getCode()) { case BOOL: return 1; + case FLOAT32: + return 4; case INT64: case FLOAT64: case ENUM: @@ -142,6 +144,8 @@ private static long estimateArrayValue(Value v) { switch (v.getType().getArrayElementType().getCode()) { case BOOL: return v.getBoolArray().size(); + case FLOAT32: + return 4L * v.getFloat32Array().size(); case INT64: case ENUM: return 8L * v.getInt64Array().size(); diff --git a/sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/spanner/MutationUtils.java b/sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/spanner/MutationUtils.java index fddbef5b256c..c0654b2cb05f 100644 --- a/sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/spanner/MutationUtils.java +++ b/sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/spanner/MutationUtils.java @@ -207,12 +207,7 @@ private static void setBeamValueToMutation( mutationBuilder.set(columnName).to(row.getInt64(columnName)); break; case FLOAT: - @Nullable Float floatValue = row.getFloat(columnName); - if (floatValue == null) { - mutationBuilder.set(columnName).to(((Double) null)); - } else { - mutationBuilder.set(columnName).to(floatValue); - } + mutationBuilder.set(columnName).to(row.getFloat(columnName)); break; case DOUBLE: mutationBuilder.set(columnName).to(row.getDouble(columnName)); @@ -311,6 +306,8 @@ private static void addIterableToMutationBuilder( mutationBuilder.set(column).toInt64Array((Iterable) ((Object) iterable)); break; case FLOAT: + mutationBuilder.set(column).toFloat32Array((Iterable) ((Object) iterable)); + break; case DOUBLE: mutationBuilder.set(column).toFloat64Array((Iterable) ((Object) iterable)); break; diff --git a/sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/spanner/SpannerSchema.java b/sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/spanner/SpannerSchema.java index 1196dbe0a53c..3fd09c63da79 100644 --- a/sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/spanner/SpannerSchema.java +++ b/sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/spanner/SpannerSchema.java @@ -172,6 +172,9 @@ private static Type parseSpannerType(String spannerType, Dialect dialect) { if ("INT64".equals(spannerType)) { return Type.int64(); } + if ("FLOAT32".equals(spannerType)) { + return Type.float32(); + } if ("FLOAT64".equals(spannerType)) { return Type.float64(); } @@ -227,6 +230,9 @@ private static Type parseSpannerType(String spannerType, Dialect dialect) { if ("BIGINT".equals(spannerType)) { return Type.int64(); } + if ("REAL".equals(spannerType)) { + return Type.float32(); + } if ("DOUBLE PRECISION".equals(spannerType)) { return Type.float64(); } diff --git a/sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/spanner/StructUtils.java b/sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/spanner/StructUtils.java index 12cb91359cd9..1f32bddba7b9 100644 --- a/sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/spanner/StructUtils.java +++ b/sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/spanner/StructUtils.java @@ -76,12 +76,7 @@ public static Struct beamRowToStruct(Row row) { addIterableToStructBuilder(structBuilder, row.getIterable(column), field); break; case FLOAT: - @Nullable Float floatValue = row.getFloat(column); - if (floatValue == null) { - structBuilder.set(column).to((Double) null); - } else { - structBuilder.set(column).to(floatValue); - } + structBuilder.set(column).to(row.getFloat(column)); break; case DOUBLE: structBuilder.set(column).to(row.getDouble(column)); @@ -187,8 +182,9 @@ private static Type simpleBeamTypeToSpannerType(Schema.FieldType beamType) { case INT16: return Type.int64(); case DOUBLE: - case FLOAT: return Type.float64(); + case FLOAT: + return Type.float32(); case DECIMAL: return Type.numeric(); case STRING: @@ -242,6 +238,8 @@ private static void addIterableToStructBuilder( structBuilder.set(column).toInt64Array((Iterable) ((Object) iterable)); break; case FLOAT: + structBuilder.set(column).toFloat32Array((Iterable) ((Object) iterable)); + break; case DOUBLE: structBuilder.set(column).toFloat64Array((Iterable) ((Object) iterable)); break; @@ -306,6 +304,8 @@ private static void addIterableToStructBuilder( return DateTime.parse(struct.getDate(column).toString()); case INT64: return struct.getLong(column); + case FLOAT32: + return struct.getFloat(column); case FLOAT64: return struct.getDouble(column); case NUMERIC: @@ -352,6 +352,8 @@ private static void addIterableToStructBuilder( .collect(toList()); case INT64: return struct.getLongList(column); + case FLOAT32: + return struct.getFloatList(column); case FLOAT64: return struct.getDoubleList(column); case STRING: diff --git a/sdks/java/io/google-cloud-platform/src/test/java/org/apache/beam/sdk/io/gcp/spanner/MutationSizeEstimatorTest.java b/sdks/java/io/google-cloud-platform/src/test/java/org/apache/beam/sdk/io/gcp/spanner/MutationSizeEstimatorTest.java index 497e33d3cfc9..d2f02aa14f9f 100644 --- a/sdks/java/io/google-cloud-platform/src/test/java/org/apache/beam/sdk/io/gcp/spanner/MutationSizeEstimatorTest.java +++ b/sdks/java/io/google-cloud-platform/src/test/java/org/apache/beam/sdk/io/gcp/spanner/MutationSizeEstimatorTest.java @@ -45,6 +45,7 @@ public class MutationSizeEstimatorTest { @Test public void primitives() throws Exception { Mutation int64 = Mutation.newInsertOrUpdateBuilder("test").set("one").to(1).build(); + Mutation float32 = Mutation.newInsertOrUpdateBuilder("test").set("one").to(1.3f).build(); Mutation float64 = Mutation.newInsertOrUpdateBuilder("test").set("one").to(2.9).build(); Mutation bool = Mutation.newInsertOrUpdateBuilder("test").set("one").to(false).build(); Mutation numeric = @@ -72,6 +73,7 @@ public void primitives() throws Exception { .build(); assertThat(MutationSizeEstimator.sizeOf(int64), is(8L)); + assertThat(MutationSizeEstimator.sizeOf(float32), is(4L)); assertThat(MutationSizeEstimator.sizeOf(float64), is(8L)); assertThat(MutationSizeEstimator.sizeOf(bool), is(1L)); assertThat(MutationSizeEstimator.sizeOf(numeric), is(30L)); @@ -89,6 +91,11 @@ public void primitiveArrays() throws Exception { .set("one") .toInt64Array(new long[] {1L, 2L, 3L}) .build(); + Mutation float32 = + Mutation.newInsertOrUpdateBuilder("test") + .set("one") + .toFloat32Array(new float[] {1.0f, 2.0f}) + .build(); Mutation float64 = Mutation.newInsertOrUpdateBuilder("test") .set("one") @@ -160,6 +167,7 @@ public void primitiveArrays() throws Exception { "customer.app.TestMessage") .build(); assertThat(MutationSizeEstimator.sizeOf(int64), is(24L)); + assertThat(MutationSizeEstimator.sizeOf(float32), is(8L)); assertThat(MutationSizeEstimator.sizeOf(float64), is(16L)); assertThat(MutationSizeEstimator.sizeOf(bool), is(4L)); assertThat(MutationSizeEstimator.sizeOf(numeric), is(153L)); @@ -180,6 +188,8 @@ public void nullPrimitiveArrays() throws Exception { .set("one") .toProtoEnumArray(null, "customer.app.TestEnum") .build(); + Mutation float32 = + Mutation.newInsertOrUpdateBuilder("test").set("one").toFloat32Array((float[]) null).build(); Mutation float64 = Mutation.newInsertOrUpdateBuilder("test") .set("one") @@ -202,6 +212,7 @@ public void nullPrimitiveArrays() throws Exception { Mutation.newInsertOrUpdateBuilder("test").set("one").toPgJsonbArray(null).build(); assertThat(MutationSizeEstimator.sizeOf(int64), is(0L)); + assertThat(MutationSizeEstimator.sizeOf(float32), is(0L)); assertThat(MutationSizeEstimator.sizeOf(float64), is(0L)); assertThat(MutationSizeEstimator.sizeOf(bool), is(0L)); assertThat(MutationSizeEstimator.sizeOf(numeric), is(0L)); @@ -384,12 +395,13 @@ public void dates() throws Exception { @Test public void group() throws Exception { Mutation int64 = Mutation.newInsertOrUpdateBuilder("test").set("one").to(1).build(); + Mutation float32 = Mutation.newInsertOrUpdateBuilder("test").set("one").to(1.3f).build(); Mutation float64 = Mutation.newInsertOrUpdateBuilder("test").set("one").to(2.9).build(); Mutation bool = Mutation.newInsertOrUpdateBuilder("test").set("one").to(false).build(); - MutationGroup group = MutationGroup.create(int64, float64, bool); + MutationGroup group = MutationGroup.create(int64, float32, float64, bool); - assertThat(MutationSizeEstimator.sizeOf(group), is(17L)); + assertThat(MutationSizeEstimator.sizeOf(group), is(21L)); } @Test diff --git a/sdks/java/io/google-cloud-platform/src/test/java/org/apache/beam/sdk/io/gcp/spanner/MutationUtilsTest.java b/sdks/java/io/google-cloud-platform/src/test/java/org/apache/beam/sdk/io/gcp/spanner/MutationUtilsTest.java index 434ffdc52ebe..6a0a1787deca 100644 --- a/sdks/java/io/google-cloud-platform/src/test/java/org/apache/beam/sdk/io/gcp/spanner/MutationUtilsTest.java +++ b/sdks/java/io/google-cloud-platform/src/test/java/org/apache/beam/sdk/io/gcp/spanner/MutationUtilsTest.java @@ -48,6 +48,7 @@ public class MutationUtilsTest { private static final Schema WRITE_ROW_SCHEMA = Schema.builder() .addNullableField("f_int64", Schema.FieldType.INT64) + .addNullableField("f_float32", Schema.FieldType.FLOAT) .addNullableField("f_float64", Schema.FieldType.DOUBLE) .addNullableField("f_string", Schema.FieldType.STRING) .addNullableField("f_bytes", Schema.FieldType.BYTES) @@ -56,6 +57,7 @@ public class MutationUtilsTest { .addNullableField("f_struct", Schema.FieldType.row(EMPTY_SCHEMA)) .addNullableField("f_struct_int64", Schema.FieldType.row(INT64_SCHEMA)) .addNullableField("f_array", Schema.FieldType.array(Schema.FieldType.INT64)) + .addNullableField("f_float_array", Schema.FieldType.array(Schema.FieldType.FLOAT)) .addNullableField("f_double_array", Schema.FieldType.array(Schema.FieldType.DOUBLE)) .addNullableField("f_decimal_array", Schema.FieldType.array(Schema.FieldType.DECIMAL)) .addNullableField("f_boolean_array", Schema.FieldType.array(Schema.FieldType.BOOLEAN)) @@ -66,7 +68,6 @@ public class MutationUtilsTest { "f_struct_array", Schema.FieldType.array(Schema.FieldType.row(INT64_SCHEMA))) .addNullableField("f_int16", Schema.FieldType.INT16) .addNullableField("f_int32", Schema.FieldType.INT32) - .addNullableField("f_float", Schema.FieldType.FLOAT) .addNullableField("f_decimal", Schema.FieldType.DECIMAL) .addNullableField("f_byte", Schema.FieldType.BYTE) .addNullableField("f_iterable", Schema.FieldType.iterable(Schema.FieldType.INT64)) @@ -75,6 +76,7 @@ public class MutationUtilsTest { private static final Row WRITE_ROW = Row.withSchema(WRITE_ROW_SCHEMA) .withFieldValue("f_int64", 1L) + .withFieldValue("f_float32", 2.1f) .withFieldValue("f_float64", 1.1) .withFieldValue("f_string", "donald_duck") .withFieldValue("f_bytes", "some_bytes".getBytes(UTF_8)) @@ -83,6 +85,7 @@ public class MutationUtilsTest { .withFieldValue("f_struct", EMPTY_ROW) .withFieldValue("f_struct_int64", INT64_ROW) .withFieldValue("f_array", ImmutableList.of(2L, 3L)) + .withFieldValue("f_float_array", ImmutableList.of(3.0f, 4.0f)) .withFieldValue("f_double_array", ImmutableList.of(1., 2.)) .withFieldValue( "f_decimal_array", @@ -101,7 +104,6 @@ public class MutationUtilsTest { .withFieldValue("f_struct_array", ImmutableList.of(INT64_ROW, INT64_ROW)) .withFieldValue("f_int16", (short) 2) .withFieldValue("f_int32", 0x7fffffff) - .withFieldValue("f_float", 0.0f) .withFieldValue("f_decimal", BigDecimal.valueOf(Long.MIN_VALUE)) .withFieldValue("f_byte", Byte.parseByte("127")) .withFieldValue("f_iterable", ImmutableList.of(2L, 3L)) @@ -110,6 +112,7 @@ public class MutationUtilsTest { private static final Schema WRITE_ROW_SCHEMA_NULLS = Schema.builder() .addNullableField("f_int64", Schema.FieldType.INT64) + .addNullableField("f_float32", Schema.FieldType.FLOAT) .addNullableField("f_float64", Schema.FieldType.DOUBLE) .addNullableField("f_string", Schema.FieldType.STRING) .addNullableField("f_bytes", Schema.FieldType.BYTES) @@ -134,11 +137,13 @@ public class MutationUtilsTest { .addValue(null) .addValue(null) .addValue(null) + .addValue(null) .build(); private static final Schema KEY_SCHEMA = Schema.builder() .addNullableField("f_int64", Schema.FieldType.INT64) + .addNullableField("f_float32", Schema.FieldType.FLOAT) .addNullableField("f_float64", Schema.FieldType.DOUBLE) .addNullableField("f_string", Schema.FieldType.STRING) .addNullableField("f_bytes", Schema.FieldType.BYTES) @@ -146,7 +151,6 @@ public class MutationUtilsTest { .addNullableField("f_bool", Schema.FieldType.BOOLEAN) .addNullableField("f_int16", Schema.FieldType.INT16) .addNullableField("f_int32", Schema.FieldType.INT32) - .addNullableField("f_float", Schema.FieldType.FLOAT) .addNullableField("f_decimal", Schema.FieldType.DECIMAL) .addNullableField("f_byte", Schema.FieldType.BYTE) .build(); @@ -154,6 +158,7 @@ public class MutationUtilsTest { private static final Row KEY_ROW = Row.withSchema(KEY_SCHEMA) .withFieldValue("f_int64", 1L) + .withFieldValue("f_float32", 2.1f) .withFieldValue("f_float64", 1.1) .withFieldValue("f_string", "donald_duck") .withFieldValue("f_bytes", "some_bytes".getBytes(UTF_8)) @@ -161,7 +166,6 @@ public class MutationUtilsTest { .withFieldValue("f_bool", false) .withFieldValue("f_int16", (short) 2) .withFieldValue("f_int32", 0x7fffffff) - .withFieldValue("f_float", 0.0f) .withFieldValue("f_decimal", BigDecimal.valueOf(Long.MIN_VALUE)) .withFieldValue("f_byte", Byte.parseByte("127")) .build(); @@ -263,6 +267,7 @@ private static Mutation createDeleteMutation() { Key key = Key.newBuilder() .append(1L) + .append(2.1f) .append(1.1) .append("donald_duck") .append(ByteArray.copyFrom("some_bytes".getBytes(UTF_8))) @@ -270,7 +275,6 @@ private static Mutation createDeleteMutation() { .append(false) .append((short) 2) .append(0x7fffffff) - .append(0.0f) .append(BigDecimal.valueOf(Long.MIN_VALUE)) .append(Byte.parseByte("127")) .build(); @@ -295,6 +299,8 @@ private static Mutation createMutation(Mutation.Op operation) { return builder .set("f_int64") .to(1L) + .set("f_float32") + .to(2.1f) .set("f_float64") .to(1.1) .set("f_string") @@ -311,6 +317,8 @@ private static Mutation createMutation(Mutation.Op operation) { .to(Struct.newBuilder().set("int64").to(3L).build()) .set("f_array") .toInt64Array(ImmutableList.of(2L, 3L)) + .set("f_float_array") + .toFloat32Array(ImmutableList.of(3.0f, 4.0f)) .set("f_double_array") .toFloat64Array(ImmutableList.of(1., 2.)) .set("f_decimal_array") @@ -339,8 +347,6 @@ private static Mutation createMutation(Mutation.Op operation) { .to((short) 2) .set("f_int32") .to(0x7fffffff) - .set("f_float") - .to(0.0f) .set("f_decimal") .to(BigDecimal.valueOf(Long.MIN_VALUE)) .set("f_byte") @@ -355,6 +361,8 @@ private static Mutation createMutationNulls(Mutation.Op operation) { return builder .set("f_int64") .to((Long) null) + .set("f_float32") + .to((Float) null) .set("f_float64") .to((Double) null) .set("f_string") diff --git a/sdks/java/io/google-cloud-platform/src/test/java/org/apache/beam/sdk/io/gcp/spanner/StructUtilsTest.java b/sdks/java/io/google-cloud-platform/src/test/java/org/apache/beam/sdk/io/gcp/spanner/StructUtilsTest.java index 90c132666f58..ca9eb025f770 100644 --- a/sdks/java/io/google-cloud-platform/src/test/java/org/apache/beam/sdk/io/gcp/spanner/StructUtilsTest.java +++ b/sdks/java/io/google-cloud-platform/src/test/java/org/apache/beam/sdk/io/gcp/spanner/StructUtilsTest.java @@ -52,6 +52,7 @@ public void testStructToBeamRow() { .addDecimalField("f_decimal") .addArrayField("f_boolean_array", Schema.FieldType.BOOLEAN) .addArrayField("f_string_array", Schema.FieldType.STRING) + .addArrayField("f_float_array", Schema.FieldType.FLOAT) .addArrayField("f_double_array", Schema.FieldType.DOUBLE) .addArrayField("f_decimal_array", Schema.FieldType.DECIMAL) .addArrayField("f_date_array", Schema.FieldType.DATETIME) @@ -64,6 +65,7 @@ public void testStructToBeamRow() { .withFieldValue("f_decimal", BigDecimal.valueOf(Long.MIN_VALUE)) .withFieldValue("f_boolean_array", ImmutableList.of(false, true)) .withFieldValue("f_string_array", ImmutableList.of("donald_duck", "micky_mouse")) + .withFieldValue("f_float_array", ImmutableList.of(3.0f, 4.0f)) .withFieldValue("f_double_array", ImmutableList.of(1., 2.)) .withFieldValue( "f_decimal_array", @@ -86,6 +88,8 @@ public void testStructToBeamRow() { .toBoolArray(ImmutableList.of(false, true)) .set("f_string_array") .toStringArray(ImmutableList.of("donald_duck", "micky_mouse")) + .set("f_float_array") + .toFloat32Array(ImmutableList.of(3.0f, 4.0f)) .set("f_double_array") .toFloat64Array(ImmutableList.of(1., 2.)) .set("f_decimal_array") @@ -133,10 +137,10 @@ public void testBeamRowToStruct() { getSchemaTemplate() .addIterableField("f_iterable", Schema.FieldType.INT64) .addDecimalField("f_decimal") - .addFloatField("f_float") .addInt16Field("f_int16") .addInt32Field("f_int32") .addByteField("f_byte") + .addArrayField("f_float_array", Schema.FieldType.FLOAT) .addArrayField("f_double_array", Schema.FieldType.DOUBLE) .addArrayField("f_decimal_array", Schema.FieldType.DECIMAL) .addArrayField("f_boolean_array", Schema.FieldType.BOOLEAN) @@ -148,10 +152,10 @@ public void testBeamRowToStruct() { getRowTemplate(schema) .withFieldValue("f_iterable", ImmutableList.of(20L)) .withFieldValue("f_decimal", BigDecimal.ONE) - .withFieldValue("f_float", 0.0f) .withFieldValue("f_int16", (short) 2) .withFieldValue("f_int32", 0x7fffffff) .withFieldValue("f_byte", Byte.parseByte("127")) + .withFieldValue("f_float_array", ImmutableList.of(3.0f, 4.0f)) .withFieldValue("f_double_array", ImmutableList.of(1., 2.)) .withFieldValue( "f_decimal_array", @@ -174,14 +178,14 @@ public void testBeamRowToStruct() { .toInt64Array(ImmutableList.of(20L)) .set("f_decimal") .to(BigDecimal.ONE) - .set("f_float") - .to(0.0f) .set("f_int16") .to((short) 2) .set("f_int32") .to(0x7fffffff) .set("f_byte") .to(Byte.parseByte("127")) + .set("f_float_array") + .toFloat32Array(ImmutableList.of(3.0f, 4.0f)) .set("f_double_array") .toFloat64Array(ImmutableList.of(1., 2.)) .set("f_decimal_array") @@ -246,7 +250,7 @@ public void testBeamTypeToSpannerTypeTranslation() { assertEquals(Type.int64(), beamTypeToSpannerType(Schema.FieldType.BYTE)); assertEquals(Type.bytes(), beamTypeToSpannerType(Schema.FieldType.BYTES)); assertEquals(Type.string(), beamTypeToSpannerType(Schema.FieldType.STRING)); - assertEquals(Type.float64(), beamTypeToSpannerType(Schema.FieldType.FLOAT)); + assertEquals(Type.float32(), beamTypeToSpannerType(Schema.FieldType.FLOAT)); assertEquals(Type.float64(), beamTypeToSpannerType(Schema.FieldType.DOUBLE)); assertEquals(Type.bool(), beamTypeToSpannerType(Schema.FieldType.BOOLEAN)); assertEquals(Type.numeric(), beamTypeToSpannerType(Schema.FieldType.DECIMAL)); @@ -261,6 +265,7 @@ public void testBeamTypeToSpannerTypeTranslation() { private Schema.Builder getSchemaTemplate() { return Schema.builder() .addNullableField("f_int64", Schema.FieldType.INT64) + .addNullableField("f_float32", Schema.FieldType.FLOAT) .addNullableField("f_float64", Schema.FieldType.DOUBLE) .addNullableField("f_string", Schema.FieldType.STRING) .addNullableField("f_bytes", Schema.FieldType.BYTES) @@ -276,6 +281,7 @@ private Schema.Builder getSchemaTemplate() { private Row.FieldValueBuilder getRowTemplate(Schema schema) { return Row.withSchema(schema) .withFieldValue("f_int64", 1L) + .withFieldValue("f_float32", 2.1f) .withFieldValue("f_float64", 5.5) .withFieldValue("f_string", "ducky_doo") .withFieldValue("f_bytes", ByteArray.copyFrom("random_bytes".getBytes(UTF_8)).toByteArray()) @@ -303,6 +309,7 @@ private Row.Builder getRowBuilder(Schema schema) { .addValue(null) .addValue(null) .addValue(null) + .addValue(null) .addValue(null); } @@ -310,6 +317,8 @@ private Struct.Builder getStructTemplate() { return Struct.newBuilder() .set("f_int64") .to(1L) + .set("f_float32") + .to(2.1f) .set("f_float64") .to(5.5) .set("f_string") @@ -340,6 +349,8 @@ private Struct.Builder getStructTemplateNulls() { return Struct.newBuilder() .set("f_int64") .to((Long) null) + .set("f_float32") + .to((Float) null) .set("f_float64") .to((Double) null) .set("f_string")