diff --git a/src/main/java/br/ufrgs/inf/prosoft/jsonserialiser/JSONSerialiser.java b/src/main/java/br/ufrgs/inf/prosoft/jsonserialiser/JSONSerialiser.java
index 53c5da4..9b257b2 100644
--- a/src/main/java/br/ufrgs/inf/prosoft/jsonserialiser/JSONSerialiser.java
+++ b/src/main/java/br/ufrgs/inf/prosoft/jsonserialiser/JSONSerialiser.java
@@ -6,7 +6,6 @@
package br.ufrgs.inf.prosoft.jsonserialiser;
import java.io.IOException;
-import java.io.Writer;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.nio.file.Files;
@@ -27,28 +26,15 @@ import java.util.Map;
public class JSONSerialiser {
private final Collection<Object> visited;
- private final Writer writer;
- private JSONSerialiser(Writer writer) {
+ private JSONSerialiser() {
this.visited = new ArrayList<>();
- this.writer = writer;
}
- public static void serialise(Object bean, Writer writer, boolean cyclicFields) throws IOException {
- JSONSerialiser jsonSerialiser = new JSONSerialiser(writer);
- jsonSerialiser.serialiseBean(bean, cyclicFields);
- }
-
- public static void serialise(Object bean, Writer writer) throws IOException {
- serialise(bean, writer, true);
- }
-
- public static String serialise(Object bean, boolean cyclicFields) {
- StringBuilder stringBuilder = new StringBuilder();
- try {
- serialise(bean, new StringBuilderWriter(stringBuilder), cyclicFields);
- } catch (IOException ex) {
- }
+ private static String serialise(Object bean, boolean cyclicFields) {
+ JSONSerialiser jsonSerialiser = new JSONSerialiser();
+ StringBuilder stringBuilder = jsonSerialiser.serialiseBean(bean, cyclicFields);
+ Utils.fixJson(stringBuilder);
return stringBuilder.toString();
}
@@ -64,23 +50,60 @@ public class JSONSerialiser {
return serialise(bean, false);
}
- public static void serialiseAcyclicObject(Object bean, Writer writer) throws IOException {
- serialise(bean, writer, false);
- }
+ private static class Utils {
+
+ private static void fixJson(StringBuilder stringBuilder) {
+ int index = 0;
+ while (true) {
+ if (index + 1 >= stringBuilder.length()) {
+ break;
+ }
+ char thisChar = stringBuilder.charAt(index);
+ char nextChar = stringBuilder.charAt(index + 1);
+ if (thisChar == ',') {
+ if (nextChar == ',') {
+ stringBuilder.deleteCharAt(index);
+ continue;
+ }
+ if (nextChar == ']' || nextChar == '}') {
+ stringBuilder.deleteCharAt(index);
+ }
+ } else if (thisChar == '[' || thisChar == '{') {
+ if (nextChar == ',') {
+ stringBuilder.deleteCharAt(index + 1);
+ continue;
+ }
+ }
+ index++;
+ }
+ }
- private void resetCycleBreaker() {
- this.visited.clear();
+ private static List<Field> getAllFields(List<Field> fields, Class<?> type) {
+ for (Field field : type.getDeclaredFields()) {
+ if (fields.contains(field)) {
+ continue;
+ }
+ if (!field.getName().startsWith("ajc$tjp_")) {
+ fields.add(field);
+ }
+ }
+ if (type.getSuperclass() != null) {
+ getAllFields(fields, type.getSuperclass());
+ }
+ return fields;
+ }
}
- private void serialiseBean(Object bean, boolean cyclicFields) throws IOException {
+ private StringBuilder serialiseBean(Object bean, boolean cyclicFields) {
+ StringBuilder stringBuilder = new StringBuilder();
if (bean == null) {
- this.writer.append("null");
- return;
+ stringBuilder.append("null");
+ return stringBuilder;
}
Class<?> klass = bean.getClass();
List<Field> fields = new ArrayList<>();
- fields = getAllFields(fields, klass);
- this.writer.append("{");
+ fields = Utils.getAllFields(fields, klass);
+ stringBuilder.append("{");
for (Iterator<Field> it = fields.iterator(); it.hasNext();) {
Field field = it.next();
try {
@@ -90,86 +113,63 @@ public class JSONSerialiser {
continue;
}
if (!cyclicFields) {
- resetCycleBreaker();
+ this.visited.clear();
}
- this.writer.append("\"").append(field.getName()).append("\"");
- this.writer.append(":");
- wrap(result);
+ stringBuilder.append("\"").append(field.getName()).append("\"");
+ stringBuilder.append(":");
+ StringBuilder wrap = wrap(result);
+ stringBuilder.append(wrap);
} catch (Exception ignore) {
System.err.println("[JSONSerialiser] field exception: " + ignore);
- this.writer.append("\"").append("JSON-FIELD-EXCEPTION").append("\"");
+ stringBuilder.append("\"").append("JSON-FIELD-EXCEPTION").append("\"");
}
if (it.hasNext()) {
- this.writer.append(",");
+ stringBuilder.append(",");
}
}
- this.writer.append("}");
+ stringBuilder.append("}");
+ return stringBuilder;
}
- private void serialiseBean(Object bean) throws IOException {
- serialiseBean(bean, true);
+ private StringBuilder serialiseBean(Object bean) {
+ return serialiseBean(bean, true);
}
- private List<Field> getAllFields(List<Field> fields, Class<?> type) {
- for (Field field : type.getDeclaredFields()) {
- if (fields.contains(field)) {
- continue;
- }
- if (!field.getName().startsWith("ajc$tjp_")) {
- fields.add(field);
- }
- }
- if (type.getSuperclass() != null) {
- getAllFields(fields, type.getSuperclass());
- }
- return fields;
- }
-
- private void wrap(Object object) throws IOException {
+ private StringBuilder wrap(Object object) {
try {
if (object == null) {
- this.writer.append("null");
- return;
+ return new StringBuilder().append("null");
}
if (object instanceof Boolean) {
- this.writer.append("\"").append(String.valueOf(object)).append("\"");
- return;
+ return new StringBuilder().append("\"").append(String.valueOf(object)).append("\"");
}
if (object instanceof Character) {
- serialiseString(String.valueOf(object));
- return;
+ return serialiseString(String.valueOf(object));
}
if (object instanceof String) {
String string = (String) object;
- serialiseString(string);
- return;
+ return serialiseString(string);
}
if (object instanceof Number) {
- this.writer.append("\"").append(String.valueOf(object)).append("\"");
- return;
+ return new StringBuilder().append("\"").append(String.valueOf(object)).append("\"");
}
if (object instanceof Enum) {
- serialiseString(((Enum<?>) object).name());
- return;
+ return serialiseString(((Enum<?>) object).name());
}
if (object instanceof Collection) {
Collection<?> collection = (Collection<?>) object;
- serialiseCollection(collection);
- return;
+ return serialiseCollection(collection);
}
if (object.getClass().isArray()) {
- serialiseArray(object);
- return;
+ return serialiseArray(object);
}
if (object instanceof Map) {
Map<?, ?> map = (Map<?, ?>) object;
- serialiseMap(map);
- return;
+ return serialiseMap(map);
}
if (object instanceof Date) {
Date date = (Date) object;
- this.writer.append("\"").append(String.valueOf(date.getTime())).append("\"");
- return;
+ return new StringBuilder().append("\"").append(String.valueOf(date.getTime())).append("\"");
}
String serialiseInternals = System.getenv("TRACER_SERIALISE_INTERNALS");
if (serialiseInternals == null) {
@@ -193,104 +193,114 @@ public class JSONSerialiser {
ignoredPackages.addAll(Arrays.asList(internals));
for (String ignoredPackage : ignoredPackages) {
if (objectPackageName.startsWith(ignoredPackage)) {
- serialiseString(String.valueOf(object));
- return;
+ return serialiseString(String.valueOf(object));
}
}
}
- if (visited.stream().parallel().anyMatch((visited) -> (visited == object))) {
+ if (this.visited.stream().parallel().anyMatch((visited) -> (visited == object))) {
+ int hashCode;
try {
- this.writer.append("{\"r\":\"").append(object.getClass().getName() + "@" + object.hashCode()).append("\"}");
+ hashCode = object.hashCode();
} catch (Exception e) {
- this.writer.append("{\"r\":\"").append(object.getClass().getName() + "@" + object.getClass().hashCode()).append("\"}");
- } finally {
- return;
+ hashCode = object.getClass().hashCode();
}
+ return new StringBuilder().append("{\"r\":\"")
+ .append(object.getClass().getName())
+ .append("@")
+ .append(hashCode)
+ .append("\"}");
}
- visited.add(object);
- serialiseBean(object);
+ this.visited.add(object);
+ return serialiseBean(object);
} catch (ConcurrentModificationException exception) {
System.err.println("[JSONSerialiser] ConcurrentModificationException");
- this.writer.append("{\"e\":\"JSON_CONCURRENT_MODIFICATION\"}");
+ return new StringBuilder().append("{\"e\":\"JSON_CONCURRENT_MODIFICATION\"}");
} catch (Exception exception) {
System.err.println("[JSONSerialiser] wrap exception: " + exception);
exception.printStackTrace();
- this.writer.append("{\"e\":\"JSON_SERIALISE_EXCEPTION\"}");
+ return new StringBuilder().append("{\"e\":\"JSON_SERIALISE_EXCEPTION\"}");
}
}
- private void serialiseMap(Map map) throws IOException {
+ private StringBuilder serialiseMap(Map map) {
+ StringBuilder stringBuilder = new StringBuilder();
+ stringBuilder.append("{");
try {
- this.writer.append("{");
- for (Iterator<?> it = map.keySet().iterator(); it.hasNext();) {
- Object key = it.next();
- if (key == null || map.get(key) == null) {
+ for (Iterator<Map.Entry<?, ?>> iterator = map.entrySet().iterator(); iterator.hasNext();) {
+ Map.Entry<?, ?> entry = iterator.next();
+ Object key = entry.getKey();
+ Object value = entry.getValue();
+ if (key == null || value == null) {
continue;
}
+ String serialisedKey;
if (!(key instanceof String)) {
- this.writer.append("\"");
- wrap(key);
- this.writer.append("\"");
+ serialisedKey = JSONSerialiser.serialise(key);
+ stringBuilder.append("\"").append(serialisedKey).append("\"");
} else {
- wrap(key);
+ StringBuilder wrappedKey = wrap(key);
+ serialisedKey = wrappedKey.toString();
}
- this.writer.append(":");
- wrap(map.get(key));
- if (it.hasNext()) {
- this.writer.append(",");
+ StringBuilder wrappedValue = wrap(value);
+ stringBuilder.append(serialisedKey).append(":").append(wrappedValue);
+ if (iterator.hasNext()) {
+ stringBuilder.append(",");
}
}
} catch (Exception ex) {
System.err.println("[JSONSerialiser] map serialise exception: " + ex);
- } finally {
- this.writer.append("}");
+ return new StringBuilder().append("{\"e\":\"JSON_MAP_EXCEPTION\"}");
}
+ return stringBuilder.append("}");
}
- private void serialiseArray(Object array) throws IOException {
- this.writer.append("[");
+ private StringBuilder serialiseArray(Object array) {
+ StringBuilder stringBuilder = new StringBuilder();
+ stringBuilder.append("[");
try {
int length = Array.getLength(array);
for (int i = 0; i < length;) {
Object object = Array.get(array, i);
- wrap(object);
+ StringBuilder wrap = wrap(object);
+ stringBuilder.append(wrap);
if (++i < length) {
- this.writer.append(",");
+ stringBuilder.append(",");
}
}
} catch (Exception ex) {
System.err.println("[JSONSerialiser] array serialise exception: " + ex);
- } finally {
- this.writer.append("]");
+ return new StringBuilder().append("[\"JSON_ARRAY_EXCEPTION\"]");
}
+ return stringBuilder.append("]");
}
- private void serialiseCollection(Collection collection) throws IOException {
+ private StringBuilder serialiseCollection(Collection collection) {
+ StringBuilder stringBuilder = new StringBuilder();
+ stringBuilder.append("[");
try {
- this.writer.append("[");
Iterator it = collection.iterator();
while (it.hasNext()) {
Object object = it.next();
- wrap(object);
+ StringBuilder wrap = wrap(object);
+ stringBuilder.append(wrap);
if (it.hasNext()) {
- this.writer.append(",");
+ stringBuilder.append(",");
}
}
} catch (Exception ex) {
System.err.println("[JSONSerialiser] collection serialise exception: " + ex);
- } finally {
- this.writer.append("]");
+ return new StringBuilder().append("[\"JSON_COLLECTION_EXCEPTION\"]");
}
+ return stringBuilder.append("]");
}
- private void serialiseString(String string) throws IOException {
+ private StringBuilder serialiseString(String string) {
+ StringBuilder stringBuilder = new StringBuilder();
if (string == null || string.isEmpty()) {
- this.writer.append("\"\"");
- return;
+ return stringBuilder.append("\"\"");
}
+ stringBuilder.append('"');
try {
- this.writer.append('"');
-
char b;
char c = 0;
String hexadecimal;
@@ -303,46 +313,46 @@ public class JSONSerialiser {
switch (c) {
case '\\':
case '"':
- this.writer.append('\\');
- this.writer.append(c);
+ stringBuilder.append('\\');
+ stringBuilder.append(c);
break;
case '/':
if (b == '<') {
- this.writer.append('\\');
+ stringBuilder.append('\\');
}
- this.writer.append(c);
+ stringBuilder.append(c);
break;
case '\b':
- this.writer.append("\\b");
+ stringBuilder.append("\\b");
break;
case '\t':
- this.writer.append("\\t");
+ stringBuilder.append("\\t");
break;
case '\n':
- this.writer.append("\\n");
+ stringBuilder.append("\\n");
break;
case '\f':
- this.writer.append("\\f");
+ stringBuilder.append("\\f");
break;
case '\r':
- this.writer.append("\\r");
+ stringBuilder.append("\\r");
break;
default:
if (c < ' ' || (c >= '\u0080' && c < '\u00a0')
|| (c >= '\u2000' && c < '\u2100')) {
- this.writer.append("\\u");
+ stringBuilder.append("\\u");
hexadecimal = Integer.toHexString(c);
- this.writer.append("0000", 0, 4 - hexadecimal.length());
- this.writer.append(hexadecimal);
+ stringBuilder.append("0000", 0, 4 - hexadecimal.length());
+ stringBuilder.append(hexadecimal);
} else {
- this.writer.append(c);
+ stringBuilder.append(c);
}
}
}
} catch (Exception ex) {
System.err.println("[JSONSerialiser] string serialise exception: " + ex);
- } finally {
- this.writer.append('"');
+ return new StringBuilder().append("\"JSON_STRING_EXCEPTION\"");
}
+ return stringBuilder.append('"');
}
}