diff --git a/src/main/java/org/apache/commons/jxpath/ri/axes/UnionContext.java b/src/main/java/org/apache/commons/jxpath/ri/axes/UnionContext.java index 01a371b61..ff7473aa7 100644 --- a/src/main/java/org/apache/commons/jxpath/ri/axes/UnionContext.java +++ b/src/main/java/org/apache/commons/jxpath/ri/axes/UnionContext.java @@ -48,6 +48,17 @@ public int getDocumentOrder() { return contexts.length > 1 ? 1 : super.getDocumentOrder(); } + @Override + public Object getValue() { + // JXPATH-204: the node set is built lazily inside setPosition(), so + // force it to be populated before delegating, otherwise callers that + // read the value without first iterating (e.g. an extension + // function receiving this context as an argument) see an empty + // NodeSet. + getContextNodeList(); + return super.getValue(); + } + @Override public boolean setPosition(final int position) { if (!prepared) { diff --git a/src/test/java/org/apache/commons/jxpath/ri/compiler/ExtensionFunctionTest.java b/src/test/java/org/apache/commons/jxpath/ri/compiler/ExtensionFunctionTest.java index eb76e767b..3cf2adec3 100644 --- a/src/test/java/org/apache/commons/jxpath/ri/compiler/ExtensionFunctionTest.java +++ b/src/test/java/org/apache/commons/jxpath/ri/compiler/ExtensionFunctionTest.java @@ -283,4 +283,13 @@ void testStaticMethodLookupWithExpressionContext() { final Function func = functions.getFunction("test", "path", args); assertEquals("1", func.invoke(new Context(Integer.valueOf(1)), args), "test:path()"); } -} \ No newline at end of file + + @Test + void testUnionOperatorArgument() { + // JXPATH-204: UnionContext computes its node list lazily (only inside + // setPosition()), so a custom function invoked with a union ('|') + // expression as an argument used to see an empty NodeSet instead of + // the union's actual nodes. + assertXPathValue(context, "test:countPointers(/beans[1] | /beans[2])", Integer.valueOf(2)); + } +}