diff --git a/README.md b/README.md
index 3b88b89..9675f6b 100644
--- a/README.md
+++ b/README.md
@@ -4,3 +4,6 @@ a JSON serializer based on bytecode manipulation
* creates a Json serializer for a java type using javassist
* deserializing not yet implemented
* see the unit tests to see how it works
+
+
+* as of java9 it needs `--add-opens java.base/java.lang=ALL-UNNAMED` as java commandline option.
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index dfe5682..57427d9 100644
--- a/pom.xml
+++ b/pom.xml
@@ -15,47 +15,21 @@
-
- commons-io
- commons-io
- 2.6
-
-
org.javassist
javassist
3.26.0-GA
-
-
- ch.qos.logback
- logback-core
- 1.2.3
-
-
-
- org.slf4j
- slf4j-api
- 1.7.30
-
-
-
- ch.qos.logback
- logback-classic
- 1.2.3
-
-
-
junit
junit
- [4.13.1,)
+ 4.13.2
test
org.assertj
assertj-core
- 1.6.0
+ 3.23.1
test
@@ -68,8 +42,21 @@
com.fasterxml.jackson.core
jackson-databind
- 2.10.5.1
+ 2.15.1
test
+
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ 3.1.0
+
+ --add-opens java.base/java.lang=ALL-UNNAMED
+
+
+
+
diff --git a/src/main/java/nl/jssl/jsontoy/serialize/JSONSerializer.java b/src/main/java/nl/jssl/jsontoy/serialize/JSONSerializer.java
index 6cc95b3..fd6ee54 100644
--- a/src/main/java/nl/jssl/jsontoy/serialize/JSONSerializer.java
+++ b/src/main/java/nl/jssl/jsontoy/serialize/JSONSerializer.java
@@ -11,9 +11,9 @@ public abstract class JSONSerializer {
if (object == null) {
return "";
} else if (object instanceof Number || object instanceof Boolean) {
- return "" + object.toString();
+ return "" + object;
} else if (object instanceof CharSequence || object instanceof Character) {
- return "\"" + object.toString() + "\"";
+ return "\"" + object + "\"";
} else {
return handle(object);
}
diff --git a/src/main/java/nl/jssl/jsontoy/serialize/SynthSerializerFactory.java b/src/main/java/nl/jssl/jsontoy/serialize/SynthSerializerFactory.java
index 5afc7b4..bf0daaf 100644
--- a/src/main/java/nl/jssl/jsontoy/serialize/SynthSerializerFactory.java
+++ b/src/main/java/nl/jssl/jsontoy/serialize/SynthSerializerFactory.java
@@ -1,5 +1,6 @@
package nl.jssl.jsontoy.serialize;
+import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
@@ -36,7 +37,7 @@ class SynthSerializerFactory {
private static final String SET = "java.util.Set";
private static final String MAP = "java.util.Map";
- private static final Map> serializers = new HashMap<>();
+ private static final Map, JSONSerializer>> serializers = new HashMap<>();
private static final String ROOT_PACKAGE = "serializer.";
private final ClassPool pool = ClassPool.getDefault();
@@ -55,37 +56,29 @@ class SynthSerializerFactory {
}
}
- JSONSerializer createSerializer(Class beanjavaClass) {
+ @SuppressWarnings("unchecked")
+ JSONSerializer createSerializer(Class beanjavaClass) {
+ if (serializers.containsKey(beanjavaClass)) {
+ return (JSONSerializer) serializers.get(beanjavaClass);
+ }
try {
CtClass beanClass = pool.get(beanjavaClass.getName());
-
- return createSerializer2(beanClass);
- } catch (NotFoundException e) {
+ return tryCreateSerializer(beanjavaClass, beanClass);
+ } catch (NotFoundException | CannotCompileException | InstantiationException | IllegalAccessException |
+ InvocationTargetException | NoSuchMethodException e) {
throw new SerializerCreationException(e);
}
}
- @SuppressWarnings("unchecked")
- private JSONSerializer createSerializer2(CtClass beanClass) {
- if (serializers.containsKey(createSerializerName(beanClass))) {
- return (JSONSerializer) serializers.get(createSerializerName(beanClass));
- }
- try {
- return tryCreateSerializer(beanClass);
- } catch (NotFoundException | CannotCompileException | InstantiationException | IllegalAccessException e) {
- throw new SerializerCreationException(e);
- }
- }
-
- private JSONSerializer tryCreateSerializer(CtClass beanClass) throws NotFoundException, CannotCompileException, InstantiationException,
- IllegalAccessException {
+ private JSONSerializer tryCreateSerializer(Class> javaClass, CtClass beanClass) throws NotFoundException, CannotCompileException, InstantiationException,
+ IllegalAccessException, InvocationTargetException, NoSuchMethodException {
CtClass serializerClass = pool.makeClass(createSerializerName(beanClass), serializerBase);
addToJsonStringMethod(beanClass, serializerClass);
JSONSerializer jsonSerializer = createSerializerInstance(serializerClass);
- serializers.put(createSerializerName(beanClass), jsonSerializer);
+ serializers.put(javaClass, jsonSerializer);
return jsonSerializer;
}
@@ -99,16 +92,16 @@ class SynthSerializerFactory {
/*
* Creates the source, handling the for JSON different types of classes
*/
- private String createToJSONStringMethodSource(CtClass beanClass) throws NotFoundException {
+ private String createToJSONStringMethodSource(CtClass beanClass) throws NotFoundException {
String source = "public String handle(Object object){\n";
if (beanClass.isArray()) {
source += "\tObject[] array=(Object[])object;\n";
- source += handleArray(beanClass);
+ source += handleArray();
} else if (isCollection(beanClass)) {
source += "\tObject[] array=((java.util.Collection)object).toArray();\n";
- source += handleArray(beanClass);
+ source += handleArray();
} else if (isMap(beanClass)) {
- source += handleMap(beanClass);
+ source += handleMap();
} else if (!isPrimitiveOrWrapperOrString(beanClass)) {
List getters = getGetters(beanClass);
if (shouldAddGetterCallers(getters)) {
@@ -117,18 +110,17 @@ class SynthSerializerFactory {
} else {
source += "\treturn \"\";}";
}
- System.out.println(source);
return source;
}
/*
* Any Collection is converted to an array, after which code is generated to handle the single elements.
- *
+ *
* A subserializer is created for every single element, but most of the time it will be the same cached instance.
- *
+ *
* The generated code fills a StringBuilder. The values are generated by the subserializers
*/
- private String handleArray(CtClass beanClass) {
+ private String handleArray() {
String source = "\tStringBuilder result=new StringBuilder(\"[\");\n";
source += "\tfor (int i=0; i getters) throws NotFoundException {
+ private String addGetterCallers(CtClass beanClass, String source, List getters) {
int index = 0;
source += "\treturn ";
source += "\"{";
@@ -176,13 +168,13 @@ class SynthSerializerFactory {
@SuppressWarnings("unchecked")
private JSONSerializer createSerializerInstance(CtClass serializerClass) throws InstantiationException, IllegalAccessException,
- CannotCompileException {
- return (JSONSerializer) serializerClass.toClass().newInstance();
+ CannotCompileException, NoSuchMethodException, InvocationTargetException {
+ return (JSONSerializer) serializerClass.toClass().getConstructor().newInstance();
}
/*
* custom root package is prepended to avoid the java.lang class in which it's illegal to create new classes
- *
+ *
* Array marks ( '[]' ) are replaced by the 'Array', Otherwise the SerializerClassName would be syntactically incorrect
*/
public String createSerializerName(CtClass beanClass) {
@@ -218,7 +210,7 @@ class SynthSerializerFactory {
/*
* The JSON vernacular for key:value is pair...
*/
- private String addPair(CtClass classToSerialize, String source, CtMethod getter) throws NotFoundException {
+ private String addPair(CtClass classToSerialize, String source, CtMethod getter) {
source += jsonKey(getter);
source += ": "; // what is the rule when it comes to spaces in json?
source += jsonValue(classToSerialize, getter);
@@ -232,20 +224,14 @@ class SynthSerializerFactory {
return "\\\"" + toFieldName(getter.getName()) + "\\\"";
}
- private String jsonValue(CtClass classToSerialize, CtMethod getter) throws NotFoundException {
- String source = "";
- CtClass returnType = getter.getReturnType();
-
+ private String jsonValue(CtClass classToSerialize, CtMethod getter) {
/* primitives are wrapped so the produced methods adhere to the JSONSerializer interface */
- source = createSubSerializerForReturnTypeAndAddInvocationToSource(classToSerialize, getter, source, returnType);
-
- return source;
+ return createSubSerializerForReturnTypeAndAddInvocationToSource(classToSerialize, getter);
}
- private String createSubSerializerForReturnTypeAndAddInvocationToSource(CtClass classToSerialize, CtMethod getter, String source, CtClass returnType) {
+ private String createSubSerializerForReturnTypeAndAddInvocationToSource(CtClass classToSerialize, CtMethod getter) {
/* NB there does not seem to be auto(un))boxing nor generic types (or other jdk1.5 stuff) in javassist compileable code */
-
- source += "\"+" + Serializer.class.getName() + ".toJSONString(";
+ String source = "\"+" + Serializer.class.getName() + ".toJSONString(";
// cast because of lack of generics
source += "(" + cast(regularClassname(classToSerialize.getName())) + "object)." + getter.getName() + "()";
@@ -331,22 +317,22 @@ class SynthSerializerFactory {
String asPrimitive(String name) {
switch (name) {
- case "int":
- return "I";
- case "byte":
- return "B";
- case "float":
- return "F";
- case "long":
- return "J";
- case "boolean":
- return "Z";
- case "char":
- return "C";
- case "double":
- return "D";
- case "short":
- return "S";
+ case "int":
+ return "I";
+ case "byte":
+ return "B";
+ case "float":
+ return "F";
+ case "long":
+ return "J";
+ case "boolean":
+ return "Z";
+ case "char":
+ return "C";
+ case "double":
+ return "D";
+ case "short":
+ return "S";
}
return "";
}
diff --git a/src/test/java/nl/jssl/jsontoy/serialize/performance/Jackson.java b/src/test/java/nl/jssl/jsontoy/serialize/performance/JacksonComparisonTest.java
similarity index 70%
rename from src/test/java/nl/jssl/jsontoy/serialize/performance/Jackson.java
rename to src/test/java/nl/jssl/jsontoy/serialize/performance/JacksonComparisonTest.java
index 56a5336..8daaa5b 100644
--- a/src/test/java/nl/jssl/jsontoy/serialize/performance/Jackson.java
+++ b/src/test/java/nl/jssl/jsontoy/serialize/performance/JacksonComparisonTest.java
@@ -13,50 +13,49 @@ import org.junit.Test;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
-public class Jackson {
- List trashbin = new ArrayList();
+public class JacksonComparisonTest {
+ private static final int ITERATIONS = 20;
+ private static final int INNERLOOP_COUNT = 100000;
+ List trashbin = new ArrayList<>();
@Test
- public void jackson() throws JsonProcessingException {
+ public void testPerformance() throws JsonProcessingException {
+ System.out.println("jackson,jsontoy");
ObjectMapper objectMapper = new ObjectMapper();
Bean1 bean1 = new Bean1();
Bean2 bean2 = new Bean2();
bean1.setData1(UUID.randomUUID().toString());
bean1.setBean2(bean2);
bean2.setData2(UUID.randomUUID().toString());
- String valueAsString = objectMapper.writeValueAsString(bean1);
- String jsonString = Serializer.toJSONString(bean1);
+ String valueAsString;
+ String jsonString;
- for (int c = 0; c < 20; c++) {
+ for (int c = 0; c < ITERATIONS; c++) {
trashbin.clear();
- System.gc();
long t0 = System.currentTimeMillis();
- for (int i = 0; i < 100000; i++) {
+ for (int i = 0; i < INNERLOOP_COUNT; i++) {
bean1 = new Bean1();
bean2 = new Bean2();
bean1.setData1(UUID.randomUUID().toString());
bean1.setBean2(bean2);
bean2.setData2(UUID.randomUUID().toString());
valueAsString = objectMapper.writeValueAsString(bean1);
- // System.out.println(valueAsString);
trashbin.add(valueAsString);
}
- System.out.print(System.currentTimeMillis() - t0);
+ System.out.printf("% 7d",(System.currentTimeMillis() - t0));
System.out.print(",");
trashbin.clear();
- System.gc();
long tt0 = System.currentTimeMillis();
- for (int i = 0; i < 100000; i++) {
+ for (int i = 0; i < INNERLOOP_COUNT; i++) {
bean1 = new Bean1();
bean2 = new Bean2();
bean1.setData1(UUID.randomUUID().toString());
bean1.setBean2(bean2);
bean2.setData2(UUID.randomUUID().toString());
jsonString = Serializer.toJSONString(bean1);
- // System.out.println(jsonString);
trashbin.add(jsonString);
}
- System.out.println(System.currentTimeMillis() - tt0);
+ System.out.printf("% 7d%n",System.currentTimeMillis() - tt0);
}
}