提问人:Dmytro Marchenko 提问时间:9/2/2020 最后编辑:Dmytro Marchenko 更新时间:11/18/2023 访问量:1823
并发使用 XPathExpression
Using XPathExpression concurrently
问:
我正在尝试并发使用 XPathExpression,但解析时可能不会调用“org.xml.sax.SAXException:FWK005 解析”。 使用 ThreadLocal 无济于事,即使为每个调用创建了新的 XPathExpression,它也会失败。 此 Junit 测试重现了以下问题:
package testxpath;
import java.io.StringReader;
import java.util.stream.IntStream;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathFactory;
import org.junit.jupiter.api.Test;
import org.xml.sax.InputSource;
import lombok.SneakyThrows;
class ConcurrentXpathTest {
private static final String XPATH = "//*[(local-name()='Node')]";
private static final String XML = "<Node>Something</Node>";
@Test
void testConcurrentXpath() {
IntStream.range(0, 10000)
.parallel()
.forEach(v -> parse());
}
@SneakyThrows
private void parse() {
XPathExpression xPathExpression = XPathFactory.newInstance().newXPath().compile(XPATH);
xPathExpression.evaluate(new InputSource(new StringReader(XML)), XPathConstants.NODESET);
}
}
如何解决这个问题?也许建议一些替代库。
堆栈跟踪:
org.xml.sax.SAXException: FWK005 parse may not be called while parsing.
at com.sun.org.apache.xerces.internal.parsers.DOMParser.parse(DOMParser.java:271)
at com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderImpl.parse(DocumentBuilderImpl.java:339)
at com.sun.org.apache.xpath.internal.jaxp.XPathExpressionImpl.evaluate(XPathExpressionImpl.java:291)
at com.corelogic.clp.tel2.gateway.services.ConcurrentXpathTest.parse(ConcurrentXpathTest.java:43)
at com.corelogic.clp.tel2.gateway.services.ConcurrentXpathTest.lambda$testConcurrentXpath$0(ConcurrentXpathTest.java:37)
at java.util.stream.ForEachOps$ForEachOp$OfInt.accept(ForEachOps.java:205)
at java.util.stream.Streams$RangeIntSpliterator.forEachRemaining(Streams.java:110)
at java.util.Spliterator$OfInt.forEachRemaining(Spliterator.java:693)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)
at java.util.stream.ForEachOps$ForEachTask.compute(ForEachOps.java:291)
at java.util.concurrent.CountedCompleter.exec(CountedCompleter.java:731)
at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)
--------------- linked to ------------------
javax.xml.xpath.XPathExpressionException: org.xml.sax.SAXException: FWK005 parse may not be called while parsing.
at com.sun.org.apache.xpath.internal.jaxp.XPathExpressionImpl.evaluate(XPathExpressionImpl.java:294)
at com.corelogic.clp.tel2.gateway.services.ConcurrentXpathTest.parse(ConcurrentXpathTest.java:43)
at com.corelogic.clp.tel2.gateway.services.ConcurrentXpathTest.lambda$testConcurrentXpath$0(ConcurrentXpathTest.java:37)
at java.util.stream.ForEachOps$ForEachOp$OfInt.accept(ForEachOps.java:205)
at java.util.stream.Streams$RangeIntSpliterator.forEachRemaining(Streams.java:110)
at java.util.Spliterator$OfInt.forEachRemaining(Spliterator.java:693)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)
at java.util.stream.ForEachOps$ForEachTask.compute(ForEachOps.java:291)
at java.util.concurrent.CountedCompleter.exec(CountedCompleter.java:731)
at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)
Caused by: org.xml.sax.SAXException: FWK005 parse may not be called while parsing.
at com.sun.org.apache.xerces.internal.parsers.DOMParser.parse(DOMParser.java:271)
at com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderImpl.parse(DocumentBuilderImpl.java:339)
at com.sun.org.apache.xpath.internal.jaxp.XPathExpressionImpl.evaluate(XPathExpressionImpl.java:291)
... 12 more
--------------- linked to ------------------
javax.xml.xpath.XPathExpressionException: javax.xml.xpath.XPathExpressionException: org.xml.sax.SAXException: FWK005 parse may not be called while parsing.
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at java.util.concurrent.ForkJoinTask.getThrowableException(ForkJoinTask.java:593)
at java.util.concurrent.ForkJoinTask.reportException(ForkJoinTask.java:677)
at java.util.concurrent.ForkJoinTask.invoke(ForkJoinTask.java:735)
at java.util.stream.ForEachOps$ForEachOp.evaluateParallel(ForEachOps.java:160)
at java.util.stream.ForEachOps$ForEachOp$OfInt.evaluateParallel(ForEachOps.java:189)
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:233)
at java.util.stream.IntPipeline.forEach(IntPipeline.java:404)
at java.util.stream.IntPipeline$Head.forEach(IntPipeline.java:560)
at com.corelogic.clp.tel2.gateway.services.ConcurrentXpathTest.testConcurrentXpath(ConcurrentXpathTest.java:37)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:532)
at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:115)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$6(TestMethodTestDescriptor.java:171)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:72)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:167)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:114)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:59)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$4(NodeTestTask.java:108)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:72)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:98)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:74)
at java.util.ArrayList.forEach(ArrayList.java:1257)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$4(NodeTestTask.java:112)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:72)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:98)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:74)
at java.util.ArrayList.forEach(ArrayList.java:1257)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$4(NodeTestTask.java:112)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:72)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:98)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:74)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:51)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:220)
at org.junit.platform.launcher.core.DefaultLauncher.lambda$execute$6(DefaultLauncher.java:188)
at org.junit.platform.launcher.core.DefaultLauncher.withInterceptedStreams(DefaultLauncher.java:202)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:181)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:128)
at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:71)
at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:220)
at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:53)
Caused by: javax.xml.xpath.XPathExpressionException: org.xml.sax.SAXException: FWK005 parse may not be called while parsing.
at com.sun.org.apache.xpath.internal.jaxp.XPathExpressionImpl.evaluate(XPathExpressionImpl.java:294)
at com.corelogic.clp.tel2.gateway.services.ConcurrentXpathTest.parse(ConcurrentXpathTest.java:43)
at com.corelogic.clp.tel2.gateway.services.ConcurrentXpathTest.lambda$testConcurrentXpath$0(ConcurrentXpathTest.java:37)
at java.util.stream.ForEachOps$ForEachOp$OfInt.accept(ForEachOps.java:205)
at java.util.stream.Streams$RangeIntSpliterator.forEachRemaining(Streams.java:110)
at java.util.Spliterator$OfInt.forEachRemaining(Spliterator.java:693)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)
at java.util.stream.ForEachOps$ForEachTask.compute(ForEachOps.java:291)
at java.util.concurrent.CountedCompleter.exec(CountedCompleter.java:731)
at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)
Caused by: org.xml.sax.SAXException: FWK005 parse may not be called while parsing.
at com.sun.org.apache.xerces.internal.parsers.DOMParser.parse(DOMParser.java:271)
at com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderImpl.parse(DocumentBuilderImpl.java:339)
at com.sun.org.apache.xpath.internal.jaxp.XPathExpressionImpl.evaluate(XPathExpressionImpl.java:291)
... 12 more
答:
1赞
predi
11/12/2021
#1
这是由于某些 Xerces 版本中的一个错误,即使是 JDK/JRE 附带的版本也是如此。
请参阅此错误报告。据推测,它在 Java 9+ 附带的默认实现中已修复,但您可能对 1.8 不走运。
可能值得检查您正在使用的是哪个 Xerces 实现。
我们偶然发现了与 Apache Xalan 2.7.1 捆绑在一起的 Xerces 的相同内容。返回的对象似乎包含非线程安全的内部状态,但在实例之间共享(或者它生成表现出相同内容的其他对象)。这似乎是异常的根本原因。DocumentBuilderFactory.newInstance()
评论
1赞
tom_mai78101
9/12/2023
不,您链接的错误报告未修复。他们在没有任何解决方案的情况下关闭了票证,因为他们无法重现提到的错误。因此,Java 9+ 仍然会有这个问题。(我在 Java 17 LTS 上,我们现在仍然看到这个问题。
0赞
Patrice Gagnon
11/18/2023
#2
我可以用 JDK 11 和 Xerces 2.12.0 轻松重现它
org.xml.sax.SAXException: FWK005 parse may not be called while parsing.
at com.sun.org.apache.xerces.internal.parsers.DOMParser.parse(DOMParser.java:276) ~[?:?]
at com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderImpl.parse(DocumentBuilderImpl.java:339) ~[?:?]
at javax.xml.parsers.DocumentBuilder.parse(DocumentBuilder.java:122) ~[?:?]
为了解决这个问题,我只需同步我的构建器:
Document xmlDocument = null;
InputStream stream = new ByteArrayInputStream(xml.getBytes("UTF-8"));
synchronized(builder) {
xmlDocument = builder.parse(stream);
}
评论
com.corelogic.clp.tel2.gateway.services.xml.HttpStatusService.getResponseStatus()