Skip to content

Commit b98942f

Browse files
committed
Add ArrayUtils.getDimensions(Object)
1 parent 934e6d8 commit b98942f

3 files changed

Lines changed: 181 additions & 0 deletions

File tree

src/changes/changes.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ The <action> type attribute can be add,update,fix,remove.
114114
<action type="add" dev="ggregory" due-to="Gary Gregory">JavaVersion.get(String) now support Java 26 and 27.</action>
115115
<action issue="LANG-1810" type="add" dev="ggregory" due-to="Yelim Koo, Gary Gregory">Deprecate ArrayUtils.SOFT_MAX_ARRAY_LENGTH in favor of SAFE_MAX_ARRAY_LENGTH #1559.</action>
116116
<action type="add" dev="ggregory" due-to="Gary Gregory, Theodora Anastasia Lazaridou">Add long support to BitField #1561.</action>
117+
<action type="add" dev="ggregory" due-to="Gary Gregory">Add ArrayUtils.getDimensions(Object).</action>
117118
<!-- UPDATE -->
118119
<action type="update" dev="ggregory" due-to="Gary Gregory, Dependabot">Bump org.apache.commons:commons-parent from 92 to 96 #1498.</action>
119120
<action type="update" dev="ggregory" due-to="Gary Gregory">[test] Bump org.apache.commons:commons-text from 1.14.0 to 1.15.0.</action>

src/main/java/org/apache/commons/lang3/ArrayUtils.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1849,6 +1849,29 @@ public static <T> Class<T> getComponentType(final T[] array) {
18491849
return ClassUtils.getComponentType(ObjectUtils.getClass(array));
18501850
}
18511851

1852+
/**
1853+
* Gets the number of dimensions of an array.
1854+
* <p>
1855+
* The <a href="https://docs.oracle.com/javase/specs/jvms/se25/html/jvms-4.html#jvms-4.3">JVM specification</a> limits the number of dimensions to 255.
1856+
* </p>
1857+
*
1858+
* @param array the array, may be {@code null}.
1859+
* @return The number of dimensions, 0 if the input is null or not an array. The JVM specification limits the number of dimensions to 255.
1860+
* @since 3.21.0
1861+
* @see <a href="https://docs.oracle.com/javase/specs/jvms/se25/html/jvms-4.html#jvms-4.3">JVM specification Field Descriptors</a>
1862+
*/
1863+
public static int getDimensions(final Object array) {
1864+
int dimensions = 0;
1865+
if (array != null) {
1866+
Class<?> arrayClass = array.getClass();
1867+
while (arrayClass.isArray()) {
1868+
dimensions++;
1869+
arrayClass = arrayClass.getComponentType();
1870+
}
1871+
}
1872+
return dimensions;
1873+
}
1874+
18521875
/**
18531876
* Gets the length of the specified array.
18541877
* This method can deal with {@link Object} arrays and with primitive arrays.
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* https://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
package org.apache.commons.lang3;
19+
20+
import static org.junit.jupiter.api.Assertions.assertEquals;
21+
22+
import java.util.stream.Stream;
23+
24+
import org.junit.jupiter.api.Test;
25+
import org.junit.jupiter.params.ParameterizedTest;
26+
import org.junit.jupiter.params.provider.Arguments;
27+
import org.junit.jupiter.params.provider.MethodSource;
28+
29+
class ArrayUtilsGetDimensions {
30+
31+
// Tests cyclic references
32+
static class Node {
33+
34+
String name;
35+
36+
Node next;
37+
38+
Node(final String name) {
39+
this.name = name;
40+
}
41+
}
42+
43+
private static Stream<Arguments> provideArraysWithExpectedDimensions() {
44+
return Stream.of(Arguments.of(new int[] { 1, 2, 3 }, 1), Arguments.of(new int[][] { { 1, 2 }, { 3, 4 } }, 2),
45+
Arguments.of(new int[][][] { { { 1 } } }, 3), Arguments.of(new String[] { "a", "b" }, 1), Arguments.of(new String[][] { { "a" }, { "b" } }, 2),
46+
Arguments.of(new Object[5], 1), Arguments.of(new boolean[2][3], 2), Arguments.of(new char[1][2][3][4], 4));
47+
}
48+
49+
@Test
50+
void testArraysOfArrays() {
51+
final Object[] arrayOfArrays = { new int[] { 1, 2 }, new String[] { "a", "b" } };
52+
assertEquals(1, ArrayUtils.getDimensions(arrayOfArrays));
53+
}
54+
55+
@Test
56+
void testArraysWithCyclicObjects() {
57+
final Node node1 = new Node("A");
58+
final Node node2 = new Node("B");
59+
node1.next = node2;
60+
node2.next = node1; // Create cycle
61+
final Node[] arr = { node1, node2 };
62+
assertEquals(1, ArrayUtils.getDimensions(arr));
63+
final Node[][] arr2D = { { node1, node2 }, { node2, node1 } };
64+
assertEquals(2, ArrayUtils.getDimensions(arr2D));
65+
}
66+
67+
@Test
68+
void testArraysWithNullElements() {
69+
final String[] arrWithNull = { null, "test", null };
70+
assertEquals(1, ArrayUtils.getDimensions(arrWithNull));
71+
final String[][] arr2DWithNull = { { null, "a" }, null, { "b" } };
72+
assertEquals(2, ArrayUtils.getDimensions(arr2DWithNull));
73+
}
74+
75+
@Test
76+
void testEmptyOneDimensionalArrays() {
77+
assertEquals(1, ArrayUtils.getDimensions(new int[0]));
78+
assertEquals(1, ArrayUtils.getDimensions(new String[0]));
79+
}
80+
81+
@Test
82+
void testHighDimensionalArrays() {
83+
assertEquals(4, ArrayUtils.getDimensions(new int[1][2][3][4]));
84+
assertEquals(5, ArrayUtils.getDimensions(new byte[1][1][1][1][1]));
85+
assertEquals(6, ArrayUtils.getDimensions(new String[2][2][2][2][2][2]));
86+
}
87+
88+
@Test
89+
void testInitializedArrays() {
90+
final int[] arr1D = { 1, 2, 3, 4, 5 };
91+
assertEquals(1, ArrayUtils.getDimensions(arr1D));
92+
final int[][] arr2D = { { 1, 2, 3 }, { 4, 5, 6 } };
93+
assertEquals(2, ArrayUtils.getDimensions(arr2D));
94+
final int[][][] arr3D = { { { 1, 2 }, { 3, 4 } }, { { 5, 6 }, { 7, 8 } } };
95+
assertEquals(3, ArrayUtils.getDimensions(arr3D));
96+
}
97+
98+
@Test
99+
void testJaggedArrays() {
100+
final int[][] jagged = { { 1, 2 }, { 3, 4, 5 }, { 6 } };
101+
assertEquals(2, ArrayUtils.getDimensions(jagged));
102+
final String[][] jaggedStrings = { { "a" }, { "b", "c", "d" } };
103+
assertEquals(2, ArrayUtils.getDimensions(jaggedStrings));
104+
}
105+
106+
@Test
107+
void testNonArrayObject() {
108+
assertEquals(0, ArrayUtils.getDimensions("Not an array"));
109+
assertEquals(0, ArrayUtils.getDimensions(42));
110+
assertEquals(0, ArrayUtils.getDimensions(new Object()));
111+
assertEquals(0, ArrayUtils.getDimensions(3.14));
112+
}
113+
114+
@Test
115+
void testNullArray() {
116+
assertEquals(0, ArrayUtils.getDimensions(null));
117+
}
118+
119+
@Test
120+
void testOneDimensionalObjectArrays() {
121+
assertEquals(1, ArrayUtils.getDimensions(new String[5]));
122+
assertEquals(1, ArrayUtils.getDimensions(new Object[10]));
123+
assertEquals(1, ArrayUtils.getDimensions(new Integer[3]));
124+
}
125+
126+
@Test
127+
void testOneDimensionalPrimitiveArrays() {
128+
assertEquals(1, ArrayUtils.getDimensions(new int[5]));
129+
assertEquals(1, ArrayUtils.getDimensions(new byte[10]));
130+
assertEquals(1, ArrayUtils.getDimensions(new short[3]));
131+
assertEquals(1, ArrayUtils.getDimensions(new long[7]));
132+
assertEquals(1, ArrayUtils.getDimensions(new float[4]));
133+
assertEquals(1, ArrayUtils.getDimensions(new double[6]));
134+
assertEquals(1, ArrayUtils.getDimensions(new boolean[2]));
135+
assertEquals(1, ArrayUtils.getDimensions(new char[8]));
136+
}
137+
138+
@Test
139+
void testThreeDimensionalArrays() {
140+
assertEquals(3, ArrayUtils.getDimensions(new int[2][3][4]));
141+
assertEquals(3, ArrayUtils.getDimensions(new String[1][2][3]));
142+
assertEquals(3, ArrayUtils.getDimensions(new Object[5][5][5]));
143+
}
144+
145+
@Test
146+
void testTwoDimensionalArrays() {
147+
assertEquals(2, ArrayUtils.getDimensions(new int[3][4]));
148+
assertEquals(2, ArrayUtils.getDimensions(new String[2][5]));
149+
assertEquals(2, ArrayUtils.getDimensions(new double[1][1]));
150+
}
151+
152+
@ParameterizedTest
153+
@MethodSource("provideArraysWithExpectedDimensions")
154+
void testVariousArrayTypes(final Object array, final int expectedDimensions) {
155+
assertEquals(expectedDimensions, ArrayUtils.getDimensions(array));
156+
}
157+
}

0 commit comments

Comments
 (0)