package org.constellation.util.json;
import com.fasterxml.jackson.core.JsonEncoding;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.sis.util.ObjectConverters;
import org.apache.sis.util.Static;
import org.apache.sis.util.UnconvertibleObjectException;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.reflect.Array;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Collection;
/**
* @author Quentin Boileau (Geomatys)
*/
class JsonUtils extends Static {
/**
* Jackson JsonFactory used to create temporary JsonGenerators.
*/
private static final JsonFactory JSON_FACTORY = new JsonFactory();
private JsonUtils(){}
/**
* Write value object depending of object type.
*
* @param value
* @param writer
* @throws java.io.IOException
* @throws IllegalArgumentException
*/
static void writeValue(Object value, JsonGenerator writer) throws IOException, IllegalArgumentException {
if (value == null) {
writer.writeNull();
return;
}
Class binding = value.getClass();
if (binding.isArray()) {
if (byte.class.isAssignableFrom(binding.getComponentType())) {
writer.writeBinary((byte[])value);
} else {
writer.writeStartArray();
final int size = Array.getLength(value);
for (int i = 0; i < size; i++) {
writeValue(Array.get(value, i), writer);
}
writer.writeEndArray();
}
} else if (Collection.class.isAssignableFrom(binding)) {
writer.writeStartArray();
Collection coll = (Collection) value;
for (Object obj : coll) {
writeValue(obj, writer);
}
writer.writeEndArray();
} else if (Double.class.isAssignableFrom(binding)) {
writer.writeNumber((Double) value);
} else if (Float.class.isAssignableFrom(binding)) {
writer.writeNumber((Float) value);
} else if (Short.class.isAssignableFrom(binding)) {
writer.writeNumber((Short) value);
} else if (Byte.class.isAssignableFrom(binding)) {
writer.writeNumber((Byte) value);
} else if (BigInteger.class.isAssignableFrom(binding)) {
writer.writeNumber((BigInteger) value);
} else if (BigDecimal.class.isAssignableFrom(binding)) {
writer.writeNumber((BigDecimal) value);
} else if (Integer.class.isAssignableFrom(binding)) {
writer.writeNumber((Integer) value);
} else if (Long.class.isAssignableFrom(binding)) {
writer.writeNumber((Long) value);
} else if (Boolean.class.isAssignableFrom(binding)) {
writer.writeBoolean((Boolean) value);
} else if (String.class.isAssignableFrom(binding)) {
writer.writeString(String.valueOf(value));
} else {
//fallback
try {
//HACK : create a temporary writer to write object.
//In case of writeObject(value) fail input writer will not be in illegal state.
final JsonGenerator tempGenerator = JSON_FACTORY.createGenerator(new ByteArrayOutputStream(), JsonEncoding.UTF8);
tempGenerator.setCodec(new ObjectMapper());
tempGenerator.writeObject(value);
//using jackson auto mapping
writer.writeObject(value);
} catch (Throwable ex) {
// last chance with converter and toString()
writer.writeString(ObjectConverters.convert(value, String.class));
}
}
}
/**
* Try to convert a JsonNode into an Object.
* This method use Jackson ObjectMapper and ApacheSIS ObjectConverters (if JsonNode is a text).
*
* @param node JsonNode that contain value
* @param binding expected java Class
* @param parameterName parameter name for exception message purpose
* @return Object instance of {@code binding}.
* @throws IOException if node can't be converted in {@code binding}
*/
static Object readValue(JsonNode node, Class binding, String parameterName) throws IOException {
try {
ObjectMapper mapper = new ObjectMapper();
return mapper.treeToValue(node, binding);
} catch (JsonProcessingException ex) {
//mapper doesn't work
}
if (node.isTextual()) {
try {
return ObjectConverters.convert(node.textValue(), binding);
} catch (UnconvertibleObjectException ex) {
//ObjectConverters doesn't work
}
}
throw new IOException("Can't convert JSON node ("+node.getNodeType().name()+") for parameter "+parameterName+" in Java type "+binding.getName());
}
}