/* * Copyright 2012 LinkedIn Corp. * * Licensed 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 azkaban.utils; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.io.Reader; import java.io.Writer; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import org.codehaus.jackson.JsonFactory; import org.codehaus.jackson.JsonNode; import org.codehaus.jackson.JsonParser; import org.codehaus.jackson.map.ObjectMapper; import org.codehaus.jackson.map.ObjectWriter; public class JSONUtils { /** * The constructor. Cannot construct this class. */ private JSONUtils() { } public static String toJSON(Object obj) { return toJSON(obj, false); } public static String toJSON(Object obj, boolean prettyPrint) { ObjectMapper mapper = new ObjectMapper(); try { if (prettyPrint) { ObjectWriter writer = mapper.writerWithDefaultPrettyPrinter(); return writer.writeValueAsString(obj); } return mapper.writeValueAsString(obj); } catch (Exception e) { throw new RuntimeException(e); } } public static void toJSON(Object obj, OutputStream stream) { toJSON(obj, stream, false); } public static void toJSON(Object obj, OutputStream stream, boolean prettyPrint) { ObjectMapper mapper = new ObjectMapper(); try { if (prettyPrint) { ObjectWriter writer = mapper.writerWithDefaultPrettyPrinter(); writer.writeValue(stream, obj); return; } mapper.writeValue(stream, obj); } catch (Exception e) { throw new RuntimeException(e); } } public static void toJSON(Object obj, File file) throws IOException { toJSON(obj, file, false); } public static void toJSON(Object obj, File file, boolean prettyPrint) throws IOException { BufferedOutputStream stream = new BufferedOutputStream(new FileOutputStream(file)); try { toJSON(obj, stream, prettyPrint); } finally { stream.close(); } } public static Object parseJSONFromStringQuiet(String json) { try { return parseJSONFromString(json); } catch (IOException e) { e.printStackTrace(); return null; } } public static Object parseJSONFromString(String json) throws IOException { ObjectMapper mapper = new ObjectMapper(); JsonFactory factory = new JsonFactory(); JsonParser parser = factory.createJsonParser(json); JsonNode node = mapper.readTree(parser); return toObjectFromJSONNode(node); } public static Object parseJSONFromFile(File file) throws IOException { ObjectMapper mapper = new ObjectMapper(); JsonFactory factory = new JsonFactory(); JsonParser parser = factory.createJsonParser(file); JsonNode node = mapper.readTree(parser); return toObjectFromJSONNode(node); } public static Object parseJSONFromReader(Reader reader) throws IOException { ObjectMapper mapper = new ObjectMapper(); JsonFactory factory = new JsonFactory(); JsonParser parser = factory.createJsonParser(reader); JsonNode node = mapper.readTree(parser); return toObjectFromJSONNode(node); } private static Object toObjectFromJSONNode(JsonNode node) { if (node.isObject()) { HashMap<String, Object> obj = new HashMap<String, Object>(); Iterator<String> iter = node.getFieldNames(); while (iter.hasNext()) { String fieldName = iter.next(); JsonNode subNode = node.get(fieldName); Object subObj = toObjectFromJSONNode(subNode); obj.put(fieldName, subObj); } return obj; } else if (node.isArray()) { ArrayList<Object> array = new ArrayList<Object>(); Iterator<JsonNode> iter = node.getElements(); while (iter.hasNext()) { JsonNode element = iter.next(); Object subObject = toObjectFromJSONNode(element); array.add(subObject); } return array; } else if (node.isTextual()) { return node.asText(); } else if (node.isNumber()) { if (node.isInt()) { return node.asInt(); } else if (node.isLong()) { return node.asLong(); } else if (node.isDouble()) { return node.asDouble(); } else { System.err.println("ERROR What is this!? " + node.getNumberType()); return null; } } else if (node.isBoolean()) { return node.asBoolean(); } else { return null; } } public static long getLongFromObject(Object obj) { if (obj instanceof Integer) { return Long.valueOf((Integer) obj); } return (Long) obj; } /* * Writes json to a stream without using any external dependencies. * * This is useful for plugins or extensions that want to write properties to a * writer without having to import the jackson, or json libraries. The * properties are expected to be a map of String keys and String values. * * The other json writing methods are more robust and will handle more cases. */ public static void writePropsNoJarDependency(Map<String, String> properties, Writer writer) throws IOException { writer.write("{\n"); int size = properties.size(); for (Map.Entry<String, String> entry : properties.entrySet()) { // tab the space writer.write('\t'); // Write key writer.write(quoteAndClean(entry.getKey())); writer.write(':'); writer.write(quoteAndClean(entry.getValue())); size -= 1; // Add comma only if it's not the last one if (size > 0) { writer.write(','); } writer.write('\n'); } writer.write("}"); } private static String quoteAndClean(String str) { if (str == null || str.isEmpty()) { return "\"\""; } StringBuffer buffer = new StringBuffer(str.length()); buffer.append('"'); for (int i = 0; i < str.length(); ++i) { char ch = str.charAt(i); switch (ch) { case '\b': buffer.append("\\b"); break; case '\t': buffer.append("\\t"); break; case '\n': buffer.append("\\n"); break; case '\f': buffer.append("\\f"); break; case '\r': buffer.append("\\r"); break; case '"': case '\\': case '/': buffer.append('\\'); buffer.append(ch); break; default: if (isCharSpecialUnicode(ch)) { buffer.append("\\u"); String hexCode = Integer.toHexString(ch); int lengthHexCode = hexCode.length(); if (lengthHexCode < 4) { buffer.append("0000".substring(0, 4 - lengthHexCode)); } buffer.append(hexCode); } else { buffer.append(ch); } } } buffer.append('"'); return buffer.toString(); } private static boolean isCharSpecialUnicode(char ch) { if (ch < ' ') { return true; } else if (ch >= '\u0080' && ch < '\u00a0') { return true; } else if (ch >= '\u2000' && ch < '\u2100') { return true; } return false; } }