This is an automated email from the ASF dual-hosted git repository.

ahmedabu98 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/beam.git


The following commit(s) were added to refs/heads/master by this push:
     new bddab868f3c ValueKind coder (#39989)
bddab868f3c is described below

commit bddab868f3ca29f74dd3176f383787be1ceba787
Author: Ahmed Abualsaud <[email protected]>
AuthorDate: Thu Sep 3 20:22:51 2026 +0200

    ValueKind coder (#39989)
    
    * valuekind coder
    
    * spotless
---
 .../org/apache/beam/sdk/coders/CoderRegistry.java  |  3 +
 .../org/apache/beam/sdk/coders/ValueKindCoder.java | 88 ++++++++++++++++++++++
 .../apache/beam/sdk/coders/ValueKindCoderTest.java | 81 ++++++++++++++++++++
 3 files changed, 172 insertions(+)

diff --git 
a/sdks/java/core/src/main/java/org/apache/beam/sdk/coders/CoderRegistry.java 
b/sdks/java/core/src/main/java/org/apache/beam/sdk/coders/CoderRegistry.java
index 2cf79a723d6..c4f8e34d61e 100644
--- a/sdks/java/core/src/main/java/org/apache/beam/sdk/coders/CoderRegistry.java
+++ b/sdks/java/core/src/main/java/org/apache/beam/sdk/coders/CoderRegistry.java
@@ -52,6 +52,7 @@ import org.apache.beam.sdk.values.KV;
 import org.apache.beam.sdk.values.TimestampedValue;
 import org.apache.beam.sdk.values.TypeDescriptor;
 import org.apache.beam.sdk.values.TypeDescriptors;
+import org.apache.beam.sdk.values.ValueKind;
 import 
org.apache.beam.vendor.guava.v32_1_2_jre.com.google.common.annotations.VisibleForTesting;
 import 
org.apache.beam.vendor.guava.v32_1_2_jre.com.google.common.collect.HashMultimap;
 import 
org.apache.beam.vendor.guava.v32_1_2_jre.com.google.common.collect.ImmutableList;
@@ -137,6 +138,8 @@ public class CoderRegistry {
           TimestampedValue.class,
           CoderProviders.fromStaticMethods(
               TimestampedValue.class, 
TimestampedValue.TimestampedValueCoder.class));
+      builder.put(
+          ValueKind.class, CoderProviders.fromStaticMethods(ValueKind.class, 
ValueKindCoder.class));
       builder.put(Void.class, CoderProviders.fromStaticMethods(Void.class, 
VoidCoder.class));
       builder.put(
           byte[].class, CoderProviders.fromStaticMethods(byte[].class, 
ByteArrayCoder.class));
diff --git 
a/sdks/java/core/src/main/java/org/apache/beam/sdk/coders/ValueKindCoder.java 
b/sdks/java/core/src/main/java/org/apache/beam/sdk/coders/ValueKindCoder.java
new file mode 100644
index 00000000000..24f1a119f42
--- /dev/null
+++ 
b/sdks/java/core/src/main/java/org/apache/beam/sdk/coders/ValueKindCoder.java
@@ -0,0 +1,88 @@
+/*
+ * 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.beam.sdk.coders;
+
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import org.apache.beam.model.fnexecution.v1.BeamFnApi.Elements;
+import org.apache.beam.sdk.values.TypeDescriptor;
+import org.apache.beam.sdk.values.ValueKind;
+import org.apache.beam.sdk.values.ValueKindUtil;
+import org.checkerframework.checker.nullness.qual.Nullable;
+
+/**
+ * A {@link Coder} for {@link ValueKind}, encoded in 1 byte as the matching 
{@link
+ * Elements.ValueKind.Enum} number, so the wire format stays stable if the 
enum is reordered and
+ * matches the portability representation.
+ */
+public class ValueKindCoder extends AtomicCoder<ValueKind> {
+
+  public static ValueKindCoder of() {
+    return INSTANCE;
+  }
+
+  private static final ValueKindCoder INSTANCE = new ValueKindCoder();
+  private static final TypeDescriptor<ValueKind> TYPE_DESCRIPTOR =
+      TypeDescriptor.of(ValueKind.class);
+
+  private ValueKindCoder() {}
+
+  @Override
+  public void encode(ValueKind value, OutputStream outStream) throws 
IOException, CoderException {
+    if (value == null) {
+      throw new CoderException("cannot encode a null ValueKind");
+    }
+    outStream.write(ValueKindUtil.toProto(value).getNumber());
+  }
+
+  @Override
+  public ValueKind decode(InputStream inStream) throws IOException, 
CoderException {
+    int number = inStream.read();
+    if (number == -1) {
+      throw new CoderException(new EOFException("EOF encountered decoding a 
ValueKind"));
+    }
+    Elements.ValueKind.@Nullable Enum proto = 
Elements.ValueKind.Enum.forNumber(number);
+    if (proto == null) {
+      throw new CoderException("Unknown ValueKind number: " + number);
+    }
+
+    return ValueKindUtil.fromProto(proto);
+  }
+
+  @Override
+  public boolean consistentWithEquals() {
+    return true;
+  }
+
+  @Override
+  public boolean isRegisterByteSizeObserverCheap(ValueKind value) {
+    return true;
+  }
+
+  @Override
+  protected long getEncodedElementByteSize(ValueKind value) {
+    return 1;
+  }
+
+  @Override
+  public TypeDescriptor<ValueKind> getEncodedTypeDescriptor() {
+    return TYPE_DESCRIPTOR;
+  }
+}
diff --git 
a/sdks/java/core/src/test/java/org/apache/beam/sdk/coders/ValueKindCoderTest.java
 
b/sdks/java/core/src/test/java/org/apache/beam/sdk/coders/ValueKindCoderTest.java
new file mode 100644
index 00000000000..aeac2132c85
--- /dev/null
+++ 
b/sdks/java/core/src/test/java/org/apache/beam/sdk/coders/ValueKindCoderTest.java
@@ -0,0 +1,81 @@
+/*
+ * 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.beam.sdk.coders;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.Arrays;
+import java.util.List;
+import org.apache.beam.sdk.testing.CoderProperties;
+import org.apache.beam.sdk.util.CoderUtils;
+import org.apache.beam.sdk.values.TypeDescriptor;
+import org.apache.beam.sdk.values.ValueKind;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Tests for {@link ValueKindCoder}. */
+@RunWith(JUnit4.class)
+public class ValueKindCoderTest {
+
+  private static final Coder<ValueKind> TEST_CODER = ValueKindCoder.of();
+
+  private static final List<ValueKind> TEST_VALUES =
+      Arrays.asList(
+          ValueKind.INSERT, ValueKind.UPDATE_BEFORE, ValueKind.UPDATE_AFTER, 
ValueKind.DELETE);
+
+  /** One byte per value, holding the proto enum number. */
+  private static final List<String> TEST_ENCODINGS = Arrays.asList("AQ", "Ag", 
"Aw", "BA");
+
+  @Rule public ExpectedException thrown = ExpectedException.none();
+
+  @Test
+  public void testDecodeEncodeEqual() throws Exception {
+    for (ValueKind value : TEST_VALUES) {
+      CoderProperties.coderDecodeEncodeEqual(TEST_CODER, value);
+    }
+  }
+
+  @Test
+  public void testWireFormatEncode() throws Exception {
+    CoderProperties.coderEncodesBase64(TEST_CODER, TEST_VALUES, 
TEST_ENCODINGS);
+  }
+
+  /** VALUE_KIND_UNSPECIFIED (0) means INSERT, for backwards compatibility. */
+  @Test
+  public void testDecodeUnspecified() throws Exception {
+    assertEquals(ValueKind.INSERT, CoderUtils.decodeFromBase64(TEST_CODER, 
"AA"));
+  }
+
+  @Test
+  public void testDecodeUnknownNumberThrows() throws Exception {
+    thrown.expect(CoderException.class);
+    thrown.expectMessage("Unknown ValueKind number: 42");
+
+    CoderUtils.decodeFromBase64(TEST_CODER, "Kg");
+  }
+
+  @Test
+  public void testCoderRegistryResolvesValueKind() throws Exception {
+    assertEquals(
+        ValueKindCoder.of(),
+        
CoderRegistry.createDefault().getCoder(TypeDescriptor.of(ValueKind.class)));
+  }
+}

Reply via email to