PageRenderTime 1823ms CodeModel.GetById 0ms RepoModel.GetById 0ms app.codeStats 0ms

/core/infinit.e.data_model/src/com/ikanow/infinit/e/data_model/api/BaseApiPojo.java

https://github.com/IKANOW/Infinit.e
Java | 283 lines | 229 code | 8 blank | 46 comment | 17 complexity | 4474287282ba84a8ce0de10000554a09 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. /*******************************************************************************
  2. * Copyright 2012 The Infinit.e Open Source Project
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. ******************************************************************************/
  16. package com.ikanow.infinit.e.data_model.api;
  17. import java.lang.reflect.ParameterizedType;
  18. import java.lang.reflect.Type;
  19. import java.util.Collection;
  20. import java.util.Date;
  21. import java.util.List;
  22. import org.bson.types.ObjectId;
  23. import com.google.gson.GsonBuilder;
  24. import com.google.gson.JsonArray;
  25. import com.google.gson.JsonDeserializationContext;
  26. import com.google.gson.JsonDeserializer;
  27. import com.google.gson.JsonElement;
  28. import com.google.gson.JsonParseException;
  29. import com.google.gson.JsonPrimitive;
  30. import com.google.gson.JsonSerializationContext;
  31. import com.google.gson.JsonSerializer;
  32. import com.google.gson.reflect.TypeToken;
  33. import com.ikanow.infinit.e.data_model.utils.ThreadSafeSimpleDateFormat;
  34. public class BaseApiPojo {
  35. // Every Pojo should "override" this static function (stick the actual class in the 2x <>s) for readability
  36. static public <S> TypeToken<List<S>> listType() { return new TypeToken<List<S>>(){}; }
  37. // Override this function to perform custom serialization (see BasePojoApiMap)
  38. public GsonBuilder extendBuilder(GsonBuilder gp) {
  39. return extendBuilder_internal(gp);
  40. }
  41. // Allows API owner to enforce some custom serializations
  42. final public static GsonBuilder getDefaultBuilder() {
  43. GsonBuilder gb =
  44. new GsonBuilder()
  45. .registerTypeAdapter(ObjectId.class, new ObjectIdSerializer())
  46. .registerTypeAdapter(ObjectId.class, new ObjectIdDeserializer())
  47. .registerTypeAdapter(Date.class, new DateDeserializer())
  48. .registerTypeAdapter(Date.class, new DateSerializer())
  49. .registerTypeAdapter(JsonArray.class, new JsonArraySerializer())
  50. ;
  51. return gb;
  52. }
  53. private static GsonBuilder extendBuilder_internal(GsonBuilder gp) {
  54. return gp;
  55. }
  56. //________________________________________________________________________________________________
  57. // Won't normally override these (but can)
  58. // DB format conversion
  59. // For BaseApiPojos
  60. // 2 versions, 1 where you need dynamic mapping (eg runtime-specific)
  61. // (in both cases for single objects, you can use the nicer class<X> or
  62. // the nastier Google TypeToken, the latter has 2 advantages:
  63. // a. consisntency with list types, where you have to use the TypeToken
  64. // b. the class<X> doesn't work where X is generic)
  65. //
  66. // Note - the code is a bit unpleastant in places....
  67. /////////////////////////////////////////////////////////////////////////////////////
  68. // To the API JSON From a single Object
  69. public static<S extends BaseApiPojo> String toApi(S s) {
  70. return toApi(s, null);
  71. }
  72. // (Nicer version of the static "toApi")
  73. public String toApi() {
  74. return toApi(this);
  75. }
  76. public static<S extends BaseApiPojo> String toApi(S s, BasePojoApiMap<S> dynamicMap) {
  77. GsonBuilder gb = s.extendBuilder(BaseApiPojo.getDefaultBuilder());
  78. if (null != dynamicMap) {
  79. gb = dynamicMap.extendBuilder(gb);
  80. }
  81. return gb.create().toJson(s);
  82. }
  83. /////////////////////////////////////////////////////////////////////////////////////
  84. // From the API JSON To a single Object
  85. public static<S extends BaseApiPojo> S fromApi(String s, Class<S> type) {
  86. return fromApi(s, type, null);
  87. }
  88. public static<S extends BaseApiPojo> S fromApi(JsonElement j, Class<S> type) {
  89. return fromApi(j, type, null);
  90. }
  91. public static<S extends BaseApiPojo> S fromApi(String s, TypeToken<S> type) {
  92. return fromApi(s, type, null);
  93. }
  94. public static<S extends BaseApiPojo> S fromApi(JsonElement j, TypeToken<S> type) {
  95. return fromApi(j, type, null);
  96. }
  97. public static<S extends BaseApiPojo> S fromApi(String s, Class<S> type, BasePojoApiMap<S> dynamicMap) {
  98. // Create a new instance of the class in order to override it
  99. GsonBuilder gb = null;
  100. try {
  101. gb = type.newInstance().extendBuilder(BaseApiPojo.getDefaultBuilder());
  102. } catch (Exception e) {
  103. return null;
  104. }
  105. if (null != dynamicMap) {
  106. gb = dynamicMap.extendBuilder(gb);
  107. }
  108. return gb.create().fromJson(s.toString(), type);
  109. }
  110. public static<S extends BaseApiPojo> S fromApi(JsonElement j, Class<S> type, BasePojoApiMap<S> dynamicMap) {
  111. // Create a new instance of the class in order to override it
  112. GsonBuilder gb = null;
  113. try {
  114. gb = type.newInstance().extendBuilder(BaseApiPojo.getDefaultBuilder());
  115. } catch (Exception e) {
  116. return null;
  117. }
  118. if (null != dynamicMap) {
  119. gb = dynamicMap.extendBuilder(gb);
  120. }
  121. return gb.create().fromJson(j, type);
  122. }
  123. @SuppressWarnings("unchecked")
  124. public static<S extends BaseApiPojo> S fromApi(String s, TypeToken<S> type, BasePojoApiMap<S> dynamicMap) {
  125. GsonBuilder gb = null;
  126. try {
  127. Class<S> clazz = (Class<S>)type.getType();
  128. gb = ((S)clazz.newInstance()).extendBuilder(BaseApiPojo.getDefaultBuilder());
  129. } catch (Exception e) {
  130. return null;
  131. }
  132. if (null != dynamicMap) {
  133. gb = dynamicMap.extendBuilder(gb);
  134. }
  135. return (S)gb.create().fromJson(s.toString(), type.getType());
  136. }
  137. @SuppressWarnings("unchecked")
  138. public static<S extends BaseApiPojo> S fromApi(JsonElement j, TypeToken<S> type, BasePojoApiMap<S> dynamicMap) {
  139. GsonBuilder gb = null;
  140. try {
  141. Class<S> clazz = (Class<S>)type.getType();
  142. gb = ((S)clazz.newInstance()).extendBuilder(BaseApiPojo.getDefaultBuilder());
  143. } catch (Exception e) {
  144. return null;
  145. }
  146. if (null != dynamicMap) {
  147. gb = dynamicMap.extendBuilder(gb);
  148. }
  149. return (S)gb.create().fromJson(j, type.getType());
  150. }
  151. /////////////////////////////////////////////////////////////////////////////////////
  152. // To the API JSON From a list of objects
  153. public static <S extends BaseApiPojo> String listToApi(Collection<S> list, TypeToken<? extends Collection<S>> listType) {
  154. return listToApi(list, listType, null);
  155. }
  156. public static <S extends BaseApiPojo> String listToApi(Collection<S> list, TypeToken<? extends Collection<S>> listType, BasePojoApiMap<S> dynamicMap) {
  157. GsonBuilder gb = null;
  158. try {
  159. if (!list.isEmpty()) {
  160. gb = list.iterator().next().extendBuilder(BaseApiPojo.getDefaultBuilder());
  161. }
  162. } catch (Exception e) {
  163. return null;
  164. }
  165. return gb.create().toJson(list, listType.getType());
  166. }
  167. /////////////////////////////////////////////////////////////////////////////////////
  168. // From the API JSON to a list of objects
  169. public static <S extends BaseApiPojo, L extends Collection<S>> L listFromApi(String json, TypeToken<? extends L> listType) {
  170. return listFromApi(json, listType, null);
  171. }
  172. public static <S extends BaseApiPojo, L extends Collection<S>> L listFromApi(JsonElement json, TypeToken<? extends L> listType) {
  173. return listFromApi(json, listType, null);
  174. }
  175. @SuppressWarnings("unchecked")
  176. public static <S extends BaseApiPojo, L extends Collection<S>> L listFromApi(String json, TypeToken<? extends L> listType, BasePojoApiMap<S> dynamicMap) {
  177. GsonBuilder gb = null;
  178. try {
  179. Class<S> clazz = (Class<S>)((ParameterizedType)listType.getType()).getActualTypeArguments()[0];
  180. // (know this works because of construction of listType)
  181. gb = (clazz.newInstance()).extendBuilder(BaseApiPojo.getDefaultBuilder());
  182. } catch (Exception e) {
  183. return null;
  184. }
  185. if (null != dynamicMap) {
  186. gb = dynamicMap.extendBuilder(gb);
  187. }
  188. return (L)gb.create().fromJson(json, listType.getType());
  189. }
  190. @SuppressWarnings("unchecked")
  191. public static <S extends BaseApiPojo, L extends Collection<S>> L listFromApi(JsonElement json, TypeToken<? extends L> listType, BasePojoApiMap<S> dynamicMap) {
  192. GsonBuilder gb = null;
  193. try {
  194. Class<S> clazz = (Class<S>)((ParameterizedType)listType.getType()).getActualTypeArguments()[0];
  195. // (know this works because of construction of listType)
  196. gb = (clazz.newInstance()).extendBuilder(BaseApiPojo.getDefaultBuilder());
  197. } catch (Exception e) {
  198. return null;
  199. }
  200. if (null != dynamicMap) {
  201. gb = dynamicMap.extendBuilder(gb);
  202. }
  203. return (L)gb.create().fromJson(json, listType.getType());
  204. }
  205. //___________________________________________________________________
  206. // Default MongoDB serialization rule:
  207. // 1. Object Ids
  208. protected static class ObjectIdSerializer implements JsonSerializer<ObjectId>
  209. {
  210. @Override
  211. public JsonElement serialize(ObjectId id, Type typeOfT, JsonSerializationContext context)
  212. {
  213. return new JsonPrimitive(id.toStringMongod());
  214. }
  215. }
  216. protected static class ObjectIdDeserializer implements JsonDeserializer<ObjectId>
  217. {
  218. @Override
  219. public ObjectId deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException
  220. {
  221. if (json.isJsonPrimitive()) {
  222. return new ObjectId(json.getAsString());
  223. }
  224. else {
  225. try {
  226. return new ObjectId(json.getAsJsonObject().get("$oid").getAsString());
  227. }
  228. catch (Exception e) {
  229. return null;
  230. }
  231. }
  232. }
  233. }
  234. protected static class DateDeserializer implements JsonDeserializer<Date>
  235. {
  236. private static ThreadSafeSimpleDateFormat _format = new ThreadSafeSimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
  237. private static ThreadSafeSimpleDateFormat _format2 = new ThreadSafeSimpleDateFormat("MMM d, yyyy hh:mm:ss a");
  238. @Override
  239. public Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
  240. throws JsonParseException
  241. {
  242. Date d = null;
  243. try {
  244. d = _format2.parse(json.getAsString());
  245. }
  246. catch (Exception e) {
  247. try {
  248. d = _format.parse(json.getAsString());
  249. }
  250. catch (Exception e2) {
  251. d = null;
  252. }
  253. }
  254. return d;
  255. }
  256. }
  257. // Just convert API calls to UTC
  258. protected static class DateSerializer implements JsonSerializer<Date>
  259. {
  260. @Override
  261. public JsonElement serialize(Date date, Type typeOfT, JsonSerializationContext context)
  262. {
  263. ThreadSafeSimpleDateFormat tsdf = new ThreadSafeSimpleDateFormat("MMM d, yyyy hh:mm:ss a 'UTC'");
  264. return new JsonPrimitive(tsdf.format(date));
  265. }
  266. }
  267. protected static class JsonArraySerializer implements JsonSerializer<JsonArray>
  268. {
  269. @Override
  270. public JsonElement serialize(JsonArray jsonArray, Type typeOfT, JsonSerializationContext context)
  271. {
  272. return jsonArray;
  273. }
  274. }
  275. }