All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.arangodb.entity.EntityDeserializers Maven / Gradle / Ivy

There is a newer version: 7.15.0
Show newest version
/*
 * Copyright (C) 2012 tamtam180
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.arangodb.entity;

import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;

import com.arangodb.entity.CollectionEntity.Figures;
import com.arangodb.entity.ReplicationApplierState.LastError;
import com.arangodb.entity.ReplicationApplierState.Progress;
import com.arangodb.entity.ReplicationInventoryEntity.Collection;
import com.arangodb.entity.ReplicationInventoryEntity.CollectionParameter;
import com.arangodb.entity.ReplicationLoggerStateEntity.Client;
import com.arangodb.entity.StatisticsDescriptionEntity.Figure;
import com.arangodb.entity.StatisticsDescriptionEntity.Group;
import com.arangodb.entity.StatisticsEntity.FigureValue;
import com.arangodb.entity.marker.VertexEntity;
import com.arangodb.util.DateUtils;
import com.google.gson.JsonArray;
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.JsonPrimitive;
import com.google.gson.reflect.TypeToken;

/**
 * Entity deserializer , internally used.
 *
 * @author tamtam180 - kirscheless at gmail.com
 * 
 */
public class EntityDeserializers {

	private static class ClassHolder {
		private Class[] clazz;
		private int idx;

		ClassHolder(Class... clazz) {
			this.clazz = clazz;
			this.idx = 0;
		}

		public boolean isEmpty() {
			return clazz == null || clazz.length == 0;
		}

		public Class get() {
			if (isEmpty()) {
				return null;
			}
			return clazz[idx];
		}

		public Class next() {
			if (isEmpty()) {
				return null;
			}
			if (idx + 1 >= clazz.length) {
				throw new IllegalStateException("idx max-over!! idx=" + (idx + 1));
			}
			return clazz[++idx];
		}

		public boolean hasNext() {
			if (isEmpty()) {
				return false;
			}
			if (idx + 1 >= clazz.length) {
				return false;
			}
			return true;
		}

		public Class back() {
			if (isEmpty()) {
				return null;
			}
			if (idx - 1 < 0) {
				throw new IllegalStateException("idx min-over!! idx=" + (idx - 1));
			}
			return clazz[--idx];
		}
	}

	private static ThreadLocal parameterizedBridger = new ThreadLocal();

	public static void setParameterized(Class... clazz) {
		parameterizedBridger.set(new ClassHolder(clazz));
	}

	public static void removeParameterized() {
		parameterizedBridger.remove();
	}

	private static Class getParameterized() {
		ClassHolder holder = parameterizedBridger.get();
		if (holder == null) {
			return null;
		}
		return holder.get();
	}

	private static boolean hasNextParameterized() {
		ClassHolder holder = parameterizedBridger.get();
		if (holder == null) {
			return false;
		}
		return holder.hasNext();
	}

	private static Class nextParameterized() {
		ClassHolder holder = parameterizedBridger.get();
		if (holder == null) {
			return null;
		}
		return holder.next();
	}

	private static Class backParameterized() {
		ClassHolder holder = parameterizedBridger.get();
		if (holder == null) {
			return null;
		}
		return holder.back();
	}

	private static  T deserializeBaseParameter(JsonObject obj, T entity) {
		if (obj.has("error") && obj.getAsJsonPrimitive("error").isBoolean()) {
			entity.error = obj.getAsJsonPrimitive("error").getAsBoolean();
		}
		if (obj.has("code") && obj.getAsJsonPrimitive("code").isNumber()) {
			entity.code = obj.getAsJsonPrimitive("code").getAsInt();
		}
		if (obj.has("errorNum") && obj.getAsJsonPrimitive("errorNum").isNumber()) {
			entity.errorNumber = obj.getAsJsonPrimitive("errorNum").getAsInt();
		}
		if (obj.has("errorMessage")) {
			entity.errorMessage = obj.getAsJsonPrimitive("errorMessage").getAsString();
		}
		if (obj.has("etag") && obj.getAsJsonPrimitive("errorNum").isNumber()) {
			entity.etag = obj.getAsJsonPrimitive("etag").getAsLong();
		}

		return entity;
	}

	private static  T deserializeDocumentParameter(JsonObject obj, T entity) {

		if (obj.has("_rev")) {
			entity.setDocumentRevision(obj.getAsJsonPrimitive("_rev").getAsLong());
		}
		if (obj.has("_id")) {
			entity.setDocumentHandle(obj.getAsJsonPrimitive("_id").getAsString());
		}
		if (obj.has("_key")) {
			entity.setDocumentKey(obj.getAsJsonPrimitive("_key").getAsString());
		}
		if (true) {

		}

		return entity;
	}

	public static class DefaultEntityDeserializer implements JsonDeserializer {
		@Override
		public DefaultEntity deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
				throws JsonParseException {
			if (json.isJsonNull()) {
				return null;
			}
			return deserializeBaseParameter(json.getAsJsonObject(), new DefaultEntity());
		}
	}

	public static class VersionDeserializer implements JsonDeserializer {
		@Override
		public ArangoVersion deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
				throws JsonParseException {

			if (json.isJsonNull()) {
				return null;
			}

			JsonObject obj = json.getAsJsonObject();
			ArangoVersion entity = deserializeBaseParameter(obj, new ArangoVersion());

			if (obj.has("server")) {
				entity.server = obj.getAsJsonPrimitive("server").getAsString();
			}

			if (obj.has("version")) {
				entity.version = obj.getAsJsonPrimitive("version").getAsString();
			}

			return entity;
		}
	}

	public static class ArangoUnixTimeDeserializer implements JsonDeserializer {
		@Override
		public ArangoUnixTime deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
				throws JsonParseException {

			if (json.isJsonNull()) {
				return null;
			}

			JsonObject obj = json.getAsJsonObject();
			ArangoUnixTime entity = deserializeBaseParameter(obj, new ArangoUnixTime());

			if (obj.has("time")) {
				entity.time = obj.getAsJsonPrimitive("time").getAsDouble();
				String time = obj.getAsJsonPrimitive("time").getAsString(); // 実際はdoubleだけど精度の問題が心配なので文字列で処理する。
				entity.second = (int) entity.time;

				int pos = time.indexOf('.');
				entity.microsecond = (pos >= 0 && pos + 1 != time.length()) ? Integer.parseInt(time.substring(pos + 1))
						: 0;
			}

			return entity;
		}
	}

	public static class FiguresDeserializer implements JsonDeserializer {
		@Override
		public Figures deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
				throws JsonParseException {

			if (json.isJsonNull()) {
				return null;
			}

			JsonObject obj = json.getAsJsonObject();
			Figures entity = new Figures();

			if (obj.has("alive")) {
				JsonObject alive = obj.getAsJsonObject("alive");
				entity.aliveCount = alive.getAsJsonPrimitive("count").getAsLong();
				entity.aliveSize = alive.getAsJsonPrimitive("size").getAsLong();
			}

			if (obj.has("dead")) {
				JsonObject dead = obj.getAsJsonObject("dead");
				entity.deadCount = dead.getAsJsonPrimitive("count").getAsLong();
				entity.deadSize = dead.getAsJsonPrimitive("size").getAsLong();
				entity.deadDeletion = dead.getAsJsonPrimitive("deletion").getAsLong();
			}

			if (obj.has("datafiles")) {
				JsonObject datafiles = obj.getAsJsonObject("datafiles");
				entity.datafileCount = datafiles.getAsJsonPrimitive("count").getAsLong();
				entity.datafileFileSize = datafiles.getAsJsonPrimitive("fileSize").getAsLong();
			}

			if (obj.has("journals")) {
				JsonObject journals = obj.getAsJsonObject("journals");
				entity.journalsCount = journals.getAsJsonPrimitive("count").getAsLong();
				entity.journalsFileSize = journals.getAsJsonPrimitive("fileSize").getAsLong();
			}

			if (obj.has("compactors")) {
				JsonObject compactors = obj.getAsJsonObject("compactors");
				entity.compactorsCount = compactors.getAsJsonPrimitive("count").getAsLong();
				entity.compactorsFileSize = compactors.getAsJsonPrimitive("fileSize").getAsLong();
			}

			if (obj.has("shapefiles")) {
				JsonObject shapefiles = obj.getAsJsonObject("shapefiles");
				entity.shapefilesCount = shapefiles.getAsJsonPrimitive("count").getAsLong();
				entity.shapefilesFileSize = shapefiles.getAsJsonPrimitive("fileSize").getAsLong();
			}

			if (obj.has("shapes")) {
				JsonObject shapes = obj.getAsJsonObject("shapes");
				entity.shapesCount = shapes.getAsJsonPrimitive("count").getAsLong();
			}

			if (obj.has("attributes")) {
				JsonObject attributes = obj.getAsJsonObject("attributes");
				entity.attributesCount = attributes.getAsJsonPrimitive("count").getAsLong();
			}

			if (obj.has("indexes")) {
				JsonObject indexes = obj.getAsJsonObject("indexes");
				entity.indexesCount = indexes.getAsJsonPrimitive("count").getAsLong();
				entity.indexesSize = indexes.getAsJsonPrimitive("size").getAsLong();
			}

			if (obj.has("lastTick")) {
				entity.lastTick = obj.getAsJsonPrimitive("lastTick").getAsLong();
			}

			if (obj.has("uncollectedLogfileEntries")) {
				entity.uncollectedLogfileEntries = obj.getAsJsonPrimitive("uncollectedLogfileEntries").getAsLong();
			}

			return entity;
		}
	}

	public static class CollectionKeyOptionDeserializer implements JsonDeserializer {
		@Override
		public CollectionKeyOption deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
				throws JsonParseException {

			if (json.isJsonNull()) {
				return null;
			}

			JsonObject obj = json.getAsJsonObject();
			CollectionKeyOption entity = new CollectionKeyOption();

			if (obj.has("type")) {
				entity.type = obj.getAsJsonPrimitive("type").getAsString();
			}

			if (obj.has("allowUserKeys")) {
				entity.allowUserKeys = obj.getAsJsonPrimitive("allowUserKeys").getAsBoolean();
			}

			if (obj.has("increment")) {
				entity.increment = obj.getAsJsonPrimitive("increment").getAsLong();
			}

			if (obj.has("offset")) {
				entity.offset = obj.getAsJsonPrimitive("offset").getAsLong();
			}

			return entity;
		}
	}

	public static class CollectionEntityDeserializer implements JsonDeserializer {
		@Override
		public CollectionEntity deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
				throws JsonParseException {

			if (json.isJsonNull()) {
				return null;
			}

			JsonObject obj = json.getAsJsonObject();
			CollectionEntity entity = deserializeBaseParameter(obj, new CollectionEntity());

			if (obj.has("name")) {
				entity.name = obj.getAsJsonPrimitive("name").getAsString();
			}

			if (obj.has("id")) {
				entity.id = obj.getAsJsonPrimitive("id").getAsLong();
			}

			if (obj.has("status")) {
				entity.status = context.deserialize(obj.get("status"), CollectionStatus.class);
			}

			if (obj.has("waitForSync")) {
				entity.waitForSync = obj.getAsJsonPrimitive("waitForSync").getAsBoolean();
			}

			if (obj.has("isSystem")) {
				entity.isSystem = obj.getAsJsonPrimitive("isSystem").getAsBoolean();
			}

			if (obj.has("isVolatile")) {
				entity.isVolatile = obj.getAsJsonPrimitive("isVolatile").getAsBoolean();
			}

			if (obj.has("journalSize")) {
				entity.journalSize = obj.getAsJsonPrimitive("journalSize").getAsLong();
			}

			if (obj.has("count")) {
				entity.count = obj.getAsJsonPrimitive("count").getAsLong();
			}

			if (obj.has("revision")) {
				entity.revision = obj.getAsJsonPrimitive("revision").getAsLong();
			}

			if (obj.has("figures")) {
				entity.figures = context.deserialize(obj.get("figures"), Figures.class);
			}

			if (obj.has("type")) {
				entity.type = CollectionType.valueOf(obj.getAsJsonPrimitive("type").getAsInt());
			}

			if (obj.has("keyOptions")) {
				entity.keyOptions = context.deserialize(obj.get("keyOptions"), CollectionKeyOption.class);
			}

			if (obj.has("checksum")) {
				entity.checksum = obj.getAsJsonPrimitive("checksum").getAsLong();
			}

			if (obj.has("doCompact")) {
				entity.doCompact = obj.getAsJsonPrimitive("doCompact").getAsBoolean();
			}

			return entity;
		}
	}

	public static class CollectionsEntityDeserializer implements JsonDeserializer {
		private Type collectionsType = new TypeToken>() {
		}.getType();
		private Type namesType = new TypeToken>() {
		}.getType();

		@Override
		public CollectionsEntity deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
				throws JsonParseException {

			if (json.isJsonNull()) {
				return null;
			}

			JsonObject obj = json.getAsJsonObject();
			CollectionsEntity entity = deserializeBaseParameter(obj, new CollectionsEntity());

			if (obj.has("collections")) {
				entity.collections = context.deserialize(obj.get("collections"), collectionsType);
			}
			if (obj.has("names")) {
				entity.names = context.deserialize(obj.get("names"), namesType);
			}

			return entity;
		}
	}

	public static class AqlfunctionsEntityDeserializer implements JsonDeserializer {

		@Override
		public AqlFunctionsEntity deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
				throws JsonParseException {

			if (json.isJsonNull()) {
				return null;
			}

			JsonArray obj = json.getAsJsonArray();
			Iterator iterator = obj.iterator();
			Map functions = new HashMap();
			while (iterator.hasNext()) {
				JsonElement e = iterator.next();
				JsonObject o = e.getAsJsonObject();
				functions.put(o.get("name").getAsString(), o.get("code").getAsString());
			}
			return new AqlFunctionsEntity(functions);
		}
	}

	public static class JobsEntityDeserializer implements JsonDeserializer {

		@Override
		public JobsEntity deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
				throws JsonParseException {

			if (json.isJsonNull()) {
				return null;
			}

			JsonArray obj = json.getAsJsonArray();
			Iterator iterator = obj.iterator();
			List jobs = new ArrayList();
			while (iterator.hasNext()) {
				JsonElement e = iterator.next();
				jobs.add(e.getAsString());
			}
			return new JobsEntity(jobs);
		}
	}

	public static class CursorEntityDeserializer implements JsonDeserializer> {
		private Type bindVarsType = new TypeToken>() {
		}.getType();

		private Type extraType = new TypeToken>() {
		}.getType();

		@Override
		public CursorEntity deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
				throws JsonParseException {

			if (json.isJsonNull()) {
				return null;
			}

			JsonObject obj = json.getAsJsonObject();
			CursorEntity entity = deserializeBaseParameter(obj, new CursorEntity());

			if (obj.has("result")) {
				JsonArray array = obj.getAsJsonArray("result");
				if (array == null || array.isJsonNull() || array.size() == 0) {
					entity.results = Collections.emptyList();
				} else {
					Class clazz = getParameterized();
					boolean withDocument = DocumentEntity.class.isAssignableFrom(clazz);
					if (withDocument) {
						nextParameterized();
					}
					try {
						List list = new ArrayList(array.size());
						for (int i = 0, imax = array.size(); i < imax; i++) {
							list.add(context.deserialize(array.get(i), clazz));
						}
						entity.results = list;
					} finally {
						if (withDocument) {
							backParameterized();
						}
					}
				}
			}

			if (obj.has("hasMore")) {
				entity.hasMore = obj.getAsJsonPrimitive("hasMore").getAsBoolean();
			}

			if (obj.has("count")) {
				entity.count = obj.getAsJsonPrimitive("count").getAsInt();
			}

			if (obj.has("id")) {
				entity.cursorId = obj.getAsJsonPrimitive("id").getAsLong();
			}

			if (obj.has("bindVars")) {
				entity.bindVars = context.deserialize(obj.get("bindVars"), bindVarsType);
			}

			if (obj.has("extra")) {
				entity.extra = context.deserialize(obj.get("extra"), extraType);

				if (entity.extra.containsKey("stats")) {
					if (entity.extra.get("stats") instanceof Map) {
						Map m = (Map) entity.extra.get("stats");
						if (m.containsKey("fullCount")) {
							try {
								if (m.get("fullCount") instanceof Double) {
									Double v = (Double) m.get("fullCount");
									entity.fullCount = v.intValue();
								}
							} catch (Exception e) {
							}
						}
					}
				}
			}

			return entity;
		}
	}

	public static class DocumentEntityDeserializer implements JsonDeserializer> {

		@Override
		public DocumentEntity deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
				throws JsonParseException {

			if (json.isJsonNull()) {
				return new DocumentEntity();
			}

			if (json.isJsonPrimitive()) {
				return new DocumentEntity();
			}

			if (json.isJsonArray()) {
				return new DocumentEntity();
			}

			JsonObject obj = json.getAsJsonObject();
			// DocumentEntity entity = deserializeBaseParameter(obj, new
			// DocumentEntity());
			// deserializeDocumentParameter(obj, entity);
			DocumentEntity entity = new DocumentEntity();
			deserializeDocumentParameter(obj, entity);

			// 他のフィールドはリフレクションで。 (TODO: Annotationのサポートと上記パラメータを弾く)
			Class clazz = getParameterized();
			if (clazz != null) {
				entity.entity = context.deserialize(obj, clazz);
				if (clazz.getName().equalsIgnoreCase(BaseDocument.class.getName())) {
					// iterate all key/value pairs of the jsonObject and
					// determine its class(String, Number, Boolean, HashMap,
					// List)
					((BaseDocument) entity.entity).setProperties(DeserializeSingleEntry.deserializeJsonObject(obj));
				}
			}

			return entity;
		}
	}

	public static class DeserializeSingleEntry {

		private static final List nonProperties = new ArrayList() {
			{
				add("_id");
				add("_rev");
				add("_key");
			}
		};

		/**
		 * desirializes any jsonElement
		 *
		 * @param jsonElement
		 * @return a object
		 */
		public static Object deserializeJsonElement(JsonElement jsonElement) {
			if (jsonElement.getClass() == JsonPrimitive.class) {
				return deserializeJsonPrimitive((JsonPrimitive) jsonElement);
			} else if (jsonElement.getClass() == JsonArray.class) {
				return deserializeJsonArray((JsonArray) jsonElement);
			} else if (jsonElement.getClass() == JsonObject.class) {
				return deserializeJsonObject((JsonObject) jsonElement);
			}
			return null;
		}

		/**
		 * desirializes a JsonObject into a Map
		 *
		 * @param jsonObject
		 *            a jsonObject
		 * @return the deserialized jsonObject
		 */
		private static Map deserializeJsonObject(JsonObject jsonObject) {
			Map result = new HashMap();
			Set> entrySet = jsonObject.entrySet();
			for (Map.Entry entry : entrySet) {
				if (!nonProperties.contains(entry.getKey())) {
					result.put(entry.getKey(), deserializeJsonElement(jsonObject.get(entry.getKey())));
				}
			}
			return result;
		}

		private static List deserializeJsonArray(JsonArray jsonArray) {
			List tmpObjectList = new ArrayList();
			Iterator iterator = jsonArray.iterator();
			while (iterator.hasNext()) {
				tmpObjectList.add(deserializeJsonElement(iterator.next()));
			}
			return tmpObjectList;
		}

		/**
		 * deserializes a jsonPrimitiv into the equivalent java primitive
		 *
		 * @param jsonPrimitive
		 * @return null|String|Double|Boolean
		 */
		private static Object deserializeJsonPrimitive(JsonPrimitive jsonPrimitive) {
			if (jsonPrimitive.isBoolean()) {
				return jsonPrimitive.getAsBoolean();
			} else if (jsonPrimitive.isNumber()) {
				return jsonPrimitive.getAsDouble();
			} else if (jsonPrimitive.isString()) {
				return jsonPrimitive.getAsString();
			}
			return null;
		}

	}

	public static class DocumentsEntityDeserializer implements JsonDeserializer {
		private Type documentsType = new TypeToken>() {
		}.getType();

		@Override
		public DocumentsEntity deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
				throws JsonParseException {

			if (json.isJsonNull()) {
				return null;
			}

			JsonObject obj = json.getAsJsonObject();
			DocumentsEntity entity = deserializeBaseParameter(obj, new DocumentsEntity());

			if (obj.has("documents")) {
				entity.documents = context.deserialize(obj.get("documents"), documentsType);
			}

			return entity;
		}

	}

	public static class IndexEntityDeserializer implements JsonDeserializer {
		private Type fieldsType = new TypeToken>() {
		}.getType();

		@Override
		public IndexEntity deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
				throws JsonParseException {

			if (json.isJsonNull()) {
				return null;
			}

			JsonObject obj = json.getAsJsonObject();
			IndexEntity entity = deserializeBaseParameter(obj, new IndexEntity());

			if (obj.has("id")) {
				entity.id = obj.getAsJsonPrimitive("id").getAsString();
			}

			if (obj.has("type")) {
				String type = obj.getAsJsonPrimitive("type").getAsString().toUpperCase(Locale.US);
				if (type.startsWith(IndexType.GEO.name())) {
					entity.type = IndexType.GEO;
				} else {
					entity.type = IndexType.valueOf(type);
				}
			}

			if (obj.has("fields")) {
				entity.fields = context.deserialize(obj.getAsJsonArray("fields"), fieldsType);
			}

			if (obj.has("geoJson")) {
				entity.geoJson = obj.getAsJsonPrimitive("geoJson").getAsBoolean();
			}

			if (obj.has("isNewlyCreated")) {
				entity.isNewlyCreated = obj.getAsJsonPrimitive("isNewlyCreated").getAsBoolean();
			}

			if (obj.has("unique")) {
				entity.unique = obj.getAsJsonPrimitive("unique").getAsBoolean();
			}

			if (obj.has("sparse")) {
				entity.sparse = obj.getAsJsonPrimitive("sparse").getAsBoolean();
			}

			if (obj.has("size")) {
				entity.size = obj.getAsJsonPrimitive("size").getAsInt();
			}

			if (obj.has("minLength")) {
				entity.minLength = obj.getAsJsonPrimitive("minLength").getAsInt();
			}

			if (obj.has("selectivityEstimate")) {
				entity.selectivityEstimate = obj.getAsJsonPrimitive("selectivityEstimate").getAsDouble();
			}

			return entity;
		}
	}

	public static class IndexesEntityDeserializer implements JsonDeserializer {
		private Type indexesType = new TypeToken>() {
		}.getType();
		private Type identifiersType = new TypeToken>() {
		}.getType();

		@Override
		public IndexesEntity deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
				throws JsonParseException {

			if (json.isJsonNull()) {
				return null;
			}

			JsonObject obj = json.getAsJsonObject();
			IndexesEntity entity = deserializeBaseParameter(obj, new IndexesEntity());

			if (obj.has("indexes")) {
				entity.indexes = context.deserialize(obj.get("indexes"), indexesType);
			}

			if (obj.has("identifiers")) {
				entity.identifiers = context.deserialize(obj.get("identifiers"), identifiersType);
			}

			return entity;
		}

	}

	public static class AdminLogEntryEntityDeserializer implements JsonDeserializer {
		@Override
		public AdminLogEntity deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
				throws JsonParseException {

			if (json.isJsonNull()) {
				return null;
			}

			JsonObject obj = json.getAsJsonObject();
			AdminLogEntity entity = deserializeBaseParameter(obj, new AdminLogEntity());
			// 全ての要素は必ずあることが前提なのでhasチェックはしない
			int[] lids = context.deserialize(obj.getAsJsonArray("lid"), int[].class);
			int[] levels = context.deserialize(obj.getAsJsonArray("level"), int[].class);
			long[] timestamps = context.deserialize(obj.getAsJsonArray("timestamp"), long[].class);
			String[] texts = context.deserialize(obj.getAsJsonArray("text"), String[].class);

			// 配列のサイズが全て同じであること
			if (lids.length != levels.length || lids.length != timestamps.length || lids.length != texts.length) {
				throw new IllegalStateException("each parameters returns wrong length.");
			}

			entity.logs = new ArrayList(lids.length);
			for (int i = 0; i < lids.length; i++) {
				AdminLogEntity.LogEntry entry = new AdminLogEntity.LogEntry();
				entry.lid = lids[i];
				entry.level = levels[i];
				entry.timestamp = new Date(timestamps[i] * 1000L);
				entry.text = texts[i];
				entity.logs.add(entry);
			}

			if (obj.has("totalAmount")) {
				entity.totalAmount = obj.getAsJsonPrimitive("totalAmount").getAsInt();
			}

			return entity;
		}
	}

	public static class StatisticsEntityDeserializer implements JsonDeserializer {
		Type countsType = new TypeToken() {
		}.getType();

		@Override
		public StatisticsEntity deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
				throws JsonParseException {

			if (json.isJsonNull()) {
				return null;
			}

			JsonObject obj = json.getAsJsonObject();
			StatisticsEntity entity = deserializeBaseParameter(obj, new StatisticsEntity());

			if (obj.has("system")) {
				StatisticsEntity.System sys = new StatisticsEntity.System();
				entity.system = sys;

				JsonObject system = obj.getAsJsonObject("system");
				if (system.has("minorPageFaults")) {
					sys.minorPageFaults = system.getAsJsonPrimitive("minorPageFaults").getAsLong();
				}
				if (system.has("majorPageFaults")) {
					sys.majorPageFaults = system.getAsJsonPrimitive("majorPageFaults").getAsLong();
				}
				if (system.has("userTime")) {
					sys.userTime = system.getAsJsonPrimitive("userTime").getAsDouble();
				}
				if (system.has("systemTime")) {
					sys.systemTime = system.getAsJsonPrimitive("systemTime").getAsDouble();
				}
				if (system.has("numberOfThreads")) {
					sys.numberOfThreads = system.getAsJsonPrimitive("numberOfThreads").getAsInt();
				}
				if (system.has("residentSize")) {
					sys.residentSize = system.getAsJsonPrimitive("residentSize").getAsLong();
				}
				if (system.has("virtualSize")) {
					sys.virtualSize = system.getAsJsonPrimitive("virtualSize").getAsLong();
				}
			}

			if (obj.has("client")) {
				StatisticsEntity.Client cli = new StatisticsEntity.Client();
				cli.figures = new TreeMap();
				entity.client = cli;

				JsonObject client = obj.getAsJsonObject("client");
				if (client.has("httpConnections")) {
					cli.httpConnections = client.getAsJsonPrimitive("httpConnections").getAsInt();
				}
				for (Entry ent : client.entrySet()) {
					if (!ent.getKey().equals("httpConnections")) {
						JsonObject f = ent.getValue().getAsJsonObject();
						FigureValue fv = new FigureValue();
						fv.sum = f.getAsJsonPrimitive("sum").getAsDouble();
						fv.count = f.getAsJsonPrimitive("count").getAsLong();
						fv.counts = context.deserialize(f.getAsJsonArray("counts"), countsType);
						cli.figures.put(ent.getKey(), fv);
					}
				}
			}

			if (obj.has("server")) {
				JsonObject svr = obj.getAsJsonObject("server");
				entity.server = new StatisticsEntity.Server();

				if (svr.has("uptime")) {
					entity.server.uptime = svr.getAsJsonPrimitive("uptime").getAsDouble();
				}
			}

			return entity;

		}
	}

	public static class StatisticsDescriptionEntityDeserializer
			implements JsonDeserializer {
		Type cutsTypes = new TypeToken() {
		}.getType();

		@Override
		public StatisticsDescriptionEntity deserialize(
			JsonElement json,
			Type typeOfT,
			JsonDeserializationContext context) throws JsonParseException {

			if (json.isJsonNull()) {
				return null;
			}

			JsonObject obj = json.getAsJsonObject();
			StatisticsDescriptionEntity entity = deserializeBaseParameter(obj, new StatisticsDescriptionEntity());

			if (obj.has("groups")) {
				JsonArray groups = obj.getAsJsonArray("groups");
				entity.groups = new ArrayList(groups.size());
				for (int i = 0, imax = groups.size(); i < imax; i++) {
					JsonObject g = groups.get(i).getAsJsonObject();

					Group group = new Group();
					group.group = g.getAsJsonPrimitive("group").getAsString();
					group.name = g.getAsJsonPrimitive("name").getAsString();
					group.description = g.getAsJsonPrimitive("description").getAsString();

					entity.groups.add(group);
				}
			}

			if (obj.has("figures")) {
				JsonArray figures = obj.getAsJsonArray("figures");
				entity.figures = new ArrayList(figures.size());
				for (int i = 0, imax = figures.size(); i < imax; i++) {
					JsonObject f = figures.get(i).getAsJsonObject();

					Figure figure = new Figure();
					figure.group = f.getAsJsonPrimitive("group").getAsString();
					figure.identifier = f.getAsJsonPrimitive("identifier").getAsString();
					figure.name = f.getAsJsonPrimitive("name").getAsString();
					figure.description = f.getAsJsonPrimitive("description").getAsString();
					figure.type = f.getAsJsonPrimitive("type").getAsString();
					figure.units = f.getAsJsonPrimitive("units").getAsString();
					if (f.has("cuts")) {
						figure.cuts = context.deserialize(f.getAsJsonArray("cuts"), cutsTypes);
					}

					entity.figures.add(figure);

				}
			}

			return entity;
		}
	}

	public static class ScalarExampleEntityDeserializer implements JsonDeserializer> {

		@Override
		public ScalarExampleEntity deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
				throws JsonParseException {

			if (json.isJsonNull()) {
				return null;
			}

			JsonObject obj = json.getAsJsonObject();
			ScalarExampleEntity entity = deserializeBaseParameter(obj, new ScalarExampleEntity());

			if (obj.has("document")) {
				entity.document = context.deserialize(obj.get("document"), DocumentEntity.class);
			}

			return entity;
		}

	}

	public static class SimpleByResultEntityDeserializer implements JsonDeserializer {

		@Override
		public SimpleByResultEntity deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
				throws JsonParseException {

			if (json.isJsonNull()) {
				return null;
			}

			JsonObject obj = json.getAsJsonObject();
			SimpleByResultEntity entity = deserializeBaseParameter(obj, new SimpleByResultEntity());

			if (obj.has("deleted")) {
				entity.count = entity.deleted = obj.getAsJsonPrimitive("deleted").getAsInt();
			}

			if (obj.has("replaced")) {
				entity.count = entity.replaced = obj.getAsJsonPrimitive("replaced").getAsInt();
			}

			if (obj.has("updated")) {
				entity.count = entity.updated = obj.getAsJsonPrimitive("updated").getAsInt();
			}

			return entity;
		}

	}

	public static class TransactionResultEntityDeserializer implements JsonDeserializer {

		@Override
		public TransactionResultEntity deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
				throws JsonParseException {

			if (json.isJsonNull()) {
				return null;
			}

			JsonObject obj = json.getAsJsonObject();
			TransactionResultEntity entity = deserializeBaseParameter(obj, new TransactionResultEntity());

			if (obj.has("result")) { // MEMO:
				if (obj.get("result") instanceof JsonObject) {
					entity.setResult(obj.get("result"));
				} else if (obj.getAsJsonPrimitive("result").isBoolean()) {
					entity.setResult((obj.getAsJsonPrimitive("result").getAsBoolean()));
				} else if (obj.getAsJsonPrimitive("result").isNumber()) {
					entity.setResult(obj.getAsJsonPrimitive("result").getAsNumber());
				} else if (obj.getAsJsonPrimitive("result").isString()) {
					entity.setResult((obj.getAsJsonPrimitive("result").getAsString()));
				}
			}

			return entity;
		}

	}

	public static class UserEntityDeserializer implements JsonDeserializer {

		@Override
		public UserEntity deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
				throws JsonParseException {

			if (json.isJsonNull()) {
				return null;
			}

			JsonObject obj = json.getAsJsonObject();
			UserEntity entity = deserializeBaseParameter(obj, new UserEntity());

			if (obj.has("user")) { // MEMO:
				// RequestはusernameなのにResponseは何故userなのか。。
				entity.username = obj.getAsJsonPrimitive("user").getAsString();
			}

			if (obj.has("password")) {
				entity.password = obj.getAsJsonPrimitive("password").getAsString();
			}

			if (obj.has("active")) {
				entity.active = obj.getAsJsonPrimitive("active").getAsBoolean();
			} else if (obj.has("authData")) {
				// for simple/all requsts
				JsonObject authData = obj.getAsJsonObject("authData");
				if (authData.has("active")) {
					entity.active = authData.getAsJsonPrimitive("active").getAsBoolean();
				}
			}

			if (obj.has("extra")) {
				entity.extra = context.deserialize(obj.getAsJsonObject("extra"), Map.class);
			} else if (obj.has("userData")) {
				// for simple/all requsts
				entity.extra = context.deserialize(obj.getAsJsonObject("userData"), Map.class);
			} else {
				entity.extra = new HashMap();
			}

			return entity;
		}

	}

	public static class ImportResultEntityDeserializer implements JsonDeserializer {
		@Override
		public ImportResultEntity deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
				throws JsonParseException {

			if (json.isJsonNull()) {
				return null;
			}

			JsonObject obj = json.getAsJsonObject();
			ImportResultEntity entity = deserializeBaseParameter(obj, new ImportResultEntity());

			if (obj.has("created")) {
				entity.created = obj.getAsJsonPrimitive("created").getAsInt();
			}

			if (obj.has("errors")) {
				entity.errors = obj.getAsJsonPrimitive("errors").getAsInt();
			}

			if (obj.has("empty")) {
				entity.empty = obj.getAsJsonPrimitive("empty").getAsInt();
			}

			return entity;
		}
	}

	public static class DatabaseEntityDeserializer implements JsonDeserializer {
		@Override
		public DatabaseEntity deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
				throws JsonParseException {

			if (json.isJsonNull()) {
				return null;
			}

			JsonObject obj = json.getAsJsonObject();
			DatabaseEntity entity = deserializeBaseParameter(obj, new DatabaseEntity());

			if (obj.has("result")) {
				JsonObject result = obj.getAsJsonObject("result");
				if (result.has("name")) {
					entity.name = result.getAsJsonPrimitive("name").getAsString();
				}
				if (result.has("id")) {
					entity.id = result.getAsJsonPrimitive("id").getAsString();
				}
				if (result.has("path")) {
					entity.path = result.getAsJsonPrimitive("path").getAsString();
				}
				if (result.has("isSystem")) {
					entity.isSystem = result.getAsJsonPrimitive("isSystem").getAsBoolean();
				}
			}

			return entity;
		}
	}

	public static class StringsResultEntityDeserializer implements JsonDeserializer {
		Type resultType = new TypeToken>() {
		}.getType();

		@Override
		public StringsResultEntity deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
				throws JsonParseException {

			if (json.isJsonNull()) {
				return null;
			}

			JsonObject obj = json.getAsJsonObject();
			StringsResultEntity entity = deserializeBaseParameter(obj, new StringsResultEntity());

			if (obj.has("result")) {
				entity.result = context.deserialize(obj.get("result"), resultType);
			}

			return entity;
		}
	}

	public static class BooleanResultEntityDeserializer implements JsonDeserializer {
		@Override
		public BooleanResultEntity deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
				throws JsonParseException {

			if (json.isJsonNull()) {
				return null;
			}

			JsonObject obj = json.getAsJsonObject();
			BooleanResultEntity entity = deserializeBaseParameter(obj, new BooleanResultEntity());

			if (obj.has("result")) {
				entity.result = obj.getAsJsonPrimitive("result").getAsBoolean();
			}

			return entity;
		}
	}

	public static class EndpointDeserializer implements JsonDeserializer {
		Type databasesType = new TypeToken>() {
		}.getType();

		@Override
		public Endpoint deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
				throws JsonParseException {

			if (json.isJsonNull()) {
				return null;
			}

			JsonObject obj = json.getAsJsonObject();

			Endpoint entity = new Endpoint();
			entity.databases = context.deserialize(obj.getAsJsonArray("databases"), databasesType);
			entity.endpoint = obj.getAsJsonPrimitive("endpoint").getAsString();

			return entity;
		}
	}

	public static class DocumentResultEntityDeserializer implements JsonDeserializer> {
		Type documentsType = new TypeToken>>() {
		}.getType();

		@Override
		public DocumentResultEntity deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
				throws JsonParseException {

			if (json.isJsonNull()) {
				return null;
			}

			JsonObject obj = json.getAsJsonObject();
			DocumentResultEntity entity = deserializeBaseParameter(obj, new DocumentResultEntity());

			if (obj.has("result")) {
				JsonElement resultElem = obj.get("result");
				if (resultElem.isJsonArray()) {
					entity.result = context.deserialize(resultElem, documentsType);
				} else if (resultElem.isJsonObject()) {
					DocumentEntity doc = context.deserialize(resultElem, DocumentEntity.class);
					List> list = new ArrayList>(1);
					list.add(doc);
					entity.result = list;
				} else {
					throw new IllegalStateException("result type is not array or object:" + resultElem);
				}
			}

			return entity;
		}
	}

	public static class ReplicationStateDeserializer implements JsonDeserializer {
		@Override
		public ReplicationState deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
				throws JsonParseException {

			if (json.isJsonNull()) {
				return null;
			}

			JsonObject obj = json.getAsJsonObject();
			ReplicationState entity = new ReplicationState();

			entity.running = obj.getAsJsonPrimitive("running").getAsBoolean();
			entity.lastLogTick = obj.getAsJsonPrimitive("lastLogTick").getAsLong();
			entity.totalEvents = obj.getAsJsonPrimitive("totalEvents").getAsLong();
			entity.time = DateUtils.parse(obj.getAsJsonPrimitive("time").getAsString());

			return entity;
		}
	}

	public static class ReplicationInventoryEntityDeserializer implements JsonDeserializer {
		private Type indexesType = new TypeToken>() {
		}.getType();

		@Override
		public ReplicationInventoryEntity deserialize(
			JsonElement json,
			Type typeOfT,
			JsonDeserializationContext context) throws JsonParseException {

			if (json.isJsonNull()) {
				return null;
			}

			JsonObject obj = json.getAsJsonObject();
			ReplicationInventoryEntity entity = deserializeBaseParameter(obj, new ReplicationInventoryEntity());

			if (obj.has("collections")) {
				JsonArray collections = obj.getAsJsonArray("collections");
				entity.collections = new ArrayList(collections.size());
				for (int i = 0, imax = collections.size(); i < imax; i++) {
					JsonObject elem = collections.get(i).getAsJsonObject();
					Collection col = new Collection();

					if (elem.has("parameters")) {
						JsonObject parameters = elem.getAsJsonObject("parameters");

						col.parameter = new CollectionParameter();
						if (parameters.has("version")) {
							col.parameter.version = parameters.getAsJsonPrimitive("version").getAsInt();
						}
						if (parameters.has("type")) {
							col.parameter.type = CollectionType
									.valueOf(parameters.getAsJsonPrimitive("type").getAsInt());
						}
						if (parameters.has("cid")) {
							col.parameter.cid = parameters.getAsJsonPrimitive("cid").getAsLong();
						}
						if (parameters.has("deleted")) {
							col.parameter.deleted = parameters.getAsJsonPrimitive("deleted").getAsBoolean();
						}
						if (parameters.has("doCompact")) {
							col.parameter.doCompact = parameters.getAsJsonPrimitive("doCompact").getAsBoolean();
						}
						if (parameters.has("maximalSize")) {
							col.parameter.maximalSize = parameters.getAsJsonPrimitive("maximalSize").getAsLong();
						}
						if (parameters.has("name")) {
							col.parameter.name = parameters.getAsJsonPrimitive("name").getAsString();
						}
						if (parameters.has("isVolatile")) {
							col.parameter.isVolatile = parameters.getAsJsonPrimitive("isVolatile").getAsBoolean();
						}
						if (parameters.has("waitForSync")) {
							col.parameter.waitForSync = parameters.getAsJsonPrimitive("waitForSync").getAsBoolean();
						}
					}

					if (elem.has("indexes")) {
						col.indexes = context.deserialize(elem.getAsJsonArray("indexes"), indexesType);
					}

					entity.collections.add(col);
				}
			}

			if (obj.has("state")) {
				entity.state = context.deserialize(obj.getAsJsonObject("state"), ReplicationState.class);
			}

			if (obj.has("tick")) {
				entity.tick = obj.getAsJsonPrimitive("tick").getAsLong();
			}

			return entity;
		}
	}

	public static class ReplicationDumpRecordDeserializer implements JsonDeserializer> {
		Type documentsType = new TypeToken>>() {
		}.getType();

		@Override
		public ReplicationDumpRecord deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
				throws JsonParseException {

			if (json.isJsonNull()) {
				return null;
			}

			JsonObject obj = json.getAsJsonObject();
			ReplicationDumpRecord> entity = new ReplicationDumpRecord>();

			if (obj.has("tick")) {
				entity.tick = obj.getAsJsonPrimitive("tick").getAsLong();
			}
			if (obj.has("type")) {
				int type = obj.getAsJsonPrimitive("type").getAsInt();
				entity.type = ReplicationEventType.valueOf(type);
			}
			if (obj.has("key")) {
				entity.key = obj.getAsJsonPrimitive("key").getAsString();
			}
			if (obj.has("rev")) {
				entity.rev = obj.getAsJsonPrimitive("rev").getAsLong();
			}
			if (obj.has("data")) {
				entity.data = context.deserialize(obj.getAsJsonObject("data"), DocumentEntity.class);
			}

			return entity;
		}
	}

	public static class ReplicationSyncEntityDeserializer implements JsonDeserializer {
		Type collectionsType = new TypeToken>() {
		}.getType();

		@Override
		public ReplicationSyncEntity deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
				throws JsonParseException {

			if (json.isJsonNull()) {
				return null;
			}

			JsonObject obj = json.getAsJsonObject();
			ReplicationSyncEntity entity = deserializeBaseParameter(obj, new ReplicationSyncEntity());

			if (obj.has("collections")) {
				entity.collections = context.deserialize(obj.getAsJsonArray("collections"), collectionsType);
			}
			if (obj.has("lastLogTick")) {
				entity.lastLogTick = obj.getAsJsonPrimitive("lastLogTick").getAsLong();
			}

			return entity;
		}
	}

	public static class MapAsEntityDeserializer implements JsonDeserializer {
		Type mapType = new TypeToken>() {
		}.getType();

		@Override
		public MapAsEntity deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
				throws JsonParseException {

			if (json.isJsonNull()) {
				return null;
			}

			JsonObject obj = json.getAsJsonObject();
			MapAsEntity entity = deserializeBaseParameter(obj, new MapAsEntity());

			entity.map = context.deserialize(obj, mapType);

			return entity;
		}
	}

	public static class ReplicationLoggerConfigEntityDeserializer
			implements JsonDeserializer {
		@Override
		public ReplicationLoggerConfigEntity deserialize(
			JsonElement json,
			Type typeOfT,
			JsonDeserializationContext context) throws JsonParseException {

			if (json.isJsonNull()) {
				return null;
			}

			JsonObject obj = json.getAsJsonObject();
			ReplicationLoggerConfigEntity entity = deserializeBaseParameter(obj, new ReplicationLoggerConfigEntity());

			if (obj.has("autoStart")) {
				entity.autoStart = obj.getAsJsonPrimitive("autoStart").getAsBoolean();
			}
			if (obj.has("logRemoteChanges")) {
				entity.logRemoteChanges = obj.getAsJsonPrimitive("logRemoteChanges").getAsBoolean();
			}
			if (obj.has("maxEvents")) {
				entity.maxEvents = obj.getAsJsonPrimitive("maxEvents").getAsLong();
			}
			if (obj.has("maxEventsSize")) {
				entity.maxEventsSize = obj.getAsJsonPrimitive("maxEventsSize").getAsLong();
			}

			return entity;
		}
	}

	public static class ReplicationApplierConfigEntityDeserializer
			implements JsonDeserializer {
		@Override
		public ReplicationApplierConfigEntity deserialize(
			JsonElement json,
			Type typeOfT,
			JsonDeserializationContext context) throws JsonParseException {

			if (json.isJsonNull()) {
				return null;
			}

			JsonObject obj = json.getAsJsonObject();
			ReplicationApplierConfigEntity entity = deserializeBaseParameter(obj, new ReplicationApplierConfigEntity());

			if (obj.has("endpoint")) {
				entity.endpoint = obj.getAsJsonPrimitive("endpoint").getAsString();
			}

			if (obj.has("database")) {
				entity.database = obj.getAsJsonPrimitive("database").getAsString();
			}

			if (obj.has("username")) {
				entity.username = obj.getAsJsonPrimitive("username").getAsString();
			}

			if (obj.has("password")) {
				entity.password = obj.getAsJsonPrimitive("password").getAsString();
			}

			if (obj.has("maxConnectRetries")) {
				entity.maxConnectRetries = obj.getAsJsonPrimitive("maxConnectRetries").getAsInt();
			}

			if (obj.has("connectTimeout")) {
				entity.connectTimeout = obj.getAsJsonPrimitive("connectTimeout").getAsInt();
			}

			if (obj.has("requestTimeout")) {
				entity.requestTimeout = obj.getAsJsonPrimitive("requestTimeout").getAsInt();
			}

			if (obj.has("chunkSize")) {
				entity.chunkSize = obj.getAsJsonPrimitive("chunkSize").getAsInt();
			}

			if (obj.has("autoStart")) {
				entity.autoStart = obj.getAsJsonPrimitive("autoStart").getAsBoolean();
			}

			if (obj.has("adaptivePolling")) {
				entity.adaptivePolling = obj.getAsJsonPrimitive("adaptivePolling").getAsBoolean();
			}

			return entity;
		}
	}

	public static class ReplicationApplierStateDeserializer implements JsonDeserializer {
		@Override
		public ReplicationApplierState deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
				throws JsonParseException {

			if (json.isJsonNull()) {
				return null;
			}

			JsonObject obj = json.getAsJsonObject();
			ReplicationApplierState state = new ReplicationApplierState();

			if (obj.has("running")) {
				state.running = obj.getAsJsonPrimitive("running").getAsBoolean();
			}
			if (obj.has("lastAppliedContinuousTick") && !obj.get("lastAppliedContinuousTick").isJsonNull()) {
				state.lastAppliedContinuousTick = obj.getAsJsonPrimitive("lastAppliedContinuousTick").getAsLong();
			}
			if (obj.has("lastProcessedContinuousTick") && !obj.get("lastProcessedContinuousTick").isJsonNull()) {
				state.lastProcessedContinuousTick = obj.getAsJsonPrimitive("lastProcessedContinuousTick").getAsLong();
			}
			if (obj.has("lastAvailableContinuousTick") && !obj.get("lastAvailableContinuousTick").isJsonNull()) {
				state.lastAvailableContinuousTick = obj.getAsJsonPrimitive("lastAvailableContinuousTick").getAsLong();
			}
			if (obj.has("time")) {
				state.time = DateUtils.parse(obj.getAsJsonPrimitive("time").getAsString());
			}
			if (obj.has("totalRequests")) {
				state.totalRequests = obj.getAsJsonPrimitive("totalRequests").getAsLong();
			}
			if (obj.has("totalFailedConnects")) {
				state.totalFailedConnects = obj.getAsJsonPrimitive("totalFailedConnects").getAsLong();
			}
			if (obj.has("totalEvents")) {
				state.totalEvents = obj.getAsJsonPrimitive("totalEvents").getAsLong();
			}

			if (obj.has("lastError") && !obj.get("lastError").isJsonNull()) {
				JsonObject lastError = obj.getAsJsonObject("lastError");
				state.lastError = new LastError();
				if (lastError.has("time")) {
					state.lastError.time = DateUtils.parse(lastError.getAsJsonPrimitive("time").getAsString());
				}
				if (lastError.has("errorNum")) {
					state.lastError.errorNum = lastError.getAsJsonPrimitive("errorNum").getAsInt();
				}
				if (lastError.has("errorMessage")) {
					state.lastError.errorMessage = lastError.getAsJsonPrimitive("errorMessage").getAsString();
				}
			}

			if (obj.has("progress")) {
				JsonObject progress = obj.getAsJsonObject("progress");
				state.progress = new Progress();
				if (progress.has("failedConnects")) {
					state.progress.failedConnects = progress.getAsJsonPrimitive("failedConnects").getAsLong();
				}
				if (progress.has("message")) {
					state.progress.message = progress.getAsJsonPrimitive("message").getAsString();
				}
				if (progress.has("time")) {
					state.progress.time = DateUtils.parse(progress.getAsJsonPrimitive("time").getAsString());
				}
			}

			return state;
		}
	}

	public static class ReplicationApplierStateEntityDeserializer
			implements JsonDeserializer {
		@Override
		public ReplicationApplierStateEntity deserialize(
			JsonElement json,
			Type typeOfT,
			JsonDeserializationContext context) throws JsonParseException {

			if (json.isJsonNull()) {
				return null;
			}

			JsonObject obj = json.getAsJsonObject();
			ReplicationApplierStateEntity entity = deserializeBaseParameter(obj, new ReplicationApplierStateEntity());

			if (obj.has("endpoint")) {
				entity.endpoint = obj.getAsJsonPrimitive("endpoint").getAsString();
			}

			if (obj.has("database")) {
				entity.database = obj.getAsJsonPrimitive("database").getAsString();
			}

			if (obj.has("server")) {
				JsonObject server = obj.getAsJsonObject("server");
				entity.serverVersion = server.getAsJsonPrimitive("version").getAsString();
				entity.serverId = server.getAsJsonPrimitive("serverId").getAsString();
			}

			if (obj.has("state")) {
				entity.state = context.deserialize(obj.get("state"), ReplicationApplierState.class);
			}

			return entity;
		}
	}

	public static class ReplicationLoggerStateEntityDeserializer
			implements JsonDeserializer {
		private Type clientsType = new TypeToken>() {
		}.getType();

		@Override
		public ReplicationLoggerStateEntity deserialize(
			JsonElement json,
			Type typeOfT,
			JsonDeserializationContext context) throws JsonParseException {

			if (json.isJsonNull()) {
				return null;
			}

			JsonObject obj = json.getAsJsonObject();
			ReplicationLoggerStateEntity entity = deserializeBaseParameter(obj, new ReplicationLoggerStateEntity());

			if (obj.has("state")) {
				entity.state = context.deserialize(obj.get("state"), ReplicationState.class);
			}

			if (obj.has("server")) {
				JsonObject server = obj.getAsJsonObject("server");
				entity.serverVersion = server.getAsJsonPrimitive("version").getAsString();
				entity.serverId = server.getAsJsonPrimitive("serverId").getAsString();
			}

			if (obj.has("clients")) {
				entity.clients = context.deserialize(obj.getAsJsonArray("clients"), clientsType);
			}

			return entity;
		}
	}

	public static class ReplicationLoggerStateEntityClientDeserializer
			implements JsonDeserializer {
		@Override
		public ReplicationLoggerStateEntity.Client deserialize(
			JsonElement json,
			Type typeOfT,
			JsonDeserializationContext context) throws JsonParseException {

			if (json.isJsonNull()) {
				return null;
			}

			JsonObject obj = json.getAsJsonObject();
			Client client = new Client();

			if (obj.has("serverId")) {
				client.serverId = obj.getAsJsonPrimitive("serverId").getAsString();
			}

			if (obj.has("lastServedTick")) {
				client.lastServedTick = obj.getAsJsonPrimitive("lastServedTick").getAsLong();
			}

			if (obj.has("time")) {
				client.time = DateUtils.parse(obj.getAsJsonPrimitive("time").getAsString());
			}

			return client;
		}
	}

	public static class GraphEntityDeserializer implements JsonDeserializer {
		@Override
		public GraphEntity deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
				throws JsonParseException {

			if (json.isJsonNull()) {
				return null;
			}

			JsonObject obj = json.getAsJsonObject();
			GraphEntity entity = deserializeBaseParameter(obj, new GraphEntity());

			JsonObject graph = obj.has("graph") ? obj.getAsJsonObject("graph") : obj;
			deserializeDocumentParameter(graph, entity);

			if (graph.has("name")) {
				entity.name = graph.get("name").getAsString();
			}

			if (graph.has("orphanCollections")) {
				JsonArray orphanCollections = graph.getAsJsonArray("orphanCollections");
				entity.orphanCollections = new ArrayList();
				if (!orphanCollections.equals(null)) {
					entity.orphanCollections = new ArrayList(orphanCollections.size());
					for (int i = 0, imax = orphanCollections.size(); i < imax; i++) {
						String orphanCollection = orphanCollections.get(i).getAsString();

						entity.orphanCollections.add(orphanCollection);
					}
				}
			}

			if (graph.has("edgeDefinitions")) {
				JsonArray edgeDefinitions = graph.getAsJsonArray("edgeDefinitions");
				entity.edgeDefinitionsEntity = new EdgeDefinitionsEntity();
				// EdgeDefinitionsEntity edgeDefinitionsEntity = new
				// EdgeDefinitionsEntity();
				if (!edgeDefinitions.equals(null)) {
					for (int i = 0, imax = edgeDefinitions.size(); i < imax; i++) {
						EdgeDefinitionEntity edgeDefinitionEntity = new EdgeDefinitionEntity();
						JsonObject edgeDefinition = edgeDefinitions.get(i).getAsJsonObject();
						if (edgeDefinition.has("collection")) {
							edgeDefinitionEntity.setCollection(edgeDefinition.get("collection").getAsString());
						}
						if (edgeDefinition.has("from")) {
							List from = new ArrayList();
							JsonElement fromElem = edgeDefinition.get("from");
							JsonArray fromArray = fromElem.getAsJsonArray();
							Iterator iterator = fromArray.iterator();
							while (iterator.hasNext()) {
								JsonElement e = iterator.next();
								from.add(e.getAsString());
							}

							edgeDefinitionEntity.setFrom(from);
						}
						if (edgeDefinition.has("to")) {
							List to = new ArrayList();
							JsonElement toElem = edgeDefinition.get("to");
							JsonArray toArray = toElem.getAsJsonArray();
							Iterator iterator = toArray.iterator();
							while (iterator.hasNext()) {
								JsonElement e = iterator.next();
								to.add(e.getAsString());
							}
							edgeDefinitionEntity.setTo(to);
						}
						entity.edgeDefinitionsEntity.addEdgeDefinition(edgeDefinitionEntity);
					}
				}
			}

			return entity;

		}
	}

	public static class GraphsEntityDeserializer implements JsonDeserializer {
		private Type graphsType = new TypeToken>() {
		}.getType();

		@Override
		public GraphsEntity deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
				throws JsonParseException {

			if (json.isJsonNull()) {
				return null;
			}

			JsonObject obj = json.getAsJsonObject();
			GraphsEntity entity = deserializeBaseParameter(obj, new GraphsEntity());

			if (obj.has("graphs")) {
				entity.graphs = context.deserialize(obj.get("graphs"), graphsType);
			}

			return entity;

		}
	}

	public static class DeleteEntityDeserializer implements JsonDeserializer {
		@Override
		public DeletedEntity deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
				throws JsonParseException {

			if (json.isJsonNull()) {
				return null;
			}

			JsonObject obj = json.getAsJsonObject();
			DeletedEntity entity = deserializeBaseParameter(obj, new DeletedEntity());

			if (obj.has("deleted")) {
				entity.deleted = obj.getAsJsonPrimitive("deleted").getAsBoolean();
			}
			if (obj.has("removed")) {
				entity.deleted = obj.getAsJsonPrimitive("removed").getAsBoolean();
			}

			return entity;

		}
	}

	public static class VertexEntityDeserializer implements JsonDeserializer> {
		@Override
		public VertexEntity deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
				throws JsonParseException {

			if (json.isJsonNull()) {
				return null;
			}

			JsonObject obj = json.getAsJsonObject();
			VertexEntity entity = deserializeBaseParameter(obj, new VertexEntity());

			JsonObject vertex = obj.has("vertex") ? obj.getAsJsonObject("vertex") : obj;
			deserializeDocumentParameter(vertex, entity);

			Class clazz = getParameterized();
			if (clazz != null) {
				entity.setEntity(context.deserialize(vertex, clazz));
			}

			return entity;
		}
	}

	public static class EdgeEntityDeserializer implements JsonDeserializer> {
		@Override
		public EdgeEntity deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
				throws JsonParseException {

			if (json.isJsonNull()) {
				return null;
			}

			JsonObject obj = json.getAsJsonObject();
			EdgeEntity entity = deserializeBaseParameter(obj, new EdgeEntity());

			JsonObject edge = obj.has("edge") ? obj.getAsJsonObject("edge") : obj;
			deserializeDocumentParameter(edge, entity);

			if (edge.has("_from")) {
				entity.fromVertexHandle = edge.getAsJsonPrimitive("_from").getAsString();
			}
			if (edge.has("_to")) {
				entity.toVertexHandle = edge.getAsJsonPrimitive("_to").getAsString();
			}

			// 他のフィールドはリフレクションで。 (TODO: Annotationのサポートと上記パラメータを弾く)
			Class clazz = getParameterized();
			if (clazz != null) {
				entity.entity = context.deserialize(edge, clazz);
			}

			return entity;
		}

	}

	public static class TraversalEntityDeserializer implements JsonDeserializer> {
		@Override
		public TraversalEntity deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
				throws JsonParseException {

			if (json.isJsonNull()) {
				return null;
			}

			JsonObject obj = json.getAsJsonObject();
			TraversalEntity entity = deserializeBaseParameter(obj,
				new TraversalEntity());
			deserializeBaseParameter(obj, entity);

			JsonObject result = getFirstResultAsJsonObject(obj);
			if (result != null) {
				if (result.getAsJsonObject().has("visited")) {
					JsonObject visited = result.getAsJsonObject().getAsJsonObject("visited");

					Class vertexClazz = getParameterized();
					Class edgeClazz = null;

					if (hasNextParameterized()) {
						edgeClazz = nextParameterized();
					}

					if (visited.has("vertices")) {
						entity.setVertices(getVertices(vertexClazz, context, visited.getAsJsonArray("vertices")));
					}
					if (visited.has("paths")) {
						entity.setPaths(getPaths(context, visited, vertexClazz, edgeClazz));
					}
				}
			}

			return entity;
		}
	}

	public static class ShortestPathEntityDeserializer implements JsonDeserializer> {
		@Override
		public ShortestPathEntity deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
				throws JsonParseException {

			if (json.isJsonNull()) {
				return null;
			}

			JsonObject obj = json.getAsJsonObject();
			ShortestPathEntity entity = deserializeBaseParameter(obj,
				new ShortestPathEntity());
			deserializeBaseParameter(obj, entity);

			JsonObject result = getFirstResultAsJsonObject(obj);
			if (result != null) {
				Class vertexClazz = getParameterized();
				Class edgeClazz = null;

				if (hasNextParameterized()) {
					edgeClazz = nextParameterized();
				}

				if (result.has("distance")) {
					entity.setDistance(result.get("distance").getAsLong());
				} else {
					entity.setDistance(-1L);
				}
				if (result.has("edges")) {
					// new version >= 2.6
					entity.setEdges(getEdges(edgeClazz, context, result.getAsJsonArray("edges")));
				}
				if (result.has("vertices")) {
					// new version >= 2.6
					entity.setVertices(getVertices(vertexClazz, context, result.getAsJsonArray("vertices")));
				}
				if (result.has("paths")) {
					// old version < 2.6
					JsonArray paths = result.getAsJsonArray("paths");
					if (!paths.equals(null) && paths.size() > 0) {
						JsonObject path = paths.get(0).getAsJsonObject();

						if (path.has("edges")) {
							entity.setEdges(getEdges(edgeClazz, context, path.getAsJsonArray("edges")));
						}
						if (path.has("vertices")) {
							entity.setVertices(getVertices(vertexClazz, context, path.getAsJsonArray("vertices")));
						}
					}
				}
			} else {
				entity.setDistance(-1L);
			}

			return entity;
		}
	}

	public static class QueryCachePropertiesEntityDeserializer implements JsonDeserializer {

		@Override
		public QueryCachePropertiesEntity deserialize(
			JsonElement json,
			Type typeOfT,
			JsonDeserializationContext context) throws JsonParseException {

			if (json.isJsonNull()) {
				return null;
			}

			JsonObject obj = json.getAsJsonObject();
			QueryCachePropertiesEntity entity = deserializeBaseParameter(obj, new QueryCachePropertiesEntity());

			if (obj.has("mode")) {
				entity.setMode(obj.getAsJsonPrimitive("mode").getAsString());
			}

			if (obj.has("maxResults")) {
				entity.setMaxResults(obj.getAsJsonPrimitive("maxResults").getAsLong());
			}

			return entity;
		}

	}

	private static JsonObject getFirstResultAsJsonObject(JsonObject obj) {
		if (obj.has("result")) {
			if (obj.get("result").isJsonArray()) {
				JsonArray result = obj.getAsJsonArray("result");

				if (result.size() > 0) {
					JsonElement jsonElement = result.get(0);
					if (jsonElement.isJsonObject()) {
						return jsonElement.getAsJsonObject();
					}
				}
			} else if (obj.get("result").isJsonObject()) {
				return obj.getAsJsonObject("result");
			}

		}
		return null;
	}

	private static List> getPaths(
		JsonDeserializationContext context,
		JsonObject visited,
		Class vertexClazz,
		Class edgeClazz) {
		List> pathEntities = new ArrayList>();
		JsonArray paths = visited.getAsJsonArray("paths");
		if (!paths.equals(null)) {
			for (int i = 0, imax = paths.size(); i < imax; i++) {
				JsonObject path = paths.get(i).getAsJsonObject();
				PathEntity pathEntity = new PathEntity();

				if (path.has("edges")) {
					pathEntity.setEdges(getEdges(edgeClazz, context, path.getAsJsonArray("edges")));
				}
				if (path.has("vertices")) {
					pathEntity.setVertices(getVertices(vertexClazz, context, path.getAsJsonArray("vertices")));
				}

				pathEntities.add(pathEntity);
			}
		}
		return pathEntities;
	}

	private static List> getVertices(
		Class vertexClazz,
		JsonDeserializationContext context,
		JsonArray vertices) {
		List> list = new ArrayList>();
		if (!vertices.equals(null)) {
			for (int i = 0, imax = vertices.size(); i < imax; i++) {
				JsonObject vertex = vertices.get(i).getAsJsonObject();
				VertexEntity ve = getVertex(context, vertex, vertexClazz);
				list.add(ve);
			}
		}
		return list;
	}

	private static VertexEntity getVertex(
		JsonDeserializationContext context,
		JsonObject vertex,
		Class vertexClazz) {
		VertexEntity ve = deserializeBaseParameter(vertex, new VertexEntity());
		deserializeDocumentParameter(vertex, ve);
		if (vertexClazz != null) {
			ve.setEntity(context.deserialize(vertex, vertexClazz));
		} else {
			ve.setEntity(context.deserialize(vertex, Object.class));
		}
		return ve;
	}

	private static List> getEdges(
		Class edgeClazz,
		JsonDeserializationContext context,
		JsonArray edges) {
		List> list = new ArrayList>();
		if (!edges.equals(null)) {
			for (int i = 0, imax = edges.size(); i < imax; i++) {
				JsonObject edge = edges.get(i).getAsJsonObject();
				EdgeEntity ve = deserializeBaseParameter(edge, new EdgeEntity());
				deserializeDocumentParameter(edge, ve);
				if (edgeClazz != null) {
					ve.setEntity(context.deserialize(edge, edgeClazz));
				} else {
					ve.setEntity(context.deserialize(edge, Object.class));
				}
				list.add(ve);
			}
		}
		return list;
	}
}