json-serialiser

first commit. created JSONSerialised based on JSON-java.

11/26/2018 12:43:52 PM

Details

.gitignore 34(+34 -0)

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..4a482b8
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,34 @@
+# ignore eclipse project files
+.project
+.classpath
+
+# ignore Intellij Idea project files
+.idea
+*.iml
+
+# Netbeans
+/nbproject/
+/nbactions.xml
+
+# Netbeans deploy
+/build/
+
+# Maven deploy
+/target/
+
+# Ant deploy
+/dist/
+
+# Class files
+*.class
+
+# Mobile Tools for Java (J2ME)
+.mtj.tmp/
+
+# Package Files #
+*.jar
+*.war
+*.ear
+
+# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
+hs_err_pid*

pom.xml 13(+13 -0)

diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..29dd961
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <groupId>br.ufrgs.inf.prosoft.jsonserialiser</groupId>
+    <artifactId>JSONSerialiser</artifactId>
+    <version>1.0</version>
+    <packaging>jar</packaging>
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <maven.compiler.source>1.8</maven.compiler.source>
+        <maven.compiler.target>1.8</maven.compiler.target>
+    </properties>
+</project>
\ No newline at end of file
diff --git a/src/main/java/br/ufrgs/inf/prosoft/jsonserialiser/JSONSerialiser.java b/src/main/java/br/ufrgs/inf/prosoft/jsonserialiser/JSONSerialiser.java
new file mode 100644
index 0000000..ad5acfa
--- /dev/null
+++ b/src/main/java/br/ufrgs/inf/prosoft/jsonserialiser/JSONSerialiser.java
@@ -0,0 +1,369 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+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.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.ConcurrentModificationException;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+/**
+ *
+ * @author romulo
+ */
+public class JSONSerialiser {
+
+    private static final Collection<Object> VISITED = new ArrayList<>();
+    private static Writer WRITER;
+
+    private static class StringBuilderWriter extends Writer {
+
+        private final StringBuilder stringBuilder;
+
+        public StringBuilderWriter(StringBuilder stringBuilder) {
+            this.stringBuilder = stringBuilder;
+        }
+
+        @Override
+        public void write(char[] cbuf, int off, int len) {
+            stringBuilder.append(cbuf, off, len);
+        }
+
+        @Override
+        public void flush() {
+        }
+
+        @Override
+        public void close() {
+        }
+
+    }
+
+    public static void serialise(Object bean, Writer writer, boolean cyclicFields) throws IOException {
+        JSONSerialiser.WRITER = writer;
+        serialiseBean(bean, cyclicFields);
+        JSONSerialiser.WRITER = null;
+    }
+
+    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) {
+        }
+        return stringBuilder.toString();
+    }
+
+    public static String serialise(Object bean) {
+        return serialise(bean, true);
+    }
+
+    public static String serialiseCylicObject(Object bean) {
+        resetCycleBreaker();
+        String serialise = serialise(bean);
+        resetCycleBreaker();
+        return serialise;
+    }
+
+    public static String serialiseAcylicObject(Object bean) {
+        resetCycleBreaker();
+        String serialise = serialise(bean, false);
+        resetCycleBreaker();
+        return serialise;
+    }
+    
+    public static void serialiseAcylicObject(Object bean, Writer writer) throws IOException {
+        resetCycleBreaker();
+        serialise(bean, writer, false);
+        resetCycleBreaker();
+    }
+
+    public static void resetCycleBreaker() {
+        JSONSerialiser.VISITED.clear();
+    }
+
+    private static void serialiseBean(Object bean, boolean cyclicFields) throws IOException {
+        if (bean == null) {
+            JSONSerialiser.WRITER.append("null");
+            return;
+        }
+        Class<?> klass = bean.getClass();
+        List<Field> fields = new ArrayList<>();
+        fields = getAllFields(fields, klass);
+        JSONSerialiser.WRITER.append("{");
+        for (Iterator<Field> it = fields.iterator(); it.hasNext();) {
+            Field field = it.next();
+            try {
+                field.setAccessible(true);
+                Object result = field.get(bean);
+                if (result == null) {
+                    continue;
+                }
+                if (!cyclicFields) {
+                    resetCycleBreaker();
+                }
+                JSONSerialiser.WRITER.append("\"").append(field.getName()).append("\"");
+                JSONSerialiser.WRITER.append(":");
+                wrap(result);
+            } catch (Exception ignore) {
+                JSONSerialiser.WRITER.append("\"").append("JSON-FIELD-EXCEPTION").append("\"");
+                System.err.println("[JSON-trace] field exception: " + ignore);
+            }
+            if (it.hasNext()) {
+                JSONSerialiser.WRITER.append(",");
+            }
+        }
+        JSONSerialiser.WRITER.append("}");
+    }
+
+    private static void serialiseBean(Object bean) throws IOException {
+        serialiseBean(bean, true);
+    }
+
+    private static List<Field> getAllFields(List<Field> fields, Class<?> type) {
+        for (Field field : type.getDeclaredFields()) {
+            if (!field.getName().startsWith("ajc$tjp_")) {
+                fields.add(field);
+            }
+        }
+        if (type.getSuperclass() != null) {
+            getAllFields(fields, type.getSuperclass());
+        }
+        return fields;
+    }
+
+    private static void wrap(Object object) throws IOException {
+        try {
+            if (object == null) {
+                JSONSerialiser.WRITER.append("null");
+                return;
+            }
+            if (object instanceof Boolean) {
+                JSONSerialiser.WRITER.append("\"").append(String.valueOf(object)).append("\"");
+                return;
+            }
+            if (object instanceof Character) {
+                serialiseString(String.valueOf(object));
+                return;
+            }
+            if (object instanceof String) {
+                String string = (String) object;
+                serialiseString(string);
+                return;
+            }
+            if (object instanceof Number) {
+                Number number = (Number) object;
+                serialiseNumber(number);
+                return;
+            }
+            if (object instanceof Enum) {
+                serialiseString(((Enum<?>) object).name());
+                return;
+            }
+            if (object instanceof Collection) {
+                Collection<?> collection = (Collection<?>) object;
+                serialiseCollection(collection);
+                return;
+            }
+            if (object.getClass().isArray()) {
+                serialiseArray(object);
+                return;
+            }
+            if (object instanceof Map) {
+                Map<?, ?> map = (Map<?, ?>) object;
+                serialiseMap(map);
+                return;
+            }
+            if (VISITED.stream().anyMatch((visited) -> (visited == object))) {
+                try {
+                    JSONSerialiser.WRITER.append("\"").append(String.valueOf(object)).append("\"");
+                } catch (Exception e) {
+                    JSONSerialiser.WRITER.append("\"").append(object.getClass().getName()).append("\"");
+                } finally {
+                    return;
+                }
+            }
+            VISITED.add(object);
+            serialiseBean(object);
+        } catch (ConcurrentModificationException exception) {
+            System.err.println("[JSONSerialiser] ConcurrentModificationException");
+        } catch (Exception exception) {
+            System.err.println("[JSON-java] serialise exception: " + exception);
+            JSONSerialiser.WRITER.append("\"").append("JSON_SERIALISE_EXCEPTION").append("\"");
+            exception.printStackTrace();
+        }
+    }
+
+    private static void serialiseMap(Map map) throws IOException {
+        try {
+            map.keySet().iterator();
+        } catch (Exception ex) {
+            return;
+        }
+        JSONSerialiser.WRITER.append("{");
+        for (Iterator<?> it = map.keySet().iterator(); it.hasNext();) {
+            Object key = it.next();
+            if (key == null || map.get(key) == null) {
+                continue;
+            }
+            if (!(key instanceof String)) {
+                JSONSerialiser.WRITER.append("\"");
+                wrap(key);
+                JSONSerialiser.WRITER.append("\"");
+            } else {
+                wrap(key);
+            }
+            JSONSerialiser.WRITER.append(":");
+            wrap(map.get(key));
+            if (it.hasNext()) {
+                JSONSerialiser.WRITER.append(",");
+            }
+        }
+        JSONSerialiser.WRITER.append("}");
+    }
+
+    private static void serialiseArray(Object array) throws IOException {
+        JSONSerialiser.WRITER.append("[");
+        int length = Array.getLength(array);
+        for (int i = 0; i < length;) {
+            Object object = Array.get(array, i);
+            wrap(object);
+            if (++i < length) {
+                JSONSerialiser.WRITER.append(",");
+            }
+        }
+        JSONSerialiser.WRITER.append("]");
+    }
+
+    private static void serialiseCollection(Collection collection) throws IOException {
+        try {
+            collection.iterator();
+        } catch (Exception ex) {
+            return;
+        }
+        JSONSerialiser.WRITER.append("[");
+        for (Iterator it = collection.iterator(); it.hasNext();) {
+            Object object = it.next();
+            wrap(object);
+            if (it.hasNext()) {
+                JSONSerialiser.WRITER.append(",");
+            }
+        }
+        JSONSerialiser.WRITER.append("]");
+    }
+
+    private static void serialiseString(String string) throws IOException {
+        if (string == null || string.isEmpty()) {
+            JSONSerialiser.WRITER.append("\"\"");
+            return;
+        }
+
+        char b;
+        char c = 0;
+        String hexadecimal;
+        int i;
+        int len = string.length();
+
+        JSONSerialiser.WRITER.append('"');
+        for (i = 0; i < len; i++) {
+            b = c;
+            c = string.charAt(i);
+            switch (c) {
+                case '\\':
+                case '"':
+                    JSONSerialiser.WRITER.append('\\');
+                    JSONSerialiser.WRITER.append(c);
+                    break;
+                case '/':
+                    if (b == '<') {
+                        JSONSerialiser.WRITER.append('\\');
+                    }
+                    JSONSerialiser.WRITER.append(c);
+                    break;
+                case '\b':
+                    JSONSerialiser.WRITER.append("\\b");
+                    break;
+                case '\t':
+                    JSONSerialiser.WRITER.append("\\t");
+                    break;
+                case '\n':
+                    JSONSerialiser.WRITER.append("\\n");
+                    break;
+                case '\f':
+                    JSONSerialiser.WRITER.append("\\f");
+                    break;
+                case '\r':
+                    JSONSerialiser.WRITER.append("\\r");
+                    break;
+                default:
+                    if (c < ' ' || (c >= '\u0080' && c < '\u00a0')
+                            || (c >= '\u2000' && c < '\u2100')) {
+                        JSONSerialiser.WRITER.append("\\u");
+                        hexadecimal = Integer.toHexString(c);
+                        JSONSerialiser.WRITER.append("0000", 0, 4 - hexadecimal.length());
+                        JSONSerialiser.WRITER.append(hexadecimal);
+                    } else {
+                        JSONSerialiser.WRITER.append(c);
+                    }
+            }
+        }
+        JSONSerialiser.WRITER.append('"');
+    }
+
+    private static void serialiseNumber(Number number) throws IOException {
+        // not all Numbers may match actual JSON Numbers. i.e. Fractions or Complex
+        final String numberAsString = numberToString(number);
+        try {
+            // Use the BigDecimal constructor for it's parser to validate the format.
+            @SuppressWarnings("unused")
+            BigDecimal unused = new BigDecimal(numberAsString);
+            // Close enough to a JSON number that we will return it unquoted
+            JSONSerialiser.WRITER.append(numberAsString);
+        } catch (NumberFormatException ex) {
+            // The Number value is not a valid JSON number.
+            // Instead we will quote it as a string
+            serialiseString(numberAsString);
+        }
+
+    }
+
+    private static String numberToString(Number number) {
+        if (number instanceof Double) {
+            if (((Double) number).isInfinite() || ((Double) number).isNaN()) {
+                return String.valueOf(number);
+            }
+        } else if (number instanceof Float) {
+            if (((Float) number).isInfinite() || ((Float) number).isNaN()) {
+                return String.valueOf(number);
+            }
+        }
+
+        // Shave off trailing zeros and decimal point, if possible.
+        String string = number.toString();
+        if (string.indexOf('.') > 0 && string.indexOf('e') < 0
+                && string.indexOf('E') < 0) {
+            while (string.endsWith("0")) {
+                string = string.substring(0, string.length() - 1);
+            }
+            if (string.endsWith(".")) {
+                string = string.substring(0, string.length() - 1);
+            }
+        }
+        return string;
+    }
+
+}