changed everything
This commit is contained in:
parent
9df9fba621
commit
f4d9d0c8c5
49 changed files with 1078 additions and 1123 deletions
12
README.md
12
README.md
|
|
@ -1,9 +1,11 @@
|
|||
# JsonToy
|
||||
# Json
|
||||
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
|
||||
* uses ASM for creating object mappers
|
||||
* deserializing not (yet?) implemented
|
||||
* write to String: Mapper.json(...)
|
||||
|
||||
|
||||
* as of java9 it needs `--add-opens java.base/java.lang=ALL-UNNAMED` as java commandline option.
|
||||
* ~~as of java9 it needs `--add-opens java.base/java.lang=ALL-UNNAMED` as java commandline option.~~
|
||||
|
||||
* prerequisite: at least jdk9
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
package nl.jssl.jsontoy.deserialize;
|
||||
|
||||
public class Deserializer {
|
||||
|
||||
private int position;
|
||||
private final String jsonString;
|
||||
|
||||
private Deserializer( String jsonString,int position) {
|
||||
this.position = position;
|
||||
this.jsonString = jsonString;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
package nl.jssl.jsontoy.serialize;
|
||||
|
||||
import java.util.Formatter;
|
||||
|
||||
public abstract class JSONSerializer<T> {
|
||||
protected abstract String handle(T object);
|
||||
|
||||
protected Formatter formatter = new Formatter();
|
||||
|
||||
public String toJSONString(T object) {
|
||||
if (object == null) {
|
||||
return "";
|
||||
} else if (object instanceof Number || object instanceof Boolean) {
|
||||
return "" + object;
|
||||
} else if (object instanceof CharSequence || object instanceof Character) {
|
||||
return "\"" + object + "\"";
|
||||
} else {
|
||||
return handle(object);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
package nl.jssl.jsontoy.serialize;
|
||||
|
||||
public class Serializer {
|
||||
private static SynthSerializerFactory instance = new SynthSerializerFactory();
|
||||
|
||||
public static String toJSONString(boolean b) {
|
||||
return Boolean.toString(b);
|
||||
}
|
||||
|
||||
public static String toJSONString(short s) {
|
||||
return Short.toString(s);
|
||||
}
|
||||
|
||||
public static String toJSONString(int i) {
|
||||
return Integer.toString(i);
|
||||
}
|
||||
|
||||
public static String toJSONString(float f) {
|
||||
return Float.toString(f);
|
||||
}
|
||||
|
||||
public static String toJSONString(double d) {
|
||||
return Double.toString(d);
|
||||
}
|
||||
|
||||
public static String toJSONString(long l) {
|
||||
return Long.toString(l);
|
||||
}
|
||||
|
||||
public static String toJSONString(char c) {
|
||||
return "\"" + c + "\"";
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> String toJSONString(T o) {
|
||||
if (o == null) {
|
||||
return "null";
|
||||
}
|
||||
return instance.createSerializer((Class<T>) o.getClass()).toJSONString(o);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
package nl.jssl.jsontoy.serialize;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public class SerializerCreationException extends RuntimeException {
|
||||
|
||||
public SerializerCreationException(Throwable t) {
|
||||
super(t);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,348 +0,0 @@
|
|||
package nl.jssl.jsontoy.serialize;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javassist.CannotCompileException;
|
||||
import javassist.ClassPool;
|
||||
import javassist.CtClass;
|
||||
import javassist.CtField;
|
||||
import javassist.CtMethod;
|
||||
import javassist.CtNewMethod;
|
||||
import javassist.Modifier;
|
||||
import javassist.NotFoundException;
|
||||
|
||||
class SynthSerializerFactory {
|
||||
private static final String STRING = "java.lang.String";
|
||||
private static final String BOOLEAN = "java.lang.Boolean";
|
||||
private static final String CHARACTER = "java.lang.Character";
|
||||
private static final String BYTE = "java.lang.Byte";
|
||||
private static final String DOUBLE = "java.lang.Double";
|
||||
private static final String FLOAT = "java.lang.Float";
|
||||
private static final String LONG = "java.lang.Long";
|
||||
private static final String SHORT = "java.lang.Short";
|
||||
private static final String INTEGER = "java.lang.Integer";
|
||||
|
||||
private final static Set<String> wrappersAndString = new HashSet<>(Arrays.asList(BOOLEAN, CHARACTER, BYTE, DOUBLE, FLOAT, LONG, SHORT, INTEGER,
|
||||
STRING));
|
||||
|
||||
private static final String COLLECTION = "java.util.Collection";
|
||||
private static final String LIST = "java.util.List";
|
||||
private static final String SET = "java.util.Set";
|
||||
private static final String MAP = "java.util.Map";
|
||||
|
||||
private static final Map<Class<?>, JSONSerializer<?>> serializers = new HashMap<>();
|
||||
private static final String ROOT_PACKAGE = "serializer.";
|
||||
|
||||
private final ClassPool pool = ClassPool.getDefault();
|
||||
private CtClass serializerBase;
|
||||
|
||||
|
||||
public SynthSerializerFactory() {
|
||||
init();
|
||||
}
|
||||
|
||||
void init() {
|
||||
try {
|
||||
serializerBase = pool.get(JSONSerializer.class.getName());
|
||||
} catch (NotFoundException e) {
|
||||
throw new SerializerCreationException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
<T> JSONSerializer<T> createSerializer(Class<T> beanjavaClass) {
|
||||
JSONSerializer<T> serializer = (JSONSerializer<T>) serializers.get(beanjavaClass);
|
||||
if (serializer != null) {
|
||||
return serializer;
|
||||
}
|
||||
try {
|
||||
return tryCreateSerializer(beanjavaClass);
|
||||
} catch (NotFoundException | CannotCompileException | InstantiationException | IllegalAccessException |
|
||||
InvocationTargetException | NoSuchMethodException e) {
|
||||
throw new SerializerCreationException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private <T> JSONSerializer<T> tryCreateSerializer(Class<?> javaClass) throws NotFoundException, CannotCompileException, InstantiationException,
|
||||
IllegalAccessException, InvocationTargetException, NoSuchMethodException {
|
||||
CtClass beanClass = pool.get(javaClass.getName());
|
||||
CtClass serializerClass = pool.makeClass(createSerializerName(beanClass), serializerBase);
|
||||
|
||||
addToJsonStringMethod(beanClass, serializerClass);
|
||||
|
||||
JSONSerializer<T> jsonSerializer = createSerializerInstance(serializerClass);
|
||||
|
||||
serializers.put(javaClass, jsonSerializer);
|
||||
return jsonSerializer;
|
||||
}
|
||||
|
||||
/*
|
||||
* create method source, compile it and add it to the class under construction
|
||||
*/
|
||||
private void addToJsonStringMethod(CtClass beanClass, CtClass serializerClass) throws NotFoundException, CannotCompileException {
|
||||
serializerClass.addMethod(CtNewMethod.make(createToJSONStringMethodSource(beanClass), serializerClass));
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates the source, handling the for JSON different types of classes
|
||||
*/
|
||||
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();
|
||||
} else if (isCollection(beanClass)) {
|
||||
source += "\tObject[] array=((java.util.Collection)object).toArray();\n";
|
||||
source += handleArray();
|
||||
} else if (isMap(beanClass)) {
|
||||
source += handleMap();
|
||||
} else if (!isPrimitiveOrWrapperOrString(beanClass)) {
|
||||
List<CtMethod> getters = getGetters(beanClass);
|
||||
if (shouldAddGetterCallers(getters)) {
|
||||
source = addGetterCallers(beanClass, source, getters);
|
||||
}
|
||||
} else {
|
||||
source += "\treturn \"\";}";
|
||||
}
|
||||
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() {
|
||||
String source = "\tStringBuilder result=new StringBuilder(\"[\");\n";
|
||||
source += "\tfor (int i=0; i<array.length; i++){\n";
|
||||
source += "\t\tresult.append(" + Serializer.class.getName() + ".toJSONString(array[i]));\n";
|
||||
source += "\t\tresult.append(\", \");\n";
|
||||
source += "\t};\n";
|
||||
source += "\tresult.setLength(result.length()-2);\n";
|
||||
source += "\tresult.append(\"]\");\n";
|
||||
source += "\treturn result.toString();\n";
|
||||
source += "}";
|
||||
return source;
|
||||
}
|
||||
|
||||
private String handleMap() {
|
||||
String source = "StringBuilder result=new StringBuilder(\"{\");\n";
|
||||
source += "\tfor (java.util.Iterator entries=((java.util.Map)object).entrySet().iterator();entries.hasNext();){\n";
|
||||
source += "\t\tjava.util.Map.Entry entry=(java.util.Map.Entry)entries.next();\n";
|
||||
source += "\t\tresult.append(\"\\\"\"+entry.getKey().toString()+\"\\\"\");\n";
|
||||
source += "\t\tresult.append(\": \");\n";
|
||||
source += "\t\tresult.append(" + Serializer.class.getName() + ".toJSONString(entry.getValue()));\n";
|
||||
source += "\t\tresult.append(\", \");\n";
|
||||
source += "\t};\n";
|
||||
source += "\tresult.setLength(result.length()-2);\n";
|
||||
source += "\tresult.append(\"}\");\n";
|
||||
source += "\treturn result.toString();\n";
|
||||
source += "}";
|
||||
return source;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the class contains fields for which public getters are available, then these will be called in the generated code.
|
||||
*/
|
||||
private String addGetterCallers(CtClass beanClass, String source, List<CtMethod> getters) {
|
||||
int index = 0;
|
||||
source += "\treturn ";
|
||||
source += "\"{";
|
||||
for (CtMethod getter : getters) {
|
||||
source = addPair(beanClass, source, getter);
|
||||
if (index++ < getters.size() - 1) {
|
||||
source += ",";
|
||||
}
|
||||
}
|
||||
source += "}\";\n}";
|
||||
return source;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> JSONSerializer<T> createSerializerInstance(CtClass serializerClass) throws InstantiationException, IllegalAccessException,
|
||||
CannotCompileException, NoSuchMethodException, InvocationTargetException {
|
||||
return (JSONSerializer<T>) 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) {
|
||||
return createSerializerName(beanClass.getName());
|
||||
}
|
||||
|
||||
public String createSerializerName(String name) {
|
||||
return ROOT_PACKAGE + name.replaceAll("\\[]", "Array") + "Serializer";
|
||||
}
|
||||
|
||||
private boolean isCollection(CtClass beanClass) throws NotFoundException {
|
||||
List<CtClass> interfaces = new ArrayList<>(Arrays.asList(beanClass.getInterfaces()));
|
||||
interfaces.add(beanClass);
|
||||
for (CtClass interfaze : interfaces) {
|
||||
if (interfaze.getName().equals(COLLECTION) || interfaze.getName().equals(LIST) || interfaze.getName().equals(SET)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isMap(CtClass beanClass) throws NotFoundException {
|
||||
List<CtClass> interfaces = new ArrayList<>(Arrays.asList(beanClass.getInterfaces()));
|
||||
interfaces.add(beanClass);
|
||||
for (CtClass interfaze : interfaces) {
|
||||
if (interfaze.getName().equals(MAP)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* The JSON vernacular for key:value is pair...
|
||||
*/
|
||||
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);
|
||||
return source;
|
||||
}
|
||||
|
||||
/*
|
||||
* derive property key from getter
|
||||
*/
|
||||
private String jsonKey(CtMethod getter) {
|
||||
return "\\\"" + toFieldName(getter.getName()) + "\\\"";
|
||||
}
|
||||
|
||||
private String jsonValue(CtClass classToSerialize, CtMethod getter) {
|
||||
/* primitives are wrapped so the produced methods adhere to the JSONSerializer interface */
|
||||
return createSubSerializerForReturnTypeAndAddInvocationToSource(classToSerialize, getter);
|
||||
}
|
||||
|
||||
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 */
|
||||
String source = "\"+" + Serializer.class.getName() + ".toJSONString(";
|
||||
|
||||
// cast because of lack of generics
|
||||
source += "(" + cast(regularClassname(classToSerialize.getName())) + "object)." + getter.getName() + "()";
|
||||
|
||||
source += ")+\"";
|
||||
return source;
|
||||
}
|
||||
|
||||
/*
|
||||
* turns for example 'getValue' into 'value'
|
||||
*/
|
||||
private String toFieldName(String name) {
|
||||
return name.substring(3, 4).toLowerCase() + (name.length() > 4 ? name.substring(4) : "");
|
||||
}
|
||||
|
||||
public String regularClassname(String name) {
|
||||
return name.replaceAll("\\$", ".");
|
||||
}
|
||||
|
||||
private String cast(String classToSerialize) {
|
||||
return "(" + classToSerialize + ")";
|
||||
}
|
||||
|
||||
/*
|
||||
* Retrieves getter methods from a class
|
||||
*/
|
||||
private List<CtMethod> getGetters(CtClass beanClass) {
|
||||
List<CtMethod> methods = new ArrayList<>();
|
||||
List<CtField> fields = getAllFields(beanClass);
|
||||
for (CtField field : fields) {
|
||||
try {
|
||||
CtMethod method = beanClass.getMethod(getGetterMethod(field), getDescription(field));
|
||||
if (Modifier.isPublic(method.getModifiers())) {
|
||||
methods.add(method);
|
||||
}
|
||||
} catch (NotFoundException n) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
return methods;
|
||||
}
|
||||
|
||||
private String getGetterMethod(CtField field) {
|
||||
return "get" + field.getName().substring(0, 1).toUpperCase() + field.getName().substring(1);
|
||||
}
|
||||
|
||||
private List<CtField> getAllFields(CtClass beanClass) {
|
||||
try {
|
||||
List<CtField> allfields = new ArrayList<>(Arrays.asList(beanClass.getDeclaredFields()));
|
||||
if (beanClass.getSuperclass() != null) {
|
||||
return getAllFields(beanClass.getSuperclass(), allfields);
|
||||
}
|
||||
return allfields;
|
||||
} catch (NotFoundException e) {
|
||||
throw new SerializerCreationException(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private List<CtField> getAllFields(CtClass beanClass, List<CtField> allfields) {
|
||||
allfields.addAll(Arrays.asList(beanClass.getDeclaredFields()));
|
||||
|
||||
return allfields;
|
||||
}
|
||||
|
||||
/*
|
||||
* is getter list is not empty then callers should be added
|
||||
*/
|
||||
boolean shouldAddGetterCallers(List<CtMethod> getters) {
|
||||
return !getters.isEmpty();
|
||||
}
|
||||
|
||||
String getDescription(CtField field) throws NotFoundException {
|
||||
if (field.getType().isArray()) {
|
||||
return "()[" + innerClassName(field.getType().getName()) + ";";
|
||||
} else if (!field.getType().isPrimitive()) {
|
||||
return "()" + innerClassName(field.getType().getName()) + ";";
|
||||
} else {
|
||||
|
||||
return "()" + asPrimitive(field.getType().getName());
|
||||
}
|
||||
}
|
||||
|
||||
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";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
String innerClassName(String name) {
|
||||
return "L" + name.replaceAll("\\.", "/").replaceAll("\\[]", "");
|
||||
}
|
||||
|
||||
static boolean isPrimitiveOrWrapperOrString(CtClass beanClass) {
|
||||
return beanClass.isPrimitive() || wrappersAndString.contains(beanClass.getName());
|
||||
}
|
||||
}
|
||||
7
src/main/java/nl/sanderhautvast/json/ser/BaseMapper.java
Normal file
7
src/main/java/nl/sanderhautvast/json/ser/BaseMapper.java
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
package nl.sanderhautvast.json.ser;
|
||||
|
||||
public abstract class BaseMapper<T> {
|
||||
|
||||
protected abstract String json(T value);
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
package nl.sanderhautvast.json.ser;
|
||||
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
public class ByteClassLoader extends ClassLoader {
|
||||
|
||||
private final ConcurrentMap<String, Class<?>> classes = new ConcurrentHashMap<>();
|
||||
|
||||
@Override
|
||||
protected Class<?> findClass(String name) throws ClassNotFoundException {
|
||||
Class<?> instance = classes.get(name);
|
||||
if (instance == null) {
|
||||
throw new ClassNotFoundException(name);
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
void addClass(String name, byte[] bytecode) {
|
||||
Class<?> classDef = defineClass(name, bytecode, 0, bytecode.length);
|
||||
classes.put(name, classDef);
|
||||
}
|
||||
}
|
||||
7
src/main/java/nl/sanderhautvast/json/ser/JsonError.java
Normal file
7
src/main/java/nl/sanderhautvast/json/ser/JsonError.java
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
package nl.sanderhautvast.json.ser;
|
||||
|
||||
public class JsonError extends RuntimeException{
|
||||
public JsonError(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
}
|
||||
302
src/main/java/nl/sanderhautvast/json/ser/Mapper.java
Normal file
302
src/main/java/nl/sanderhautvast/json/ser/Mapper.java
Normal file
|
|
@ -0,0 +1,302 @@
|
|||
package nl.sanderhautvast.json.ser;
|
||||
|
||||
import org.objectweb.asm.ClassReader;
|
||||
import org.objectweb.asm.ClassWriter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
|
||||
public class Mapper {
|
||||
private static final Map<Class<?>, BaseMapper<?>> mappers = new ConcurrentHashMap<>();
|
||||
|
||||
private static final ByteClassLoader generatedClassesLoader = new ByteClassLoader();
|
||||
|
||||
static {
|
||||
addMapper(String.class, new StringMapper());
|
||||
addMapper(Boolean.class, new BooleanMapper());
|
||||
addMapper(Integer.class, new IntegerMapper());
|
||||
addMapper(Long.class, new LongMapper());
|
||||
addMapper(Short.class, new ShortMapper());
|
||||
addMapper(Byte.class, new ByteMapper());
|
||||
addMapper(Character.class, new CharMapper());
|
||||
addMapper(Float.class, new FloatMapper());
|
||||
addMapper(Double.class, new DoubleMapper());
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new (custom) mapper implementation for the specified type
|
||||
*
|
||||
* @param type The class to serialize to json
|
||||
* @param mapper the Mapper implementation
|
||||
*/
|
||||
public static <T> void addMapper(Class<T> type, BaseMapper<T> mapper) {
|
||||
mappers.put(type, mapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the json representation of the value as a String
|
||||
*/
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
public static <J> String json(Object value) {
|
||||
if (value == null) {
|
||||
return "null";
|
||||
}
|
||||
Class<J> type = (Class<J>) value.getClass();
|
||||
if (type.isArray()) {
|
||||
return array((Object[]) value);
|
||||
}
|
||||
if (value instanceof Collection) {
|
||||
return list((Collection) value);
|
||||
}
|
||||
if (value instanceof Map) {
|
||||
return object((Map) value);
|
||||
}
|
||||
BaseMapper mapper = mappers.computeIfAbsent(type, key -> createObjectMapper(type));
|
||||
return mapper.json(value);
|
||||
}
|
||||
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
private static String array(Object[] array) {
|
||||
if (array.length == 0) {
|
||||
return "[]";
|
||||
}
|
||||
Object first = array[0];
|
||||
Class<?> elementType = first.getClass();
|
||||
BaseMapper mapper = mappers.computeIfAbsent(elementType, key -> createObjectMapper(elementType));
|
||||
StringBuilder builder = new StringBuilder("[");
|
||||
builder.append(mapper.json(first));
|
||||
Arrays.stream(array).skip(1)
|
||||
.forEach(element -> {
|
||||
builder.append(",");
|
||||
builder.append(mapper.json(element));
|
||||
});
|
||||
builder.append("]");
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
private static String list(Collection list) {
|
||||
if (list.isEmpty()) {
|
||||
return "[]";
|
||||
}
|
||||
Object first = list.iterator().next();
|
||||
Class<?> elementType = first.getClass();
|
||||
BaseMapper mapper = mappers.computeIfAbsent(elementType, key -> createObjectMapper(elementType));
|
||||
StringBuilder builder = new StringBuilder("[");
|
||||
builder.append(mapper.json(first));
|
||||
list.stream().skip(1)
|
||||
.forEach(element -> {
|
||||
builder.append(",");
|
||||
builder.append(mapper.json(element));
|
||||
});
|
||||
builder.append("]");
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
private static String object(Map map) {
|
||||
if (map.isEmpty()) {
|
||||
return "{}";
|
||||
}
|
||||
Set<Map.Entry> entries = map.entrySet();
|
||||
Map.Entry first = entries.iterator().next();
|
||||
Class<?> valueType = first.getValue().getClass();
|
||||
|
||||
BaseMapper mapper = mappers.computeIfAbsent(valueType, key -> createObjectMapper(valueType));
|
||||
StringBuilder builder = new StringBuilder("{");
|
||||
builder.append("\"").append(first.getKey()).append("\":").append(mapper.json(first.getValue()));
|
||||
entries.stream().skip(1)
|
||||
.forEach(entry -> {
|
||||
builder.append(",\"");
|
||||
builder.append(entry.getKey()).append("\":");
|
||||
builder.append(mapper.json(entry.getValue()));
|
||||
});
|
||||
builder.append("}");
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
public static String json(byte value) {
|
||||
return Byte.toString(value);
|
||||
}
|
||||
|
||||
public static String json(boolean value) {
|
||||
return Boolean.toString(value);
|
||||
}
|
||||
|
||||
public static String json(short value) {
|
||||
return Short.toString(value);
|
||||
}
|
||||
|
||||
public static String json(int value) {
|
||||
return Integer.toString(value);
|
||||
}
|
||||
|
||||
public static String json(long value) {
|
||||
return Long.toString(value);
|
||||
}
|
||||
|
||||
public static String json(char value) {
|
||||
return "\"" + escape(value) + "\"";
|
||||
}
|
||||
|
||||
public static String json(float value) {
|
||||
return Float.toString(value);
|
||||
}
|
||||
|
||||
public static String json(double value) {
|
||||
return Double.toString(value);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <T> BaseMapper<T> createObjectMapper(Class<T> forType) {
|
||||
try {
|
||||
ClassReader cr = new ClassReader(forType.getName());
|
||||
MapperFactory mapperFactory = new MapperFactory();
|
||||
cr.accept(mapperFactory, 0);
|
||||
ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
|
||||
|
||||
mapperFactory.classNode.accept(classWriter);
|
||||
byte[] byteArray = classWriter.toByteArray();
|
||||
generatedClassesLoader.addClass(mapperFactory.classNode.name, byteArray);
|
||||
return (BaseMapper<T>) generatedClassesLoader.loadClass(mapperFactory.classNode.name).getConstructor().newInstance();
|
||||
} catch (IOException | ClassNotFoundException | NoSuchMethodException | InstantiationException |
|
||||
IllegalAccessException | InvocationTargetException e) {
|
||||
throw new JsonError(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static String escape(char c) {
|
||||
return escape(String.valueOf(c));
|
||||
}
|
||||
|
||||
static String escape(String value) {
|
||||
StringBuilder b = new StringBuilder(value);
|
||||
int i = 0;
|
||||
while (i < b.length()) {
|
||||
char c = b.charAt(i);
|
||||
switch (c) {
|
||||
case '\t':
|
||||
b.replace(i,i+1, "\\");
|
||||
b.insert(i+1, "t");
|
||||
break;
|
||||
case '\"':
|
||||
b.replace(i,i+1, "\\");
|
||||
b.insert(++i, "\"");
|
||||
break;
|
||||
case '/':
|
||||
b.replace(i,i+1, "\\");
|
||||
b.insert(++i, "/");
|
||||
break;
|
||||
case '\r':
|
||||
b.replace(i,i+1, "\\");
|
||||
b.insert(++i, "r");
|
||||
break;
|
||||
case '\n':
|
||||
b.replace(i,i+1, "\\");
|
||||
b.insert(++i, "n");
|
||||
break;
|
||||
case '\b':
|
||||
b.replace(i,i+1, "\\");
|
||||
b.insert(++i, "b");
|
||||
break;
|
||||
case '\f':
|
||||
b.replace(i,i+1, "\\");
|
||||
b.insert(++i, "f");
|
||||
break;
|
||||
case '\\':
|
||||
b.replace(i,i+1, "\\");
|
||||
b.insert(++i, "\\");
|
||||
break;
|
||||
case '\'':
|
||||
break;
|
||||
default:
|
||||
if ((c <= '\u001F') || (c >= '\u007F' && c <= '\u009F') || (c >= '\u2000' && c <= '\u20FF')) {
|
||||
String ss = Integer.toHexString(c);
|
||||
b.replace(i,i+1,"\\");
|
||||
b.insert(++i, "u");
|
||||
for (int k = 0; k < 4 - ss.length(); k++) {
|
||||
b.insert(++i,'0');
|
||||
}
|
||||
b.insert(++i,ss.toUpperCase());
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return b.toString();
|
||||
}
|
||||
}
|
||||
|
||||
class BooleanMapper extends BaseMapper<Boolean> {
|
||||
|
||||
@Override
|
||||
public String json(Boolean b) {
|
||||
return Boolean.toString(b);
|
||||
}
|
||||
}
|
||||
|
||||
class ShortMapper extends BaseMapper<Short> {
|
||||
|
||||
@Override
|
||||
public String json(Short value) {
|
||||
return Short.toString(value);
|
||||
}
|
||||
}
|
||||
|
||||
class StringMapper extends BaseMapper<String> {
|
||||
@Override
|
||||
public String json(String value) {
|
||||
return "\"" + Mapper.escape(value) + "\"";
|
||||
}
|
||||
}
|
||||
|
||||
class IntegerMapper extends BaseMapper<Integer> {
|
||||
|
||||
@Override
|
||||
public String json(Integer value) {
|
||||
return Integer.toString(value);
|
||||
}
|
||||
}
|
||||
|
||||
class LongMapper extends BaseMapper<Long> {
|
||||
|
||||
@Override
|
||||
public String json(Long value) {
|
||||
return Long.toString(value);
|
||||
}
|
||||
}
|
||||
|
||||
class ByteMapper extends BaseMapper<Byte> {
|
||||
|
||||
@Override
|
||||
protected String json(Byte value) {
|
||||
return Byte.toString(value);
|
||||
}
|
||||
}
|
||||
|
||||
class CharMapper extends BaseMapper<Character> {
|
||||
|
||||
@Override
|
||||
protected String json(Character value) {
|
||||
return "\"" + value + "\"";
|
||||
}
|
||||
}
|
||||
|
||||
class FloatMapper extends BaseMapper<Float> {
|
||||
|
||||
@Override
|
||||
protected String json(Float value) {
|
||||
return Float.toString(value);
|
||||
}
|
||||
}
|
||||
|
||||
class DoubleMapper extends BaseMapper<Double> {
|
||||
|
||||
@Override
|
||||
protected String json(Double value) {
|
||||
return Double.toString(value);
|
||||
}
|
||||
}
|
||||
148
src/main/java/nl/sanderhautvast/json/ser/MapperFactory.java
Normal file
148
src/main/java/nl/sanderhautvast/json/ser/MapperFactory.java
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
package nl.sanderhautvast.json.ser;
|
||||
|
||||
import org.objectweb.asm.ClassVisitor;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
import org.objectweb.asm.tree.*;
|
||||
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.LinkedList;
|
||||
import java.util.UUID;
|
||||
|
||||
import static org.objectweb.asm.Opcodes.*;
|
||||
|
||||
public class MapperFactory extends ClassVisitor {
|
||||
|
||||
public static final String MAPPERBASECLASS = javaName(BaseMapper.class.getName());
|
||||
|
||||
public static final String INIT = "<init>";
|
||||
public static final String ZERO_ARGS_VOID = "()V";
|
||||
public static final String APPEND = "append";
|
||||
public static final String STRINGBUILDER = "java/lang/StringBuilder";
|
||||
public static final String MAPPER = "nl/sanderhautvast/json/ser/Mapper";
|
||||
public static final String APPEND_SIGNATURE = "(Ljava/lang/String;)Ljava/lang/StringBuilder;";
|
||||
public static final String OBJECT = "Ljava/lang/Object;";
|
||||
|
||||
public MapperFactory() {
|
||||
super(ASM7);
|
||||
init();
|
||||
}
|
||||
|
||||
final ClassNode classNode = new ClassNode();
|
||||
|
||||
private String classToMap;
|
||||
|
||||
private MethodNode jsonMethod;
|
||||
|
||||
private boolean firstGetter = true;
|
||||
|
||||
private final LinkedList<AbstractInsnNode> getterInsnList = new LinkedList<>();
|
||||
|
||||
private void init() {
|
||||
classNode.version = V1_5;
|
||||
classNode.access = ACC_PUBLIC;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
|
||||
this.classToMap = name;
|
||||
classNode.name = "Mapper"+ UUID.randomUUID();
|
||||
classNode.superName = MAPPERBASECLASS;
|
||||
MethodNode constructor = new MethodNode(ACC_PUBLIC, INIT, ZERO_ARGS_VOID, null, null);
|
||||
constructor.instructions.add(new VarInsnNode(ALOAD, 0));
|
||||
constructor.instructions.add(new MethodInsnNode(INVOKESPECIAL, MAPPERBASECLASS, INIT, ZERO_ARGS_VOID));
|
||||
constructor.instructions.add(new InsnNode(RETURN));
|
||||
classNode.methods.add(constructor);
|
||||
|
||||
jsonMethod = new MethodNode(ACC_PUBLIC,
|
||||
"json", "(Ljava/lang/Object;)Ljava/lang/String;", null, null);
|
||||
classNode.methods.add(jsonMethod);
|
||||
add(new VarInsnNode(ALOAD, 1));
|
||||
add(new TypeInsnNode(CHECKCAST, name));
|
||||
add(new VarInsnNode(ASTORE, 1));
|
||||
add(new TypeInsnNode(NEW, STRINGBUILDER));
|
||||
add(new InsnNode(DUP));
|
||||
add(new MethodInsnNode(INVOKESPECIAL, STRINGBUILDER, "<init>", "()V"));
|
||||
add(new VarInsnNode(ASTORE, 2));
|
||||
add(new VarInsnNode(ALOAD, 2));
|
||||
add(new LdcInsnNode("{"));
|
||||
add(new MethodInsnNode(INVOKEVIRTUAL, STRINGBUILDER, APPEND, APPEND_SIGNATURE));
|
||||
add(new InsnNode(POP));
|
||||
}
|
||||
|
||||
public MethodVisitor visitMethod(int access, String methodname,
|
||||
String desc, String signature, String[] exceptions) {
|
||||
if (!hasArgs(desc) && access == Modifier.PUBLIC &&
|
||||
(methodname.startsWith("get") || (methodname.startsWith("is")) && desc.equals("()Z"))) {
|
||||
visitGetter(methodname, getReturnType(desc));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void visitGetter(String getterMethodName, String returnType) {
|
||||
int startIndex;
|
||||
if (getterMethodName.startsWith("is")) {
|
||||
startIndex = 2;
|
||||
} else {
|
||||
startIndex = 3;
|
||||
}
|
||||
|
||||
if (!firstGetter){
|
||||
getterInsnList.add(new VarInsnNode(ALOAD, 2));
|
||||
getterInsnList.add(new LdcInsnNode(","));
|
||||
getterInsnList.add(new MethodInsnNode(INVOKEVIRTUAL, STRINGBUILDER, APPEND, APPEND_SIGNATURE));
|
||||
getterInsnList.add(new InsnNode(POP));
|
||||
} else {
|
||||
firstGetter = false;
|
||||
}
|
||||
|
||||
getterInsnList.add(new VarInsnNode(ALOAD, 2));
|
||||
getterInsnList.add(new LdcInsnNode("\"" + getterMethodName.substring(startIndex).toLowerCase() + "\":"));
|
||||
getterInsnList.add(new MethodInsnNode(INVOKEVIRTUAL, STRINGBUILDER, APPEND, APPEND_SIGNATURE));
|
||||
getterInsnList.add(new InsnNode(POP));
|
||||
getterInsnList.add(new VarInsnNode(ALOAD, 2));
|
||||
getterInsnList.add(new VarInsnNode(ALOAD, 1));
|
||||
getterInsnList.add(new MethodInsnNode(INVOKEVIRTUAL, classToMap, getterMethodName, "()" + returnType));
|
||||
getterInsnList.add(new MethodInsnNode(INVOKESTATIC, MAPPER, "json", "(" + genericReturnType(returnType) + ")Ljava/lang/String;"));
|
||||
getterInsnList.add(new MethodInsnNode(INVOKEVIRTUAL, STRINGBUILDER, APPEND, APPEND_SIGNATURE));
|
||||
getterInsnList.add(new InsnNode(POP));
|
||||
}
|
||||
|
||||
private static String genericReturnType(String returnType) {
|
||||
char firstChar = returnType.charAt(0);
|
||||
if (firstChar == 'L' || firstChar == '[') {
|
||||
return OBJECT;
|
||||
} else {
|
||||
return returnType;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnd() {
|
||||
for (AbstractInsnNode insn : getterInsnList) {
|
||||
add(insn);
|
||||
}
|
||||
add(new VarInsnNode(ALOAD, 2));
|
||||
add(new LdcInsnNode("}"));
|
||||
add(new MethodInsnNode(INVOKEVIRTUAL, STRINGBUILDER, APPEND, APPEND_SIGNATURE));
|
||||
add(new VarInsnNode(ALOAD, 2));
|
||||
add(new MethodInsnNode(INVOKEVIRTUAL, STRINGBUILDER, "toString", "()Ljava/lang/String;"));
|
||||
add(new InsnNode(ARETURN));
|
||||
}
|
||||
|
||||
private void add(AbstractInsnNode ins) {
|
||||
jsonMethod.instructions.add(ins);
|
||||
}
|
||||
|
||||
private String getReturnType(String desc) {
|
||||
return desc.substring(2);
|
||||
}
|
||||
|
||||
private boolean hasArgs(String desc) {
|
||||
return desc.charAt(1) != ')';
|
||||
}
|
||||
|
||||
private static String javaName(String className) {
|
||||
return className.replaceAll("\\.", "/");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,51 +0,0 @@
|
|||
package nl.jssl.jsontoy.serialize;
|
||||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class StringPropertyTest {
|
||||
|
||||
@Test
|
||||
public void stringValue() {
|
||||
assertEquals("\"value\"", Serializer.toJSONString("value"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void stringProperty() {
|
||||
Bean object = new Bean();
|
||||
object.setData1("value1");
|
||||
object.setData2("value2");
|
||||
assertEquals("{\"data1\": \"value1\",\"data2\": \"value2\"}", Serializer.toJSONString(object));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void stringPropertyNull() {
|
||||
Bean object = new Bean();
|
||||
object.setData1("value1");
|
||||
object.setData2("null");
|
||||
assertEquals("{\"data1\": \"value1\",\"data2\": \"null\"}", Serializer.toJSONString(object));
|
||||
}
|
||||
|
||||
public class Bean {
|
||||
private String data1;
|
||||
private String data2;
|
||||
|
||||
public String getData1() {
|
||||
return data1;
|
||||
}
|
||||
|
||||
public void setData1(String data1) {
|
||||
this.data1 = data1;
|
||||
}
|
||||
|
||||
public String getData2() {
|
||||
return data2;
|
||||
}
|
||||
|
||||
public void setData2(String data2) {
|
||||
this.data2 = data2;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
package nl.jssl.jsontoy.serialize.collections;
|
||||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
import nl.jssl.jsontoy.serialize.Serializer;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class ArrayTest {
|
||||
@Test
|
||||
public void testValue() {
|
||||
assertEquals("[\"value1\", \"value2\"]", Serializer.toJSONString(new String[] { "value1", "value2" }));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPropertyValue() {
|
||||
Bean object = new Bean();
|
||||
object.setArray(new String[] { "value1", "value2" });
|
||||
assertEquals("{\"array\": [\"value1\", \"value2\"]}", Serializer.toJSONString(object));
|
||||
}
|
||||
|
||||
public class Bean {
|
||||
private String[] array;
|
||||
|
||||
public String[] getArray() {
|
||||
return array;
|
||||
}
|
||||
|
||||
public void setArray(String[] array) {
|
||||
this.array = array;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,41 +0,0 @@
|
|||
package nl.jssl.jsontoy.serialize.collections;
|
||||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import nl.jssl.jsontoy.serialize.Serializer;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class ListTest {
|
||||
@Test
|
||||
public void testValue() {
|
||||
List<String> list = new ArrayList();
|
||||
list.add("value1");
|
||||
list.add("value2");
|
||||
assertEquals("[\"value1\", \"value2\"]", Serializer.toJSONString(list));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPropertyValue() {
|
||||
Bean object = new Bean();
|
||||
object.setArray(new String[] { "value1", "value2" });
|
||||
assertEquals("{\"array\": [\"value1\", \"value2\"]}", Serializer.toJSONString(object));
|
||||
}
|
||||
|
||||
public class Bean {
|
||||
private String[] array;
|
||||
|
||||
public String[] getArray() {
|
||||
return array;
|
||||
}
|
||||
|
||||
public void setArray(String[] array) {
|
||||
this.array = array;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,47 +0,0 @@
|
|||
package nl.jssl.jsontoy.serialize.collections;
|
||||
|
||||
import nl.jssl.jsontoy.serialize.Serializer;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class MapTest {
|
||||
@Test
|
||||
public void testValue() {
|
||||
Map<String, String> map = new HashMap<>();
|
||||
map.put("key1", "value1");
|
||||
map.put("key2", "value2");
|
||||
String jsonString = Serializer.toJSONString(map);
|
||||
assertTrue("{\"key1\": \"value1\", \"key2\": \"value2\"}".equals(jsonString) || "{\"key2\": \"value2\", \"key1\": \"value1\"}".equals(jsonString));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPropertyValue() {
|
||||
Bean object = new Bean();
|
||||
Map<String, String> map = new HashMap<>();
|
||||
map.put("key1", "value1");
|
||||
map.put("key2", "value2");
|
||||
object.setMap(map);
|
||||
String jsonString = Serializer.toJSONString(object);
|
||||
assertTrue("{\"map\": {\"key1\": \"value1\", \"key2\": \"value2\"}}".equals(jsonString)
|
||||
|| "{\"map\": {\"key2\": \"value2\", \"key1\": \"value1\"}}".equals(jsonString));
|
||||
}
|
||||
|
||||
public class Bean {
|
||||
|
||||
private Map<String, String> map;
|
||||
|
||||
public Map<String, String> getMap() {
|
||||
return map;
|
||||
}
|
||||
|
||||
public void setMap(Map<String, String> map) {
|
||||
this.map = map;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
package nl.jssl.jsontoy.serialize.collections;
|
||||
|
||||
import static junit.framework.Assert.assertTrue;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import nl.jssl.jsontoy.serialize.Serializer;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class SetTest {
|
||||
@Test
|
||||
public void testValue() {
|
||||
Set<String> list = new HashSet<String>();
|
||||
list.add("value1");
|
||||
list.add("value2");
|
||||
String jsonString = Serializer.toJSONString(list);
|
||||
assertTrue("[\"value2\", \"value1\"]".equals(jsonString) || "[\"value1\", \"value2\"]".equals(jsonString));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPropertyValue() {
|
||||
Bean object = new Bean();
|
||||
object.setSet(new HashSet<String>(Arrays.asList("value1", "value2")));
|
||||
String jsonString = Serializer.toJSONString(object);
|
||||
assertTrue("{\"set\": [\"value2\", \"value1\"]}".equals(jsonString) || "{\"set\": [\"value1\", \"value2\"]}".equals(jsonString));
|
||||
}
|
||||
|
||||
public class Bean {
|
||||
private Set<String> set;
|
||||
|
||||
public Set<String> getSet() {
|
||||
return set;
|
||||
}
|
||||
|
||||
public void setSet(Set<String> set) {
|
||||
this.set = set;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,48 +0,0 @@
|
|||
package nl.jssl.jsontoy.serialize.nested;
|
||||
|
||||
public class Bean1 {
|
||||
private String data1;
|
||||
private Bean2 bean2;
|
||||
|
||||
public String getData1() {
|
||||
return data1;
|
||||
}
|
||||
|
||||
public void setData1(String data1) {
|
||||
this.data1 = data1;
|
||||
}
|
||||
|
||||
public Bean2 getBean2() {
|
||||
return bean2;
|
||||
}
|
||||
|
||||
public void setBean2(Bean2 bean2) {
|
||||
this.bean2 = bean2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((data1 == null) ? 0 : data1.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
Bean1 other = (Bean1) obj;
|
||||
if (data1 == null) {
|
||||
if (other.data1 != null)
|
||||
return false;
|
||||
} else if (!data1.equals(other.data1))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
package nl.jssl.jsontoy.serialize.nested;
|
||||
|
||||
public class Bean2 {
|
||||
private String data2;
|
||||
|
||||
public String getData2() {
|
||||
return data2;
|
||||
}
|
||||
|
||||
public void setData2(String data2) {
|
||||
this.data2 = data2;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
package nl.jssl.jsontoy.serialize.nested;
|
||||
|
||||
public class Bean2Child extends Bean2 {
|
||||
private String data3;
|
||||
|
||||
public String getData3() {
|
||||
return data3;
|
||||
}
|
||||
|
||||
public void setData3(String data3) {
|
||||
this.data3 = data3;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
package nl.jssl.jsontoy.serialize.nested;
|
||||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
import nl.jssl.jsontoy.serialize.Serializer;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class NestedBeanTest {
|
||||
@Test
|
||||
public void testBeans() {
|
||||
Bean1 object1 = new Bean1();
|
||||
object1.setData1("value1");
|
||||
Bean2 object2 = new Bean2();
|
||||
object2.setData2("value2");
|
||||
object1.setBean2(object2);
|
||||
assertEquals("{\"data1\": \"value1\",\"bean2\": {\"data2\": \"value2\"}}", Serializer.toJSONString(object1));
|
||||
assertEquals("{\"data1\": \"value1\",\"bean2\": {\"data2\": \"value2\"}}", Serializer.toJSONString(object1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNullValueForBean() {
|
||||
Bean1 object1 = new Bean1();
|
||||
object1.setData1("value1");
|
||||
assertEquals("{\"data1\": \"value1\",\"bean2\": null}", Serializer.toJSONString(object1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBeanChildren() {
|
||||
Bean1 object1 = new Bean1();
|
||||
object1.setData1("value1");
|
||||
Bean2Child object3 = new Bean2Child();
|
||||
object3.setData2("value2");
|
||||
object3.setData3("value3");
|
||||
object1.setBean2(object3);
|
||||
assertEquals("{\"data1\": \"value1\",\"bean2\": {\"data3\": \"value3\",\"data2\": \"value2\"}}", Serializer.toJSONString(object1));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
package nl.jssl.jsontoy.serialize.primitives;
|
||||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
import nl.jssl.jsontoy.serialize.Serializer;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class BooleanPropertyTest {
|
||||
|
||||
@Test
|
||||
public void testPrimitive() {
|
||||
assertEquals("false", Serializer.toJSONString(false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWrapper() {
|
||||
assertEquals("false", Serializer.toJSONString(Boolean.FALSE));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProperty() {
|
||||
Bean object = new Bean();
|
||||
object.setData(true);
|
||||
assertEquals("{\"data\": true}", Serializer.toJSONString(object));
|
||||
}
|
||||
|
||||
public class Bean {
|
||||
private boolean data;
|
||||
|
||||
public boolean getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public void setData(boolean data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
package nl.jssl.jsontoy.serialize.primitives;
|
||||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
import nl.jssl.jsontoy.serialize.Serializer;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class BytePropertyTest {
|
||||
@Test
|
||||
public void testPrimitive() {
|
||||
assertEquals("-55", Serializer.toJSONString((byte) -55));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWrapper() {
|
||||
assertEquals("55", Serializer.toJSONString((byte) 55));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProperty() {
|
||||
Bean object = new Bean();
|
||||
object.setData((byte) 1);
|
||||
assertEquals("{\"data\": 1}", Serializer.toJSONString(object));
|
||||
}
|
||||
|
||||
public class Bean {
|
||||
private byte data;
|
||||
|
||||
public byte getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public void setData(byte data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
package nl.jssl.jsontoy.serialize.primitives;
|
||||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
import nl.jssl.jsontoy.serialize.Serializer;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class CharPropertyTest {
|
||||
@Test
|
||||
public void testPrimitive() {
|
||||
assertEquals("\"d\"", Serializer.toJSONString('d'));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWrapper() {
|
||||
assertEquals("\"s\"", Serializer.toJSONString('s'));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProperty() {
|
||||
Bean object = new Bean();
|
||||
object.setData('a');
|
||||
assertEquals("{\"data\": \"a\"}", Serializer.toJSONString(object));
|
||||
}
|
||||
|
||||
public class Bean {
|
||||
private char data;
|
||||
|
||||
public char getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public void setData(char data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
package nl.jssl.jsontoy.serialize.primitives;
|
||||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
import nl.jssl.jsontoy.serialize.Serializer;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class DoublePropertyTest {
|
||||
@Test
|
||||
public void testPrimitive() {
|
||||
assertEquals("-55.6", Serializer.toJSONString(-55.6D));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWrapper() {
|
||||
assertEquals("55.0", Serializer.toJSONString(Double.valueOf("55.0")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProperty() {
|
||||
Bean object = new Bean();
|
||||
object.setData(326.2D);
|
||||
assertEquals("{\"data\": 326.2}", Serializer.toJSONString(object));
|
||||
}
|
||||
|
||||
public class Bean {
|
||||
private double data;
|
||||
|
||||
public double getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public void setData(double data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
package nl.jssl.jsontoy.serialize.primitives;
|
||||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
import nl.jssl.jsontoy.serialize.Serializer;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class FloatPropertyTest {
|
||||
@Test
|
||||
public void testPrimitive() {
|
||||
assertEquals("-55.6", Serializer.toJSONString(-55.6F));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWrapper() {
|
||||
assertEquals("55.0", Serializer.toJSONString(Float.valueOf("55.0")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProperty() {
|
||||
Bean object = new Bean();
|
||||
object.setData(1F);
|
||||
assertEquals("{\"data\": 1.0}", Serializer.toJSONString(object));
|
||||
}
|
||||
|
||||
public class Bean {
|
||||
private float data;
|
||||
|
||||
public float getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public void setData(float data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
package nl.jssl.jsontoy.serialize.primitives;
|
||||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
import nl.jssl.jsontoy.serialize.Serializer;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class IntPropertyTest {
|
||||
|
||||
@Test
|
||||
public void testPrimitive() {
|
||||
assertEquals("-55", Serializer.toJSONString(-55));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWrapper() {
|
||||
assertEquals("55", Serializer.toJSONString(Integer.valueOf("55")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPropertyValue() {
|
||||
Bean object = new Bean();
|
||||
object.setData(1);
|
||||
assertEquals("{\"data\": 1}", Serializer.toJSONString(object));
|
||||
}
|
||||
|
||||
public class Bean {
|
||||
private int data;
|
||||
|
||||
public int getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public void setData(int data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
package nl.jssl.jsontoy.serialize.primitives;
|
||||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
import nl.jssl.jsontoy.serialize.Serializer;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class LongPropertyTest {
|
||||
@Test
|
||||
public void testPrimitive() {
|
||||
assertEquals("-55", Serializer.toJSONString(-55L));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWrapper() {
|
||||
assertEquals("55", Serializer.toJSONString(Long.valueOf("55")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProperty() {
|
||||
Bean object = new Bean();
|
||||
object.setData(1L);
|
||||
assertEquals("{\"data\": 1}", Serializer.toJSONString(object));
|
||||
}
|
||||
|
||||
public class Bean {
|
||||
private long data;
|
||||
|
||||
public long getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public void setData(long data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
package nl.jssl.jsontoy.serialize.primitives;
|
||||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
import nl.jssl.jsontoy.serialize.Serializer;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class NullPropertyTest {
|
||||
|
||||
@Test
|
||||
public void testPrimitive() {
|
||||
assertEquals("null", Serializer.toJSONString(null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProperty() {
|
||||
Bean object = new Bean();
|
||||
assertEquals("{\"data\": null}", Serializer.toJSONString(object));
|
||||
}
|
||||
|
||||
public class Bean {
|
||||
private String data;
|
||||
|
||||
public String getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public void setData(String data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
package nl.jssl.jsontoy.serialize.primitives;
|
||||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
import nl.jssl.jsontoy.serialize.Serializer;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class ShortPropertyTest {
|
||||
@Test
|
||||
public void testPrimitive() {
|
||||
assertEquals("-55", Serializer.toJSONString((short) -55));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWrapper() {
|
||||
assertEquals("5", Serializer.toJSONString(Short.valueOf("5")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProperty() {
|
||||
Bean object = new Bean();
|
||||
object.setData((short) 3);
|
||||
assertEquals("{\"data\": 3}", Serializer.toJSONString(object));
|
||||
}
|
||||
|
||||
public class Bean {
|
||||
private short data;
|
||||
|
||||
public short getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public void setData(short data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
package nl.sanderhautvast.json.ser;
|
||||
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
public class ByteClassLoaderTest {
|
||||
|
||||
@Test
|
||||
public void foo() {
|
||||
assertThrows(ClassNotFoundException.class, () -> new ByteClassLoader().findClass("WrongName"));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
package nl.sanderhautvast.json.ser;
|
||||
|
||||
import lombok.Data;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
|
||||
public class StringPropertyTest {
|
||||
|
||||
@Test
|
||||
public void stringValue() {
|
||||
assertEquals("\"value\"", Mapper.json("value"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void stringProperty() {
|
||||
Bean object = new Bean();
|
||||
object.setData1("value1");
|
||||
object.setData2("value2");
|
||||
assertEquals("{\"data1\":\"value1\",\"data2\":\"value2\"}", Mapper.json(object));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void stringPropertyNull() {
|
||||
Bean object = new Bean();
|
||||
object.setData1("value1");
|
||||
object.setData2(null);
|
||||
assertEquals("{\"data1\":\"value1\",\"data2\":null}", Mapper.json(object));
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class Bean {
|
||||
private String data1;
|
||||
private String data2;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
package nl.sanderhautvast.json.ser.collections;
|
||||
|
||||
|
||||
import lombok.Data;
|
||||
import nl.sanderhautvast.json.ser.Mapper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public class ArrayTest {
|
||||
@Test
|
||||
public void testValue() {
|
||||
assertEquals("[\"value1\",\"value2\"]", Mapper.json(new String[]{"value1", "value2"}));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPropertyValue() {
|
||||
Bean object = new Bean();
|
||||
object.setArray(new String[]{"value1", "value2"});
|
||||
assertEquals("{\"array\":[\"value1\",\"value2\"]}", Mapper.json(object));
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class Bean {
|
||||
private String[] array;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
package nl.sanderhautvast.json.ser.collections;
|
||||
|
||||
|
||||
import lombok.Data;
|
||||
import nl.sanderhautvast.json.ser.Mapper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public class ListTest {
|
||||
|
||||
@Test
|
||||
void testEmpty() {
|
||||
assertEquals("[]", Mapper.json(List.of()));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testValue() {
|
||||
assertEquals("[\"value1\",\"value2\"]", Mapper.json(List.of("value1", "value2")));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testPropertyValue() {
|
||||
Bean object = new Bean();
|
||||
object.setList(List.of("value1", "value2"));
|
||||
assertEquals("{\"list\":[\"value1\",\"value2\"]}", Mapper.json((object)));
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class Bean {
|
||||
private List<String> list;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
package nl.sanderhautvast.json.ser.collections;
|
||||
|
||||
|
||||
import lombok.Data;
|
||||
import nl.sanderhautvast.json.ser.Mapper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
|
||||
public class MapTest {
|
||||
@Test
|
||||
public void testValue() {
|
||||
String jsonString = Mapper.json(Map.of("key1", "value1", "key2", "value2"));
|
||||
assertTrue("{\"key1\":\"value1\",\"key2\":\"value2\"}".equals(jsonString)
|
||||
|| "{\"key2\":\"value2\",\"key1\":\"value1\"}".equals(jsonString), jsonString); //order doesn't matter
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIntegerKeys() {
|
||||
String jsonString = Mapper.json(Map.of(1, "value1", 2, "value2"));
|
||||
assertTrue("{\"1\":\"value1\",\"2\":\"value2\"}".equals(jsonString)
|
||||
|| "{\"2\":\"value2\",\"1\":\"value1\"}".equals(jsonString), jsonString); //order doesn't matter
|
||||
}
|
||||
|
||||
@Test
|
||||
void testEmpty(){
|
||||
assertEquals("{}", Mapper.json(Map.of()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPropertyValue() {
|
||||
Bean object = new Bean();
|
||||
object.setMap(Map.of("key1", "value1", "key2", "value2"));
|
||||
String jsonString = Mapper.json(object);
|
||||
assertTrue("{\"map\":{\"key1\":\"value1\",\"key2\":\"value2\"}}".equals(jsonString)
|
||||
|| "{\"map\":{\"key2\":\"value2\",\"key1\":\"value1\"}}".equals(jsonString), jsonString);
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class Bean {
|
||||
private Map<String, String> map;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
package nl.sanderhautvast.json.ser.collections;
|
||||
|
||||
import lombok.Data;
|
||||
import nl.sanderhautvast.json.ser.Mapper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
public class SetTest {
|
||||
|
||||
@Test
|
||||
void testEmpty(){
|
||||
assertEquals("[]", Mapper.json(Set.of()));
|
||||
}
|
||||
@Test
|
||||
public void testValue() {
|
||||
String jsonString = Mapper.json(Set.of("value1", "value2"));
|
||||
assertTrue("[\"value2\",\"value1\"]".equals(jsonString)
|
||||
|| "[\"value1\",\"value2\"]".equals(jsonString), jsonString);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPropertyValue() {
|
||||
Bean object = new Bean();
|
||||
object.setSet(Set.of("value1", "value2"));
|
||||
String jsonString = Mapper.json(object);
|
||||
assertTrue("{\"set\":[\"value2\",\"value1\"]}".equals(jsonString)
|
||||
|| "{\"set\":[\"value1\",\"value2\"]}".equals(jsonString));
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class Bean {
|
||||
private Set<String> set;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
package nl.sanderhautvast.json.ser.collections;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import nl.sanderhautvast.json.ser.Mapper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
class StringTests {
|
||||
|
||||
@Test
|
||||
void testCharEscapes() {
|
||||
assertEquals("\"\\t\"", Mapper.json('\t'));
|
||||
assertEquals("\"\\b\"", Mapper.json('\b'));
|
||||
assertEquals("\"\\r\"", Mapper.json('\r'));
|
||||
assertEquals("\"\\n\"", Mapper.json('\n'));
|
||||
assertEquals("\"\\\"\"", Mapper.json('\"'));
|
||||
assertEquals("\"\\\\\"", Mapper.json('\\'));
|
||||
assertEquals("\"\\f\"", Mapper.json('\f'));
|
||||
assertEquals("\"\\/\"", Mapper.json('/'));
|
||||
assertEquals("\"'\"", Mapper.json('\''));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testStringEscapes() {
|
||||
assertEquals("\"bla\\tbla\"", Mapper.json("bla\tbla"));
|
||||
assertEquals("\"\\b\\b\"", Mapper.json("\b\b"));
|
||||
assertEquals("\"\\r\\n\"", Mapper.json("\r\n"));
|
||||
assertEquals("\"\\n\"", Mapper.json("\n"));
|
||||
assertEquals("\"\\\"\"", Mapper.json("\""));
|
||||
assertEquals("\"\\\\\"", Mapper.json("\\"));
|
||||
assertEquals("\"\\f\"", Mapper.json("\f"));
|
||||
assertEquals("\"\\/\"", Mapper.json("/"));
|
||||
assertEquals("\"'\"", Mapper.json("'"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void unicodeTests() {
|
||||
assertEquals("\"angry=😠\"", Mapper.json("angry=😠"));
|
||||
assertEquals("\"\\u20A7dings\"", Mapper.json("₧dings"));
|
||||
assertEquals("\"狗=dog\"", Mapper.json("狗=dog")); // dog
|
||||
}
|
||||
|
||||
}
|
||||
10
src/test/java/nl/sanderhautvast/json/ser/nested/Bean1.java
Normal file
10
src/test/java/nl/sanderhautvast/json/ser/nested/Bean1.java
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
package nl.sanderhautvast.json.ser.nested;
|
||||
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class Bean1 {
|
||||
private String data1;
|
||||
private Bean2 bean2;
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
package nl.sanderhautvast.json.ser.nested;
|
||||
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class Bean2 {
|
||||
private String data2;
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
//package nl.jssl.jsontoy.serialize.nested;
|
||||
//
|
||||
//import static junit.framework.Assert.assertEquals;
|
||||
//import nl.jssl.jsontoy.serialize.Serializer;
|
||||
//
|
||||
//import org.junit.Test;
|
||||
//
|
||||
//public class NestedBeanTest {
|
||||
// @Test
|
||||
// public void testBeans() {
|
||||
// Bean1 object1 = new Bean1();
|
||||
// object1.setData1("value1");
|
||||
// Bean2 object2 = new Bean2();
|
||||
// object2.setData2("value2");
|
||||
// object1.setBean2(object2);
|
||||
// assertEquals("{\"data1\": \"value1\",\"bean2\": {\"data2\": \"value2\"}}", Serializer.toJSONString(object1));
|
||||
// assertEquals("{\"data1\": \"value1\",\"bean2\": {\"data2\": \"value2\"}}", Serializer.toJSONString(object1));
|
||||
// }
|
||||
//
|
||||
// @Test
|
||||
// public void testNullValueForBean() {
|
||||
// Bean1 object1 = new Bean1();
|
||||
// object1.setData1("value1");
|
||||
// assertEquals("{\"data1\": \"value1\",\"bean2\": null}", Serializer.toJSONString(object1));
|
||||
// }
|
||||
//
|
||||
// @Test
|
||||
// public void testBeanChildren() {
|
||||
// Bean1 object1 = new Bean1();
|
||||
// object1.setData1("value1");
|
||||
// Bean2Child object3 = new Bean2Child();
|
||||
// object3.setData2("value2");
|
||||
// object3.setData3("value3");
|
||||
// object1.setBean2(object3);
|
||||
// assertEquals("{\"data1\": \"value1\",\"bean2\": {\"data3\": \"value3\",\"data2\": \"value2\"}}", Serializer.toJSONString(object1));
|
||||
// }
|
||||
//}
|
||||
|
|
@ -1,22 +1,21 @@
|
|||
package nl.jssl.jsontoy.serialize.performance;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import nl.jssl.jsontoy.serialize.Serializer;
|
||||
import nl.jssl.jsontoy.serialize.nested.Bean1;
|
||||
import nl.jssl.jsontoy.serialize.nested.Bean2;
|
||||
|
||||
import org.junit.Test;
|
||||
package nl.sanderhautvast.json.ser.performance;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import nl.sanderhautvast.json.ser.Mapper;
|
||||
import nl.sanderhautvast.json.ser.nested.Bean1;
|
||||
import nl.sanderhautvast.json.ser.nested.Bean2;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/*
|
||||
* => about 10% faster than jackson
|
||||
*/
|
||||
public class JacksonComparisonTest {
|
||||
private static final int ITERATIONS = 20;
|
||||
private static final int INNERLOOP_COUNT = 100000;
|
||||
List<String> trashbin = new ArrayList<>();
|
||||
private final List<String> trashbin = new ArrayList<>();
|
||||
|
||||
@Test
|
||||
public void testPerformance() throws JsonProcessingException {
|
||||
|
|
@ -52,7 +51,7 @@ public class JacksonComparisonTest {
|
|||
bean1.setData1(UUID.randomUUID().toString());
|
||||
bean1.setBean2(bean2);
|
||||
bean2.setData2(UUID.randomUUID().toString());
|
||||
jsonString = Serializer.toJSONString(bean1);
|
||||
jsonString = Mapper.json(bean1);
|
||||
trashbin.add(jsonString);
|
||||
}
|
||||
System.out.printf("% 7d%n",System.currentTimeMillis() - tt0);
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
package nl.sanderhautvast.json.ser.primitives;
|
||||
|
||||
import lombok.Data;
|
||||
import nl.sanderhautvast.json.ser.Mapper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public class BooleanPropertyTest {
|
||||
|
||||
@Test
|
||||
public void testPrimitive() {
|
||||
assertEquals("true", Mapper.json(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWrapper() {
|
||||
assertEquals("true", Mapper.json(Boolean.TRUE));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProperty() {
|
||||
Bean object = new Bean();
|
||||
object.setData(true);
|
||||
assertEquals("{\"data\":true}", Mapper.json(object));
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class Bean {
|
||||
boolean data;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
package nl.sanderhautvast.json.ser.primitives;
|
||||
|
||||
import lombok.Data;
|
||||
import nl.sanderhautvast.json.ser.Mapper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public class BytePropertyTest {
|
||||
@Test
|
||||
public void testPrimitive() {
|
||||
assertEquals("-55", Mapper.json((byte) -55));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWrapper() {
|
||||
assertEquals("55", Mapper.json(Byte.valueOf((byte) 55)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProperty() {
|
||||
Bean object = new Bean();
|
||||
object.setData((byte) 1);
|
||||
assertEquals("{\"data\":1}", Mapper.json(object));
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class Bean {
|
||||
private byte data;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
package nl.sanderhautvast.json.ser.primitives;
|
||||
|
||||
import lombok.Data;
|
||||
import nl.sanderhautvast.json.ser.Mapper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public class CharPropertyTest {
|
||||
@Test
|
||||
public void testPrimitive() {
|
||||
assertEquals("\"d\"", Mapper.json('d'));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWrapper() {
|
||||
assertEquals("\"s\"", Mapper.json(Character.valueOf('s')));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProperty() {
|
||||
Bean object = new Bean();
|
||||
object.setData('a');
|
||||
assertEquals("{\"data\":\"a\"}", Mapper.json(object));
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class Bean {
|
||||
private char data;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
package nl.sanderhautvast.json.ser.primitives;
|
||||
|
||||
import lombok.Data;
|
||||
import nl.sanderhautvast.json.ser.Mapper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public class DoublePropertyTest {
|
||||
@Test
|
||||
public void testPrimitive() {
|
||||
assertEquals("-55.6", Mapper.json(-55.6D));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWrapper() {
|
||||
assertEquals("55.0", Mapper.json(Double.valueOf("55.0")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProperty() {
|
||||
Bean object = new Bean();
|
||||
object.setData(326.2D);
|
||||
assertEquals("{\"data\":326.2}", Mapper.json(object));
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class Bean {
|
||||
private double data;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
package nl.sanderhautvast.json.ser.primitives;
|
||||
|
||||
import lombok.Data;
|
||||
import nl.sanderhautvast.json.ser.Mapper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public class FloatPropertyTest {
|
||||
@Test
|
||||
public void testPrimitive() {
|
||||
assertEquals("-55.6", Mapper.json(-55.6F));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWrapper() {
|
||||
assertEquals("55.0", Mapper.json(Float.valueOf("55.0")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProperty() {
|
||||
Bean object = new Bean();
|
||||
object.setData(1F);
|
||||
assertEquals("{\"data\":1.0}", Mapper.json(object));
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class Bean {
|
||||
private float data;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
package nl.sanderhautvast.json.ser.primitives;
|
||||
|
||||
import lombok.Data;
|
||||
import nl.sanderhautvast.json.ser.Mapper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public class IntPropertyTest {
|
||||
|
||||
@Test
|
||||
public void testPrimitive() {
|
||||
assertEquals("-55", Mapper.json(-55));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWrapper() {
|
||||
assertEquals("55", Mapper.json(Integer.valueOf("55")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPropertyValue() {
|
||||
Bean object = new Bean();
|
||||
object.setData(1);
|
||||
assertEquals("{\"data\":1}", Mapper.json(object));
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class Bean {
|
||||
int data;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
package nl.sanderhautvast.json.ser.primitives;
|
||||
|
||||
import lombok.Data;
|
||||
import nl.sanderhautvast.json.ser.Mapper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
|
||||
public class LongPropertyTest {
|
||||
@Test
|
||||
public void testPrimitive() {
|
||||
assertEquals("-55", Mapper.json(-55L));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWrapper() {
|
||||
assertEquals("55", Mapper.json(Long.valueOf("55")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProperty() {
|
||||
Bean object = new Bean();
|
||||
object.setData(1L);
|
||||
assertEquals("{\"data\":1}", Mapper.json(object));
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class Bean {
|
||||
private long data;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
package nl.sanderhautvast.json.ser.primitives;
|
||||
|
||||
import lombok.Data;
|
||||
import nl.sanderhautvast.json.ser.Mapper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public class NullPropertyTest {
|
||||
|
||||
@Test
|
||||
public void testProperty() {
|
||||
Bean object = new Bean();
|
||||
assertEquals("{\"data\":null}", Mapper.json(object));
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class Bean {
|
||||
private String data;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
package nl.sanderhautvast.json.ser.primitives;
|
||||
|
||||
import lombok.Data;
|
||||
import nl.sanderhautvast.json.ser.Mapper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public class ShortPropertyTest {
|
||||
@Test
|
||||
public void testPrimitive() {
|
||||
assertEquals("-55", Mapper.json((short) -55));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWrapper() {
|
||||
assertEquals("5", Mapper.json(Short.valueOf("5")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProperty() {
|
||||
Bean object = new Bean();
|
||||
object.setData((short) 3);
|
||||
assertEquals("{\"data\":3}", Mapper.json(object));
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class Bean {
|
||||
private short data;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue