8284400: Improve XPath exception handling

Reviewed-by: lancea, naoto
This commit is contained in:
Joe Wang 2022-05-27 21:47:05 +00:00
parent d3e781de08
commit ed8e8ac289
11 changed files with 684 additions and 246 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@ -55,7 +55,7 @@ import org.w3c.dom.traversal.NodeIterator;
* to the same calls; the disadvantage is that some of them may return
* less-than-enlightening results when you do so.</p>
* @xsl.usage advanced
* @LastModified: Nov 2017
* @LastModified: May 2022
*/
public class NodeSet
implements NodeList, NodeIterator, Cloneable, ContextNodeList
@ -379,11 +379,7 @@ public class NodeSet
*/
public void addNode(Node n)
{
if (!m_mutable)
throw new RuntimeException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NODESET_NOT_MUTABLE, null)); //"This NodeSet is not mutable!");
this.addElement(n);
addElement(n);
}
/**
@ -397,10 +393,6 @@ public class NodeSet
*/
public void insertNode(Node n, int pos)
{
if (!m_mutable)
throw new RuntimeException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NODESET_NOT_MUTABLE, null)); //"This NodeSet is not mutable!");
insertElementAt(n, pos);
}
@ -413,11 +405,7 @@ public class NodeSet
*/
public void removeNode(Node n)
{
if (!m_mutable)
throw new RuntimeException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NODESET_NOT_MUTABLE, null)); //"This NodeSet is not mutable!");
this.removeElement(n);
removeElement(n);
}
/**
@ -431,10 +419,6 @@ public class NodeSet
*/
public void addNodes(NodeList nodelist)
{
if (!m_mutable)
throw new RuntimeException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NODESET_NOT_MUTABLE, null)); //"This NodeSet is not mutable!");
if (null != nodelist) // defensive to fix a bug that Sanjiva reported.
{
int nChildren = nodelist.getLength();
@ -471,10 +455,6 @@ public class NodeSet
*/
public void addNodes(NodeSet ns)
{
if (!m_mutable)
throw new RuntimeException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NODESET_NOT_MUTABLE, null)); //"This NodeSet is not mutable!");
addNodes((NodeIterator) ns);
}
@ -488,10 +468,6 @@ public class NodeSet
*/
public void addNodes(NodeIterator iterator)
{
if (!m_mutable)
throw new RuntimeException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NODESET_NOT_MUTABLE, null)); //"This NodeSet is not mutable!");
if (null != iterator) // defensive to fix a bug that Sanjiva reported.
{
Node obj;
@ -516,10 +492,6 @@ public class NodeSet
*/
public void addNodesInDocOrder(NodeList nodelist, XPathContext support)
{
if (!m_mutable)
throw new RuntimeException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NODESET_NOT_MUTABLE, null)); //"This NodeSet is not mutable!");
int nChildren = nodelist.getLength();
for (int i = 0; i < nChildren; i++)
@ -544,10 +516,6 @@ public class NodeSet
*/
public void addNodesInDocOrder(NodeIterator iterator, XPathContext support)
{
if (!m_mutable)
throw new RuntimeException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NODESET_NOT_MUTABLE, null)); //"This NodeSet is not mutable!");
Node node;
while (null != (node = iterator.nextNode()))
@ -572,10 +540,6 @@ public class NodeSet
private boolean addNodesInDocOrder(int start, int end, int testIndex,
NodeList nodelist, XPathContext support)
{
if (!m_mutable)
throw new RuntimeException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NODESET_NOT_MUTABLE, null)); //"This NodeSet is not mutable!");
boolean foundit = false;
int i;
Node node = nodelist.item(testIndex);
@ -632,10 +596,6 @@ public class NodeSet
*/
public int addNodeInDocOrder(Node node, boolean test, XPathContext support)
{
if (!m_mutable)
throw new RuntimeException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NODESET_NOT_MUTABLE, null)); //XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NODESET_NOT_MUTABLE, null)); //"This NodeSet is not mutable!");
int insertIndex = -1;
if (test)
@ -706,10 +666,6 @@ public class NodeSet
*/
public int addNodeInDocOrder(Node node, XPathContext support)
{
if (!m_mutable)
throw new RuntimeException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NODESET_NOT_MUTABLE, null)); //"This NodeSet is not mutable!");
return addNodeInDocOrder(node, true, support);
} // end addNodeInDocOrder(Vector v, Object obj)
@ -767,9 +723,6 @@ public class NodeSet
return n;
}
/** True if this list can be mutated. */
transient protected boolean m_mutable = true;
/** True if this list is cached.
* @serial */
transient protected boolean m_cacheNodes = true;
@ -804,7 +757,6 @@ public class NodeSet
XSLMessages.createXPATHMessage(XPATHErrorResources.ER_CANNOT_CALL_SETSHOULDCACHENODE, null)); //"Can not call setShouldCacheNodes after nextNode has been called!");
m_cacheNodes = b;
m_mutable = true;
}
@ -875,9 +827,6 @@ public class NodeSet
*/
public void addElement(Node value)
{
if (!m_mutable)
throw new RuntimeException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NODESET_NOT_MUTABLE, null)); //"This NodeSet is not mutable!");
if ((m_firstFree + 1) >= m_mapSize)
{
if (null == m_map)
@ -1102,9 +1051,6 @@ public class NodeSet
*/
public void insertElementAt(Node value, int at)
{
if (!m_mutable)
throw new RuntimeException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NODESET_NOT_MUTABLE, null)); //"This NodeSet is not mutable!");
if (null == m_map)
{
m_map = new Node[m_blocksize];
@ -1195,9 +1141,6 @@ public class NodeSet
*/
public boolean removeElement(Node s)
{
if (!m_mutable)
throw new RuntimeException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NODESET_NOT_MUTABLE, null)); //"This NodeSet is not mutable!");
if (null == m_map)
return false;
@ -1258,9 +1201,6 @@ public class NodeSet
*/
public void setElementAt(Node node, int index)
{
if (!m_mutable)
throw new RuntimeException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NODESET_NOT_MUTABLE, null)); //"This NodeSet is not mutable!");
if (null == m_map)
{
m_map = new Node[m_blocksize];

View File

@ -1,6 +1,5 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@ -57,6 +56,7 @@ import org.w3c.dom.traversal.NodeIterator;
* to the same calls; the disadvantage is that some of them may return
* less-than-enlightening results when you do so.</p>
* @xsl.usage advanced
* @LastModified: May 2022
*/
public class NodeSetDTM extends NodeVector
implements /* NodeList, NodeIterator, */ DTMIterator,
@ -536,11 +536,7 @@ public class NodeSetDTM extends NodeVector
*/
public void addNode(int n)
{
if (!m_mutable)
throw new RuntimeException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NODESETDTM_NOT_MUTABLE, null)); //"This NodeSetDTM is not mutable!");
this.addElement(n);
addElement(n);
}
/**
@ -554,10 +550,6 @@ public class NodeSetDTM extends NodeVector
*/
public void insertNode(int n, int pos)
{
if (!m_mutable)
throw new RuntimeException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NODESETDTM_NOT_MUTABLE, null)); //"This NodeSetDTM is not mutable!");
insertElementAt(n, pos);
}
@ -570,10 +562,6 @@ public class NodeSetDTM extends NodeVector
*/
public void removeNode(int n)
{
if (!m_mutable)
throw new RuntimeException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NODESETDTM_NOT_MUTABLE, null)); //"This NodeSetDTM is not mutable!");
this.removeElement(n);
}
@ -647,10 +635,6 @@ public class NodeSetDTM extends NodeVector
*/
public void addNodes(DTMIterator iterator)
{
if (!m_mutable)
throw new RuntimeException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NODESETDTM_NOT_MUTABLE, null)); //"This NodeSetDTM is not mutable!");
if (null != iterator) // defensive to fix a bug that Sanjiva reported.
{
int obj;
@ -704,10 +688,6 @@ public class NodeSetDTM extends NodeVector
*/
public void addNodesInDocOrder(DTMIterator iterator, XPathContext support)
{
if (!m_mutable)
throw new RuntimeException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NODESETDTM_NOT_MUTABLE, null)); //"This NodeSetDTM is not mutable!");
int node;
while (DTM.NULL != (node = iterator.nextNode()))
@ -793,10 +773,6 @@ public class NodeSetDTM extends NodeVector
*/
public int addNodeInDocOrder(int node, boolean test, XPathContext support)
{
if (!m_mutable)
throw new RuntimeException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NODESETDTM_NOT_MUTABLE, null)); //"This NodeSetDTM is not mutable!");
int insertIndex = -1;
if (test)
@ -868,10 +844,6 @@ public class NodeSetDTM extends NodeVector
*/
public int addNodeInDocOrder(int node, XPathContext support)
{
if (!m_mutable)
throw new RuntimeException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NODESETDTM_NOT_MUTABLE, null)); //"This NodeSetDTM is not mutable!");
return addNodeInDocOrder(node, true, support);
} // end addNodeInDocOrder(Vector v, Object obj)
@ -894,10 +866,6 @@ public class NodeSetDTM extends NodeVector
*/
public void addElement(int value)
{
if (!m_mutable)
throw new RuntimeException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NODESETDTM_NOT_MUTABLE, null)); //"This NodeSetDTM is not mutable!");
super.addElement(value);
}
@ -914,10 +882,6 @@ public class NodeSetDTM extends NodeVector
*/
public void insertElementAt(int value, int at)
{
if (!m_mutable)
throw new RuntimeException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NODESETDTM_NOT_MUTABLE, null)); //"This NodeSetDTM is not mutable!");
super.insertElementAt(value, at);
}
@ -930,10 +894,6 @@ public class NodeSetDTM extends NodeVector
*/
public void appendNodes(NodeVector nodes)
{
if (!m_mutable)
throw new RuntimeException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NODESETDTM_NOT_MUTABLE, null)); //"This NodeSetDTM is not mutable!");
super.appendNodes(nodes);
}
@ -947,10 +907,6 @@ public class NodeSetDTM extends NodeVector
*/
public void removeAllElements()
{
if (!m_mutable)
throw new RuntimeException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NODESETDTM_NOT_MUTABLE, null)); //"This NodeSetDTM is not mutable!");
super.removeAllElements();
}
@ -969,10 +925,6 @@ public class NodeSetDTM extends NodeVector
*/
public boolean removeElement(int s)
{
if (!m_mutable)
throw new RuntimeException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NODESETDTM_NOT_MUTABLE, null)); //"This NodeSetDTM is not mutable!");
return super.removeElement(s);
}
@ -988,10 +940,6 @@ public class NodeSetDTM extends NodeVector
*/
public void removeElementAt(int i)
{
if (!m_mutable)
throw new RuntimeException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NODESETDTM_NOT_MUTABLE, null)); //"This NodeSetDTM is not mutable!");
super.removeElementAt(i);
}
@ -1009,10 +957,6 @@ public class NodeSetDTM extends NodeVector
*/
public void setElementAt(int node, int index)
{
if (!m_mutable)
throw new RuntimeException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NODESETDTM_NOT_MUTABLE, null)); //"This NodeSetDTM is not mutable!");
super.setElementAt(node, index);
}
@ -1026,10 +970,6 @@ public class NodeSetDTM extends NodeVector
*/
public void setItem(int node, int index)
{
if (!m_mutable)
throw new RuntimeException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NODESETDTM_NOT_MUTABLE, null)); //"This NodeSetDTM is not mutable!");
super.setElementAt(node, index);
}
@ -1157,9 +1097,6 @@ public class NodeSetDTM extends NodeVector
return n;
}
/** True if this list can be mutated. */
transient protected boolean m_mutable = true;
/** True if this list is cached.
* @serial */
transient protected boolean m_cacheNodes = true;
@ -1197,7 +1134,6 @@ public class NodeSetDTM extends NodeVector
XSLMessages.createXPATHMessage(XPATHErrorResources.ER_CANNOT_CALL_SETSHOULDCACHENODE, null)); //"Can not call setShouldCacheNodes after nextNode has been called!");
m_cacheNodes = b;
m_mutable = true;
}
/**
@ -1208,7 +1144,7 @@ public class NodeSetDTM extends NodeVector
*/
public boolean isMutable()
{
return m_mutable;
return true;
}
transient private int m_last = 0;

View File

@ -42,7 +42,7 @@ import jdk.xml.internal.XMLSecurityManager;
* The XPath class wraps an expression object and provides general services
* for execution of that expression.
* @xsl.usage advanced
* @LastModified: Jan 2022
* @LastModified: May 2022
*/
public class XPath implements Serializable, ExpressionOwner
{
@ -208,22 +208,16 @@ public class XPath implements Serializable, ExpressionOwner
else if (MATCH == type)
parser.initMatchPattern(compiler, exprString, prefixResolver);
else
throw new RuntimeException(XSLMessages.createXPATHMessage(
throw new TransformerException(XSLMessages.createXPATHMessage(
XPATHErrorResources.ER_CANNOT_DEAL_XPATH_TYPE,
new Object[]{Integer.toString(type)}));
//"Can not deal with XPath type: " + type);
// System.out.println("----------------");
Expression expr = compiler.compileExpression(0);
// System.out.println("expr: "+expr);
this.setExpression(expr);
m_mainExp = compiler.compileExpression(0);
if((null != locator) && locator instanceof ExpressionNode)
{
expr.exprSetParent((ExpressionNode)locator);
m_mainExp.exprSetParent((ExpressionNode)locator);
}
}
/**
@ -274,7 +268,7 @@ public class XPath implements Serializable, ExpressionOwner
*/
public XPath(Expression expr)
{
this.setExpression(expr);
m_mainExp = expr;
initFunctionTable();
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@ -24,6 +24,7 @@ import com.sun.org.apache.xml.internal.dtm.DTM;
import com.sun.org.apache.xml.internal.dtm.DTMIterator;
import com.sun.org.apache.xml.internal.utils.PrefixResolver;
import com.sun.org.apache.xml.internal.utils.QName;
import com.sun.org.apache.xml.internal.utils.WrappedRuntimeException;
import com.sun.org.apache.xpath.internal.Expression;
import com.sun.org.apache.xpath.internal.ExpressionOwner;
import com.sun.org.apache.xpath.internal.XPathContext;
@ -34,7 +35,7 @@ import com.sun.org.apache.xpath.internal.patterns.NodeTest;
import java.util.List;
/**
* @LastModified: May 2020
* @LastModified: May 2022
*/
public abstract class PredicatedNodeTest extends NodeTest implements SubContextList
{
@ -491,9 +492,8 @@ public abstract class PredicatedNodeTest extends NodeTest implements SubContextL
}
catch (javax.xml.transform.TransformerException se)
{
// TODO: Fix this.
throw new RuntimeException(se.getMessage());
// the Xalan/XPath impl use WrappedRuntimeException to carry errors over
throw new WrappedRuntimeException(se);
}
finally
{

View File

@ -35,7 +35,7 @@ import jdk.xml.internal.XMLSecurityManager;
* Tokenizes and parses XPath expressions. This should really be named
* XPathParserImpl, and may be renamed in the future.
* @xsl.usage general
* @LastModified: Apr 2022
* @LastModified: May 2022
*/
public class XPathParser
{
@ -79,6 +79,16 @@ public class XPathParser
// XML security manager
XMLSecurityManager m_xmlSecMgr;
// Union operands must be node-sets, e.g. //a | //b
// A flag indicating whether the operand is a location path
boolean isLocationPath = false;
// A flag indicating whether the next operand is required to be a location path
boolean lPathRequired = false;
// Keep track of the status of reading the next token after lPathRequired is flagged
boolean nextTokenRead = false;
/**
* The parser constructor.
*/
@ -434,9 +444,19 @@ public class XPathParser
* Retrieve the next token from the command and
* store it in m_token string.
*/
private final void nextToken()
private final void nextToken() throws TransformerException
{
// before reading another token, check the last one
if (lPathRequired) {
if (nextTokenRead) {
// check whether the operand behind the union was a Location path
checkNodeSet();
lPathRequired = false;
nextTokenRead = false;
} else {
nextTokenRead = true;
}
}
if (m_queueMark < m_ops.getTokenQueueSize())
{
m_token = (String) m_ops.m_tokenQueue.elementAt(m_queueMark++);
@ -497,31 +517,28 @@ public class XPathParser
}
/**
* Consume an expected token, throwing an exception if it
* isn't there.
*
* @param expected The string to be expected.
*
* @throws TransformerException
* Checks whether the function token represents a function that returns a
* nodeset.
* @param funcTok the function token
* @return true if the function token represents a function that returns a
* nodeset, false otherwise
*/
private final void consumeExpected(String expected)
throws TransformerException
{
private boolean isNodesetFunction(int funcTok) {
return (funcTok == FunctionTable.FUNC_CURRENT || funcTok == FunctionTable.FUNC_HERE
|| funcTok == FunctionTable.FUNC_ID);
}
if (tokenIs(expected))
/**
* Checks whether the operand is a location path, reports error if not.
*
* @throws TransformerException if an error is found
*/
private void checkNodeSet() throws TransformerException {
if (!isLocationPath)
{
nextToken();
error(XPATHErrorResources.ER_UNION_MUST_BE_NODESET,
new Object[]{});
}
else
{
error(XPATHErrorResources.ER_EXPECTED_BUT_FOUND, new Object[]{ expected,
m_token }); //"Expected "+expected+", but found: "+m_token);
// Patch for Christina's gripe. She wants her errorHandler to return from
// this error and continue trying to parse, rather than throwing an exception.
// Without the patch, that put us into an endless loop.
throw new XPathProcessorException(CONTINUE_AFTER_FATAL_ERROR);
}
}
/**
@ -1209,13 +1226,17 @@ public class XPathParser
if (tokenIs(Token.VBAR))
{
// check whether the operand before the union is a location path
checkNodeSet();
if (false == foundUnion)
{
foundUnion = true;
insertOp(opPos, 2, OpCodes.OP_UNION);
}
isLocationPath = false;
lPathRequired = true;
nextToken();
}
else
@ -1464,7 +1485,7 @@ public class XPathParser
m_ops.setOp(opPos + OpMap.MAPINDEX_LENGTH + 1, m_queueMark - 1);
nextToken();
consumeExpected(':');
consumeExpected(Token.COLON);
m_ops.setOp(opPos + OpMap.MAPINDEX_LENGTH + 2, m_queueMark - 1);
@ -1494,6 +1515,10 @@ public class XPathParser
m_ops.setOp(opPos + OpMap.MAPINDEX_LENGTH + 1, funcTok);
}
// XML Signature here() function returns a node-set
if (isNodesetFunction(funcTok)) {
isLocationPath = true;
}
nextToken();
}
@ -1544,7 +1569,7 @@ public class XPathParser
*/
protected void LocationPath() throws TransformerException
{
isLocationPath = true;
int opPos = m_ops.getOp(OpMap.MAPINDEX_LENGTH);
// int locationPathOpPos = opPos;
@ -1861,7 +1886,7 @@ public class XPathParser
}
nextToken();
consumeExpected(':');
consumeExpected(Token.COLON);
}
else
{
@ -1908,7 +1933,7 @@ public class XPathParser
nextToken();
PredicateExpr();
countPredicate--;
consumeExpected(']');
consumeExpected(Token.RBRACK);
}
}
@ -1950,7 +1975,7 @@ public class XPathParser
m_ops.setOp(OpMap.MAPINDEX_LENGTH, m_ops.getOp(OpMap.MAPINDEX_LENGTH) + 1);
nextToken();
consumeExpected(':');
consumeExpected(Token.COLON);
}
else
{
@ -1969,7 +1994,7 @@ public class XPathParser
* NCName ::= (Letter | '_') (NCNameChar)
* NCNameChar ::= Letter | Digit | '.' | '-' | '_' | CombiningChar | Extender
*/
protected void NCName()
protected void NCName() throws TransformerException
{
m_ops.setOp(m_ops.getOp(OpMap.MAPINDEX_LENGTH), m_queueMark - 1);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@ -34,13 +34,14 @@ import com.sun.org.apache.xpath.internal.res.XPATHErrorResources;
import com.sun.org.apache.xpath.internal.res.XPATHMessages;
import java.util.ArrayList;
import java.util.List;
import javax.xml.transform.TransformerException;
/**
* An object of this class represents an extension call expression. When
* the expression executes, it calls ExtensionsTable#extFunction, and then
* converts the result to the appropriate XObject.
* @xsl.usage advanced
* @LastModified: Oct 2017
* @LastModified: May 2022
*/
public class FuncExtFunction extends Function
{
@ -183,8 +184,7 @@ public class FuncExtFunction extends Function
*
* @throws javax.xml.transform.TransformerException
*/
public XObject execute(XPathContext xctxt)
throws javax.xml.transform.TransformerException
public XObject execute(XPathContext xctxt) throws TransformerException
{
if (xctxt.isSecureProcessing())
throw new javax.xml.transform.TransformerException(
@ -209,6 +209,12 @@ public class FuncExtFunction extends Function
}
//dml
ExtensionsProvider extProvider = (ExtensionsProvider)xctxt.getOwnerObject();
if (extProvider == null) {
String fmsg = XSLMessages.createXPATHMessage(
XPATHErrorResources.ER_NO_XPATH_FUNCTION_PROVIDER,
new Object[] {argVec} );
throw new TransformerException ( fmsg );
}
Object val = extProvider.extFunction(this, argVec);
if (null != val)

View File

@ -1,6 +1,5 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@ -38,6 +37,7 @@ import com.sun.org.apache.xalan.internal.res.XSLMessages;
* {@link javax.xml.xpath.XPathVariableResolver}.
*
* @author Ramesh Mandava
* @LastModified: May 2022
*/
public class JAXPVariableStack extends VariableStack {
@ -61,6 +61,13 @@ public class JAXPVariableStack extends VariableStack {
new javax.xml.namespace.QName(
qname.getNamespace(),
qname.getLocalPart());
if (resolver == null) {
String fmsg = XSLMessages.createXPATHMessage(
XPATHErrorResources.ER_NO_XPATH_VARIABLE_RESOLVER,
new Object[] { name.toString()} );
throw new TransformerException( fmsg );
}
Object varValue = resolver.resolveVariable( name );
if ( varValue == null ) {
String fmsg = XSLMessages.createXPATHMessage(

View File

@ -20,6 +20,7 @@
package com.sun.org.apache.xpath.internal.jaxp;
import com.sun.org.apache.xml.internal.utils.WrappedRuntimeException;
import com.sun.org.apache.xpath.internal.objects.XObject;
import javax.xml.namespace.QName;
import javax.xml.transform.TransformerException;
@ -27,6 +28,7 @@ import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathEvaluationResult;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFunctionException;
import javax.xml.xpath.XPathFunctionResolver;
import javax.xml.xpath.XPathVariableResolver;
import jdk.xml.internal.JdkXmlFeatures;
@ -37,7 +39,7 @@ import org.xml.sax.InputSource;
* The XPathExpression interface encapsulates a (compiled) XPath expression.
*
* @author Ramesh Mandava
* @LastModified: Apr 2022
* @LastModified: May 2022
*/
public class XPathExpressionImpl extends XPathImplUtil implements XPathExpression {
@ -77,7 +79,7 @@ public class XPathExpressionImpl extends XPathImplUtil implements XPathExpressio
}
public Object eval(Object item, QName returnType)
throws javax.xml.transform.TransformerException {
throws TransformerException {
XObject resultObject = eval(item, xpath);
return getResultAsType(resultObject, returnType);
}
@ -88,20 +90,20 @@ public class XPathExpressionImpl extends XPathImplUtil implements XPathExpressio
isSupported(returnType);
try {
return eval(item, returnType);
} catch (java.lang.NullPointerException npe) {
// If VariableResolver returns null Or if we get
// NullPointerException at this stage for some other reason
// then we have to reurn XPathException
throw new XPathExpressionException (npe);
} catch (javax.xml.transform.TransformerException te) {
} catch (TransformerException te) {
Throwable nestedException = te.getException();
if (nestedException instanceof javax.xml.xpath.XPathFunctionException) {
throw (javax.xml.xpath.XPathFunctionException)nestedException;
if (nestedException instanceof XPathFunctionException) {
throw (XPathFunctionException)nestedException;
} else {
// For any other exceptions we need to throw
// XPathExpressionException (as per spec)
throw new XPathExpressionException(te);
}
} catch (RuntimeException re) {
if (re instanceof WrappedRuntimeException) {
throw new XPathExpressionException(((WrappedRuntimeException)re).getException());
}
throw new XPathExpressionException(re);
}
}
@ -115,12 +117,18 @@ public class XPathExpressionImpl extends XPathImplUtil implements XPathExpressio
@Override
public Object evaluate(InputSource source, QName returnType)
throws XPathExpressionException {
requireNonNull(source, "Source");
isSupported (returnType);
try {
Document document = getDocument(source);
return eval(document, returnType);
} catch (TransformerException e) {
throw new XPathExpressionException(e);
} catch (RuntimeException re) {
if (re instanceof WrappedRuntimeException) {
throw new XPathExpressionException(((WrappedRuntimeException)re).getException());
}
throw new XPathExpressionException(re);
}
}
@ -143,8 +151,13 @@ public class XPathExpressionImpl extends XPathImplUtil implements XPathExpressio
return XPathResultImpl.getValue(resultObject, type);
}
} catch (javax.xml.transform.TransformerException te) {
} catch (TransformerException te) {
throw new XPathExpressionException(te);
} catch (RuntimeException re) {
if (re instanceof WrappedRuntimeException) {
throw new XPathExpressionException(((WrappedRuntimeException)re).getException());
}
throw new XPathExpressionException(re);
}
}

View File

@ -20,6 +20,7 @@
package com.sun.org.apache.xpath.internal.jaxp;
import com.sun.org.apache.xml.internal.utils.WrappedRuntimeException;
import com.sun.org.apache.xpath.internal.*;
import com.sun.org.apache.xpath.internal.objects.XObject;
import javax.xml.namespace.NamespaceContext;
@ -47,7 +48,7 @@ import org.xml.sax.InputSource;
* New methods: evaluateExpression
* Refactored to share code with XPathExpressionImpl.
*
* @LastModified: Jan 2022
* @LastModified: May 2022
*/
public class XPathImpl extends XPathImplUtil implements javax.xml.xpath.XPath {
@ -134,11 +135,6 @@ public class XPathImpl extends XPathImplUtil implements javax.xml.xpath.XPath {
XObject resultObject = eval(expression, item);
return getResultAsType(resultObject, returnType);
} catch (java.lang.NullPointerException npe) {
// If VariableResolver returns null Or if we get
// NullPointerException at this stage for some other reason
// then we have to reurn XPathException
throw new XPathExpressionException (npe);
} catch (TransformerException te) {
Throwable nestedException = te.getException();
if (nestedException instanceof javax.xml.xpath.XPathFunctionException) {
@ -146,10 +142,14 @@ public class XPathImpl extends XPathImplUtil implements javax.xml.xpath.XPath {
} else {
// For any other exceptions we need to throw
// XPathExpressionException (as per spec)
throw new XPathExpressionException (te);
throw new XPathExpressionException(te);
}
} catch (RuntimeException re) {
if (re instanceof WrappedRuntimeException) {
throw new XPathExpressionException(((WrappedRuntimeException)re).getException());
}
throw new XPathExpressionException(re);
}
}
//-Override-
@ -172,26 +172,18 @@ public class XPathImpl extends XPathImplUtil implements javax.xml.xpath.XPath {
return ximpl;
} catch (TransformerException te) {
throw new XPathExpressionException (te) ;
} catch (RuntimeException re) {
if (re instanceof WrappedRuntimeException) {
throw new XPathExpressionException(((WrappedRuntimeException)re).getException());
}
throw new XPathExpressionException(re);
}
}
//-Override-
public Object evaluate(String expression, InputSource source,
QName returnType) throws XPathExpressionException {
isSupported(returnType);
try {
Document document = getDocument(source);
XObject resultObject = eval(expression, document);
return getResultAsType(resultObject, returnType);
} catch (TransformerException te) {
Throwable nestedException = te.getException();
if (nestedException instanceof javax.xml.xpath.XPathFunctionException) {
throw (javax.xml.xpath.XPathFunctionException)nestedException;
} else {
throw new XPathExpressionException (te);
}
}
return evaluate(expression, getDocument(source), returnType);
}
//-Override-
@ -210,7 +202,8 @@ public class XPathImpl extends XPathImplUtil implements javax.xml.xpath.XPath {
//-Override-
public <T> T evaluateExpression(String expression, Object item, Class<T> type)
throws XPathExpressionException {
isSupportedClassType(type);
requireNonNull(expression, "XPath expression");
isSupportedClassType(type);
try {
XObject resultObject = eval(expression, item);
if (type == XPathEvaluationResult.class) {
@ -219,7 +212,12 @@ public class XPathImpl extends XPathImplUtil implements javax.xml.xpath.XPath {
return XPathResultImpl.getValue(resultObject, type);
}
} catch (TransformerException te) {
throw new XPathExpressionException (te);
throw new XPathExpressionException(te);
} catch (RuntimeException re) {
if (re instanceof WrappedRuntimeException) {
throw new XPathExpressionException(((WrappedRuntimeException)re).getException());
}
throw new XPathExpressionException(re);
}
}

View File

@ -31,7 +31,7 @@ import java.util.ListResourceBundle;
* Also you need to update the count of messages(MAX_CODE)or
* the count of warnings(MAX_WARNING) [ Information purpose only]
* @xsl.usage advanced
* @LastModified: Apr 2022
* @LastModified: May 2022
*/
public class XPATHErrorResources extends ListResourceBundle
{
@ -140,6 +140,7 @@ public class XPATHErrorResources extends ListResourceBundle
"ER_EXPECTED_SINGLE_QUOTE";
public static final String ER_EMPTY_EXPRESSION = "ER_EMPTY_EXPRESSION";
public static final String ER_EXPECTED_BUT_FOUND = "ER_EXPECTED_BUT_FOUND";
public static final String ER_UNION_MUST_BE_NODESET = "ER_UNION_MUST_BE_NODESET";
public static final String ER_INCORRECT_PROGRAMMER_ASSERTION =
"ER_INCORRECT_PROGRAMMER_ASSERTION";
public static final String ER_BOOLEAN_ARG_NO_LONGER_OPTIONAL =
@ -203,9 +204,6 @@ public static final String ER_IGNORABLE_WHITESPACE_NOT_HANDLED =
"ER_FUNCTION_TOKEN_NOT_FOUND";
public static final String ER_CANNOT_DEAL_XPATH_TYPE =
"ER_CANNOT_DEAL_XPATH_TYPE";
public static final String ER_NODESET_NOT_MUTABLE = "ER_NODESET_NOT_MUTABLE";
public static final String ER_NODESETDTM_NOT_MUTABLE =
"ER_NODESETDTM_NOT_MUTABLE";
/** Variable not resolvable: */
public static final String ER_VAR_NOT_RESOLVABLE = "ER_VAR_NOT_RESOLVABLE";
/** Null error handler */
@ -309,6 +307,8 @@ public static final String ER_IGNORABLE_WHITESPACE_NOT_HANDLED =
//BEGIN: Keys needed for exception messages of JAXP 1.3 XPath API implementation
public static final String ER_EXTENSION_FUNCTION_CANNOT_BE_INVOKED = "ER_EXTENSION_FUNCTION_CANNOT_BE_INVOKED";
public static final String ER_RESOLVE_VARIABLE_RETURNS_NULL = "ER_RESOLVE_VARIABLE_RETURNS_NULL";
public static final String ER_NO_XPATH_VARIABLE_RESOLVER = "ER_NO_XPATH_VARIABLE_RESOLVER";
public static final String ER_NO_XPATH_FUNCTION_PROVIDER = "ER_NO_XPATH_FUNCTION_PROVIDER";
public static final String ER_UNSUPPORTED_RETURN_TYPE = "ER_UNSUPPORTED_RETURN_TYPE";
public static final String ER_SOURCE_RETURN_TYPE_CANNOT_BE_NULL = "ER_SOURCE_RETURN_TYPE_CANNOT_BE_NULL";
public static final String ER_ARG_CANNOT_BE_NULL = "ER_ARG_CANNOT_BE_NULL";
@ -460,6 +460,9 @@ public static final String ER_IGNORABLE_WHITESPACE_NOT_HANDLED =
{ ER_EXPECTED_BUT_FOUND,
"Expected {0}, but found: {1}"},
{ ER_UNION_MUST_BE_NODESET,
"Operands for a union must be node-sets."},
{ ER_INCORRECT_PROGRAMMER_ASSERTION,
"Programmer assertion is incorrect! - {0}"},
@ -574,12 +577,6 @@ public static final String ER_IGNORABLE_WHITESPACE_NOT_HANDLED =
{ ER_CANNOT_DEAL_XPATH_TYPE,
"Can not deal with XPath type: {0}"},
{ ER_NODESET_NOT_MUTABLE,
"This NodeSet is not mutable"},
{ ER_NODESETDTM_NOT_MUTABLE,
"This NodeSetDTM is not mutable"},
{ ER_VAR_NOT_RESOLVABLE,
"Variable not resolvable: {0}"},
@ -780,6 +777,12 @@ public static final String ER_IGNORABLE_WHITESPACE_NOT_HANDLED =
{ ER_RESOLVE_VARIABLE_RETURNS_NULL,
"resolveVariable for variable {0} returning null"},
{ ER_NO_XPATH_VARIABLE_RESOLVER,
"Attempting to resolve variable {0}, but a variable resolver is not set."},
{ ER_NO_XPATH_FUNCTION_PROVIDER,
"Attempting to call an extension function {0}, but an extension provider is not set."},
/** Field ER_UNSUPPORTED_RETURN_TYPE */
{ ER_UNSUPPORTED_RETURN_TYPE,

View File

@ -24,34 +24,96 @@
package xpath;
import java.io.StringReader;
import javax.xml.namespace.QName;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath;
import static javax.xml.xpath.XPathConstants.BOOLEAN;
import static javax.xml.xpath.XPathConstants.NODE;
import static javax.xml.xpath.XPathConstants.NODESET;
import static javax.xml.xpath.XPathConstants.NUMBER;
import static javax.xml.xpath.XPathConstants.STRING;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import javax.xml.xpath.XPathNodes;
import org.testng.Assert;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.xml.sax.InputSource;
/*
* @test
* @bug 8284548
* @bug 8284400 8284548
* @run testng xpath.XPathExceptionTest
* @summary This is a general test for Exception handling. Additional cases may
* be added with a bug id in the test cases.
* @summary This is a general test for Exception handling in XPath. This test
* covers the followings:
* NPE: refer to DataProvider NPE for more details.
* IAE: covered by existing tests: Bug4991939, XPathAnyTypeTest, XPathExpAnyTypeTest
* and XPathTest
* XPathExpressionException: all other cass other than NPE and IAE.
*/
public class XPathExceptionTest {
private final String XPATH_EXPRESSION = "ext:helloWorld()";
/*
* DataProvider: invalid XPath expressions
* Illegal expressions and structures that may escape the validation check.
* DataProvider: used for NPE test, provides the following fields:
* expression, context, useSource, source, QName, class type, provided
* Refer to testNPEWithEvaluate.
*/
@DataProvider(name = "invalid")
public Object[][] getInvalid() throws Exception {
@DataProvider(name = "NPE")
public Object[][] getNullParameter() throws Exception {
return new Object[][]{
/**
* Existing NPE tests:
* for XPath::evaluate:
* Bug4992788: expression != null, source = null
* Bug4992793: expression = null, source != null
* Bug4992805: source != null, QName = null
*
* for XPath::evaluateExpression
* XPathAnyTypeTest: expression = null or classType = null
*/
// NPE if expression = null
{null, (Node)null, false, null, STRING, String.class, true},
{null, getDummyDoc(), false, null, STRING, String.class, true},
{null, (Node)null, false, null, null, null, false},
{null, getDummyDoc(), false, null, null, null, false},
// NPE if returnType = null
{"exp", (Node)null, false, null, null, null, true},
{"exp", getDummyDoc(), false, null, null, null, true},
// NPE if source = null
{"exp", (Node)null, true, null, STRING, String.class, true},
{"exp", getDummyDoc(), true, null, STRING, String.class, true},
{"exp", (Node)null, true, null, null, null, false},
{"exp", getDummyDoc(), true, null, null, null, false},
};
}
/*
* DataProvider: used for compile-time error test, provides:
* invalid XPath expressions
*/
@DataProvider(name = "invalidExp")
public Object[][] getInvalidExp() throws Exception {
return new Object[][]{
{"8|b"},
{"8[x=2]|b"},
{"8/a|b"},
{"a|7"},
{"a|7|b"},
{"a|7[x=2]"},
{"b|'literal'"},
{"b|\"literal\""},
{"a|$x:y"},
{"a|(x or y)"},
{"a|(x and y)"},
{"a|(x=2)"},
{"a|string-length(\"xy\")"},
{"/a/b/preceding-sibling::comment()|7"},
// @bug JDK-8284548: expressions ending with relational operators
// throw StringIndexOutOfBoundsException instead of XPathExpressionException
{"/a/b/c[@d >"},
@ -61,22 +123,476 @@ public class XPathExceptionTest {
};
}
/*
* DataProvider: expressions that cause exceptions in the given context.
*/
@DataProvider(name = "expInContext1")
public Object[][] getExpressionAndContext1() throws Exception {
InputSource source = new InputSource(new StringReader("<A/>"));
return new Object[][]{
// expressions invalid for the null context, return type not provided
{"x+1", (Node)null, false, null, null, null, false},
{"5 mod a", (Node)null, false, null, null, null, false},
{"8 div ", (Node)null, false, null, null, null, false},
{"/bookstore/book[price>xx]", (Node)null, false, null, null, null, false},
// expressions invalid for the null context, return type is irrelevant
// for the eval, but needs to be a valid one when used
// Note that invalid class type was tested in XPathAnyTypeTest,
// and invalid QName tested in Bug4991939.
{"x+1", (Node)null, false, null, STRING, String.class, true},
{"5 mod a", (Node)null, false, null, STRING, String.class, true},
{"8 div ", (Node)null, false, null, STRING, String.class, true},
{"/bookstore/book[price>xx]", (Node)null, false, null, STRING, String.class, true},
// undefined variable, context not relevant, return type not provided
{"/ * [n*$d2]/s", getDummyDoc(), false, null, null, null, false},
{"/ * [n|$d1]/s", getDummyDoc(), false, null, null, null, false},
{"/ * [n*$d2]/s", null, true, source, null, null, false},
{"/ * [n|$d1]/s", null, true, source, null, null, false},
// undefined variable, context/return type not relevant for the eval
// but need to be valid when provided
{"/ * [n*$d2]/s", getDummyDoc(), false, null, STRING, String.class, true},
{"/ * [n|$d1]/s", getDummyDoc(), false, null, STRING, String.class, true},
{"/ * [n*$d2]/s", null, true, source, STRING, String.class, true},
{"/ * [n|$d1]/s", null, true, source, STRING, String.class, true},
};
}
/*
* DataProvider: provides edge cases that are valid
*/
@DataProvider(name = "expInContext2")
public Object[][] getExpressionAndContext2() throws Exception {
return new Object[][]{
// The context can be empty
{"/node[x=2]", getEmptyDocument(), false, null, STRING, String.class, true},
{"/a/b/c", getEmptyDocument(), false, null, BOOLEAN, Boolean.class, true},
};
}
/*
* DataProvider: provides expressions that contain function calls.
*/
@DataProvider(name = "functions")
public Object[][] getExpressionWithFunctions() throws Exception {
InputSource source = new InputSource(new StringReader("<A/>"));
return new Object[][]{
// expression with a function call
{XPATH_EXPRESSION, getEmptyDocument(), false, null, STRING, String.class, true},
{XPATH_EXPRESSION, null, true, source, BOOLEAN, Boolean.class, true},
};
}
/**
* Verifies that the XPath processor throws XPathExpressionException upon
* encountering illegal XPath expressions.
* Verifies that NPE is thrown if the expression, source, or returnType is
* null.
* This test tests these methods:
* XPath::evaluate and XPathExpression::evaluate.
* XPath::evaluateExpression and XPathExpression::evaluateExpression.
*
* @param expression the expression
* @param item the context item, can be null (for non-context dependent expressions)
* @param useSource a flag indicating whether the source shall be used instead
* of the context item
* @param source the source
* @param qn the return type in the form of a QName, can be null
* @param cls the return type in the form of a class type, can be null
* @param provided a flag indicating whether the return type is provided
* @throws Exception if the test fails
*/
@Test(dataProvider = "NPE")
public void testNPEWithEvaluate(String expression, Object item, boolean useSource,
InputSource source, QName qn, Class<?> cls, boolean provided)
throws Exception {
XPath xPath = XPathFactory.newInstance().newXPath();
// test with XPath::evaluate
Assert.assertThrows(NullPointerException.class, () -> xpathEvaluate(
xPath, expression, item, useSource, source, qn, provided));
// test with XPathExpression::evaluate
Assert.assertThrows(NullPointerException.class, () -> xpathExpressionEvaluate(
xPath, expression, item, useSource, source, qn, provided));
// test with XPath::evaluateExpression
Assert.assertThrows(NullPointerException.class, () -> xpathEvaluateExpression(
xPath, expression, item, useSource, source, cls, provided));
// test with XPathExpression::evaluateExpression
Assert.assertThrows(NullPointerException.class, () -> xpathExpressionEvaluateExpression(
xPath, expression, item, useSource, source, cls, provided));
}
/**
* Verifies that XPathExpressionException is thrown upon encountering illegal
* XPath expressions when XPath::compile is called.
*
* @param invalidExp an illegal XPath expression
* @throws Exception if the test fails
*/
@Test(dataProvider = "invalid")
public void testIllegalExp(String invalidExp) throws Exception {
DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
Document doc = builder.parse(new org.xml.sax.InputSource(new StringReader("<A/>")));
Assert.assertThrows(XPathExpressionException.class, () -> evaluate(doc, invalidExp));
@Test(dataProvider = "invalidExp")
public void testXPathCompile(String invalidExp) throws Exception {
Assert.assertThrows(XPathExpressionException.class, () -> xpathCompile(invalidExp));
}
private void evaluate(Document doc, String s) throws XPathExpressionException {
/**
* Verifies that XPathExpressionException is thrown upon encountering illegal
* XPath expressions.
* This test tests these methods:
* XPath::evaluate and XPathExpression::evaluate.
* XPath::evaluateExpression and XPathExpression::evaluateExpression.
*
* @param expression an illegal XPath expression
* @throws Exception if the test fails
*/
@Test(dataProvider = "invalidExp")
public void testCompileErrorWithEvaluate(String expression)
throws Exception {
XPath xPath = XPathFactory.newInstance().newXPath();
// test with XPath::evaluate
Assert.assertThrows(XPathExpressionException.class, () -> xpathEvaluate(
xPath, expression, (Node)null, false, null, null, false));
// test with XPathExpression::evaluate
Assert.assertThrows(XPathExpressionException.class, () -> xpathExpressionEvaluate(
xPath, expression, (Node)null, false, null, null, false));
// test with XPath::evaluateExpression
Assert.assertThrows(XPathExpressionException.class, () -> xpathEvaluateExpression(
xPath, expression, (Node)null, false, null, null, false));
// test with XPathExpression::evaluateExpression
Assert.assertThrows(XPathExpressionException.class, () -> xpathExpressionEvaluateExpression(
xPath, expression, (Node)null, false, null, null, false));
}
/**
* Verifies that XPathExpressionException is thrown if the expression is
* invalid with the given context.
* This test tests these methods:
* XPath::evaluate and XPathExpression::evaluate.
* XPath::evaluateExpression and XPathExpression::evaluateExpression.
*
* @param expression the expression
* @param item the context item, can be null (for non-context dependent expressions)
* @param useSource a flag indicating whether the source shall be used instead
* of the context item
* @param source the source
* @param qn the return type in the form of a QName, can be null
* @param cls the return type in the form of a class type, can be null
* @param provided a flag indicating whether the return type is provided
* @throws Exception if the test fails
*/
@Test(dataProvider = "expInContext1")
public void testExpInContextEval1(String expression, Object item, boolean useSource,
InputSource source, QName qn, Class<?> cls, boolean provided)
throws Exception {
XPath xPath = XPathFactory.newInstance().newXPath();
// test with XPath::evaluate
Assert.assertThrows(XPathExpressionException.class, () -> xpathEvaluate(
xPath, expression, item, useSource, source, qn, provided));
// test with XPathExpression::evaluate
Assert.assertThrows(XPathExpressionException.class, () -> xpathExpressionEvaluate(
xPath, expression, item, useSource, source, qn, provided));
// test with XPath::evaluateExpression
Assert.assertThrows(XPathExpressionException.class, () -> xpathEvaluateExpression(
xPath, expression, item, useSource, source, cls, provided));
// test with XPathExpression::evaluateExpression
Assert.assertThrows(XPathExpressionException.class, () -> xpathExpressionEvaluateExpression(
xPath, expression, item, useSource, source, cls, provided));
}
/**
* Verifies that XPathExpressionException is thrown if the expression is
* invalid with the given context.
* This test tests these methods:
* XPath::evaluate and XPathExpression::evaluate.
* XPath::evaluateExpression and XPathExpression::evaluateExpression.
*
* @param expression the expression
* @param item the context item, can be null (for non-context dependent expressions)
* @param useSource a flag indicating whether the source shall be used instead
* of the context item
* @param source the source
* @param qn the return type in the form of a QName, can be null
* @param cls the return type in the form of a class type, can be null
* @param provided a flag indicating whether the return type is provided
* @throws Exception if the test fails
*/
@Test(dataProvider = "expInContext1")
public void testExpInContext(String expression, Object item, boolean useSource,
InputSource source, QName qn, Class<?> cls, boolean provided)
throws Exception {
QName[] qns = {NUMBER, STRING, BOOLEAN, NODESET, NODE};
Class[] classes = {Integer.class, Boolean.class, String.class, XPathNodes.class, Node.class};
XPath xPath = XPathFactory.newInstance().newXPath();
for (QName qn1 : qns) {
// test with XPath::evaluate
Assert.assertThrows(XPathExpressionException.class, () -> xpathEvaluate(
xPath, expression, item, useSource, source, qn1, provided));
// test with XPathExpression::evaluate
Assert.assertThrows(XPathExpressionException.class, () -> xpathExpressionEvaluate(
xPath, expression, item, useSource, source, qn1, provided));
}
for (Class<?> cls1 : classes) {
// test with XPath::evaluateExpression
Assert.assertThrows(XPathExpressionException.class, () -> xpathEvaluateExpression(
xPath, expression, item, useSource, source, cls1, provided));
// test with XPathExpression::evaluateExpression
Assert.assertThrows(XPathExpressionException.class, () -> xpathExpressionEvaluateExpression(
xPath, expression, item, useSource, source, cls1, provided));
}
}
/**
* Verifies that the expression is valid with the given context.
* This test tests these methods:
* XPath::evaluate and XPathExpression::evaluate.
* XPath::evaluateExpression and XPathExpression::evaluateExpression.
*
* @param expression the expression
* @param item the context item, can be null (for non-context dependent expressions)
* @param useSource a flag indicating whether the source shall be used instead
* of the context item
* @param source the source
* @param qn the return type in the form of a QName, can be null
* @param cls the return type in the form of a class type, can be null
* @param provided a flag indicating whether the return type is provided
* @throws Exception if the test fails
*/
@Test(dataProvider = "expInContext2")
public void testExpInContextEval2(String expression, Object item, boolean useSource,
InputSource source, QName qn, Class<?> cls, boolean provided)
throws Exception {
XPath xPath = XPathFactory.newInstance().newXPath();
// test with XPath::evaluate
xpathEvaluate(xPath, expression, item, useSource, source, qn, provided);
// test with XPathExpression::evaluate
xpathExpressionEvaluate(xPath, expression, item, useSource, source, qn, provided);
// test with XPath::evaluateExpression
xpathEvaluateExpression(xPath, expression, item, useSource, source, cls, provided);
// test with XPathExpression::evaluateExpression
xpathExpressionEvaluateExpression(xPath, expression, item, useSource, source, cls, provided);
}
/**
* Verifies that the XPath processor without XPathFunctionResolver throws
* XPathExpressionException upon processing an XPath expression that attempts
* to call a function.
*
* @param expression the expression
* @param item the context item, can be null (for non-context dependent expressions)
* @param useSource a flag indicating whether the source shall be used instead
* of the context item
* @param source the source
* @param qn the return type in the form of a QName, can be null
* @param cls the return type in the form of a class type, can be null
* @param provided a flag indicating whether the return type is provided
* @throws Exception if the test fails
*/
@Test(dataProvider = "functions")
public void testFunction(String expression, Object item, boolean useSource,
InputSource source, QName qn, Class<?> cls, boolean provided)
throws Exception {
XPath xPath = XPathFactory.newInstance().newXPath();
// test with XPath::evaluate
Assert.assertThrows(XPathExpressionException.class, () -> xpathEvaluate(
xPath, expression, item, useSource, source, qn, provided));
// test with XPathExpression::evaluate
Assert.assertThrows(XPathExpressionException.class, () -> xpathExpressionEvaluate(
xPath, expression, item, useSource, source, qn, provided));
// test with XPath::evaluateExpression
Assert.assertThrows(XPathExpressionException.class, () -> xpathEvaluateExpression(
xPath, expression, item, useSource, source, cls, provided));
// test with XPathExpression::evaluateExpression
Assert.assertThrows(XPathExpressionException.class, () -> xpathExpressionEvaluateExpression(
xPath, expression, item, useSource, source, cls, provided));
}
// ---- utility methods ----
/**
* Compiles the specified expression.
* @param s the expression
* @throws XPathExpressionException if the expression is invalid
*/
private void xpathCompile(String s) throws XPathExpressionException {
XPath xp = XPathFactory.newInstance().newXPath();
XPathExpression xe = xp.compile(s);
xe.evaluateExpression(doc, Node.class);
}
/**
* Runs evaluation using the XPath::evaluate methods.
*
* @param xPath the XPath object
* @param expression the expression
* @param item the context item, can be null (for non-context dependent expressions)
* @param useSource a flag indicating whether the source shall be used instead
* of the context item
* @param source the source
* @param qn the return type in the form of a QName, can be null
* @param qnProvided a flag indicating whether the QName is provided
* @throws XPathExpressionException
*/
private void xpathEvaluate(XPath xPath, String expression, Object item,
boolean useSource, InputSource source, QName qn, boolean qnProvided)
throws XPathExpressionException {
if (useSource) {
if (!qnProvided) {
xPath.evaluate(expression, source);
} else {
xPath.evaluate(expression, source, qn);
}
} else {
if (!qnProvided) {
xPath.evaluate(expression, item);
} else {
xPath.evaluate(expression, item, qn);
}
}
}
/**
* Runs evaluation using the XPathExpression::evaluate methods.
*
* @param xe the XPathExpression object
* @param item the context item, can be null (for non-context dependent expressions)
* @param useSource a flag indicating whether the source shall be used instead
* of the context item
* @param source the source
* @param qn the return type in the form of a QName, can be null
* @param qnProvided a flag indicating whether the QName is provided
* @throws XPathExpressionException
*/
private void xpathExpressionEvaluate(XPath xPath, String expression, Object item,
boolean useSource, InputSource source, QName qn, boolean qnProvided)
throws XPathExpressionException {
XPathExpression xe = xPath.compile(expression);
if (useSource) {
if (!qnProvided) {
xe.evaluate(source);
} else {
xe.evaluate(source, qn);
}
} else {
if (!qnProvided) {
xe.evaluate(item);
} else {
xe.evaluate(item, qn);
}
}
}
/**
* Runs evaluation using the XPath::evaluateExpression methods.
*
* @param xPath the XPath object
* @param expression the expression
* @param item the context item, can be null (for non-context dependent expressions)
* @param useSource a flag indicating whether the source shall be used instead
* of the context item
* @param source the source
* @param cls the class type, can be null
* @param clsProvided a flag indicating whether the class type is provided
* @throws XPathExpressionException
*/
private void xpathEvaluateExpression(XPath xPath, String expression, Object item,
boolean useSource, InputSource source, Class<?> cls, boolean clsProvided)
throws XPathExpressionException {
if (useSource) {
if (!clsProvided) {
xPath.evaluateExpression(expression, source);
} else {
xPath.evaluateExpression(expression, source, cls);
}
} else {
if (!clsProvided) {
xPath.evaluateExpression(expression, item);
} else {
xPath.evaluateExpression(expression, item, cls);
}
}
}
/**
* Runs evaluation using the XPathExpression::evaluateExpression methods.
*
* @param xe the XPathExpression object
* @param item the context item, can be null (for non-context dependent expressions)
* @param useSource a flag indicating whether the source shall be used instead
* of the context item
* @param source the source
* @param qn the return type in the form of a QName, can be null
* @param qnProvided a flag indicating whether the QName is provided
* @throws XPathExpressionException
*/
private void xpathExpressionEvaluateExpression(XPath xPath, String expression,
Object item, boolean useSource, InputSource source, Class<?> cls, boolean qnProvided)
throws XPathExpressionException {
XPathExpression xe = xPath.compile(expression);
if (useSource) {
if (!qnProvided) {
xe.evaluateExpression(source);
} else {
xe.evaluateExpression(source, cls);
}
} else {
if (!qnProvided) {
xe.evaluateExpression(item);
} else {
xe.evaluateExpression(item, cls);
}
}
}
/**
* Returns an empty {@link org.w3c.dom.Document}.
* @return a DOM Document, null in case of Exception
*/
private Document getEmptyDocument() {
try {
return DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
} catch (ParserConfigurationException e) {
return null;
}
}
/**
* Returns a DOM Document with dummy content.
* @return a DOM Document
* @throws Exception
*/
private Document getDummyDoc() throws Exception {
DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
return builder.parse(new InputSource(new StringReader("<A/>")));
}
/**
* Returns a DOM Document with the specified source.
* @param s the source
* @return a DOM Document
* @throws Exception
*/
private Document getDoc(InputSource s) throws Exception {
DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
return builder.parse(s);
}
}