From 72b3b6a90f6955b4f3c8b6a1ffcb6eed95169e77 Mon Sep 17 00:00:00 2001 From: Kaustav Sarkar Date: Wed, 24 Dec 2025 15:10:20 +0530 Subject: [PATCH 1/2] GH-399 Fix setPosition fails with NullPointerException Added null checks for setPosition and test cases to validate the issue --- .gitignore | 2 + .../codegen/templates/DenseUnionWriter.java | 4 +- .../complex/impl/TestDenseUnionWriterNPE.java | 86 +++++++++++++++++++ 3 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 vector/src/test/java/org/apache/arrow/vector/complex/impl/TestDenseUnionWriterNPE.java diff --git a/.gitignore b/.gitignore index b57597af47..4d28cc9869 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,8 @@ .classpath .factorypath .idea/ +.vscode/ +.cursor/ .project .settings/ /*-build/ diff --git a/vector/src/main/codegen/templates/DenseUnionWriter.java b/vector/src/main/codegen/templates/DenseUnionWriter.java index 8515b759e6..9aeea5b054 100644 --- a/vector/src/main/codegen/templates/DenseUnionWriter.java +++ b/vector/src/main/codegen/templates/DenseUnionWriter.java @@ -55,7 +55,9 @@ public DenseUnionWriter(DenseUnionVector vector, NullableStructWriterFactory nul public void setPosition(int index) { super.setPosition(index); for (BaseWriter writer : writers) { - writer.setPosition(index); + if (writer != null) { + writer.setPosition(index); + } } } diff --git a/vector/src/test/java/org/apache/arrow/vector/complex/impl/TestDenseUnionWriterNPE.java b/vector/src/test/java/org/apache/arrow/vector/complex/impl/TestDenseUnionWriterNPE.java new file mode 100644 index 0000000000..fdd03be4da --- /dev/null +++ b/vector/src/test/java/org/apache/arrow/vector/complex/impl/TestDenseUnionWriterNPE.java @@ -0,0 +1,86 @@ +/* + * 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.arrow.vector.complex.impl; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.List; +import org.apache.arrow.memory.BufferAllocator; +import org.apache.arrow.memory.RootAllocator; +import org.apache.arrow.vector.complex.ListVector; +import org.apache.arrow.vector.types.Types; +import org.apache.arrow.vector.types.pojo.FieldType; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public class TestDenseUnionWriterNPE { + + private BufferAllocator allocator; + + @BeforeEach + public void init() { + allocator = new RootAllocator(Long.MAX_VALUE); + } + + @AfterEach + public void terminate() { + allocator.close(); + } + + @Test + public void testListOfDenseUnionWriterNPE() { + try (ListVector listVector = ListVector.empty("list", allocator)) { + listVector.addOrGetVector(FieldType.nullable(Types.MinorType.DENSEUNION.getType())); + UnionListWriter listWriter = listVector.getWriter(); + + listWriter.startList(); + listWriter.endList(); + } + } + + @Test + public void testListOfDenseUnionWriterWithData() { + try (ListVector listVector = ListVector.empty("list", allocator)) { + listVector.addOrGetVector(FieldType.nullable(Types.MinorType.DENSEUNION.getType())); + + UnionListWriter listWriter = listVector.getWriter(); + listWriter.startList(); + listWriter.writeInt(100); + listWriter.writeBigInt(200L); + listWriter.endList(); + + listWriter.startList(); + listWriter.writeFloat4(3.14f); + listWriter.endList(); + + listVector.setValueCount(2); + + assertEquals(2, listVector.getValueCount()); + + List value0 = (List) listVector.getObject(0); + List value1 = (List) listVector.getObject(1); + + assertEquals(2, value0.size()); + assertEquals(100, value0.get(0)); + assertEquals(200L, value0.get(1)); + + assertEquals(1, value1.size()); + assertEquals(3.14f, value1.get(0)); + } + } +} From 1eaa535eefdf5a433c66310d60fa1e22963805b7 Mon Sep 17 00:00:00 2001 From: Kaustav Sarkar Date: Fri, 26 Dec 2025 22:47:42 +0530 Subject: [PATCH 2/2] GH-399 Moved tests to a common file and added comment linking to issue --- .../complex/impl/TestDenseUnionWriterNPE.java | 86 ------------------- .../complex/writer/TestComplexWriter.java | 43 ++++++++++ 2 files changed, 43 insertions(+), 86 deletions(-) delete mode 100644 vector/src/test/java/org/apache/arrow/vector/complex/impl/TestDenseUnionWriterNPE.java diff --git a/vector/src/test/java/org/apache/arrow/vector/complex/impl/TestDenseUnionWriterNPE.java b/vector/src/test/java/org/apache/arrow/vector/complex/impl/TestDenseUnionWriterNPE.java deleted file mode 100644 index fdd03be4da..0000000000 --- a/vector/src/test/java/org/apache/arrow/vector/complex/impl/TestDenseUnionWriterNPE.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * 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.arrow.vector.complex.impl; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -import java.util.List; -import org.apache.arrow.memory.BufferAllocator; -import org.apache.arrow.memory.RootAllocator; -import org.apache.arrow.vector.complex.ListVector; -import org.apache.arrow.vector.types.Types; -import org.apache.arrow.vector.types.pojo.FieldType; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -public class TestDenseUnionWriterNPE { - - private BufferAllocator allocator; - - @BeforeEach - public void init() { - allocator = new RootAllocator(Long.MAX_VALUE); - } - - @AfterEach - public void terminate() { - allocator.close(); - } - - @Test - public void testListOfDenseUnionWriterNPE() { - try (ListVector listVector = ListVector.empty("list", allocator)) { - listVector.addOrGetVector(FieldType.nullable(Types.MinorType.DENSEUNION.getType())); - UnionListWriter listWriter = listVector.getWriter(); - - listWriter.startList(); - listWriter.endList(); - } - } - - @Test - public void testListOfDenseUnionWriterWithData() { - try (ListVector listVector = ListVector.empty("list", allocator)) { - listVector.addOrGetVector(FieldType.nullable(Types.MinorType.DENSEUNION.getType())); - - UnionListWriter listWriter = listVector.getWriter(); - listWriter.startList(); - listWriter.writeInt(100); - listWriter.writeBigInt(200L); - listWriter.endList(); - - listWriter.startList(); - listWriter.writeFloat4(3.14f); - listWriter.endList(); - - listVector.setValueCount(2); - - assertEquals(2, listVector.getValueCount()); - - List value0 = (List) listVector.getObject(0); - List value1 = (List) listVector.getObject(1); - - assertEquals(2, value0.size()); - assertEquals(100, value0.get(0)); - assertEquals(200L, value0.get(1)); - - assertEquals(1, value1.size()); - assertEquals(3.14f, value1.get(0)); - } - } -} diff --git a/vector/src/test/java/org/apache/arrow/vector/complex/writer/TestComplexWriter.java b/vector/src/test/java/org/apache/arrow/vector/complex/writer/TestComplexWriter.java index 46c259bda0..871a3cc461 100644 --- a/vector/src/test/java/org/apache/arrow/vector/complex/writer/TestComplexWriter.java +++ b/vector/src/test/java/org/apache/arrow/vector/complex/writer/TestComplexWriter.java @@ -2530,4 +2530,47 @@ public void extensionWriterReader() throws Exception { } } } + + @Test + void testListOfDenseUnionWriterNPE() { + // Regression test for https://github.com/apache/arrow-java/issues/399 + try (ListVector listVector = ListVector.empty("list", allocator)) { + listVector.addOrGetVector(FieldType.nullable(MinorType.DENSEUNION.getType())); + UnionListWriter listWriter = listVector.getWriter(); + + listWriter.startList(); + listWriter.endList(); + } + } + + @Test + void testListOfDenseUnionWriterWithData() { + try (ListVector listVector = ListVector.empty("list", allocator)) { + listVector.addOrGetVector(FieldType.nullable(MinorType.DENSEUNION.getType())); + + UnionListWriter listWriter = listVector.getWriter(); + listWriter.startList(); + listWriter.writeInt(100); + listWriter.writeBigInt(200L); + listWriter.endList(); + + listWriter.startList(); + listWriter.writeFloat4(3.14f); + listWriter.endList(); + + listVector.setValueCount(2); + + assertEquals(2, listVector.getValueCount()); + + List value0 = (List) listVector.getObject(0); + List value1 = (List) listVector.getObject(1); + + assertEquals(2, value0.size()); + assertEquals(100, value0.get(0)); + assertEquals(200L, value0.get(1)); + + assertEquals(1, value1.size()); + assertEquals(3.14f, value1.get(0)); + } + } }