CAMEL-10969: Use json-simple as json parser in JSonSchemaHelper instead of our own home-ground parser.
Project: http://git-wip-us.apache.org/repos/asf/camel/repo Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/d0f31f18 Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/d0f31f18 Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/d0f31f18 Branch: refs/heads/json-simple Commit: d0f31f18f5c292f0f2e20d314adf84de45b9f15d Parents: 372f327 Author: Claus Ibsen <davscl...@apache.org> Authored: Sun Sep 24 11:25:23 2017 +0200 Committer: Claus Ibsen <davscl...@apache.org> Committed: Sun Sep 24 11:25:23 2017 +0200 ---------------------------------------------------------------------- tooling/apt/pom.xml | 23 ++-- .../tools/apt/helper/JsonSchemaHelper.java | 120 ++++++++---------- .../maven/camel-package-maven-plugin/pom.xml | 7 ++ .../maven/packaging/CollectionStringBuffer.java | 58 +++++++++ .../camel/maven/packaging/JSonSchemaHelper.java | 125 +++++++------------ 5 files changed, 176 insertions(+), 157 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/camel/blob/d0f31f18/tooling/apt/pom.xml ---------------------------------------------------------------------- diff --git a/tooling/apt/pom.xml b/tooling/apt/pom.xml index 7ba1572..7e75194 100644 --- a/tooling/apt/pom.xml +++ b/tooling/apt/pom.xml @@ -36,12 +36,21 @@ </properties> <dependencies> + + <!-- camel annotations --> <dependency> <groupId>org.apache.camel</groupId> <artifactId>spi-annotations</artifactId> <version>${project.version}</version> </dependency> + <!-- json parser --> + <dependency> + <groupId>com.github.cliftonlabs</groupId> + <artifactId>json-simple</artifactId> + <version>${json-simple2-version}</version> + </dependency> + <!-- logging --> <dependency> <groupId>org.apache.logging.log4j</groupId> @@ -58,7 +67,11 @@ <artifactId>log4j-slf4j-impl</artifactId> <scope>test</scope> </dependency> - + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-log4j12</artifactId> + <scope>test</scope> + </dependency> <!-- testing --> <dependency> @@ -67,12 +80,6 @@ <scope>test</scope> </dependency> - <!-- logging --> - <dependency> - <groupId>org.slf4j</groupId> - <artifactId>slf4j-log4j12</artifactId> - <scope>test</scope> - </dependency> </dependencies> <build> @@ -82,7 +89,7 @@ <configuration> <source>${jdk.version}</source> <target>${jdk.version}</target> - <!-- Disable annotation processing for ourselves. --> + <!-- Disable annotation processing for ourselves --> <proc>none</proc> <verbose>false</verbose> </configuration> http://git-wip-us.apache.org/repos/asf/camel/blob/d0f31f18/tooling/apt/src/main/java/org/apache/camel/tools/apt/helper/JsonSchemaHelper.java ---------------------------------------------------------------------- diff --git a/tooling/apt/src/main/java/org/apache/camel/tools/apt/helper/JsonSchemaHelper.java b/tooling/apt/src/main/java/org/apache/camel/tools/apt/helper/JsonSchemaHelper.java index 7e3ec25..f27f95c 100644 --- a/tooling/apt/src/main/java/org/apache/camel/tools/apt/helper/JsonSchemaHelper.java +++ b/tooling/apt/src/main/java/org/apache/camel/tools/apt/helper/JsonSchemaHelper.java @@ -25,8 +25,9 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; -import java.util.regex.Matcher; -import java.util.regex.Pattern; + +import org.json.simple.JsonObject; +import org.json.simple.Jsoner; /** * A helper class for <a href="http://json-schema.org/">JSON schema</a>. @@ -34,9 +35,6 @@ import java.util.regex.Pattern; public final class JsonSchemaHelper { private static final String VALID_CHARS = ".-='/\\!&():;"; - // 0 = text, 1 = enum, 2 = boolean, 3 = integer or number - private static final Pattern PATTERN = Pattern.compile("\"(.+?)\"|\\[(.+)\\]|(true|false)|(-?\\d+\\.?\\d*)"); - private static final String QUOT = """; private JsonSchemaHelper() { } @@ -326,82 +324,62 @@ public final class JsonSchemaHelper { * @param json the json * @return a list of all the rows, where each row is a set of key value pairs with metadata */ + @SuppressWarnings("unchecked") public static List<Map<String, String>> parseJsonSchema(String group, String json, boolean parseProperties) { - List<Map<String, String>> answer = new ArrayList<Map<String, String>>(); + List<Map<String, String>> answer = new ArrayList<>(); if (json == null) { return answer; } - boolean found = false; - - // parse line by line - String[] lines = json.split("\n"); - for (String line : lines) { - // we need to find the group first - if (!found) { - String s = line.trim(); - found = s.startsWith("\"" + group + "\":") && s.endsWith("{"); - continue; - } - - // we should stop when we end the group - if (line.equals(" },") || line.equals(" }")) { - break; - } - - // need to safe encode \" so we can parse the line - line = line.replaceAll("\"\\\\\"\"", '"' + QUOT + '"'); - - Map<String, String> row = new LinkedHashMap<String, String>(); - Matcher matcher = PATTERN.matcher(line); - - String key; - if (parseProperties) { - // when parsing properties the first key is given as name, so the first parsed token is the value of the name - key = "name"; - } else { - key = null; - } - while (matcher.find()) { - if (key == null) { - key = matcher.group(1); - } else { - String value = matcher.group(1); - if (value != null) { - // its text based - value = value.trim(); - // decode - value = value.replaceAll(QUOT, "\""); - value = decodeJson(value); - } - if (value == null) { - // not text then its maybe an enum? - value = matcher.group(2); - if (value != null) { - // its an enum so strip out " and trim spaces after comma - value = value.replaceAll("\"", ""); - value = value.replaceAll(", ", ","); - value = value.trim(); - } + // convert into a List<Map<String, String>> structure which is expected as output from this parser + JsonObject output = Jsoner.deserialize(json, new JsonObject()); + for (String key : output.keySet()) { + Map row = output.getMap(key); + if (key.equals(group)) { + if (parseProperties) { + // flattern each entry in the row with name as they key, and its value as the content (its a map also) + for (Object obj : row.entrySet()) { + Map.Entry entry = (Map.Entry) obj; + Map<String, String> newRow = new LinkedHashMap(); + newRow.put("name", entry.getKey().toString()); + + Map newData = transformMap((Map) entry.getValue()); + newRow.putAll(newData); + answer.add(newRow); } - if (value == null) { - // not text then its maybe a boolean? - value = matcher.group(3); - } - if (value == null) { - // not text then its maybe a integer? - value = matcher.group(4); - } - if (value != null) { - row.put(key, value); + } else { + // flattern each entry in the row as a list of single Map<key, value> elements + Map newData = transformMap(row); + for (Object obj : newData.entrySet()) { + Map.Entry entry = (Map.Entry) obj; + Map<String, String> newRow = new LinkedHashMap<>(); + newRow.put(entry.getKey().toString(), entry.getValue().toString()); + answer.add(newRow); } - // reset - key = null; } } - if (!row.isEmpty()) { - answer.add(row); + } + + return answer; + } + + private static Map<String, String> transformMap(Map jsonMap) { + Map<String, String> answer = new LinkedHashMap<>(); + + for (Object rowObj : jsonMap.entrySet()) { + Map.Entry rowEntry = (Map.Entry) rowObj; + // if its a list type then its an enum, and we need to parse it as a single line separated with comma + // to be backwards compatible + Object newValue = rowEntry.getValue(); + if (newValue instanceof List) { + List list = (List) newValue; + CollectionStringBuffer csb = new CollectionStringBuffer(","); + for (Object line : list) { + csb.append(line); + } + newValue = csb.toString(); } + answer.put(rowEntry.getKey().toString(), newValue.toString()); } return answer; http://git-wip-us.apache.org/repos/asf/camel/blob/d0f31f18/tooling/maven/camel-package-maven-plugin/pom.xml ---------------------------------------------------------------------- diff --git a/tooling/maven/camel-package-maven-plugin/pom.xml b/tooling/maven/camel-package-maven-plugin/pom.xml index d9ad4cf..7405c23 100644 --- a/tooling/maven/camel-package-maven-plugin/pom.xml +++ b/tooling/maven/camel-package-maven-plugin/pom.xml @@ -46,6 +46,13 @@ <dependencies> + <!-- json parser --> + <dependency> + <groupId>com.github.cliftonlabs</groupId> + <artifactId>json-simple</artifactId> + <version>${json-simple2-version}</version> + </dependency> + <dependency> <groupId>org.mvel</groupId> <artifactId>mvel2</artifactId> http://git-wip-us.apache.org/repos/asf/camel/blob/d0f31f18/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/CollectionStringBuffer.java ---------------------------------------------------------------------- diff --git a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/CollectionStringBuffer.java b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/CollectionStringBuffer.java new file mode 100644 index 0000000..00c49f8 --- /dev/null +++ b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/CollectionStringBuffer.java @@ -0,0 +1,58 @@ +/** + * 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. + */ +package org.apache.camel.maven.packaging; + +/** + * A little helper class for converting a collection of values to a (usually comma separated) string. + */ +public class CollectionStringBuffer { + + private final StringBuilder buffer = new StringBuilder(); + private String separator; + private boolean first = true; + + public CollectionStringBuffer() { + this(", "); + } + + public CollectionStringBuffer(String separator) { + this.separator = separator; + } + + @Override + public String toString() { + return buffer.toString(); + } + + public void append(Object value) { + if (first) { + first = false; + } else { + buffer.append(separator); + } + buffer.append(value); + } + + public String getSeparator() { + return separator; + } + + public void setSeparator(String separator) { + this.separator = separator; + } + +} http://git-wip-us.apache.org/repos/asf/camel/blob/d0f31f18/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/JSonSchemaHelper.java ---------------------------------------------------------------------- diff --git a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/JSonSchemaHelper.java b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/JSonSchemaHelper.java index 96f3b3c..feafe5c 100644 --- a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/JSonSchemaHelper.java +++ b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/JSonSchemaHelper.java @@ -20,14 +20,11 @@ import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -public final class JSonSchemaHelper { +import org.json.simple.JsonObject; +import org.json.simple.Jsoner; - // 0 = text, 1 = enum, 2 = boolean, 3 = integer or number - private static final Pattern PATTERN = Pattern.compile("\"(.+?)\"|\\[(.+)\\]|(true|false)|(-?\\d+\\.?\\d*)"); - private static final String QUOT = """; +public final class JSonSchemaHelper { private JSonSchemaHelper() { } @@ -39,93 +36,65 @@ public final class JSonSchemaHelper { * @param json the json * @return a list of all the rows, where each row is a set of key value pairs with metadata */ + @SuppressWarnings("unchecked") public static List<Map<String, String>> parseJsonSchema(String group, String json, boolean parseProperties) { - List<Map<String, String>> answer = new ArrayList<Map<String, String>>(); + List<Map<String, String>> answer = new ArrayList<>(); if (json == null) { return answer; } - boolean found = false; - - // parse line by line - String[] lines = json.split("\n"); - for (String line : lines) { - // we need to find the group first - if (!found) { - String s = line.trim(); - found = s.startsWith("\"" + group + "\":") && s.endsWith("{"); - continue; - } - - // we should stop when we end the group - if (line.equals(" },") || line.equals(" }")) { - break; - } - - // need to safe encode \" so we can parse the line - line = line.replaceAll("\"\\\\\"\"", '"' + QUOT + '"'); - - Map<String, String> row = new LinkedHashMap<String, String>(); - Matcher matcher = PATTERN.matcher(line); - - String key; - if (parseProperties) { - // when parsing properties the first key is given as name, so the first parsed token is the value of the name - key = "name"; - } else { - key = null; - } - while (matcher.find()) { - if (key == null) { - key = matcher.group(1); - } else { - String value = matcher.group(1); - if (value != null) { - // its text based - value = value.trim(); - // decode - value = value.replaceAll(QUOT, "\""); - value = decodeJson(value); - } - if (value == null) { - // not text then its maybe an enum? - value = matcher.group(2); - if (value != null) { - // its an enum so strip out " and trim spaces after comma - value = value.replaceAll("\"", ""); - value = value.replaceAll(", ", ","); - value = value.trim(); - } - } - if (value == null) { - // not text then its maybe a boolean? - value = matcher.group(3); + // convert into a List<Map<String, String>> structure which is expected as output from this parser + JsonObject output = Jsoner.deserialize(json, new JsonObject()); + for (String key : output.keySet()) { + Map row = output.getMap(key); + if (key.equals(group)) { + if (parseProperties) { + // flattern each entry in the row with name as they key, and its value as the content (its a map also) + for (Object obj : row.entrySet()) { + Map.Entry entry = (Map.Entry) obj; + Map<String, String> newRow = new LinkedHashMap(); + newRow.put("name", entry.getKey().toString()); + + Map newData = transformMap((Map) entry.getValue()); + newRow.putAll(newData); + answer.add(newRow); } - if (value == null) { - // not text then its maybe a integer? - value = matcher.group(4); - } - if (value != null) { - row.put(key, value); + } else { + // flattern each entry in the row as a list of single Map<key, value> elements + Map newData = transformMap(row); + for (Object obj : newData.entrySet()) { + Map.Entry entry = (Map.Entry) obj; + Map<String, String> newRow = new LinkedHashMap<>(); + newRow.put(entry.getKey().toString(), entry.getValue().toString()); + answer.add(newRow); } - // reset - key = null; } } - if (!row.isEmpty()) { - answer.add(row); - } } return answer; } - private static String decodeJson(String value) { - // json encodes a \ as \\ so we need to decode from \\ back to \ - if ("\\\\".equals(value)) { - value = "\\"; + private static Map<String, String> transformMap(Map jsonMap) { + Map<String, String> answer = new LinkedHashMap<>(); + + for (Object rowObj : jsonMap.entrySet()) { + Map.Entry rowEntry = (Map.Entry) rowObj; + // if its a list type then its an enum, and we need to parse it as a single line separated with comma + // to be backwards compatible + Object newValue = rowEntry.getValue(); + if (newValue instanceof List) { + List list = (List) newValue; + CollectionStringBuffer csb = new CollectionStringBuffer(","); + for (Object line : list) { + csb.append(line); + } + newValue = csb.toString(); + } + answer.put(rowEntry.getKey().toString(), newValue.toString()); } - return value; + + return answer; } /**