Skip to content

Commit acd677d

Browse files
committed
Fix for #47, switch from XPath expression to non-resolving SAX parser.
1 parent 0d5453d commit acd677d

File tree

2 files changed

+68
-19
lines changed

2 files changed

+68
-19
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ Changelog
66
- Focused so much on getting Thymeleaf Natures _added_ to a project, that we
77
forgot to test _removing_ it, which suffered from the same bugs as adding it
88
did. Fixed. ([#45](https://github.com/thymeleaf/thymeleaf-extras-eclipse-plugin/issues/45))
9+
- Fixed a non-blocking error that occurs when the XML namespace checking tries
10+
to resolve external resources ([#47](https://github.com/thymeleaf/thymeleaf-extras-eclipse-plugin/issues/47))
911

1012
### 2.1.0
1113
- Support for Thymeleaf 2.1's new features! ([#33](https://github.com/thymeleaf/thymeleaf-extras-eclipse-plugin/issues/33),

bundles/thymeleaf-extras-eclipse-plugin.core/src/main/java/org/thymeleaf/extras/eclipse/dialect/ProjectDependencyDialectLocator.java

Lines changed: 66 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@
2525
import org.eclipse.jdt.core.IJavaProject;
2626
import org.eclipse.jdt.core.IPackageFragment;
2727
import org.eclipse.jdt.core.IPackageFragmentRoot;
28-
import org.xml.sax.InputSource;
28+
import org.xml.sax.Attributes;
29+
import org.xml.sax.SAXException;
30+
import org.xml.sax.helpers.DefaultHandler;
2931
import static org.thymeleaf.extras.eclipse.CorePlugin.*;
3032

3133
import java.io.IOException;
@@ -39,10 +41,9 @@
3941
import java.util.concurrent.Future;
4042
import java.util.concurrent.TimeUnit;
4143

42-
import javax.xml.xpath.XPath;
43-
import javax.xml.xpath.XPathExpression;
44-
import javax.xml.xpath.XPathExpressionException;
45-
import javax.xml.xpath.XPathFactory;
44+
import javax.xml.parsers.ParserConfigurationException;
45+
import javax.xml.parsers.SAXParser;
46+
import javax.xml.parsers.SAXParserFactory;
4647

4748
/**
4849
* Locates Thymeleaf dialect XML help files from a project's dependencies.
@@ -51,10 +52,30 @@
5152
*/
5253
public class ProjectDependencyDialectLocator implements DialectLocator<InputStream> {
5354

55+
private static final String XML_FEATURE_LOAD_DTD_GRAMMAR =
56+
"http://apache.org/xml/features/nonvalidating/load-dtd-grammar";
57+
private static final String XML_FEATURE_LOAD_EXTERNAL_DTD =
58+
"http://apache.org/xml/features/nonvalidating/load-external-dtd";
59+
5460
private static final String DIALECT_EXTRAS_NAMESPACE = "http://www.thymeleaf.org/extras/dialect";
5561

62+
private static final SAXParserFactory parserfactory;
63+
static {
64+
try {
65+
parserfactory = SAXParserFactory.newInstance();
66+
parserfactory.setNamespaceAware(true);
67+
parserfactory.setFeature(XML_FEATURE_LOAD_DTD_GRAMMAR, false);
68+
parserfactory.setFeature(XML_FEATURE_LOAD_EXTERNAL_DTD, false);
69+
}
70+
catch (SAXException ex) {
71+
throw new RuntimeException(ex);
72+
}
73+
catch (ParserConfigurationException ex) {
74+
throw new RuntimeException(ex);
75+
}
76+
}
77+
5678
private final IJavaProject project;
57-
private final XPathExpression namespaceexpression;
5879
private final ArrayList<IPath> dialectfilepaths = new ArrayList<IPath>();
5980

6081
/**
@@ -66,14 +87,6 @@ public class ProjectDependencyDialectLocator implements DialectLocator<InputStre
6687
public ProjectDependencyDialectLocator(IJavaProject project) {
6788

6889
this.project = project;
69-
try {
70-
XPathFactory factory = XPathFactory.newInstance();
71-
XPath xpath = factory.newXPath();
72-
namespaceexpression = xpath.compile("namespace-uri(/*)");
73-
}
74-
catch (XPathExpressionException ex) {
75-
throw new RuntimeException(ex);
76-
}
7790
}
7891

7992
/**
@@ -96,7 +109,7 @@ public List<IPath> getDialectFilePaths() {
96109
* @return <tt>true</tt> if the resource is an XML file in the
97110
* <tt>http://www.thymeleaf.org/extras/dialect</tt> namespace.
98111
*/
99-
private boolean isDialectHelpXMLFile(IStorage resource) {
112+
private static boolean isDialectHelpXMLFile(IStorage resource) {
100113

101114
InputStream resourcestream = null;
102115
try {
@@ -106,15 +119,25 @@ private boolean isDialectHelpXMLFile(IStorage resource) {
106119

107120
// Check if the XML file namespace is correct
108121
resourcestream = resource.getContents();
109-
String namespace = namespaceexpression.evaluate(new InputSource(resourcestream));
110-
if (namespace.equals(DIALECT_EXTRAS_NAMESPACE)) {
122+
SAXParser parser = parserfactory.newSAXParser();
123+
NamespaceHandler handler = new NamespaceHandler();
124+
parser.parse(resourcestream, handler);
125+
if (handler.namespace != null && handler.namespace.equals(DIALECT_EXTRAS_NAMESPACE)) {
111126
return true;
112127
}
113128
}
114129
return false;
115130
}
116-
catch (XPathExpressionException ex) {
117-
logError("Unable to execute XPath expression", ex);
131+
catch (ParserConfigurationException ex) {
132+
logError("Unable to read XML file", ex);
133+
return false;
134+
}
135+
catch (IOException ex) {
136+
logError("Unable to read XML file", ex);
137+
return false;
138+
}
139+
catch (SAXException ex) {
140+
logError("Unable to read XML file", ex);
118141
return false;
119142
}
120143
catch (CoreException ex) {
@@ -207,4 +230,28 @@ public IStorage call() throws Exception {
207230
logInfo("Scanning complete. Execution time: " + (System.currentTimeMillis() - start) + "ms");
208231
return dialectstreams;
209232
}
233+
234+
/**
235+
* Basic SAX handler that cares only about the document namespace.
236+
*/
237+
private static class NamespaceHandler extends DefaultHandler {
238+
239+
private String namespace;
240+
241+
/**
242+
* Saves the document namespace, then does nothing after that.
243+
*
244+
* @param uri
245+
* @param localName
246+
* @param qName
247+
* @param attributes
248+
*/
249+
@Override
250+
public void startElement(String uri, String localName, String qName, Attributes attributes) {
251+
252+
if (namespace == null) {
253+
namespace = uri;
254+
}
255+
}
256+
}
210257
}

0 commit comments

Comments
 (0)