/* (c) 2014 LinkedIn Corp. All rights reserved. * * 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. */ package com.linkedin.cubert.utils; import java.io.IOException; import java.util.ArrayList; import java.util.List; import org.codehaus.jackson.JsonGenerationException; import org.codehaus.jackson.JsonNode; import org.codehaus.jackson.JsonParseException; import org.codehaus.jackson.JsonParser.NumberType; import org.codehaus.jackson.map.JsonMappingException; import org.codehaus.jackson.map.ObjectMapper; import org.codehaus.jackson.node.ArrayNode; import org.codehaus.jackson.node.ObjectNode; /** * Various utility methods for operating with Json objects. * * @author Maneesh Varshney * */ public class JsonUtils { private static ObjectMapper mapper; private static ObjectMapper getMapper() { if (mapper == null) { mapper = new ObjectMapper(); } return mapper; } public static JsonNode get(JsonNode node, String property) { JsonNode val = node.get(property); if (val == null) { throw new IllegalArgumentException("Property " + property + " is not defined in " + node); } return val; } public static String getText(JsonNode node, String property, String defaultValue) { if (!node.has(property)) return defaultValue; return get(node, property).getTextValue(); } public static String getText(JsonNode node, String property) { return get(node, property).getTextValue(); } public static String[] asArray(JsonNode parent, String property) { if (!parent.has(property) || parent.get(property).isNull()) return null; return asArray(get(parent, property)); } public static String[] asArray(JsonNode node) { if (node == null) throw new IllegalArgumentException("Specified JsonNode is null"); if (node.isArray()) { ArrayNode anode = (ArrayNode) node; int nelements = anode.size(); String[] array = new String[nelements]; for (int i = 0; i < nelements; i++) { array[i] = anode.get(i).getTextValue(); } return array; } else { return new String[] { node.getTextValue() }; } } public static Object asObject(JsonNode node) { if (node.isTextual()) return node.getTextValue(); else if (node.isInt()) return node.getIntValue(); else if (node.isFloatingPointNumber()) return node.getDoubleValue(); else if (node.isBoolean()) return node.getBooleanValue(); return null; } public static ObjectNode createObjectNode(Object... keyvals) { ObjectNode node = getMapper().createObjectNode(); for (int i = 0; i < keyvals.length; i += 2) { if (keyvals[i + 1] instanceof String) { node.put((String) keyvals[i], (String) keyvals[i + 1]); } else if (keyvals[i + 1] instanceof Integer) { int val = (Integer) keyvals[i + 1]; node.put((String) keyvals[i], val); } else if (keyvals[i + 1] instanceof Boolean) { boolean val = (Boolean) keyvals[i + 1]; node.put((String) keyvals[i], val); } else { node.put((String) keyvals[i], (JsonNode) keyvals[i + 1]); } } return node; } public static ArrayNode createArrayNode(String item) { return createArrayNode(new String[] { item }); } public static ArrayNode createArrayNode() { return getMapper().createArrayNode(); } public static ArrayNode createArrayNode(JsonNode... elementNodes) { ArrayNode result = getMapper().createArrayNode(); for (int i = 0; i < elementNodes.length; i++) result.add(elementNodes[i]); return result; } public static ArrayNode createArrayNode(String[] items) { ArrayNode anode = getMapper().createArrayNode(); for (String item : items) { anode.add(item); } return anode; } public static int getIndexFromArray(ArrayNode anode, JsonNode element) { for (int i = 0; i < anode.size(); i++) { if (anode.get(i) == element) return i; } return -1; } public static void deleteFromArrayNode(ArrayNode parentNode, ObjectNode operatorNode) { // TODO Auto-generated method stub int index = getIndexFromArray((ArrayNode) parentNode, operatorNode); ((ArrayNode) parentNode).remove(index); } public static JsonNode makeJson(String str) { str = str.replace('\'', '"'); try { return mapper.readValue(str, JsonNode.class); } catch (JsonParseException e) { int idx = (int) e.getLocation().getCharOffset(); System.out.println(str); if (idx >= str.length()) { idx = 1; } String substr = str.substring(0, idx); System.out.println(substr); e.printStackTrace(); } catch (JsonMappingException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { } throw new RuntimeException(); } public static ArrayList<JsonNode> toArrayList(ArrayNode arrayNode) { ArrayList<JsonNode> result = new ArrayList<JsonNode>(); for (JsonNode elem : arrayNode) result.add(elem); return result; } public static ArrayNode toArrayNode(List<JsonNode> nodelist) { ArrayNode result = createArrayNode(); for (JsonNode elem : nodelist) result.add(elem); return result; } public static JsonNode cloneNode(JsonNode json) { String str = json.toString(); try { return getMapper().readValue(str, JsonNode.class); } catch (JsonParseException e) { e.printStackTrace(); return null; } catch (JsonMappingException e) { e.printStackTrace(); return null; } catch (IOException e) { e.printStackTrace(); return null; } } public static String encodePath(JsonNode path) { if (path.isTextual()) return path.getTextValue(); else { String root = getText(path, "root"); int startDate = Integer.parseInt(getText(path, "startDate")); int endDate = Integer.parseInt(getText(path, "endDate")); if (path.get("origStartDate") != null) return String.format("%s#START%d#END%d#ORIGSTART%d", root, startDate, endDate, Integer.parseInt(getText(path, "origStartDate"))); return String.format("%s#START%d#END%d", root, startDate, endDate); } } public static JsonNode decodePath(String pathStr) { ObjectNode node = getMapper().createObjectNode(); if (pathStr.contains("#START")) { String root = pathStr.split("#START")[0]; String[] startEnd; int origStartDate = -1; int startDate, endDate; if (!pathStr.contains("#ORIGSTART")){ startEnd= pathStr.split("#START")[1].split("#END"); startDate = Integer.parseInt(startEnd[0]); endDate = Integer.parseInt(startEnd[1]); } else { startDate = Integer.parseInt(pathStr.split("#START")[1].split("#END")[0]); endDate = Integer.parseInt(pathStr.split("#START")[1].split("#END")[1].split("#ORIGSTART")[0]); origStartDate = Integer.parseInt(pathStr.split("#START")[1].split("#END")[1].split("#ORIGSTART")[1]); } node.put("root", root); node.put("startDate", startDate); node.put("endDate", endDate); if (origStartDate != -1) node.put("origStartDate", origStartDate); return node; } else { node.put("tmp", pathStr); return node.get("tmp"); } } public static boolean isPrefixArray(ArrayNode pnode, ArrayNode snode) { if (pnode == null || snode == null || pnode.size() > snode.size()) return false; for (int i = 0; i < pnode.size(); i++) { if (!pnode.get(i).getTextValue().equals(snode.get(i).getTextValue())) return false; } return true; } public static ArrayNode insertNodeListAfter(ArrayNode arrayNode, ObjectNode afterThisNode, List<ObjectNode> nodeList) { ArrayList<JsonNode> currentNodeList = JsonUtils.toArrayList(arrayNode); int insertPosition = CommonUtils.indexOfByRef(currentNodeList, afterThisNode); currentNodeList.addAll(insertPosition + 1, nodeList); return JsonUtils.toArrayNode(currentNodeList); } public static ArrayNode insertNodeListBefore(ArrayNode arrayNode, ObjectNode beforeThisNode, List<ObjectNode> nodeList) { ArrayList<JsonNode> currentNodeList = JsonUtils.toArrayList(arrayNode); int insertPosition = CommonUtils.indexOfByRef(currentNodeList, beforeThisNode); currentNodeList.addAll(insertPosition, nodeList); return JsonUtils.toArrayNode(currentNodeList); } public static Object decodeConstant(JsonNode valNode, String valType) { if (valType != null && valNode.isNumber()) { NumberType numType; Number numVal = valNode.getNumberValue(); if (valType != null) { numType = NumberType.valueOf(valType.toUpperCase()); switch (numType) { case DOUBLE: return numVal.doubleValue(); case FLOAT: return numVal.floatValue(); case INT: return numVal.intValue(); case LONG: return numVal.longValue(); default: break; } } } return asObject(valNode); } public static void prettyPrint(String json) throws JsonGenerationException, JsonMappingException, IOException { System.out.println(new ObjectMapper().writer().writeValueAsString(json)); } }