package dk.silverbullet.telemed.questionnaire.expression;
import java.lang.reflect.Array;
import java.lang.reflect.Type;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
public class ExpressionInterfaceAdapter<T extends Expression<?>> implements JsonSerializer<T>, JsonDeserializer<T> {
public JsonElement serialize(T object, Type interfaceType, JsonSerializationContext context) {
final JsonObject wrapper = new JsonObject();
if (object instanceof BinaryOperation) {
JsonObject operands = new JsonObject();
operands.add("left", context.serialize(((BinaryOperation<?, ?>) object).getLeft(), Expression.class));
operands.add("right", context.serialize(((BinaryOperation<?, ?>) object).getRight(), Expression.class));
if (object instanceof NumericalBinaryOperation) { // taking two operands
if (object instanceof AddExpression) {
wrapper.add("add", operands);
} else if (object instanceof SubtractExpression) {
wrapper.add("sub", operands);
} else if (object instanceof MultiplyExpression) {
wrapper.add("mul", operands);
} else if (object instanceof DivideExpression) {
wrapper.add("div", operands);
} else
throw new RuntimeException("Unknown object type: " + object.getClass().getName());
} else if (object instanceof CompareExpression) { // taking two operands
if (object instanceof LessThan) {
wrapper.add("lt", operands);
} else if (object instanceof GreaterThan) {
wrapper.add("gt", operands);
} else if (object instanceof LessThanOrEqual) {
wrapper.add("lte", operands);
} else if (object instanceof GreaterThanOrEqual) {
wrapper.add("gte", operands);
} else if (object instanceof Equals) {
wrapper.add("eq", operands);
} else
throw new RuntimeException("Unknown object type: " + object.getClass().getName());
}
} else if (object instanceof Variable) {
wrapper.addProperty("type", "name");
wrapper.addProperty("value", ((Variable<?>) object).getName());
} else if (object instanceof Constant) {
Constant<?> value = (Constant<?>) object;
wrapper.addProperty("type", value.getType());
wrapper.add("value", context.serialize(((Constant<?>) object).getValue()));
} else
throw new RuntimeException("Unknown object type: " + object.getClass().getName());
return wrapper;
}
@SuppressWarnings({ "unchecked", "rawtypes" })
public T deserialize(JsonElement elem, Type interfaceType, JsonDeserializationContext context)
throws JsonParseException {
final JsonObject wrapper = (JsonObject) elem;
if (wrapper.has("add")) {
JsonElement operands = wrapper.get("add");
return context.deserialize(operands, AddExpression.class);
} else if (wrapper.has("sub")) {
JsonElement operands = wrapper.get("sub");
return context.deserialize(operands, SubtractExpression.class);
} else if (wrapper.has("mul")) {
JsonElement operands = wrapper.get("mul");
return context.deserialize(operands, MultiplyExpression.class);
} else if (wrapper.has("div")) {
JsonElement operands = wrapper.get("div");
return context.deserialize(operands, DivideExpression.class);
} else if (wrapper.has("lt")) {
JsonElement operands = wrapper.get("lt");
return context.deserialize(operands, LessThan.class);
} else if (wrapper.has("lte")) {
JsonElement operands = wrapper.get("lte");
return context.deserialize(operands, LessThanOrEqual.class);
} else if (wrapper.has("gt")) {
JsonElement operands = wrapper.get("gt");
return context.deserialize(operands, GreaterThan.class);
} else if (wrapper.has("gte")) {
JsonElement operands = wrapper.get("gte");
return context.deserialize(operands, GreaterThanOrEqual.class);
} else if (wrapper.has("eq")) {
JsonElement operands = wrapper.get("eq");
return context.deserialize(operands, Equals.class);
} else if (wrapper.has("type")) {
String typeName = wrapper.get("type").getAsString();
if (typeName.equals("name")) {
return (T) new Variable<Object>(wrapper.get("value").getAsString(), Object.class);
} else {
Class<?>[] types = new Class[] { Integer.class, Float.class, Double.class, String.class, Short.class,
Byte.class, Long.class, Boolean.class };
boolean array = typeName.endsWith("[]");
if (array)
typeName = typeName.substring(0, typeName.length() - 2);
for (Class<?> cls : types) {
String name = cls.getName();
if (name.substring(name.lastIndexOf('.') + 1).startsWith(typeName)) {
if (array) {
return (T) new Constant(context.deserialize(wrapper.get("value"), Array.newInstance(cls, 0)
.getClass()));
} else {
return (T) new Constant(context.deserialize(wrapper.get("value"), cls));
}
}
}
}
}
throw new JsonParseException("Unrecognized element: " + elem);
}
}