6211561: XPath.evaluate(String,Object,QName) throws exception if context node is null
authorjoehw
Tue, 16 Aug 2016 17:35:47 -0700
changeset 40483 cb7f243e782d
parent 40320 2e83d21d78cd
child 40484 be0ddc78275b
6211561: XPath.evaluate(String,Object,QName) throws exception if context node is null Reviewed-by: lancea
jaxp/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathImplUtil.java
jaxp/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/res/XPATHErrorResources.java
jaxp/src/java.xml/share/classes/javax/xml/xpath/XPath.java
jaxp/src/java.xml/share/classes/javax/xml/xpath/XPathExpression.java
jaxp/test/javax/xml/jaxp/unittest/xpath/XPathTest.java
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathImplUtil.java	Wed Jul 05 22:05:29 2017 +0200
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathImplUtil.java	Tue Aug 16 17:35:47 2016 -0700
@@ -28,6 +28,7 @@
 import com.sun.org.apache.xalan.internal.res.XSLMessages;
 import com.sun.org.apache.xalan.internal.utils.FactoryImpl;
 import com.sun.org.apache.xml.internal.dtm.DTM;
+import com.sun.org.apache.xpath.internal.axes.LocPathIterator;
 import com.sun.org.apache.xpath.internal.objects.XObject;
 import com.sun.org.apache.xpath.internal.res.XPATHErrorResources;
 import java.io.IOException;
@@ -73,6 +74,12 @@
     XObject eval(Object contextItem, com.sun.org.apache.xpath.internal.XPath xpath)
             throws javax.xml.transform.TransformerException {
         com.sun.org.apache.xpath.internal.XPathContext xpathSupport;
+        if (contextItem == null && xpath.getExpression() instanceof LocPathIterator) {
+            // the operation must have no dependency on the context that is null
+            throw new TransformerException(XSLMessages.createXPATHMessage(
+                    XPATHErrorResources.ER_CONTEXT_CAN_NOT_BE_NULL,
+                    new Object[] {}));
+        }
         if (functionResolver != null) {
             JAXPExtensionsProvider jep = new JAXPExtensionsProvider(
                     functionResolver, featureSecureProcessing, featureManager);
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/res/XPATHErrorResources.java	Wed Jul 05 22:05:29 2017 +0200
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/res/XPATHErrorResources.java	Tue Aug 16 17:35:47 2016 -0700
@@ -93,6 +93,7 @@
   public static final String ER_CURRENT_TAKES_NO_ARGS =
          "ER_CURRENT_TAKES_NO_ARGS";
   public static final String ER_DOCUMENT_REPLACED = "ER_DOCUMENT_REPLACED";
+  public static final String ER_CONTEXT_CAN_NOT_BE_NULL = "ER_CONTEXT_CAN_NOT_BE_NULL";
   public static final String ER_CONTEXT_HAS_NO_OWNERDOC =
          "ER_CONTEXT_HAS_NO_OWNERDOC";
   public static final String ER_LOCALNAME_HAS_TOO_MANY_ARGS =
@@ -368,6 +369,9 @@
   { ER_DOCUMENT_REPLACED,
       "document() function implementation has been replaced by com.sun.org.apache.xalan.internal.xslt.FuncDocument!"},
 
+  { ER_CONTEXT_CAN_NOT_BE_NULL,
+      "The context can not be null when the operation is context-dependent."},
+
   { ER_CONTEXT_HAS_NO_OWNERDOC,
       "context does not have an owner document!"},
 
--- a/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPath.java	Wed Jul 05 22:05:29 2017 +0200
+++ b/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPath.java	Tue Aug 16 17:35:47 2016 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -34,18 +34,20 @@
  *
  * <a name="XPath-evaluation"></a>
  * <table border="1" cellpadding="2">
- *   <thead>
- *     <tr>
- *       <th colspan="2">Evaluation of XPath Expressions.</th>
- *     </tr>
- *   </thead>
- *     <tr>
- *       <td>context</td>
- *       <td>
- *         If a request is made to evaluate the expression in the absence
- * of a context item, an empty document node will be used for the context.
- * For the purposes of evaluating XPath expressions, a DocumentFragment
- * is treated like a Document node.
+ *    <thead>
+ *      <tr>
+ *        <th colspan="2">Evaluation of XPath Expressions.</th>
+ *      </tr>
+ *    </thead>
+ *    <tr>
+ *      <td>context</td>
+ *      <td>
+ *        The type of the context is implementation-dependent. If the value is
+ *        null, the operation must have no dependency on the context, otherwise
+ *        an XPathExpressionException will be thrown.
+ *
+ *        For the purposes of evaluating XPath expressions, a DocumentFragment
+ *        is treated like a Document node.
  *      </td>
  *    </tr>
  *    <tr>
--- a/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPathExpression.java	Wed Jul 05 22:05:29 2017 +0200
+++ b/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPathExpression.java	Tue Aug 16 17:35:47 2016 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -33,19 +33,20 @@
  *
  * <a name="XPathExpression-evaluation"></a>
  * <table border="1" cellpadding="2">
- *   <thead>
- *     <tr>
- *       <th colspan="2">Evaluation of XPath Expressions.</th>
- *     </tr>
- *   </thead>
- *   <tbody>
- *     <tr>
- *       <td>context</td>
- *       <td>
- *         If a request is made to evaluate the expression in the absence
- * of a context item, an empty document node will be used for the context.
- * For the purposes of evaluating XPath expressions, a DocumentFragment
- * is treated like a Document node.
+ *    <thead>
+ *      <tr>
+ *        <th colspan="2">Evaluation of XPath Expressions.</th>
+ *      </tr>
+ *    </thead>
+ *    <tr>
+ *      <td>context</td>
+ *      <td>
+ *        The type of the context is implementation-dependent. If the value is
+ *        null, the operation must have no dependency on the context, otherwise
+ *        an XPathExpressionException will be thrown.
+ *
+ *        For the purposes of evaluating XPath expressions, a DocumentFragment
+ *        is treated like a Document node.
  *      </td>
  *    </tr>
  *    <tr>
--- a/jaxp/test/javax/xml/jaxp/unittest/xpath/XPathTest.java	Wed Jul 05 22:05:29 2017 +0200
+++ b/jaxp/test/javax/xml/jaxp/unittest/xpath/XPathTest.java	Tue Aug 16 17:35:47 2016 -0700
@@ -24,11 +24,17 @@
 package xpath;
 
 import javax.xml.namespace.NamespaceContext;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
 import javax.xml.xpath.XPath;
+import javax.xml.xpath.XPathConstants;
+import javax.xml.xpath.XPathExpressionException;
 import javax.xml.xpath.XPathFactory;
-
+import org.testng.annotations.DataProvider;
 import org.testng.annotations.Listeners;
 import org.testng.annotations.Test;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
 
 /*
  * @test
@@ -36,19 +42,105 @@
  * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest
  * @run testng/othervm -DrunSecMngr=true xpath.XPathTest
  * @run testng/othervm xpath.XPathTest
- * @summary Test XPath.getNamespaceContext() is supported.
+ * @summary Test XPath functions. See details for each test.
  */
 @Listeners({jaxp.library.BasePolicy.class})
 public class XPathTest {
 
+    /*
+      @bug 6211561
+     * Verifies the specification for XPath and XPathExpression:
+     * If a null value is provided for item (the context),
+     * the expression must have no dependency on the context.
+    */
+    @Test(dataProvider = "noContextDependency")
+    public void testNoContextDependency1(String expression, Object item) throws XPathExpressionException {
+        XPath xPath = XPathFactory.newInstance().newXPath();
+        xPath.evaluate(expression, item, XPathConstants.STRING);
+    }
+
+    @Test(dataProvider = "noContextDependency")
+    public void testNoContextDependency2(String expression, Object item) throws XPathExpressionException {
+        XPath xPath = XPathFactory.newInstance().newXPath();
+        xPath.evaluateExpression(expression, item, String.class);
+    }
+
+    /*
+      @bug 6211561
+     * Verifies the specification for XPath and XPathExpression:
+     * If a null value is provided for item (the context) that the operation
+     * depends on, XPathExpressionException will be thrown
+    */
+    @Test(dataProvider = "hasContextDependency", expectedExceptions = XPathExpressionException.class)
+    public void testHasContextDependency1(String expression, Object item) throws XPathExpressionException {
+        XPath xPath = XPathFactory.newInstance().newXPath();
+        xPath.evaluate(expression, item, XPathConstants.STRING);
+    }
+
+    @Test(dataProvider = "hasContextDependency", expectedExceptions = XPathExpressionException.class)
+    public void testHasContextDependency2(String expression, Object item) throws XPathExpressionException {
+        XPath xPath = XPathFactory.newInstance().newXPath();
+        xPath.evaluateExpression(expression, item, String.class);
+    }
+
+    /*
+      @bug 6376058
+      Verifies that XPath.getNamespaceContext() is supported.
+    */
     @Test
     public void testNamespaceContext() {
-
         XPathFactory xPathFactory = XPathFactory.newInstance();
         XPath xPath = xPathFactory.newXPath();
+        NamespaceContext namespaceContext = xPath.getNamespaceContext();
+    }
 
-        NamespaceContext namespaceContext = xPath.getNamespaceContext();
+    /*
+     * DataProvider: the expression has no dependency on the context
+     */
+    @DataProvider(name = "noContextDependency")
+    public Object[][] getExpressionContext() throws Exception {
+        return new Object[][]{
+            {"1+1", (Node)null},
+            {"5 mod 2", (Node)null},
+            {"8 div 2", (Node)null},
+            {"/node", getEmptyDocument()}
+        };
+    }
 
+    /*
+     * DataProvider: the expression has dependency on the context, but the context
+     * is null.
+     */
+    @DataProvider(name = "hasContextDependency")
+    public Object[][] getExpressionContext1() throws Exception {
+        return new Object[][]{
+            {"/node", (Node)null},
+            {"//@lang", (Node)null},
+            {"bookstore//book", (Node)null},
+            {"/bookstore/book[last()]", (Node)null},
+            {"//title[@lang='en']", (Node)null},
+            {"/bookstore/book[price>9.99]", (Node)null},
+            {"/bookstore/book[price>8.99 and price<9.99]", (Node)null},
+            {"/bookstore/*", (Node)null},
+            {"//title[@*]", (Node)null},
+            {"//title | //price", (Node)null},
+            {"//book/title | //book/price", (Node)null},
+            {"/bookstore/book/title | //price", (Node)null},
+            {"child::book", (Node)null},
+            {"child::text()", (Node)null},
+            {"child::*/child::price", (Node)null}
+        };
+    }
+
+    /**
+     * Returns an empty {@link org.w3c.dom.Document}.
+     * @return a DOM Document, null in case of Exception
+     */
+    public Document getEmptyDocument() {
+        try {
+            return DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
+        } catch (ParserConfigurationException e) {
+            return null;
+        }
     }
 }
-