/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE file at the root of the source
* tree and available online at
*
* https://github.com/keeps/roda
*/
package org.roda.core.data.utils;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.commons.io.IOUtils;
import org.roda.core.data.common.RodaConstants;
import org.roda.core.data.exceptions.GenericException;
import org.roda.core.data.v2.ip.metadata.DescriptiveMetadata;
import org.roda.core.data.v2.ip.metadata.DescriptiveMetadataMixIn;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.type.TypeFactory;
public final class JsonUtils {
private static final Logger LOGGER = LoggerFactory.getLogger(JsonUtils.class);
private static final String JSON_ERROR_MESSAGE = "Error while parsing JSON";
/** Private empty constructor */
private JsonUtils() {
}
public static <T> T readObjectFromFile(Path jsonFile, Class<T> objectClass) throws GenericException {
try (InputStream stream = Files.newInputStream(jsonFile)) {
return getObjectFromJson(stream, objectClass);
} catch (IOException e) {
throw new GenericException(e);
}
}
public static void writeObjectToFile(Object object, Path file) throws GenericException {
try {
String json = getJsonFromObject(object);
if (json != null) {
Files.write(file, json.getBytes(), StandardOpenOption.CREATE);
}
} catch (IOException e) {
throw new GenericException("Error writing object, as json, to file", e);
}
}
public static void appendObjectToFile(Object object, Path file) throws GenericException {
try {
String json = getJsonFromObject(object) + "\n";
Files.write(file, json.getBytes(), StandardOpenOption.APPEND);
} catch (IOException e) {
throw new GenericException("Error writing object, as json, to file", e);
}
}
public static Map<String, String> getMapFromJson(String json) {
Map<String, String> ret = new HashMap<>();
try {
ObjectMapper mapper = new ObjectMapper(new JsonFactory());
ret = mapper.readValue(json, new TypeReference<Map<String, String>>() {});
} catch (IOException e) {
LOGGER.error("Error transforming json string to Map<String,String>", e);
}
return ret;
}
public static String getJsonFromObject(Object object) {
String ret = null;
try {
ObjectMapper mapper = new ObjectMapper(new JsonFactory());
mapper = addMixinsToMapper(mapper, object);
ret = mapper.writeValueAsString(object);
} catch (IOException e) {
LOGGER.error("Error transforming object '{}' to json string", object, e);
}
return ret;
}
private static ObjectMapper addMixinsToMapper(ObjectMapper mapper, Object object) {
if (!(object instanceof DescriptiveMetadata)) {
if (object instanceof List<?>) {
List<?> objectList = (List<?>) object;
if (!objectList.isEmpty() && !(objectList.get(0) instanceof DescriptiveMetadata)) {
mapper.addMixIn(DescriptiveMetadata.class, DescriptiveMetadataMixIn.class);
}
} else {
mapper.addMixIn(DescriptiveMetadata.class, DescriptiveMetadataMixIn.class);
}
}
return mapper;
}
public static <T> T getObjectFromJson(Path json, Class<T> objectClass) throws GenericException {
T ret;
InputStream stream = null;
try {
stream = Files.newInputStream(json);
String jsonString = IOUtils.toString(stream, RodaConstants.DEFAULT_ENCODING);
ret = getObjectFromJson(jsonString, objectClass);
} catch (IOException e) {
throw new GenericException(JSON_ERROR_MESSAGE, e);
} finally {
IOUtils.closeQuietly(stream);
}
return ret;
}
public static <T> T getObjectFromJson(InputStream json, Class<T> objectClass) throws GenericException {
T ret;
try {
String jsonString = IOUtils.toString(json, RodaConstants.DEFAULT_ENCODING);
ret = getObjectFromJson(jsonString, objectClass);
} catch (IOException e) {
throw new GenericException(e);
} finally {
IOUtils.closeQuietly(json);
}
return ret;
}
public static <T> T getObjectFromJson(String json, Class<T> objectClass) throws GenericException {
try {
ObjectMapper mapper = new ObjectMapper(new JsonFactory());
return mapper.readValue(json, objectClass);
} catch (IOException e) {
throw new GenericException(JSON_ERROR_MESSAGE, e);
}
}
public static <T> List<T> getListFromJson(String json, Class<T> objectClass) throws GenericException {
try {
ObjectMapper mapper = new ObjectMapper(new JsonFactory());
TypeFactory t = TypeFactory.defaultInstance();
return mapper.readValue(json, t.constructCollectionType(ArrayList.class, objectClass));
} catch (IOException e) {
throw new GenericException(JSON_ERROR_MESSAGE, e);
}
}
public static JsonNode parseJson(String json) throws GenericException {
try {
ObjectMapper mapper = new ObjectMapper(new JsonFactory());
return mapper.readTree(json);
} catch (IOException e) {
throw new GenericException(JSON_ERROR_MESSAGE, e);
}
}
public static JsonNode parseJson(InputStream json) throws GenericException {
try {
ObjectMapper mapper = new ObjectMapper(new JsonFactory());
return mapper.readTree(json);
} catch (IOException e) {
throw new GenericException(JSON_ERROR_MESSAGE, e);
} finally {
IOUtils.closeQuietly(json);
}
}
public static String getJsonFromNode(JsonNode node) {
String ret = null;
try {
ObjectMapper mapper = new ObjectMapper(new JsonFactory());
ret = mapper.writeValueAsString(node);
} catch (IOException e) {
LOGGER.error("Error transforming object '{}' to json string", node, e);
}
return ret;
}
public static ObjectNode refactor(ObjectNode obj, Map<String, String> mapping) {
for (Entry<String, String> entry : mapping.entrySet()) {
String oldName = entry.getKey();
String newName = entry.getValue();
JsonNode jsonNode = obj.get(oldName);
if (jsonNode != null) {
obj.set(newName, jsonNode);
obj.remove(oldName);
}
}
return obj;
}
}