From e6ec627951b97337280377b41e69d1d4457a97c8 Mon Sep 17 00:00:00 2001 From: Ryan Blue Date: Thu, 16 Jul 2026 16:20:22 -0700 Subject: [PATCH] API, Core: Make variant classes serializable. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../iceberg/variants/SerializedArray.java | 21 ++++++++- .../iceberg/variants/SerializedMetadata.java | 19 +++++++- .../iceberg/variants/SerializedObject.java | 21 ++++++++- .../iceberg/variants/SerializedPrimitive.java | 19 +++++++- .../variants/SerializedShortString.java | 20 ++++++++- .../apache/iceberg/variants/VariantData.java | 3 +- .../iceberg/variants/TestSerializedArray.java | 11 +++++ .../variants/TestSerializedMetadata.java | 12 +++++ .../variants/TestSerializedObject.java | 13 ++++++ .../variants/TestSerializedPrimitives.java | 24 ++++++++++ .../apache/iceberg/variants/TestVariant.java | 44 +++++++++++++++++++ .../iceberg/variants/PrimitiveWrapper.java | 31 +++++++++---- .../iceberg/variants/ShreddedObject.java | 5 ++- .../apache/iceberg/variants/ValueArray.java | 5 ++- .../variants/TestPrimitiveWrapper.java | 8 ++++ .../iceberg/variants/TestShreddedObject.java | 10 +++++ .../iceberg/variants/TestValueArray.java | 11 +++++ 17 files changed, 259 insertions(+), 18 deletions(-) create mode 100644 api/src/test/java/org/apache/iceberg/variants/TestVariant.java diff --git a/api/src/main/java/org/apache/iceberg/variants/SerializedArray.java b/api/src/main/java/org/apache/iceberg/variants/SerializedArray.java index d215e018449e..6350e03425a1 100644 --- a/api/src/main/java/org/apache/iceberg/variants/SerializedArray.java +++ b/api/src/main/java/org/apache/iceberg/variants/SerializedArray.java @@ -18,13 +18,14 @@ */ package org.apache.iceberg.variants; +import java.io.Serializable; import java.nio.ByteBuffer; import java.nio.ByteOrder; import org.apache.iceberg.relocated.com.google.common.annotations.VisibleForTesting; import org.apache.iceberg.relocated.com.google.common.base.Preconditions; import org.apache.iceberg.util.ByteBuffers; -class SerializedArray implements VariantArray, SerializedValue { +class SerializedArray implements VariantArray, SerializedValue, Serializable { private static final int HEADER_SIZE = 1; private static final int OFFSET_SIZE_MASK = 0b1100; private static final int OFFSET_SIZE_SHIFT = 2; @@ -91,4 +92,22 @@ public ByteBuffer buffer() { public String toString() { return VariantArray.asString(this); } + + private Object writeReplace() { + return new SerializationProxy(this); + } + + private static class SerializationProxy implements Serializable { + private final VariantMetadata metadata; + private final byte[] valueBytes; + + private SerializationProxy(SerializedArray array) { + this.metadata = array.metadata; + this.valueBytes = ByteBuffers.toByteArray(array.buffer()); + } + + private Object readResolve() { + return SerializedArray.from(metadata, valueBytes); + } + } } diff --git a/api/src/main/java/org/apache/iceberg/variants/SerializedMetadata.java b/api/src/main/java/org/apache/iceberg/variants/SerializedMetadata.java index 9eff21536de6..4cdcc8580b4c 100644 --- a/api/src/main/java/org/apache/iceberg/variants/SerializedMetadata.java +++ b/api/src/main/java/org/apache/iceberg/variants/SerializedMetadata.java @@ -18,13 +18,14 @@ */ package org.apache.iceberg.variants; +import java.io.Serializable; import java.nio.ByteBuffer; import java.nio.ByteOrder; import org.apache.iceberg.relocated.com.google.common.annotations.VisibleForTesting; import org.apache.iceberg.relocated.com.google.common.base.Preconditions; import org.apache.iceberg.util.ByteBuffers; -class SerializedMetadata implements VariantMetadata, Serialized { +class SerializedMetadata implements VariantMetadata, Serialized, Serializable { private static final int HEADER_SIZE = 1; private static final int SUPPORTED_VERSION = 1; private static final int VERSION_MASK = 0b1111; @@ -138,4 +139,20 @@ public int writeTo(ByteBuffer buffer, int offset) { public String toString() { return VariantMetadata.asString(this); } + + private Object writeReplace() { + return new SerializationProxy(this); + } + + private static class SerializationProxy implements Serializable { + private final byte[] metadataBytes; + + private SerializationProxy(SerializedMetadata metadata) { + this.metadataBytes = ByteBuffers.toByteArray(metadata.buffer()); + } + + private Object readResolve() { + return SerializedMetadata.from(metadataBytes); + } + } } diff --git a/api/src/main/java/org/apache/iceberg/variants/SerializedObject.java b/api/src/main/java/org/apache/iceberg/variants/SerializedObject.java index bd9510c9a9b2..e1ce7cc3f1d4 100644 --- a/api/src/main/java/org/apache/iceberg/variants/SerializedObject.java +++ b/api/src/main/java/org/apache/iceberg/variants/SerializedObject.java @@ -18,6 +18,7 @@ */ package org.apache.iceberg.variants; +import java.io.Serializable; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.Iterator; @@ -29,7 +30,7 @@ import org.apache.iceberg.relocated.com.google.common.collect.Maps; import org.apache.iceberg.util.ByteBuffers; -class SerializedObject implements VariantObject, SerializedValue { +class SerializedObject implements VariantObject, SerializedValue, Serializable { private static final int HEADER_SIZE = 1; private static final int OFFSET_SIZE_MASK = 0b1100; private static final int OFFSET_SIZE_SHIFT = 2; @@ -238,4 +239,22 @@ public boolean equals(Object obj) { public String toString() { return VariantObject.asString(this); } + + private Object writeReplace() { + return new SerializationProxy(this); + } + + private static class SerializationProxy implements Serializable { + private final VariantMetadata metadata; + private final byte[] valueBytes; + + private SerializationProxy(SerializedObject object) { + this.metadata = object.metadata; + this.valueBytes = ByteBuffers.toByteArray(object.buffer()); + } + + private Object readResolve() { + return SerializedObject.from(metadata, valueBytes); + } + } } diff --git a/api/src/main/java/org/apache/iceberg/variants/SerializedPrimitive.java b/api/src/main/java/org/apache/iceberg/variants/SerializedPrimitive.java index 8ea35312737d..61b6e902e7b7 100644 --- a/api/src/main/java/org/apache/iceberg/variants/SerializedPrimitive.java +++ b/api/src/main/java/org/apache/iceberg/variants/SerializedPrimitive.java @@ -18,6 +18,7 @@ */ package org.apache.iceberg.variants; +import java.io.Serializable; import java.math.BigDecimal; import java.math.BigInteger; import java.nio.ByteBuffer; @@ -26,7 +27,7 @@ import org.apache.iceberg.util.ByteBuffers; import org.apache.iceberg.util.UUIDUtil; -class SerializedPrimitive implements VariantPrimitive, SerializedValue { +class SerializedPrimitive implements VariantPrimitive, SerializedValue, Serializable { private static final int PRIMITIVE_TYPE_SHIFT = 2; private static final int PRIMITIVE_OFFSET = 1; @@ -150,4 +151,20 @@ public boolean equals(Object other) { public String toString() { return VariantPrimitive.asString(this); } + + private Object writeReplace() { + return new SerializationProxy(this); + } + + private static class SerializationProxy implements Serializable { + private final byte[] valueBytes; + + private SerializationProxy(SerializedPrimitive primitive) { + this.valueBytes = ByteBuffers.toByteArray(primitive.buffer()); + } + + private Object readResolve() { + return SerializedPrimitive.from(valueBytes); + } + } } diff --git a/api/src/main/java/org/apache/iceberg/variants/SerializedShortString.java b/api/src/main/java/org/apache/iceberg/variants/SerializedShortString.java index 90fb54f3b13e..706bfce910c0 100644 --- a/api/src/main/java/org/apache/iceberg/variants/SerializedShortString.java +++ b/api/src/main/java/org/apache/iceberg/variants/SerializedShortString.java @@ -18,11 +18,13 @@ */ package org.apache.iceberg.variants; +import java.io.Serializable; import java.nio.ByteBuffer; import java.nio.ByteOrder; import org.apache.iceberg.relocated.com.google.common.base.Preconditions; +import org.apache.iceberg.util.ByteBuffers; -class SerializedShortString implements VariantPrimitive, SerializedValue { +class SerializedShortString implements VariantPrimitive, SerializedValue, Serializable { private static final int HEADER_SIZE = 1; private static final int LENGTH_MASK = 0b11111100; private static final int LENGTH_SHIFT = 2; @@ -81,4 +83,20 @@ public boolean equals(Object other) { public String toString() { return VariantPrimitive.asString(this); } + + private Object writeReplace() { + return new SerializationProxy(this); + } + + private static class SerializationProxy implements Serializable { + private final byte[] valueBytes; + + private SerializationProxy(SerializedShortString string) { + this.valueBytes = ByteBuffers.toByteArray(string.buffer()); + } + + private Object readResolve() { + return SerializedShortString.from(valueBytes); + } + } } diff --git a/api/src/main/java/org/apache/iceberg/variants/VariantData.java b/api/src/main/java/org/apache/iceberg/variants/VariantData.java index 193d54218856..675b8cc3c9a6 100644 --- a/api/src/main/java/org/apache/iceberg/variants/VariantData.java +++ b/api/src/main/java/org/apache/iceberg/variants/VariantData.java @@ -18,9 +18,10 @@ */ package org.apache.iceberg.variants; +import java.io.Serializable; import org.apache.iceberg.relocated.com.google.common.base.Preconditions; -class VariantData implements Variant { +class VariantData implements Variant, Serializable { private final VariantMetadata metadata; private final VariantValue value; diff --git a/api/src/test/java/org/apache/iceberg/variants/TestSerializedArray.java b/api/src/test/java/org/apache/iceberg/variants/TestSerializedArray.java index 5d53c82a317f..2ad68131f688 100644 --- a/api/src/test/java/org/apache/iceberg/variants/TestSerializedArray.java +++ b/api/src/test/java/org/apache/iceberg/variants/TestSerializedArray.java @@ -23,9 +23,11 @@ import java.nio.ByteBuffer; import java.util.Random; +import org.apache.iceberg.TestHelpers.RoundTripSerializer; import org.apache.iceberg.util.RandomUtil; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; import org.junit.jupiter.params.provider.ValueSource; public class TestSerializedArray { @@ -197,4 +199,13 @@ public void testNegativeArraySize() { .isInstanceOf(NegativeArraySizeException.class) .hasMessage("-1"); } + + @ParameterizedTest + @MethodSource("org.apache.iceberg.TestHelpers#serializers") + public void testSerialization(RoundTripSerializer serializer) throws Exception { + ByteBuffer buffer = VariantTestUtil.createArray(A, B, C, I34, I1234); + SerializedArray array = SerializedArray.from(EMPTY_METADATA, buffer, buffer.get(0)); + + VariantTestUtil.assertEqual(array, serializer.apply(array)); + } } diff --git a/api/src/test/java/org/apache/iceberg/variants/TestSerializedMetadata.java b/api/src/test/java/org/apache/iceberg/variants/TestSerializedMetadata.java index 70b6a28b946d..2c96df9d2ae8 100644 --- a/api/src/test/java/org/apache/iceberg/variants/TestSerializedMetadata.java +++ b/api/src/test/java/org/apache/iceberg/variants/TestSerializedMetadata.java @@ -24,10 +24,12 @@ import java.nio.ByteBuffer; import java.util.Random; import java.util.Set; +import org.apache.iceberg.TestHelpers.RoundTripSerializer; import org.apache.iceberg.relocated.com.google.common.collect.Sets; import org.apache.iceberg.util.RandomUtil; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; import org.junit.jupiter.params.provider.ValueSource; public class TestSerializedMetadata { @@ -251,4 +253,14 @@ public void testLengthTooShort() { () -> SerializedMetadata.from(new byte[] {(byte) 0b11010001, 0x00, 0x00, 0x00})) .isInstanceOf(IndexOutOfBoundsException.class); } + + @ParameterizedTest + @MethodSource("org.apache.iceberg.TestHelpers#serializers") + public void testSerialization(RoundTripSerializer serializer) + throws Exception { + SerializedMetadata metadata = + SerializedMetadata.from(VariantTestUtil.createMetadata(Set.of("a", "b", "c"), true)); + + VariantTestUtil.assertEqual(metadata, serializer.apply(metadata)); + } } diff --git a/api/src/test/java/org/apache/iceberg/variants/TestSerializedObject.java b/api/src/test/java/org/apache/iceberg/variants/TestSerializedObject.java index 07f7c9a2c5da..6dfcaf44325c 100644 --- a/api/src/test/java/org/apache/iceberg/variants/TestSerializedObject.java +++ b/api/src/test/java/org/apache/iceberg/variants/TestSerializedObject.java @@ -25,6 +25,7 @@ import java.util.Random; import java.util.Set; import java.util.stream.Stream; +import org.apache.iceberg.TestHelpers.RoundTripSerializer; import org.apache.iceberg.relocated.com.google.common.collect.ImmutableList; import org.apache.iceberg.relocated.com.google.common.collect.ImmutableMap; import org.apache.iceberg.relocated.com.google.common.collect.Maps; @@ -339,4 +340,16 @@ public void testThreeByteFieldIds(boolean sortFieldNames) { assertThat(object.get("ZZ").type()).isEqualTo(PhysicalType.INT8); assertThat(object.get("ZZ").asPrimitive().get()).isEqualTo((byte) 3); } + + @ParameterizedTest + @MethodSource("org.apache.iceberg.TestHelpers#serializers") + public void testSerialization(RoundTripSerializer serializer) throws Exception { + Map data = ImmutableMap.of("a", I1, "b", I2, "c", I3); + ByteBuffer meta = VariantTestUtil.createMetadata(data.keySet(), true /* sort names */); + ByteBuffer value = VariantTestUtil.createObject(meta, data); + SerializedObject object = + SerializedObject.from(SerializedMetadata.from(meta), value, value.get(0)); + + VariantTestUtil.assertEqual(object, serializer.apply(object)); + } } diff --git a/api/src/test/java/org/apache/iceberg/variants/TestSerializedPrimitives.java b/api/src/test/java/org/apache/iceberg/variants/TestSerializedPrimitives.java index 37ae2085fdd0..6522ad4cf308 100644 --- a/api/src/test/java/org/apache/iceberg/variants/TestSerializedPrimitives.java +++ b/api/src/test/java/org/apache/iceberg/variants/TestSerializedPrimitives.java @@ -25,8 +25,11 @@ import java.math.BigDecimal; import java.nio.ByteBuffer; import java.util.UUID; +import org.apache.iceberg.TestHelpers.RoundTripSerializer; import org.apache.iceberg.util.DateTimeUtil; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; public class TestSerializedPrimitives { @Test @@ -617,4 +620,25 @@ public void testUnsupportedType() { private static byte primitiveHeader(int primitiveType) { return (byte) (primitiveType << 2); } + + @ParameterizedTest + @MethodSource("org.apache.iceberg.TestHelpers#serializers") + public void testPrimitiveSerialization(RoundTripSerializer serializer) + throws Exception { + // date value + SerializedPrimitive primitive = + SerializedPrimitive.from(new byte[] {primitiveHeader(11), (byte) 0xF4, 0x43, 0x00, 0x00}); + + VariantTestUtil.assertEqual(primitive, serializer.apply(primitive)); + } + + @ParameterizedTest + @MethodSource("org.apache.iceberg.TestHelpers#serializers") + public void testShortStringSerialization(RoundTripSerializer serializer) + throws Exception { + SerializedShortString string = + SerializedShortString.from(new byte[] {0b11101, 'i', 'c', 'e', 'b', 'e', 'r', 'g'}); + + VariantTestUtil.assertEqual(string, serializer.apply(string)); + } } diff --git a/api/src/test/java/org/apache/iceberg/variants/TestVariant.java b/api/src/test/java/org/apache/iceberg/variants/TestVariant.java new file mode 100644 index 000000000000..2e414e66cccf --- /dev/null +++ b/api/src/test/java/org/apache/iceberg/variants/TestVariant.java @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.iceberg.variants; + +import java.util.Map; +import org.apache.iceberg.TestHelpers.RoundTripSerializer; +import org.apache.iceberg.relocated.com.google.common.collect.ImmutableMap; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +public class TestVariant { + @ParameterizedTest + @MethodSource("org.apache.iceberg.TestHelpers#serializers") + public void testSerialization(RoundTripSerializer serializer) throws Exception { + Map data = + ImmutableMap.of( + "a", + SerializedPrimitive.from(new byte[] {0b1100, 1}), // int8 = 1 + "b", + VariantTestUtil.createShortString("iceberg")); + Variant variant = VariantTestUtil.variant(data); + + Variant result = serializer.apply(variant); + + VariantTestUtil.assertEqual(variant.metadata(), result.metadata()); + VariantTestUtil.assertEqual(variant.value(), result.value()); + } +} diff --git a/core/src/main/java/org/apache/iceberg/variants/PrimitiveWrapper.java b/core/src/main/java/org/apache/iceberg/variants/PrimitiveWrapper.java index 6fd211156b00..b99a4e7fe9d8 100644 --- a/core/src/main/java/org/apache/iceberg/variants/PrimitiveWrapper.java +++ b/core/src/main/java/org/apache/iceberg/variants/PrimitiveWrapper.java @@ -18,15 +18,17 @@ */ package org.apache.iceberg.variants; +import java.io.Serializable; import java.math.BigDecimal; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.charset.StandardCharsets; import java.util.UUID; import org.apache.iceberg.relocated.com.google.common.base.Preconditions; +import org.apache.iceberg.util.ByteBuffers; import org.apache.iceberg.util.UUIDUtil; -class PrimitiveWrapper implements VariantPrimitive { +class PrimitiveWrapper implements VariantPrimitive, Serializable { private static final byte NULL_HEADER = VariantUtil.primitiveHeader(Primitives.TYPE_NULL); private static final byte TRUE_HEADER = VariantUtil.primitiveHeader(Primitives.TYPE_TRUE); private static final byte FALSE_HEADER = VariantUtil.primitiveHeader(Primitives.TYPE_FALSE); @@ -57,7 +59,9 @@ class PrimitiveWrapper implements VariantPrimitive { private final PhysicalType type; private final T value; - private ByteBuffer buffer = null; + // binary values are held as a serializable byte array rather than a non-serializable ByteBuffer + private final byte[] binary; + private transient ByteBuffer buffer = null; PrimitiveWrapper(PhysicalType type, T value) { if (value instanceof Boolean @@ -67,7 +71,14 @@ class PrimitiveWrapper implements VariantPrimitive { } else { this.type = type; } - this.value = value; + + if (this.type == PhysicalType.BINARY) { + this.binary = ByteBuffers.toByteArray((ByteBuffer) value); + this.value = null; + } else { + this.value = value; + this.binary = null; + } } @Override @@ -76,7 +87,12 @@ public PhysicalType type() { } @Override + @SuppressWarnings("unchecked") public T get() { + if (type == PhysicalType.BINARY) { + return (T) ByteBuffer.wrap(binary); + } + return value; } @@ -110,7 +126,7 @@ public int sizeInBytes() { case DECIMAL16: return 18; // 1 header + 1 scale + 16 unscaled value case BINARY: - return 5 + ((ByteBuffer) value).remaining(); // 1 header + 4 length + value length + return 5 + binary.length; // 1 header + 4 length + value length case STRING: if (null == buffer) { this.buffer = ByteBuffer.wrap(((String) value).getBytes(StandardCharsets.UTF_8)); @@ -205,11 +221,10 @@ public int writeTo(ByteBuffer outBuffer, int offset) { } return 18; case BINARY: - ByteBuffer binary = (ByteBuffer) value; outBuffer.put(offset, BINARY_HEADER); - outBuffer.putInt(offset + 1, binary.remaining()); - outBuffer.put(offset + 5, binary, binary.position(), binary.remaining()); - return 5 + binary.remaining(); + outBuffer.putInt(offset + 1, binary.length); + outBuffer.put(offset + 5, binary, 0, binary.length); + return 5 + binary.length; case STRING: if (null == buffer) { this.buffer = ByteBuffer.wrap(((String) value).getBytes(StandardCharsets.UTF_8)); diff --git a/core/src/main/java/org/apache/iceberg/variants/ShreddedObject.java b/core/src/main/java/org/apache/iceberg/variants/ShreddedObject.java index bd1fbad07547..8c683f9effdf 100644 --- a/core/src/main/java/org/apache/iceberg/variants/ShreddedObject.java +++ b/core/src/main/java/org/apache/iceberg/variants/ShreddedObject.java @@ -18,6 +18,7 @@ */ package org.apache.iceberg.variants; +import java.io.Serializable; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.Map; @@ -39,12 +40,12 @@ * fields. This also does not allow updating or replacing the metadata for the unshredded object, * which could require recursively rewriting field IDs. */ -public class ShreddedObject implements VariantObject { +public class ShreddedObject implements VariantObject, Serializable { private final VariantMetadata metadata; private final VariantObject unshredded; private final Map shreddedFields = Maps.newHashMap(); private final Set removedFields = Sets.newHashSet(); - private SerializationState serializationState = null; + private transient SerializationState serializationState = null; ShreddedObject(VariantMetadata metadata) { this(metadata, null); diff --git a/core/src/main/java/org/apache/iceberg/variants/ValueArray.java b/core/src/main/java/org/apache/iceberg/variants/ValueArray.java index c51cb2db74c3..f022078811cf 100644 --- a/core/src/main/java/org/apache/iceberg/variants/ValueArray.java +++ b/core/src/main/java/org/apache/iceberg/variants/ValueArray.java @@ -18,6 +18,7 @@ */ package org.apache.iceberg.variants; +import java.io.Serializable; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.List; @@ -25,8 +26,8 @@ import org.apache.iceberg.relocated.com.google.common.collect.Lists; import org.apache.iceberg.util.ByteBuffers; -public class ValueArray implements VariantArray { - private SerializationState serializationState = null; +public class ValueArray implements VariantArray, Serializable { + private transient SerializationState serializationState = null; private List elements = Lists.newArrayList(); ValueArray() {} diff --git a/core/src/test/java/org/apache/iceberg/variants/TestPrimitiveWrapper.java b/core/src/test/java/org/apache/iceberg/variants/TestPrimitiveWrapper.java index c131ad0d5013..e54523d751ee 100644 --- a/core/src/test/java/org/apache/iceberg/variants/TestPrimitiveWrapper.java +++ b/core/src/test/java/org/apache/iceberg/variants/TestPrimitiveWrapper.java @@ -24,6 +24,7 @@ import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.Random; +import org.apache.iceberg.TestHelpers; import org.apache.iceberg.types.Conversions; import org.apache.iceberg.types.Types; import org.apache.iceberg.util.RandomUtil; @@ -98,4 +99,11 @@ public void testByteBufferConversion(VariantPrimitive primitive) { VariantTestUtil.assertEqual(expectedVariant.metadata(), readValue.metadata()); VariantTestUtil.assertEqual(expectedVariant.value(), readValue.value()); } + + @ParameterizedTest + @FieldSource("PRIMITIVES") + public void testSerialization(VariantPrimitive primitive) throws Exception { + VariantTestUtil.assertEqual(primitive, TestHelpers.roundTripSerialize(primitive)); + VariantTestUtil.assertEqual(primitive, TestHelpers.KryoHelpers.roundTripSerialize(primitive)); + } } diff --git a/core/src/test/java/org/apache/iceberg/variants/TestShreddedObject.java b/core/src/test/java/org/apache/iceberg/variants/TestShreddedObject.java index cea1c6922c09..c71ba19d4019 100644 --- a/core/src/test/java/org/apache/iceberg/variants/TestShreddedObject.java +++ b/core/src/test/java/org/apache/iceberg/variants/TestShreddedObject.java @@ -27,6 +27,7 @@ import java.util.Map; import java.util.Random; import java.util.Set; +import org.apache.iceberg.TestHelpers.RoundTripSerializer; import org.apache.iceberg.relocated.com.google.common.collect.ImmutableMap; import org.apache.iceberg.relocated.com.google.common.collect.Maps; import org.apache.iceberg.relocated.com.google.common.collect.Sets; @@ -36,6 +37,7 @@ import org.apache.iceberg.util.RandomUtil; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; import org.junit.jupiter.params.provider.ValueSource; public class TestShreddedObject { @@ -452,4 +454,12 @@ private static SerializedObject createSerializedObject(Map Variants.metadata(metadataBuffer), VariantTestUtil.createObject(metadataBuffer, fields)); } + + @ParameterizedTest + @MethodSource("org.apache.iceberg.TestHelpers#serializers") + public void testSerialization(RoundTripSerializer serializer) throws Exception { + ShreddedObject object = createShreddedObject(FIELDS); + + VariantTestUtil.assertEqual(object, serializer.apply(object)); + } } diff --git a/core/src/test/java/org/apache/iceberg/variants/TestValueArray.java b/core/src/test/java/org/apache/iceberg/variants/TestValueArray.java index 7a8b3c533dd0..076675360cb7 100644 --- a/core/src/test/java/org/apache/iceberg/variants/TestValueArray.java +++ b/core/src/test/java/org/apache/iceberg/variants/TestValueArray.java @@ -25,6 +25,7 @@ import java.nio.ByteOrder; import java.util.List; import java.util.Random; +import org.apache.iceberg.TestHelpers.RoundTripSerializer; import org.apache.iceberg.relocated.com.google.common.collect.ImmutableList; import org.apache.iceberg.relocated.com.google.common.collect.Lists; import org.apache.iceberg.types.Conversions; @@ -32,6 +33,7 @@ import org.apache.iceberg.util.RandomUtil; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; import org.junit.jupiter.params.provider.ValueSource; public class TestValueArray { @@ -173,4 +175,13 @@ private static ValueArray createArray(List elements) { return arr; } + + @ParameterizedTest + @MethodSource("org.apache.iceberg.TestHelpers#serializers") + public void testSerialization(RoundTripSerializer serializer) throws Exception { + ValueArray array = new ValueArray(); + ELEMENTS.forEach(array::add); + + VariantTestUtil.assertEqual(array, serializer.apply(array)); + } }