json-serialiser

Changes

src/main/java/br/ufrgs/inf/prosoft/jsonserialiser/StringBuilderWriter.java 35(+0 -35)

Details

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('"');
     }
 }