Mercurial > hg > thermostat-ng
view common/src/main/java/com/redhat/thermostat/common/yaml/YamlToJson.java @ 25:dd0992bd51aa
Add Maven Central upload, refactor lang-schema and json libs to thermostat-common library
- merge common-json and common-lang-schema packages into thermostat- common.
- add targets to generate Javadoc and source jars, and modify sources
to remove some Javadoc warnings.
- add targets to sign and deploy thermostat-common to Maven Central.
Reviewed-by: sgehwolf, neugens
Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2017-September/025214.html
author | Simon Tooke <stooke@redhat.com> |
---|---|
date | Fri, 29 Sep 2017 14:48:00 -0400 |
parents | common/json/src/main/java/com/redhat/thermostat/common/yaml/YamlToJson.java@ab2706b9b1e3 |
children | 33cf0b946e3d |
line wrap: on
line source
/* * Copyright 2012-2017 Red Hat, Inc. * * This file is part of Thermostat. * * Thermostat is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published * by the Free Software Foundation; either version 2, or (at your * option) any later version. * * Thermostat is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Thermostat; see the file COPYING. If not see * <http://www.gnu.org/licenses/>. * * Linking this code with other modules is making a combined work * based on this code. Thus, the terms and conditions of the GNU * General Public License cover the whole combination. * * As a special exception, the copyright holders of this code give * you permission to link this code with independent modules to * produce an executable, regardless of the license terms of these * independent modules, and to copy and distribute the resulting * executable under terms of your choice, provided that you also * meet, for each linked independent module, the terms and conditions * of the license of that module. An independent module is a module * which is not derived from or based on this code. If you modify * this code, you may extend this exception to your version of the * library, but you are not obligated to do so. If you do not wish * to do so, delete this exception statement from your version. */ package com.redhat.thermostat.common.yaml; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonNull; import com.google.gson.JsonObject; import com.google.gson.JsonPrimitive; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.io.StringWriter; import java.io.Writer; import java.util.Stack; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * Utility class to read YAML files and convert to GSON objects * * Limitations: * Only enough code to read Swagger YAML is implemented * $ref only works within the same document, not across the network */ public class YamlToJson { public YamlToJson() { } public JsonObject yamlToJsonObject(final File fn) throws IOException { try (final Reader in = new FileReader(fn)) { return yamlToJsonObject(in); } } public JsonObject yamlToJsonObject(final String yaml) throws IOException { try (final Reader in = new StringReader(yaml)) { return yamlToJsonObject(in); } } public JsonObject yamlToJsonObject(final Reader in) throws IOException { try (final PushableReader pr = new PushableReader(in instanceof BufferedReader ? (BufferedReader)in : new BufferedReader(in));) { final JsonObject obj = new JsonObject(); yamlToJson(pr, obj, 0); pr.close(); return obj; } } private void yamlToJson(PushableReader in, JsonElement parent, int currentIndent) throws IOException { for (String s = in.readLine(); s != null; s = in.readLine()) { YamlLine line = new YamlLine(s); if (line.indent == 0 && line.value == null && line.name == null) { // blsnk or unparseable line continue; } if (line.indent < currentIndent) { in.push(s); return; } final JsonElement child; if (line.hasColon) { if (line.value != null && !line.value.isEmpty()) { if (">-".equals(line.value)) { //the next few lines are the value for the current line child = makeUnquotedPrimitive(absorb(in, currentIndent)); } else { JsonElement ce = makeUnquotedPrimitive(line.value); if (parent.isJsonArray()) { JsonObject childobj = new JsonObject(); childobj.add(makeUnquotedString(line.name), ce); child = childobj; } else { child = ce; } } } else { // no value specified; this could be the start of an object or array final String next = in.readLine(); boolean isArray = false; if (next != null) { YamlLine nextLine = new YamlLine(next); isArray = nextLine.hasDashPrefix; in.push(next); } child = isArray ? new JsonArray() : new JsonObject(); yamlToJson(in, child, line.indent); } } else { child = (line.value != null) ? makeUnquotedPrimitive(line.value) : new JsonPrimitive(""); } if (parent.isJsonArray()) { if (line.hasDashPrefix) { JsonArray parray = parent.getAsJsonArray(); parray.add(child); } else { System.err.println("Array member must begin with dash: " + s); } } else if (parent.isJsonObject()) { JsonObject pobject = parent.getAsJsonObject(); pobject.add(makeUnquotedString(line.name), child); } else { System.err.println("Error: parent is neither object nor array"); } currentIndent = line.indent; } } private static String makeUnquotedString(final String s) { String ret = s; if (s.length() >= 2) { if ((s.charAt(0) == '\'') && (s.charAt(s.length() - 1) == '\'') || (s.charAt(0) == '"') && (s.charAt(s.length() - 1) == '"')) { ret = s.substring(1, s.length() - 1); } } return ret; } private static JsonPrimitive makeUnquotedPrimitive(final String s) { final String uqString = makeUnquotedString(s); // anything quoted will return a string, otherwise try to parse if (uqString.length() == s.length()) { if ("true".equals(uqString)) return new JsonPrimitive(true); else if ("false".equals(uqString)) return new JsonPrimitive(false); else if ("null".equals(uqString)) return null; else { // test for number final char c0 = uqString.charAt(0); if (Character.isDigit(c0) || c0 == '+' || c0 == '-') { try { return new JsonPrimitive(new Long(uqString)); } catch (NumberFormatException ignored) { ; // fall through to return String } } } } return new JsonPrimitive(uqString); } private static String absorb(PushableReader in, int currentIndent) throws IOException { // append lines until the indentation is the same as the currentIndent StringBuilder a = new StringBuilder(); for (String s = in.readLine(); s != null; s = in.readLine()) { int wsCount; for (wsCount = 0; wsCount < s.length(); wsCount++) { if (!Character.isWhitespace(s.charAt(wsCount))) { break; } } if (wsCount > currentIndent) { a.append(a.length() == 0 ? s.trim() : ' ' + s.trim()); } else { in.push(s); break; } } return a.toString(); } /** * YamlLine - parse a single line of YAML file */ static class YamlLine { int indent; String name; String value; boolean hasColon; boolean hasDashPrefix; private static final String regexpr = "^([\\s]*)([-]?[\\s]*)([^:]+)([:]?)(.*)$"; private static final Pattern p = Pattern.compile(regexpr); YamlLine(String line) throws IOException { Matcher m = p.matcher(line); if (m.matches()) { final String s1 = m.group(1); // leading whitespace final String s2 = m.group(2); // optional '-' indicating array element final String s3 = m.group(3); // key final String s4 = m.group(4); // ':' final String s5 = m.group(5).trim(); // value or optional '>-' hasColon = !(s4 == null || s4.isEmpty()); hasDashPrefix = !(s2 == null || s2.isEmpty()); indent = s1.length() + (hasDashPrefix ? s2.length() : 0); if (hasColon) { name = s3.trim(); value = s5.trim(); } else { name = null; value = s3 + s5; value = value.trim(); } } else { if (line.isEmpty()) { name = null; value = null; indent = 0; } else { throw new IOException("parse error in YAML '" + line + "'"); } } } } static class PushableReader implements AutoCloseable { final Stack<String> stack = new Stack<>(); final BufferedReader in; PushableReader(BufferedReader in) { this.in = in; } String readLine() throws IOException { if (stack.isEmpty()) { return in.readLine(); } else { return stack.pop(); } } void push(String s) { stack.push(s); } @Override public void close() throws IOException { in.close(); } } /* * utility function to convert YAML file to JSON stdout */ public static void main(String[] args) { boolean pretty = false; for (final String fn : args) { if ("--pretty".equals(fn)) { pretty = true; } else if ("--help".equals("fn")) { System.err.println("YamlToJason [--pretty] [--help] infile1 [infile2] ..."); } else { try { final YamlToJson y2j = new YamlToJson(); final File fin = new File(fn); final JsonObject json = y2j.yamlToJsonObject(fin); if (pretty) { final GsonBuilder gsonBuilder = new GsonBuilder(); gsonBuilder.setPrettyPrinting(); final Gson gson = gsonBuilder.create(); System.out.println(gson.toJson(json)); } else { System.out.println(json.toString()); } } catch (IOException e) { e.printStackTrace(); } } } } }