// Path: src/main/java/tw/me/ychuang/rpc/Response.java
// public class Response {
// 	private static final Logger log = LoggerFactory.getLogger(Response.class);
// 
// 	/**
// 	 * A kind of constructor
// 	 * 
// 	 * @param id unique id
// 	 * @param result a result
// 	 */
// 	public Response(Long id, Result result, String resultClass) {
// 		super();
// 		this.id = id;
// 		this.result = result;
// 		this.resultClass = resultClass;
// 	}
// 
// 	/**
// 	 * Response's id
// 	 */
// 	private final Long id;
// 
// 	/**
// 	 * Getter method for field 'id'
// 	 * 
// 	 * @return response's unqiue id
// 	 */
// 	public Long getId() {
// 		return this.id;
// 	}
// 
// 	/**
// 	 * A result is wrapped in this response
// 	 */
// 	private final Result result;
// 
// 	/**
// 	 * Getter method for field 'result'
// 	 * 
// 	 * @return a result
// 	 */
// 	public Result getResult() {
// 		return this.result;
// 	}
// 
// 	/**
// 	 * A class name of result
// 	 */
// 	private final String resultClass;
// 
// 	/**
// 	 * Getter method for field 'resultClass'
// 	 * 
// 	 * @return a class name of a result
// 	 */
// 	public String getResultClass() {
// 		return this.resultClass;
// 	}
// 
// 	@Override
// 	public String toString() {
// 		String format = String.format("Response-%d", this.id);
// 
// 		return format;
// 	}
// }
// 
// Path: src/main/java/tw/me/ychuang/rpc/Result.java
// public class Result {
// 	private static final Logger log = LoggerFactory.getLogger(Result.class);
// 
// 	/**
// 	 * A specific kind of return is Void
// 	 */
// 	public static final Result VOID_RETURN = new Result(null, Void.class);
// 
// 	/**
// 	 * A kind of constructor
// 	 * 
// 	 * @param returnObj a return
// 	 * @param returnClass a class of a return
// 	 */
// 	public Result(Object returnObj, Class returnClass) {
// 		super();
// 		this.returnObj = returnObj;
// 		this.returnClass = returnClass;
// 		this.exceptional = Throwable.class.isAssignableFrom(returnClass);
// 	}
// 
// 	private final Object returnObj;
// 
// 	public Object getReturn() {
// 		return this.returnObj;
// 	}
// 
// 	private final Class returnClass;
// 
// 	public Class getReturnClass() {
// 		return this.returnClass;
// 	}
// 
// 	private final boolean exceptional;
// 
// 	public boolean isExceptional() {
// 		return this.exceptional;
// 	}
// }


import java.lang.reflect.Type;
import org.apache.commons.lang3.ClassUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import tw.me.ychuang.rpc.Response;
import tw.me.ychuang.rpc.Result;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonNull;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
		return jsonResponse;
	}

	/**
	 * Deserialize a json element to a response
	 */
	@Override
	public Response deserialize(JsonElement jsonElement, Type responseClass, JsonDeserializationContext context) throws JsonParseException {
		JsonObject jsonResponse = (JsonObject) jsonElement;
		long id = jsonResponse.getAsJsonPrimitive("id").getAsLong();
		JsonElement jsonRsElement = jsonResponse.get("result");

		Response response = null;
		if (jsonRsElement.isJsonNull()) {
			response = new Response(id, null, null);
			return response;
		}

		JsonObject jsonResult = jsonRsElement.getAsJsonObject();
		JsonElement jsonReturn = jsonResult.get("return");
		JsonPrimitive jsonReturnClass = jsonResult.getAsJsonPrimitive("returnClass");
		JsonPrimitive jsonExceptional = jsonResult.getAsJsonPrimitive("exceptional");

		Class resultClass = null;
		try {
			resultClass = ClassUtils.getClass(jsonReturnClass.getAsString());
		} catch (ClassNotFoundException e) {
			throw new JsonParseException("Cannot find a matching class by name: " + jsonReturnClass.getAsString(), e);
		}

// Path: src/main/java/tw/me/ychuang/rpc/Response.java
// public class Response {
// 	private static final Logger log = LoggerFactory.getLogger(Response.class);
// 
// 	/**
// 	 * A kind of constructor
// 	 * 
// 	 * @param id unique id
// 	 * @param result a result
// 	 */
// 	public Response(Long id, Result result, String resultClass) {
// 		super();
// 		this.id = id;
// 		this.result = result;
// 		this.resultClass = resultClass;
// 	}
// 
// 	/**
// 	 * Response's id
// 	 */
// 	private final Long id;
// 
// 	/**
// 	 * Getter method for field 'id'
// 	 * 
// 	 * @return response's unqiue id
// 	 */
// 	public Long getId() {
// 		return this.id;
// 	}
// 
// 	/**
// 	 * A result is wrapped in this response
// 	 */
// 	private final Result result;
// 
// 	/**
// 	 * Getter method for field 'result'
// 	 * 
// 	 * @return a result
// 	 */
// 	public Result getResult() {
// 		return this.result;
// 	}
// 
// 	/**
// 	 * A class name of result
// 	 */
// 	private final String resultClass;
// 
// 	/**
// 	 * Getter method for field 'resultClass'
// 	 * 
// 	 * @return a class name of a result
// 	 */
// 	public String getResultClass() {
// 		return this.resultClass;
// 	}
// 
// 	@Override
// 	public String toString() {
// 		String format = String.format("Response-%d", this.id);
// 
// 		return format;
// 	}
// }
// 
// Path: src/main/java/tw/me/ychuang/rpc/Result.java
// public class Result {
// 	private static final Logger log = LoggerFactory.getLogger(Result.class);
// 
// 	/**
// 	 * A specific kind of return is Void
// 	 */
// 	public static final Result VOID_RETURN = new Result(null, Void.class);
// 
// 	/**
// 	 * A kind of constructor
// 	 * 
// 	 * @param returnObj a return
// 	 * @param returnClass a class of a return
// 	 */
// 	public Result(Object returnObj, Class returnClass) {
// 		super();
// 		this.returnObj = returnObj;
// 		this.returnClass = returnClass;
// 		this.exceptional = Throwable.class.isAssignableFrom(returnClass);
// 	}
// 
// 	private final Object returnObj;
// 
// 	public Object getReturn() {
// 		return this.returnObj;
// 	}
// 
// 	private final Class returnClass;
// 
// 	public Class getReturnClass() {
// 		return this.returnClass;
// 	}
// 
// 	private final boolean exceptional;
// 
// 	public boolean isExceptional() {
// 		return this.exceptional;
// 	}
// }


// Path: src/main/java/tw/me/ychuang/rpc/json/ResponseTypeAdapter.java
import java.lang.reflect.Type;
import org.apache.commons.lang3.ClassUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import tw.me.ychuang.rpc.Response;
import tw.me.ychuang.rpc.Result;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonNull;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;

		return jsonResponse;
	}

	/**
	 * Deserialize a json element to a response
	 */
	@Override
	public Response deserialize(JsonElement jsonElement, Type responseClass, JsonDeserializationContext context) throws JsonParseException {
		JsonObject jsonResponse = (JsonObject) jsonElement;
		long id = jsonResponse.getAsJsonPrimitive("id").getAsLong();
		JsonElement jsonRsElement = jsonResponse.get("result");

		Response response = null;
		if (jsonRsElement.isJsonNull()) {
			response = new Response(id, null, null);
			return response;
		}

		JsonObject jsonResult = jsonRsElement.getAsJsonObject();
		JsonElement jsonReturn = jsonResult.get("return");
		JsonPrimitive jsonReturnClass = jsonResult.getAsJsonPrimitive("returnClass");
		JsonPrimitive jsonExceptional = jsonResult.getAsJsonPrimitive("exceptional");

		Class resultClass = null;
		try {
			resultClass = ClassUtils.getClass(jsonReturnClass.getAsString());
		} catch (ClassNotFoundException e) {
			throw new JsonParseException("Cannot find a matching class by name: " + jsonReturnClass.getAsString(), e);
		}

		Result result = null;