package gov.nasa.jpl.mbee.mdk.json;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.NullNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import gov.nasa.jpl.mbee.mdk.util.MDUtils;
import gov.nasa.jpl.mbee.mdk.options.MDKOptionsGroup;
import org.apache.commons.lang.math.NumberUtils;
import java.io.IOException;
import java.util.LinkedList;
import java.util.function.Function;
/**
* Created by igomes on 9/26/16.
*/
public class JacksonUtils {
private static ObjectMapper OBJECT_MAPPER_INSTANCE;
private static JsonFactory JSON_FACTORY_INSTANCE;
public static ObjectMapper getObjectMapper() {
if (OBJECT_MAPPER_INSTANCE == null) {
OBJECT_MAPPER_INSTANCE = new ObjectMapper();
if (MDUtils.isDeveloperMode()) {
OBJECT_MAPPER_INSTANCE.configure(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS, true);
if (MDKOptionsGroup.getMDKOptions().isLogJson()) {
OBJECT_MAPPER_INSTANCE.enable(SerializationFeature.INDENT_OUTPUT);
}
}
}
return OBJECT_MAPPER_INSTANCE;
}
public static JsonFactory getJsonFactory() {
if (JSON_FACTORY_INSTANCE == null) {
JSON_FACTORY_INSTANCE = new JsonFactory();
JSON_FACTORY_INSTANCE.setCodec(JacksonUtils.getObjectMapper());
}
return JSON_FACTORY_INSTANCE;
}
public static JsonNode getAtPath(JsonNode json, String path) {
if (path.startsWith("/")) {
path = path.substring(1);
}
for (String key : path.split("/")) {
key = key.replace("~0", "~").replace("~1", "/");
if (json.isArray()) {
if (!NumberUtils.isDigits(key)) {
return NullNode.getInstance();
}
int index = Integer.parseInt(key);
if (index >= json.size()) {
return NullNode.getInstance();
}
json = json.get(index);
}
else {
if (!json.has(key)) {
return NullNode.getInstance();
}
json = json.get(key);
}
}
return json;
}
public static <R> R getAtPath(JsonNode json, String path, Function<JsonNode, R> function) {
return function.apply(getAtPath(json, path));
}
@Deprecated
public static void put(ObjectNode objectNode, String fieldName, Object object) {
if (object == null) {
objectNode.putNull(fieldName);
}
else if (object instanceof JsonNode) {
objectNode.set(fieldName, (JsonNode) object);
}
else if (object instanceof String) {
objectNode.put(fieldName, (String) object);
}
else if (object instanceof Boolean) {
objectNode.put(fieldName, (Boolean) object);
}
else if (object instanceof Integer) {
objectNode.put(fieldName, (Integer) object);
}
else if (object instanceof Double) {
objectNode.put(fieldName, (Double) object);
}
else if (object instanceof Long) {
objectNode.put(fieldName, (Long) object);
}
else if (object instanceof Short) {
objectNode.put(fieldName, (Short) object);
}
else if (object instanceof Float) {
objectNode.put(fieldName, (Float) object);
}
else if (object instanceof byte[]) {
objectNode.put(fieldName, (byte[]) object);
}
}
public static ObjectNode parseJsonObject(JsonParser jsonParser) throws IOException {
JsonToken current = (jsonParser.getCurrentToken() == null ? jsonParser.nextToken() : jsonParser.getCurrentToken());
if (current != JsonToken.START_OBJECT) {
throw new IOException("Unable to build object from JSON parser.");
}
ObjectNode objectNode = getObjectMapper().readTree(jsonParser);
return objectNode;
}
public static ArrayNode parseJsonArray(JsonParser jsonParser, ArrayNode arrayNode) throws IOException {
JsonToken current = (jsonParser.getCurrentToken() == null ? jsonParser.nextToken() : jsonParser.getCurrentToken());
if (current != JsonToken.START_ARRAY) {
throw new IOException("Unable to build array from JSON parser.");
}
current = jsonParser.nextToken();
if (arrayNode == null) {
arrayNode = getObjectMapper().createArrayNode();
}
while (current != JsonToken.END_ARRAY) {
if (jsonParser.getCurrentToken() == JsonToken.START_OBJECT) {
arrayNode.add(parseJsonObject(jsonParser));
}
else if (jsonParser.getCurrentToken() == JsonToken.START_ARRAY) {
arrayNode.add(parseJsonArray(jsonParser, null));
if (jsonParser.getCurrentToken() != JsonToken.END_ARRAY) {
throw new IOException("Missed Array End.");
}
}
else {
arrayNode.add(jsonParser.getText());
}
current = jsonParser.nextToken();
}
return arrayNode;
}
public static LinkedList<ObjectNode> parseJsonResponseToObjectList(JsonParser jsonParser, ObjectNode messages) throws IOException {
JsonToken current = (jsonParser.getCurrentToken() == null ? jsonParser.nextToken() : jsonParser.getCurrentToken());
if (current != JsonToken.START_OBJECT) {
throw new IOException("Unable to build object from JSON parser.");
}
LinkedList<ObjectNode> results = new LinkedList<>();
while (current != JsonToken.END_OBJECT) {
if (jsonParser.getCurrentName() == null) {
current = jsonParser.nextToken();
continue;
}
String keyName = jsonParser.getCurrentName();
switch (keyName) {
case "orgs":
case "projects":
case "refs":
case "elements": {
jsonParser.nextToken();
current = jsonParser.nextToken();
while (current != JsonToken.END_ARRAY) {
if (current == JsonToken.START_OBJECT) {
results.add(parseJsonObject(jsonParser));
}
else {
// consume and ignore
current = jsonParser.nextToken();
}
current = jsonParser.getCurrentToken();
}
break;
}
default: {
current = jsonParser.nextToken();
if (messages != null) {
if (current == JsonToken.START_ARRAY) {
ArrayNode arraynode = messages.putArray(keyName);
JacksonUtils.parseJsonArray(jsonParser, arraynode);
}
else {
messages.put(keyName, jsonParser.getText());
}
}
}
}
current = jsonParser.nextToken();
}
return results;
}
}