Skip to content

Commit dd793f4

Browse files
committed
[feature] Add an ArrayWrapper type to help inform Java Object types to XDM types conversion
1 parent c176665 commit dd793f4

4 files changed

Lines changed: 149 additions & 0 deletions

File tree

exist-core/pom.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -770,6 +770,7 @@
770770
<include>src/main/java/org/exist/xquery/functions/system/FunctionAvailable.java</include>
771771
<include>src/test/java/org/exist/xquery/functions/xmldb/XMLDBStoreTest.java</include>
772772
<include>src/test/java/org/exist/xquery/functions/xquery3/SerializeTest.java</include>
773+
<include>src/main/java/org/exist/xquery/value/ArrayWrapper.java</include>
773774
<include>src/test/java/org/exist/xquery/value/DateTimeTypesTest.java</include>
774775
</includes>
775776
</licenseSet>
@@ -1935,6 +1936,7 @@
19351936
<exclude>src/main/java/org/exist/xquery/value/AbstractTimeRelatedTest.java</exclude>
19361937
<exclude>src/main/java/org/exist/xquery/value/AnyURIValue.java</exclude>
19371938
<exclude>src/main/java/org/exist/xquery/value/ArrayListValueSequence.java</exclude>
1939+
<exclude>src/main/java/org/exist/xquery/value/ArrayWrapper.java</exclude>
19381940
<exclude>src/main/java/org/exist/xquery/value/AtomicValueComparator.java</exclude>
19391941
<exclude>src/test/java/org/exist/xquery/value/Base64BinaryValueTypeTest.java</exclude>
19401942
<exclude>src/test/java/org/exist/xquery/value/BifurcanMapTest.java</exclude>

exist-core/src/main/java/org/exist/xquery/XPathUtil.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -775,6 +775,13 @@ public static final Sequence javaObjectToXPath(final Object obj, final XQueryCon
775775

776776
} else if (arrayToSequence && obj instanceof Object[] array) {
777777
return javaArrayToXPath(Arrays.asList(array), context, expandChars, listToSequence, arrayToSequence, expression);
778+
779+
} else if (obj instanceof ArrayWrapper arrayWrapper) {
780+
final List<Sequence> xdmArrayItems = new ArrayList<>(arrayWrapper.array.length);
781+
for (final Object javaArrayItem : arrayWrapper.array) {
782+
xdmArrayItems.add(javaObjectToXPath(javaArrayItem, context, expandChars, listToSequence, arrayToSequence, expression));
783+
}
784+
return new ArrayType(expression, context, xdmArrayItems);
778785
}
779786

780787
final int xdmType = javaClassToXdmType(obj.getClass());
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* Elemental
3+
* Copyright (C) 2024, Evolved Binary Ltd
4+
*
5+
* admin@evolvedbinary.com
6+
* https://www.evolvedbinary.com | https://www.elemental.xyz
7+
*
8+
* This library is free software; you can redistribute it and/or
9+
* modify it under the terms of the GNU Lesser General Public
10+
* License as published by the Free Software Foundation; version 2.1.
11+
*
12+
* This library is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15+
* Lesser General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU Lesser General Public
18+
* License along with this library; if not, write to the Free Software
19+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20+
*/
21+
package org.exist.xquery.value;
22+
23+
import org.exist.xquery.Expression;
24+
import org.exist.xquery.XQueryContext;
25+
26+
/**
27+
* This class is used to wrap a Java Array
28+
* that should be converted to an XDM Array.
29+
* It helps disambiguate between a Java Array
30+
* that should be converted to an XDM Sequence,
31+
* and a Java Array that should be converted to
32+
* an XDM Array.
33+
*
34+
* See {@link org.exist.xquery.XPathUtil#javaObjectToXPath(Object, XQueryContext, boolean, boolean, boolean, Expression)}.
35+
*
36+
* @author <a href="mailto:adam@evolvedbinary.com">Adam Retter</a>
37+
*/
38+
public class ArrayWrapper<T> {
39+
public final T[] array;
40+
41+
public ArrayWrapper(final T[] array) {
42+
this.array = array;
43+
}
44+
}

exist-core/src/test/java/org/exist/xquery/XPathUtilTest.java

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,16 +20,21 @@
2020
*/
2121
package org.exist.xquery;
2222

23+
import org.exist.xquery.functions.array.ArrayType;
24+
import org.exist.xquery.value.ArrayWrapper;
25+
import org.exist.xquery.value.Item;
2326
import org.exist.xquery.value.Sequence;
2427
import org.exist.xquery.value.Type;
2528
import org.junit.jupiter.api.Test;
2629

2730
import java.util.Arrays;
2831
import java.util.List;
2932

33+
import static org.easymock.EasyMock.expect;
3034
import static org.easymock.EasyMock.mock;
3135
import static org.easymock.EasyMock.replay;
3236
import static org.easymock.EasyMock.verify;
37+
import static org.junit.Assert.assertTrue;
3338
import static org.junit.jupiter.api.Assertions.assertEquals;
3439

3540
public class XPathUtilTest {
@@ -108,4 +113,95 @@ public void arrayArrayStringsToSequenceStrings() throws XPathException {
108113
}
109114
verify(mockContext);
110115
}
116+
117+
@Test
118+
public void arrayWrapperStringsToArrayStrings() throws XPathException {
119+
final XQueryContext mockContext = mock(XQueryContext.class);
120+
expect(mockContext.nextExpressionId()).andReturn(1).anyTimes();
121+
122+
final ArrayWrapper strings = new ArrayWrapper(new String[] { "hello", "goodbye" });
123+
124+
replay(mockContext);
125+
final Sequence result = XPathUtil.javaObjectToXPath(strings, mockContext);
126+
assertEquals(1, result.getItemCount());
127+
final Item resultItem = result.itemAt(0);
128+
assertEquals(Type.ARRAY_ITEM, resultItem.getType());
129+
final ArrayType resultArray = (ArrayType) resultItem;
130+
for (int i = 0; i < strings.array.length; i++) {
131+
final Sequence arrayItem = resultArray.get(i);
132+
assertTrue(arrayItem.hasOne());
133+
assertEquals(Type.STRING, arrayItem.itemAt(0).getType());
134+
assertEquals(strings.array[i], arrayItem.itemAt(0).getStringValue());
135+
}
136+
verify(mockContext);
137+
}
138+
139+
@Test
140+
public void arrayArrayWrapperStringsToArrayStrings() throws XPathException {
141+
final XQueryContext mockContext = mock(XQueryContext.class);
142+
expect(mockContext.nextExpressionId()).andReturn(1).anyTimes();
143+
144+
final ArrayWrapper[] strings = {
145+
new ArrayWrapper(new String[] { "hello" }),
146+
new ArrayWrapper(new String[] { "goodbye", "see you again soon" }),
147+
};
148+
149+
replay(mockContext);
150+
final Sequence result = XPathUtil.javaObjectToXPath(strings, mockContext);
151+
assertEquals(strings.length, result.getItemCount());
152+
for (int i = 0; i < strings.length; i++) {
153+
final Item resultItem = result.itemAt(i);
154+
assertEquals(Type.ARRAY_ITEM, resultItem.getType());
155+
156+
final ArrayType resultArray = (ArrayType) resultItem;
157+
for (int j = 0; j < strings[i].array.length; j++) {
158+
final Sequence arrayItem = resultArray.get(j);
159+
assertTrue(arrayItem.hasOne());
160+
assertEquals(Type.STRING, arrayItem.itemAt(0).getType());
161+
assertEquals(strings[i].array[j], arrayItem.itemAt(0).getStringValue());
162+
}
163+
}
164+
verify(mockContext);
165+
}
166+
167+
@Test
168+
public void arrayArrayWrapperStringSequenceToArrayStrings() throws XPathException {
169+
final XQueryContext mockContext = mock(XQueryContext.class);
170+
expect(mockContext.nextExpressionId()).andReturn(1).anyTimes();
171+
172+
final ArrayWrapper[] strings = {
173+
new ArrayWrapper(new String[] { "hello" }),
174+
new ArrayWrapper(new Object[] { "goodbye", new String[] { "see you again soon", "42" } }),
175+
};
176+
177+
replay(mockContext);
178+
179+
final Sequence result = XPathUtil.javaObjectToXPath(strings, mockContext);
180+
assertEquals(strings.length, result.getItemCount());
181+
Item resultItem = result.itemAt(0);
182+
assertEquals(Type.ARRAY_ITEM, resultItem.getType());
183+
ArrayType resultArray = (ArrayType) resultItem;
184+
assertEquals(1, resultArray.getSize());
185+
Sequence arrayEntry = resultArray.get(0);
186+
assertEquals(1, arrayEntry.getItemCount());
187+
assertEquals(Type.STRING, arrayEntry.itemAt(0).getType());
188+
assertEquals("hello", arrayEntry.itemAt(0).getStringValue());
189+
190+
resultItem = result.itemAt(1);
191+
assertEquals(Type.ARRAY_ITEM, resultItem.getType());
192+
resultArray = (ArrayType) resultItem;
193+
assertEquals(2, resultArray.getSize());
194+
arrayEntry = resultArray.get(0);
195+
assertEquals(1, arrayEntry.getItemCount());
196+
assertEquals(Type.STRING, arrayEntry.itemAt(0).getType());
197+
assertEquals("goodbye", arrayEntry.itemAt(0).getStringValue());
198+
arrayEntry = resultArray.get(1);
199+
assertEquals(2, arrayEntry.getItemCount());
200+
assertEquals(Type.STRING, arrayEntry.itemAt(0).getType());
201+
assertEquals("see you again soon", arrayEntry.itemAt(0).getStringValue());
202+
assertEquals(Type.STRING, arrayEntry.itemAt(1).getType());
203+
assertEquals("42", arrayEntry.itemAt(1).getStringValue());
204+
205+
verify(mockContext);
206+
}
111207
}

0 commit comments

Comments
 (0)