PageRenderTime 71ms CodeModel.GetById 29ms RepoModel.GetById 0ms app.codeStats 0ms

/tags/0.9.21/core/src/main/java/com/orientechnologies/orient/core/serialization/serializer/record/string/ORecordSerializerJSON.java

http://orient.googlecode.com/
Java | 355 lines | 271 code | 53 blank | 31 comment | 106 complexity | a9f751dd25848ead60c288cba1cc77af MD5 | raw file
Possible License(s): Apache-2.0, AGPL-3.0
  1. /*
  2. * Copyright 1999-2010 Luca Garulli (l.garulli--at--orientechnologies.com)
  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.orientechnologies.orient.core.serialization.serializer.record.string;
  17. import java.io.IOException;
  18. import java.io.StringWriter;
  19. import java.util.ArrayList;
  20. import java.util.Collection;
  21. import java.util.HashSet;
  22. import java.util.LinkedHashMap;
  23. import java.util.List;
  24. import java.util.Map;
  25. import com.orientechnologies.common.parser.OStringParser;
  26. import com.orientechnologies.orient.core.db.OUserObject2RecordHandler;
  27. import com.orientechnologies.orient.core.db.record.ODatabaseRecord;
  28. import com.orientechnologies.orient.core.exception.OSerializationException;
  29. import com.orientechnologies.orient.core.id.ORecordId;
  30. import com.orientechnologies.orient.core.metadata.schema.OProperty;
  31. import com.orientechnologies.orient.core.metadata.schema.OType;
  32. import com.orientechnologies.orient.core.record.ORecordFactory;
  33. import com.orientechnologies.orient.core.record.ORecordInternal;
  34. import com.orientechnologies.orient.core.record.ORecordSchemaAware;
  35. import com.orientechnologies.orient.core.record.ORecordStringable;
  36. import com.orientechnologies.orient.core.record.impl.ODocument;
  37. import com.orientechnologies.orient.core.record.impl.ORecordBytes;
  38. import com.orientechnologies.orient.core.record.impl.ORecordColumn;
  39. import com.orientechnologies.orient.core.serialization.OBase64Utils;
  40. import com.orientechnologies.orient.core.serialization.serializer.OJSONWriter;
  41. import com.orientechnologies.orient.core.serialization.serializer.OStringSerializerHelper;
  42. public class ORecordSerializerJSON extends ORecordSerializerStringAbstract {
  43. public static final String NAME = "json";
  44. public static final ORecordSerializerJSON INSTANCE = new ORecordSerializerJSON();
  45. public static final String ATTRIBUTE_ID = "@rid";
  46. public static final String ATTRIBUTE_VERSION = "@version";
  47. public static final String ATTRIBUTE_TYPE = "@type";
  48. public static final String ATTRIBUTE_CLASS = "@class";
  49. @Override
  50. public ORecordInternal<?> fromString(final ODatabaseRecord<?> iDatabase, final String iSource) {
  51. return fromString(iDatabase, iSource, null);
  52. }
  53. @Override
  54. public ORecordInternal<?> fromString(final ODatabaseRecord<?> iDatabase, String iSource, ORecordInternal<?> iRecord) {
  55. iSource = iSource.trim();
  56. if (!iSource.startsWith("{") || !iSource.endsWith("}"))
  57. throw new OSerializationException("Error on unmarshalling JSON content: content must be embraced by { }");
  58. if (iRecord != null) {
  59. iRecord.reset();
  60. iRecord.setDirty();
  61. }
  62. iSource = iSource.substring(1, iSource.length() - 1).trim();
  63. String[] fields = OStringParser.getWords(iSource, ":,", true);
  64. try {
  65. if (fields != null && fields.length > 0) {
  66. String fieldName;
  67. String fieldValue;
  68. String fieldValueAsString;
  69. for (int i = 0; i < fields.length; i += 2) {
  70. fieldName = fields[i];
  71. fieldName = fieldName.substring(1, fieldName.length() - 1);
  72. fieldValue = fields[i + 1];
  73. fieldValueAsString = fieldValue.length() >= 2 ? fieldValue.substring(1, fieldValue.length() - 1) : fieldValue;
  74. // RECORD ATTRIBUTES
  75. if (fieldName.equals(ATTRIBUTE_ID))
  76. iRecord.setIdentity(new ORecordId(fieldValueAsString));
  77. else if (fieldName.equals(ATTRIBUTE_VERSION))
  78. iRecord.setVersion(Integer.parseInt(fieldValue));
  79. else if (fieldName.equals(ATTRIBUTE_TYPE)) {
  80. if (iRecord == null || iRecord.getRecordType() != fieldValueAsString.charAt(0)) {
  81. // CREATE THE RIGHT RECORD INSTANCE
  82. iRecord = ORecordFactory.newInstance((byte) fieldValueAsString.charAt(0));
  83. iRecord.setDatabase(iDatabase);
  84. }
  85. } else if (fieldName.equals(ATTRIBUTE_CLASS) && iRecord instanceof ODocument)
  86. ((ODocument) iRecord).setClassName("null".equals(fieldValueAsString) ? null : fieldValueAsString);
  87. // RECORD VALUE(S)
  88. else if (fieldName.equals("value")) {
  89. if (iRecord instanceof ORecordColumn) {
  90. fieldValueAsString = fieldValueAsString.trim();
  91. final String[] items = OStringParser.getWords(fieldValueAsString, ",");
  92. for (String item : items) {
  93. ((ORecordColumn) iRecord).add(item);
  94. }
  95. } else if (iRecord instanceof ORecordBytes) {
  96. // BYTES
  97. iRecord.fromStream(OBase64Utils.decode(fieldValueAsString));
  98. } else if (iRecord instanceof ORecordStringable) {
  99. ((ORecordStringable) iRecord).value(fieldValueAsString);
  100. }
  101. } else {
  102. if (iRecord instanceof ODocument)
  103. ((ODocument) iRecord).field(fieldName,
  104. getValue((ODocument) iRecord, fieldName, fieldValue, fieldValueAsString, null, null));
  105. }
  106. }
  107. }
  108. } catch (Exception e) {
  109. e.printStackTrace();
  110. throw new OSerializationException("Error on unmarshalling JSON content", e);
  111. }
  112. return iRecord;
  113. }
  114. private Object getValue(final ODocument iRecord, String iFieldName, String iFieldValue, String iFieldValueAsString, OType type,
  115. OType linkedType) {
  116. if (iFieldValueAsString.equals("null"))
  117. return null;
  118. if (iFieldName != null)
  119. if (iRecord.getSchemaClass() != null) {
  120. final OProperty p = iRecord.getSchemaClass().getProperty(iFieldName);
  121. if (p != null) {
  122. type = p.getType();
  123. linkedType = p.getLinkedType();
  124. }
  125. }
  126. if (iFieldValue.startsWith("{") && iFieldValue.endsWith("}")) {
  127. // OBJECT OR MAP. CHECK THE TYPE ATTRIBUTE TO KNOW IT
  128. String[] fields = OStringParser.getWords(iFieldValueAsString, ":,", true);
  129. if (fields == null || fields.length == 0)
  130. // EMPTY, WHAT EVER IT WAS
  131. return null;
  132. if (fields[0].equals("\"@type\""))
  133. // OBJECT
  134. return fromString(iRecord.getDatabase(), iFieldValue, null);
  135. else {
  136. // MAP
  137. final Map<String, Object> embeddedMap = new LinkedHashMap<String, Object>();
  138. for (int i = 0; i < fields.length; i += 2) {
  139. iFieldName = fields[i];
  140. if (iFieldName.length() >= 2)
  141. iFieldName = iFieldName.substring(1, iFieldName.length() - 1);
  142. iFieldValue = fields[i + 1];
  143. iFieldValueAsString = iFieldValue.length() >= 2 ? iFieldValue.substring(1, iFieldValue.length() - 1) : iFieldValue;
  144. embeddedMap.put(iFieldName, getValue(iRecord, null, iFieldValue, iFieldValueAsString, linkedType, null));
  145. }
  146. return embeddedMap;
  147. }
  148. } else if (iFieldValue.startsWith("[") && iFieldValue.endsWith("]")) {
  149. // EMBEDDED VALUES
  150. final Collection<Object> embeddedCollection;
  151. if (type == OType.LINKSET || type == OType.EMBEDDEDSET)
  152. embeddedCollection = new HashSet<Object>();
  153. else
  154. embeddedCollection = new ArrayList<Object>();
  155. iFieldValue = iFieldValue.substring(1, iFieldValue.length() - 1);
  156. if (iFieldValue.length() > 0) {
  157. // EMBEDDED VALUES
  158. List<String> items = OStringSerializerHelper.smartSplit(iFieldValue, ',');
  159. for (String item : items) {
  160. iFieldValue = item.trim();
  161. iFieldValueAsString = iFieldValue.length() >= 2 ? iFieldValue.substring(1, iFieldValue.length() - 1) : iFieldValue;
  162. embeddedCollection.add(getValue(iRecord, null, iFieldValue, iFieldValueAsString, linkedType, null));
  163. }
  164. }
  165. return embeddedCollection;
  166. }
  167. if (type == null)
  168. // TRY TO DETERMINE THE CONTAINED TYPE from THE FIRST VALUE
  169. if (iFieldValue.charAt(0) != '\"') {
  170. if (iFieldValue.equalsIgnoreCase("false") || iFieldValue.equalsIgnoreCase("true"))
  171. type = OType.BOOLEAN;
  172. else if (OStringSerializerHelper.contains(iFieldValue, '.'))
  173. type = OType.DOUBLE;
  174. else
  175. type = OType.LONG;
  176. } else if (iFieldValueAsString.length() >= 4 && iFieldValueAsString.charAt(0) == '#')
  177. type = OType.LINK;
  178. else if (iFieldValueAsString.startsWith("{") && iFieldValueAsString.endsWith("}"))
  179. type = OType.EMBEDDED;
  180. else
  181. type = OType.STRING;
  182. if (type != null)
  183. switch (type) {
  184. case STRING:
  185. return iFieldValueAsString;
  186. case LINK:
  187. final int pos = iFieldValueAsString.indexOf("@");
  188. if (pos > -1)
  189. // CREATE DOCUMENT
  190. return new ODocument(iRecord.getDatabase(), iFieldValueAsString.substring(1, pos), new ORecordId(
  191. iFieldValueAsString.substring(pos + 1)));
  192. else
  193. // CREATE SIMPLE RID
  194. return new ORecordId(iFieldValueAsString.substring(1));
  195. case EMBEDDED:
  196. return fromString(iRecord.getDatabase(), iFieldValueAsString);
  197. default:
  198. return OStringSerializerHelper.fieldTypeFromStream(type, iFieldValue);
  199. }
  200. return iFieldValueAsString;
  201. }
  202. @Override
  203. public String toString(final ORecordInternal<?> iRecord, final String iFormat, final OUserObject2RecordHandler iObjHandler,
  204. final Map<ORecordInternal<?>, ORecordId> iMarshalledRecords) {
  205. try {
  206. final StringWriter buffer = new StringWriter();
  207. final OJSONWriter json = new OJSONWriter(buffer);
  208. boolean includeVer;
  209. boolean includeType;
  210. boolean includeId;
  211. boolean includeClazz;
  212. boolean attribSameRow;
  213. int indentLevel;
  214. if (iFormat == null) {
  215. includeType = true;
  216. includeVer = true;
  217. includeId = true;
  218. includeClazz = true;
  219. attribSameRow = true;
  220. indentLevel = 0;
  221. } else {
  222. includeType = true;
  223. includeVer = false;
  224. includeId = false;
  225. includeClazz = false;
  226. attribSameRow = false;
  227. indentLevel = 0;
  228. String[] format = iFormat.split(",");
  229. for (String f : format)
  230. if (f.equals("type"))
  231. includeType = true;
  232. else if (f.equals("rid"))
  233. includeId = true;
  234. else if (f.equals("version"))
  235. includeVer = true;
  236. else if (f.equals("class"))
  237. includeClazz = true;
  238. else if (f.equals("attribSameRow"))
  239. attribSameRow = true;
  240. else if (f.startsWith("indent"))
  241. indentLevel = Integer.parseInt(f.substring(f.indexOf(":") + 1));
  242. }
  243. json.beginObject(indentLevel);
  244. boolean firstAttribute = true;
  245. if (includeType) {
  246. json.writeAttribute(firstAttribute ? indentLevel + 1 : 0, firstAttribute, ATTRIBUTE_TYPE,
  247. "" + (char) iRecord.getRecordType());
  248. if (attribSameRow)
  249. firstAttribute = false;
  250. }
  251. if (includeId) {
  252. json.writeAttribute(firstAttribute ? indentLevel + 1 : 0, firstAttribute, ATTRIBUTE_ID, iRecord.getIdentity().toString());
  253. if (attribSameRow)
  254. firstAttribute = false;
  255. }
  256. if (includeVer) {
  257. json.writeAttribute(firstAttribute ? indentLevel + 1 : 0, firstAttribute, ATTRIBUTE_VERSION, iRecord.getVersion());
  258. if (attribSameRow)
  259. firstAttribute = false;
  260. }
  261. if (includeClazz && iRecord instanceof ORecordSchemaAware<?>) {
  262. json.writeAttribute(firstAttribute ? indentLevel + 1 : 0, firstAttribute, ATTRIBUTE_CLASS,
  263. ((ORecordSchemaAware<?>) iRecord).getClassName());
  264. if (attribSameRow)
  265. firstAttribute = false;
  266. }
  267. if (iRecord instanceof ORecordSchemaAware<?>) {
  268. // SCHEMA AWARE
  269. final ORecordSchemaAware<?> record = (ORecordSchemaAware<?>) iRecord;
  270. for (String fieldName : record.fieldNames()) {
  271. json.writeAttribute(indentLevel + 1, true, fieldName, encode(record.field(fieldName)));
  272. }
  273. } else if (iRecord instanceof ORecordStringable) {
  274. // STRINGABLE
  275. final ORecordStringable record = (ORecordStringable) iRecord;
  276. json.writeAttribute(indentLevel + 1, true, "value", record.value());
  277. } else if (iRecord instanceof ORecordBytes) {
  278. // BYTES
  279. final ORecordBytes record = (ORecordBytes) iRecord;
  280. json.writeAttribute(indentLevel + 1, true, "value", OBase64Utils.encodeBytes(record.toStream()));
  281. } else
  282. throw new OSerializationException("Error on marshalling record of type '" + iRecord.getClass()
  283. + "' to JSON. The record type can't be exported to JSON");
  284. json.endObject(indentLevel);
  285. return buffer.toString();
  286. } catch (IOException e) {
  287. throw new OSerializationException("Error on marshalling of record to JSON", e);
  288. }
  289. }
  290. private Object encode(final Object iValue) {
  291. if (iValue instanceof String) {
  292. final String encoded = ((String) iValue).replace('"', '\'');
  293. return encoded;
  294. } else
  295. return iValue;
  296. }
  297. @Override
  298. public String toString() {
  299. return NAME;
  300. }
  301. }