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

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


The following commit(s) were added to refs/heads/master by this push:
     new 861845ae950 [FLINK-39157][table-common] Add 
ColumnList.hashCode()/equals()
861845ae950 is described below

commit 861845ae950cb6cf7187d54e67271485763d576c
Author: Timo Walther <[email protected]>
AuthorDate: Mon Mar 2 12:12:53 2026 +0100

    [FLINK-39157][table-common] Add ColumnList.hashCode()/equals()
    
    This closes #27674.
---
 .../java/org/apache/flink/types/ColumnList.java    |  31 +++-
 .../org/apache/flink/types/ColumnListTest.java     | 162 +++++++++++++++++++++
 2 files changed, 190 insertions(+), 3 deletions(-)

diff --git 
a/flink-table/flink-table-common/src/main/java/org/apache/flink/types/ColumnList.java
 
b/flink-table/flink-table-common/src/main/java/org/apache/flink/types/ColumnList.java
index bc70a660662..e07442bcf96 100644
--- 
a/flink-table/flink-table-common/src/main/java/org/apache/flink/types/ColumnList.java
+++ 
b/flink-table/flink-table-common/src/main/java/org/apache/flink/types/ColumnList.java
@@ -27,6 +27,7 @@ import org.apache.flink.util.Preconditions;
 
 import java.io.Serializable;
 import java.util.List;
+import java.util.Objects;
 import java.util.stream.Collectors;
 import java.util.stream.IntStream;
 
@@ -46,15 +47,22 @@ public final class ColumnList implements Serializable {
     private final List<DataType> dataTypes;
 
     private ColumnList(List<String> names, List<DataType> dataTypes) {
-        this.names = Preconditions.checkNotNull(names, "Names must not be 
null.");
-        this.dataTypes = Preconditions.checkNotNull(dataTypes, "Data types 
must be null.");
+        Preconditions.checkNotNull(names, "Names must not be null.");
+        Preconditions.checkNotNull(dataTypes, "Data types must not be null.");
+        Preconditions.checkArgument(
+                names.stream().noneMatch(Objects::isNull), "Names must not 
contain null elements.");
+        Preconditions.checkArgument(
+                dataTypes.stream().noneMatch(Objects::isNull),
+                "Data types must not contain null elements.");
         Preconditions.checkArgument(
                 dataTypes.isEmpty() || dataTypes.size() == names.size(),
                 "Mismatch between data types and names.");
+        this.names = List.copyOf(names);
+        this.dataTypes = List.copyOf(dataTypes);
     }
 
     public static ColumnList of(List<String> names, List<DataType> dataTypes) {
-        return new ColumnList(List.copyOf(names), List.copyOf(dataTypes));
+        return new ColumnList(names, dataTypes);
     }
 
     public static ColumnList of(List<String> names) {
@@ -105,4 +113,21 @@ public final class ColumnList implements Serializable {
                         })
                 .collect(Collectors.joining(", ", "(", ")"));
     }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        final ColumnList that = (ColumnList) o;
+        return Objects.equals(names, that.names) && Objects.equals(dataTypes, 
that.dataTypes);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(names, dataTypes);
+    }
 }
diff --git 
a/flink-table/flink-table-common/src/test/java/org/apache/flink/types/ColumnListTest.java
 
b/flink-table/flink-table-common/src/test/java/org/apache/flink/types/ColumnListTest.java
new file mode 100644
index 00000000000..735ddb27537
--- /dev/null
+++ 
b/flink-table/flink-table-common/src/test/java/org/apache/flink/types/ColumnListTest.java
@@ -0,0 +1,162 @@
+/*
+ * 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.flink.types;
+
+import org.apache.flink.table.api.DataTypes;
+import org.apache.flink.table.types.DataType;
+
+import org.junit.jupiter.api.Test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+/** Tests for {@link ColumnList}. */
+class ColumnListTest {
+
+    @Test
+    void testWithNamesAndDataTypes() {
+        final List<String> names = List.of("a", "b", "c");
+        final List<DataType> dataTypes =
+                List.of(DataTypes.INT(), DataTypes.STRING(), 
DataTypes.BOOLEAN());
+
+        final ColumnList columnList = ColumnList.of(names, dataTypes);
+
+        assertThat(columnList.getNames()).isEqualTo(names);
+        assertThat(columnList.getDataTypes()).isEqualTo(dataTypes);
+    }
+
+    @Test
+    void testWithNamesOnly() {
+        final List<String> names = List.of("a", "b", "c");
+
+        final ColumnList columnList = ColumnList.of(names);
+
+        assertThat(columnList.getNames()).isEqualTo(names);
+        assertThat(columnList.getDataTypes()).isEmpty();
+    }
+
+    @Test
+    void testWithEmptyLists() {
+        final ColumnList columnList = ColumnList.of(List.of(), List.of());
+
+        assertThat(columnList.getNames()).isEmpty();
+        assertThat(columnList.getDataTypes()).isEmpty();
+    }
+
+    @Test
+    void testToStringWithNamesOnly() {
+        final ColumnList columnList = ColumnList.of("a", "b", "c");
+
+        assertThat(columnList.toString()).isEqualTo("(`a`, `b`, `c`)");
+    }
+
+    @Test
+    void testToStringWithNamesAndDataTypes() {
+        final List<String> names = List.of("a", "b", "c");
+        final List<DataType> dataTypes =
+                List.of(DataTypes.INT(), DataTypes.STRING(), 
DataTypes.BOOLEAN());
+
+        final ColumnList columnList = ColumnList.of(names, dataTypes);
+
+        assertThat(columnList.toString()).isEqualTo("(`a` INT, `b` STRING, `c` 
BOOLEAN)");
+    }
+
+    @Test
+    void testEqualsAndHashCode() {
+        final List<String> names = List.of("a", "b");
+        final List<DataType> dataTypes = List.of(DataTypes.INT(), 
DataTypes.STRING());
+
+        final ColumnList columnList1 = ColumnList.of(names, dataTypes);
+        final ColumnList columnList2 = ColumnList.of(names, dataTypes);
+        final ColumnList columnList3 = ColumnList.of(List.of("a", "b"));
+
+        assertThat(columnList1).isEqualTo(columnList2);
+        assertThat(columnList1.hashCode()).isEqualTo(columnList2.hashCode());
+        assertThat(columnList1).isNotEqualTo(columnList3);
+    }
+
+    @Test
+    void testNullNamesThrowsException() {
+        assertThatThrownBy(() -> ColumnList.of(null, List.of()))
+                .isInstanceOf(NullPointerException.class)
+                .hasMessageContaining("Names must not be null");
+    }
+
+    @Test
+    void testNullDataTypesThrowsException() {
+        assertThatThrownBy(() -> ColumnList.of(List.of("a"), null))
+                .isInstanceOf(NullPointerException.class)
+                .hasMessageContaining("Data types must not be null");
+    }
+
+    @Test
+    void testMismatchedDataTypesAndNamesThrowsException() {
+        final List<String> names = List.of("a", "b", "c");
+        final List<DataType> dataTypes = List.of(DataTypes.INT(), 
DataTypes.STRING());
+
+        assertThatThrownBy(() -> ColumnList.of(names, dataTypes))
+                .isInstanceOf(IllegalArgumentException.class)
+                .hasMessageContaining("Mismatch between data types and names");
+    }
+
+    @Test
+    void testNullElementInNamesThrowsException() {
+        final List<String> names = Arrays.asList("a", null, "c");
+
+        assertThatThrownBy(() -> ColumnList.of(names))
+                .isInstanceOf(IllegalArgumentException.class)
+                .hasMessageContaining("Names must not contain null elements");
+    }
+
+    @Test
+    void testNullElementInDataTypesThrowsException() {
+        final List<String> names = List.of("a", "b", "c");
+        final List<DataType> dataTypes = Arrays.asList(DataTypes.INT(), null, 
DataTypes.BOOLEAN());
+
+        assertThatThrownBy(() -> ColumnList.of(names, dataTypes))
+                .isInstanceOf(IllegalArgumentException.class)
+                .hasMessageContaining("Data types must not contain null 
elements");
+    }
+
+    @Test
+    void testImmutabilityOfNames() {
+        final List<String> names = new ArrayList<>(List.of("a", "b"));
+        final ColumnList columnList = ColumnList.of(names);
+
+        names.add("c");
+
+        assertThat(columnList.getNames()).containsExactly("a", "b");
+    }
+
+    @Test
+    void testImmutabilityOfDataTypes() {
+        final List<String> names = new ArrayList<>(List.of("a", "b"));
+        final List<DataType> dataTypes =
+                new ArrayList<>(List.of(DataTypes.INT(), DataTypes.STRING()));
+        final ColumnList columnList = ColumnList.of(names, dataTypes);
+
+        dataTypes.add(DataTypes.BOOLEAN());
+
+        assertThat(columnList.getDataTypes()).hasSize(2);
+    }
+}

Reply via email to