You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2023/10/02 14:34:40 UTC
[camel] branch main updated: CAMEL-19936: camel-xml-io - Parsing error with line precise error (#11627)
This is an automated email from the ASF dual-hosted git repository.
davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/main by this push:
new c74b0a25af9 CAMEL-19936: camel-xml-io - Parsing error with line precise error (#11627)
c74b0a25af9 is described below
commit c74b0a25af97f7d7be03a824c8f594e528a5adb8
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Mon Oct 2 16:34:33 2023 +0200
CAMEL-19936: camel-xml-io - Parsing error with line precise error (#11627)
---
.../main/java/org/apache/camel/util/IOHelper.java | 28 ++++++++
.../java/org/apache/camel/xml/in/BaseParser.java | 25 +++++++
.../xml/io/XmlPullParserLocationException.java | 77 ++++++++++++++++++++++
.../org/apache/camel/xml/in/ModelParserTest.java | 21 ++++++
.../resources/invalid/convertBodyParseError.xml | 25 +++++++
5 files changed, 176 insertions(+)
diff --git a/core/camel-util/src/main/java/org/apache/camel/util/IOHelper.java b/core/camel-util/src/main/java/org/apache/camel/util/IOHelper.java
index e18d2168e46..c5892043305 100644
--- a/core/camel-util/src/main/java/org/apache/camel/util/IOHelper.java
+++ b/core/camel-util/src/main/java/org/apache/camel/util/IOHelper.java
@@ -475,6 +475,34 @@ public final class IOHelper {
}
}
+ /**
+ * Loads the entire stream into memory as a String and returns the given line number.
+ * <p/>
+ * Warning, don't use for crazy big streams :)
+ */
+ public static String loadTextLine(InputStream in, int lineNumber) throws IOException {
+ int i = 0;
+ InputStreamReader isr = new InputStreamReader(in);
+ try {
+ BufferedReader reader = buffered(isr);
+ while (true) {
+ String line = reader.readLine();
+ if (line != null) {
+ i++;
+ if (i >= lineNumber) {
+ return line;
+ }
+ } else {
+ break;
+ }
+ }
+ } finally {
+ close(isr, in);
+ }
+
+ return null;
+ }
+
/**
* Appends the text to the file.
*/
diff --git a/core/camel-xml-io/src/main/java/org/apache/camel/xml/in/BaseParser.java b/core/camel-xml-io/src/main/java/org/apache/camel/xml/in/BaseParser.java
index 1a181110fae..aa168ff15f5 100644
--- a/core/camel-xml-io/src/main/java/org/apache/camel/xml/in/BaseParser.java
+++ b/core/camel-xml-io/src/main/java/org/apache/camel/xml/in/BaseParser.java
@@ -49,6 +49,7 @@ import org.apache.camel.util.URISupport;
import org.apache.camel.xml.io.MXParser;
import org.apache.camel.xml.io.XmlPullParser;
import org.apache.camel.xml.io.XmlPullParserException;
+import org.apache.camel.xml.io.XmlPullParserLocationException;
public class BaseParser {
@@ -103,6 +104,30 @@ public class BaseParser {
T definition, AttributeHandler<T> attributeHandler, ElementHandler<T> elementHandler, ValueHandler<T> valueHandler,
boolean supportsExternalNamespaces)
throws IOException, XmlPullParserException {
+
+ try {
+ return doParseXml(definition, attributeHandler, elementHandler, valueHandler, supportsExternalNamespaces);
+ } catch (Exception e) {
+ if (e instanceof XmlPullParserLocationException) {
+ throw e;
+ }
+ // wrap in XmlPullParserLocationException so we have line-precise error
+ String msg = e.getMessage();
+ Throwable cause = e;
+ if (e instanceof XmlPullParserException) {
+ if (e.getCause() != null) {
+ cause = e.getCause();
+ msg = e.getCause().getMessage();
+ }
+ }
+ throw new XmlPullParserLocationException(msg, resource, parser.getLineNumber(), parser.getColumnNumber(), cause);
+ }
+ }
+
+ protected <T> T doParseXml(
+ T definition, AttributeHandler<T> attributeHandler, ElementHandler<T> elementHandler, ValueHandler<T> valueHandler,
+ boolean supportsExternalNamespaces)
+ throws IOException, XmlPullParserException {
if (definition instanceof LineNumberAware) {
// we want to get the line number where the tag starts (in case its multi-line)
int line = parser.getStartLineNumber();
diff --git a/core/camel-xml-io/src/main/java/org/apache/camel/xml/io/XmlPullParserLocationException.java b/core/camel-xml-io/src/main/java/org/apache/camel/xml/io/XmlPullParserLocationException.java
new file mode 100644
index 00000000000..ca7e21f9b35
--- /dev/null
+++ b/core/camel-xml-io/src/main/java/org/apache/camel/xml/io/XmlPullParserLocationException.java
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* -*- c-basic-offset: 4; indent-tabs-mode: nil; -*- //------100-columns-wide------>|*/
+// for license please see accompanying LICENSE.txt file (available also at http://www.xmlpull.org/)
+package org.apache.camel.xml.io;
+
+import org.apache.camel.spi.Resource;
+import org.apache.camel.util.IOHelper;
+
+/**
+ * This exception is thrown to signal XML Pull Parser related faults.
+ */
+public class XmlPullParserLocationException extends RuntimeException {
+ private final int row;
+ private final int column;
+ private final Resource resource;
+
+ public XmlPullParserLocationException(String s, Resource resource, int row, int column, Throwable cause) {
+ super(createMessage(s, resource, row, column, cause), cause);
+ this.row = row;
+ this.column = column;
+ this.resource = resource;
+ }
+
+ public int getLineNumber() {
+ return row;
+ }
+
+ public int getColumnNumber() {
+ return column;
+ }
+
+ public Resource getResource() {
+ return resource;
+ }
+
+ private static String createMessage(String s, Resource resource, int row, int column, Throwable cause) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(cause.getMessage()).append("\n");
+ if (resource != null) {
+ sb.append("in ").append(resource.getLocation()).append(", line ")
+ .append(row).append(", column ").append(column)
+ .append(":\n");
+ try {
+ String line = IOHelper.loadTextLine(resource.getInputStream(), row);
+ if (line != null) {
+ sb.append(line).append("\n");
+ if (column > 1) {
+ String pad = " ".repeat(column - 2);
+ sb.append(pad);
+ }
+ sb.append("^\n");
+ }
+ } catch (Exception e) {
+ // ignore
+ }
+ sb.append("\n");
+ }
+ return sb.toString();
+ }
+
+}
diff --git a/core/camel-xml-io/src/test/java/org/apache/camel/xml/in/ModelParserTest.java b/core/camel-xml-io/src/test/java/org/apache/camel/xml/in/ModelParserTest.java
index d5c68160ae9..51e8864348f 100644
--- a/core/camel-xml-io/src/test/java/org/apache/camel/xml/in/ModelParserTest.java
+++ b/core/camel-xml-io/src/test/java/org/apache/camel/xml/in/ModelParserTest.java
@@ -50,6 +50,9 @@ import org.apache.camel.model.rest.ParamDefinition;
import org.apache.camel.model.rest.RestDefinition;
import org.apache.camel.model.rest.RestsDefinition;
import org.apache.camel.model.rest.VerbDefinition;
+import org.apache.camel.spi.Resource;
+import org.apache.camel.support.ResourceHelper;
+import org.apache.camel.xml.io.XmlPullParserLocationException;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
@@ -60,6 +63,7 @@ import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
public class ModelParserTest {
@@ -420,6 +424,23 @@ public class ModelParserTest {
assertEquals("myPolicy", dlc.getRedeliveryPolicyRef());
}
+ @Test
+ public void testParseError() throws Exception {
+ Path dir = getResourceFolder();
+ Path path = new File(dir.toFile() + "/invalid", "convertBodyParseError.xml").toPath();
+ Resource resource = ResourceHelper.fromString("file:convertBodyParseError.xml", Files.readString(path));
+ try {
+ ModelParser parser = new ModelParser(resource, NAMESPACE);
+ parser.parseRoutesDefinition();
+ fail("Should throw exception");
+ } catch (XmlPullParserLocationException e) {
+ assertEquals(22, e.getLineNumber());
+ assertEquals(25, e.getColumnNumber());
+ assertEquals("file:convertBodyParseError.xml", e.getResource().getLocation());
+ assertTrue(e.getMessage().startsWith("Unexpected attribute '{}ref'"));
+ }
+ }
+
private Path getResourceFolder() {
String childFileString = getClass().getClassLoader().getResource("barInterceptorRoute.xml").getFile();
File parentFile = new File(childFileString).getParentFile();
diff --git a/core/camel-xml-io/src/test/resources/invalid/convertBodyParseError.xml b/core/camel-xml-io/src/test/resources/invalid/convertBodyParseError.xml
new file mode 100644
index 00000000000..bf2c966f6bf
--- /dev/null
+++ b/core/camel-xml-io/src/test/resources/invalid/convertBodyParseError.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+-->
+<routes id="camel" xmlns="http://camel.apache.org/schema/spring">
+ <route>
+ <from ref="seda:a"/>
+ <convertBodyTo type="java.lang.Integer"/>
+ </route>
+</routes>