added java bean support
This commit is contained in:
parent
75e40ae502
commit
a8a364b557
46 changed files with 1241 additions and 100 deletions
6
pom.xml
6
pom.xml
|
|
@ -59,9 +59,9 @@
|
||||||
|
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>junit</groupId>
|
<groupId>org.junit.jupiter</groupId>
|
||||||
<artifactId>junit</artifactId>
|
<artifactId>junit-jupiter-engine</artifactId>
|
||||||
<version>4.13</version>
|
<version>5.6.2</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|
|
||||||
153
src/main/java/nl/sander/jsontoy2/JavaObjectReaderFactory.java
Normal file
153
src/main/java/nl/sander/jsontoy2/JavaObjectReaderFactory.java
Normal file
|
|
@ -0,0 +1,153 @@
|
||||||
|
package nl.sander.jsontoy2;
|
||||||
|
|
||||||
|
import javassist.*;
|
||||||
|
import nl.sander.jsontoy2.javassist.ClassCreationException;
|
||||||
|
import nl.sander.jsontoy2.javassist.Javassist;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public class JavaObjectReaderFactory {
|
||||||
|
public static final String ROOT_PACKAGE = "serializer.";
|
||||||
|
private final static CtClass DESERIALIZER_BASE = Javassist.getTypeDefinition(JsonValueReader.class);
|
||||||
|
private static final CtClass[] NO_EXCEPTIONS = {};
|
||||||
|
private static final CtClass[] PARSER_PARAM = {Javassist.getTypeDefinition(Parser.class)};
|
||||||
|
private static final Class<?>[] NO_PARAMS = {};
|
||||||
|
private static final CtClass[] CT_NO_PARAMS = {};
|
||||||
|
private final static CtClass OBJECT_CLASS = Javassist.getTypeDefinition(Object.class);
|
||||||
|
private final static CtClass BOOLEAN = Javassist.getTypeDefinition(boolean.class);
|
||||||
|
private final static CtClass INT = Javassist.getTypeDefinition(int.class);
|
||||||
|
private final static CtClass LONG = Javassist.getTypeDefinition(long.class);
|
||||||
|
private final static CtClass BYTE = Javassist.getTypeDefinition(byte.class);
|
||||||
|
private final static CtClass SHORT = Javassist.getTypeDefinition(short.class);
|
||||||
|
private final static CtClass FLOAT = Javassist.getTypeDefinition(float.class);
|
||||||
|
private final static CtClass DOUBLE = Javassist.getTypeDefinition(double.class);
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
static <T> JsonValueReader<T> createReaderInstance(Class<T> type) {
|
||||||
|
try {
|
||||||
|
Class<?> jsonTypeReader = createReaderClass(type);
|
||||||
|
return (JsonValueReader<T>) jsonTypeReader.getDeclaredConstructor(NO_PARAMS).newInstance(new Object[]{});
|
||||||
|
|
||||||
|
} catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
|
||||||
|
throw new JsonParseException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Class<?> createReaderClass(Class<?> type) {
|
||||||
|
String name = createDeserializerName(type);
|
||||||
|
CtClass deserializerClass = Javassist.createClass(name, DESERIALIZER_BASE);
|
||||||
|
|
||||||
|
try {
|
||||||
|
deserializerClass.addConstructor(CtNewConstructor.make(CT_NO_PARAMS, NO_EXCEPTIONS, "{super();}", deserializerClass));
|
||||||
|
deserializerClass.addMethod(createReadJsonMethod(deserializerClass, type));
|
||||||
|
return deserializerClass.toClass();
|
||||||
|
} catch (CannotCompileException e) {
|
||||||
|
throw new ClassCreationException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static CtMethod createReadJsonMethod(CtClass serializerClass, Class<?> type) {
|
||||||
|
try {
|
||||||
|
String readMethodBodySource = createReadMethodBodySource(type);
|
||||||
|
System.out.println(readMethodBodySource);
|
||||||
|
return CtNewMethod.make(Modifier.PUBLIC, OBJECT_CLASS, "read", PARSER_PARAM, NO_EXCEPTIONS, readMethodBodySource, serializerClass);
|
||||||
|
} catch (CannotCompileException e) {
|
||||||
|
throw new ClassCreationException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static String createReadMethodBodySource(Class<?> type) {
|
||||||
|
String source = "{";
|
||||||
|
String typeName = type.getName();
|
||||||
|
if (ReaderFactory.readerSuppliers.containsKey(type)) {
|
||||||
|
source += "return " + JsonReader.class.getName() + ".read(" + typeName + ".class, $1);";
|
||||||
|
} else {
|
||||||
|
source += "java.util.Map object=" + JsonReader.class.getName() + ".readJavaObject(" + typeName + ".class,$1);\n";
|
||||||
|
source += typeName + " instance = new " + typeName + "();\n";
|
||||||
|
|
||||||
|
for (Field field : type.getDeclaredFields()) {
|
||||||
|
source += "instance.set" + capitalize(field.getName())
|
||||||
|
+ "(" + getSourceForGetValueFromObject(field) + ");\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
source += "return instance;";
|
||||||
|
}
|
||||||
|
|
||||||
|
source += "}\n";
|
||||||
|
return source;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private static String getSourceForGetValueFromObject(Field field) {
|
||||||
|
Class<?> fieldType = field.getType();
|
||||||
|
String fieldName = field.getName();
|
||||||
|
if (fieldType == boolean.class) {
|
||||||
|
return "getBoolean(\"" + fieldName + "\", object)";
|
||||||
|
} else if (fieldType == int.class) {
|
||||||
|
return "getInt(\"" + fieldName + "\", object)";
|
||||||
|
} else if (fieldType == long.class) {
|
||||||
|
return "getLong(\"" + fieldName + "\",object)";
|
||||||
|
} else if (fieldType == short.class) {
|
||||||
|
return "getShort(\"" + fieldName + "\",object)";
|
||||||
|
} else if (fieldType == byte.class) {
|
||||||
|
return "getByte(\"" + fieldName + "\",object)";
|
||||||
|
} else if (fieldType == float.class) {
|
||||||
|
return "getFloat(\"" + fieldName + "\",object)";
|
||||||
|
} else if (fieldType == double.class) {
|
||||||
|
return "getDouble(\"" + fieldName + "\",object)";
|
||||||
|
} else if (Set.class.isAssignableFrom(fieldType)) {
|
||||||
|
return "getSet(\"" + fieldName + "\",object)";
|
||||||
|
} else {
|
||||||
|
return "(" + fieldType.getName() + ")(object.get(\"" + fieldName + "\"))";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static String genericType(CtField field) {
|
||||||
|
try {
|
||||||
|
if (!Javassist.isCollection(field.getType())) {
|
||||||
|
return "";
|
||||||
|
} else {
|
||||||
|
|
||||||
|
String genericSignature = field.getGenericSignature(); // java.util.List<java.lang.String;>;
|
||||||
|
Pattern p = Pattern.compile("(.+?)<(.+?);>;");
|
||||||
|
Matcher matcher = p.matcher(genericSignature);
|
||||||
|
if (matcher.find()) {
|
||||||
|
String[] genericTypes = matcher.group(2).substring(1).replaceAll("/", ".").split(";L");
|
||||||
|
for (int i = 0; i < genericTypes.length; i++) {
|
||||||
|
genericTypes[i] += ".class";
|
||||||
|
}
|
||||||
|
return String.join(",", genericTypes);
|
||||||
|
}
|
||||||
|
throw new ClassCreationException("Generic type not ok");
|
||||||
|
}
|
||||||
|
} catch (NotFoundException e) {
|
||||||
|
throw new ClassCreationException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String capitalize(String lowercase) {
|
||||||
|
return lowercase.substring(0, 1).toUpperCase() + lowercase.substring(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Set<String> createTypeList(Class<?>... classes) {
|
||||||
|
return Arrays.stream(classes).map(Class::getName).collect(Collectors.toSet());
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
private static String createDeserializerName(Class<?> type) {
|
||||||
|
return ROOT_PACKAGE + type.getName().replaceAll("\\[]", "Array") + "Deserializer";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,33 +1,21 @@
|
||||||
package nl.sander.jsontoy2;
|
package nl.sander.jsontoy2;
|
||||||
|
|
||||||
import nl.sander.jsontoy2.readers.*;
|
|
||||||
|
|
||||||
import java.io.BufferedInputStream;
|
import java.io.BufferedInputStream;
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.lang.ref.SoftReference;
|
import java.lang.ref.SoftReference;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.time.LocalDateTime;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
import java.util.concurrent.ConcurrentMap;
|
|
||||||
import java.util.function.Supplier;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* public api
|
* public api
|
||||||
*/
|
*/
|
||||||
public class JsonReader {
|
public class JsonReader {
|
||||||
private static final ConcurrentMap<Class<?>, Supplier<JsonValueReader<?>>> readSuppliers = new ConcurrentHashMap<>();
|
|
||||||
private static final ConcurrentMap<Class<?>, JsonValueReader<?>> readers = new ConcurrentHashMap<>();
|
|
||||||
|
|
||||||
private final static ThreadLocal<SoftReference<Parser>> PARSERS = new ThreadLocal<>();
|
private final static ThreadLocal<SoftReference<Parser>> PARSERS = new ThreadLocal<>();
|
||||||
|
|
||||||
static {
|
|
||||||
registerPrimitiveTypeReaders();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* reads a value from a stream for a type that is not known beforehand
|
* reads a value from a stream for a type that is not known beforehand
|
||||||
|
|
@ -43,21 +31,12 @@ public class JsonReader {
|
||||||
* array => List
|
* array => List
|
||||||
*/
|
*/
|
||||||
public static Object read(InputStream inputStream) {
|
public static Object read(InputStream inputStream) {
|
||||||
final InputStream in = ensureBuffered(inputStream);
|
final InputStream in = ensureBufferedStream(inputStream);
|
||||||
try (Parser parser = getParser(in)) {
|
try (Parser parser = getParser(in)) {
|
||||||
return read(parser);
|
return read(parser);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static InputStream ensureBuffered(InputStream inputStream) {
|
|
||||||
if (inputStream instanceof BufferedInputStream) {
|
|
||||||
return inputStream;
|
|
||||||
} else {
|
|
||||||
return new BufferedInputStream(inputStream);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads a value from a string for a type that is not known beforehand
|
* Reads a value from a string for a type that is not known beforehand
|
||||||
*
|
*
|
||||||
|
|
@ -68,28 +47,6 @@ public class JsonReader {
|
||||||
return read(getParser(jsonString));
|
return read(getParser(jsonString));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Parser getParser(String jsonString) {
|
|
||||||
return getParser(new ByteArrayInputStream(jsonString.getBytes(StandardCharsets.UTF_8)));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Parser getParser(InputStream inputStream) {
|
|
||||||
Objects.requireNonNull(inputStream, "File not found");
|
|
||||||
Parser parser;
|
|
||||||
SoftReference<Parser> parserReference = PARSERS.get();
|
|
||||||
if (parserReference == null || (parser = parserReference.get()) == null) {
|
|
||||||
parser = new Parser(inputStream);
|
|
||||||
parserReference = new SoftReference<>(parser);
|
|
||||||
PARSERS.set(parserReference);
|
|
||||||
} else {
|
|
||||||
parser.init(inputStream);
|
|
||||||
}
|
|
||||||
return parser;
|
|
||||||
}
|
|
||||||
|
|
||||||
static Object read(Parser parser) {
|
|
||||||
return parser.parseAny();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads a value from a stream for the given type
|
* Reads a value from a stream for the given type
|
||||||
*
|
*
|
||||||
|
|
@ -117,41 +74,47 @@ public class JsonReader {
|
||||||
return read(type, getParser(jsonString));
|
return read(type, getParser(jsonString));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Parser getParser(String jsonString) {
|
||||||
|
return getParser(new ByteArrayInputStream(jsonString.getBytes(StandardCharsets.UTF_8)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Parser getParser(InputStream inputStream) {
|
||||||
|
Objects.requireNonNull(inputStream, "File not found");
|
||||||
|
Parser parser;
|
||||||
|
SoftReference<Parser> parserReference = PARSERS.get();
|
||||||
|
if (parserReference == null || (parser = parserReference.get()) == null) {
|
||||||
|
parser = new Parser(inputStream);
|
||||||
|
parserReference = new SoftReference<>(parser);
|
||||||
|
PARSERS.set(parserReference);
|
||||||
|
} else {
|
||||||
|
parser.init(inputStream);
|
||||||
|
}
|
||||||
|
return parser;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Object read(Parser parser) {
|
||||||
|
return parser.parseAny();
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private static <T> T read(Class<T> type, Parser parser) {
|
public static <T> T read(Class<T> type, Parser parser) {
|
||||||
return (T) getReader(type).read(parser);
|
return (T) ReaderFactory.getReader(type).read(parser);
|
||||||
// class.cast() does not work well for primitives;
|
// class.cast() does not work well for primitives;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static <T> JsonValueReader<?> getReader(Class<T> type) {
|
@SuppressWarnings("unused")
|
||||||
return readers.computeIfAbsent(type, k -> readSuppliers.get(k).get());
|
public static Map<?, ?> readJavaObject(Class<?> type, Parser parser) {
|
||||||
|
return parser.parseObject(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static <T> void register(Class<T> type, Supplier<JsonValueReader<?>> objectReader) {
|
|
||||||
readSuppliers.put(type, objectReader);
|
private static InputStream ensureBufferedStream(InputStream inputStream) {
|
||||||
|
if (inputStream instanceof BufferedInputStream) {
|
||||||
|
return inputStream;
|
||||||
|
} else {
|
||||||
|
return new BufferedInputStream(inputStream);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void registerPrimitiveTypeReaders() {
|
|
||||||
register(Boolean.class, BooleanReader::new);
|
|
||||||
register(boolean.class, BooleanReader::new);
|
|
||||||
register(Integer.class, IntegerReader::new);
|
|
||||||
register(int.class, IntegerReader::new);
|
|
||||||
register(Long.class, LongReader::new);
|
|
||||||
register(long.class, LongReader::new);
|
|
||||||
register(Byte.class, ByteReader::new);
|
|
||||||
register(byte.class, ByteReader::new);
|
|
||||||
register(Short.class, ShortReader::new);
|
|
||||||
register(short.class, ShortReader::new);
|
|
||||||
register(Double.class, DoubleReader::new);
|
|
||||||
register(double.class, DoubleReader::new);
|
|
||||||
register(Float.class, FloatReader::new);
|
|
||||||
register(float.class, FloatReader::new);
|
|
||||||
register(Date.class, DateReader::new);
|
|
||||||
register(Character.class, CharReader::new);
|
|
||||||
register(char.class, CharReader::new);
|
|
||||||
register(String.class, StringReader::new);
|
|
||||||
register(LocalDateTime.class, LocalDateTimeReader::new);
|
|
||||||
register(List.class, ListReader::new);
|
|
||||||
register(Map.class, MapReader::new);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,57 @@
|
||||||
package nl.sander.jsontoy2;
|
package nl.sander.jsontoy2;
|
||||||
|
|
||||||
public interface JsonValueReader<T> {
|
import java.util.HashSet;
|
||||||
T read(Parser parser);
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class for generated readers
|
||||||
|
*
|
||||||
|
* @param <T> the type that the reader produces
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unused") /* these methods will be called from generated code*/
|
||||||
|
public abstract class JsonValueReader<T> {
|
||||||
|
public abstract T read(Parser parser);
|
||||||
|
|
||||||
|
protected boolean getBoolean(String fieldName, Map<String, ?> values) {
|
||||||
|
Object value = values.get(fieldName);
|
||||||
|
return value == null ? false : (Boolean) value;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected int getInt(String fieldName, Map<String, ?> values) {
|
||||||
|
Object value = values.get(fieldName);
|
||||||
|
return value == null ? 0 : (Integer) value;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected long getLong(String fieldName, Map<String, ?> values) {
|
||||||
|
Object value = values.get(fieldName);
|
||||||
|
return value == null ? 0L : (Long) value;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected short getShort(String fieldName, Map<String, ?> values) {
|
||||||
|
Object value = values.get(fieldName);
|
||||||
|
return value == null ? (short) 0 : (Short) value;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected byte getByte(String fieldName, Map<String, ?> values) {
|
||||||
|
Object value = values.get(fieldName);
|
||||||
|
return value == null ? (byte) 0 : (Byte) value;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected float getFloat(String fieldName, Map<String, ?> values) {
|
||||||
|
Object value = values.get(fieldName);
|
||||||
|
return value == null ? 0F : (Float) value;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected double getDouble(String fieldName, Map<String, ?> values) {
|
||||||
|
Object value = values.get(fieldName);
|
||||||
|
return value == null ? 0D : (Double) value;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Set<?> getSet(String fieldName, Map<String, ?> values) {
|
||||||
|
Object value = values.get(fieldName);
|
||||||
|
return value == null ? null : new HashSet<>((List<?>) value);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,10 @@ public class Lexer implements AutoCloseable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void eatUntil(char until) {
|
||||||
|
eatUntil(new char[]{until});
|
||||||
|
}
|
||||||
|
|
||||||
void eatUntil(char... until) {
|
void eatUntil(char... until) {
|
||||||
while (current > -1 && (!contains(until, current) | Character.isWhitespace(current))) {
|
while (current > -1 && (!contains(until, current) | Character.isWhitespace(current))) {
|
||||||
advance();
|
advance();
|
||||||
|
|
@ -67,4 +71,9 @@ public class Lexer implements AutoCloseable {
|
||||||
throw new JsonParseException(e);
|
throw new JsonParseException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public byte current() {
|
||||||
|
return current;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ public class Parser extends Lexer {
|
||||||
|
|
||||||
public Integer parseInteger() {
|
public Integer parseInteger() {
|
||||||
final String value = parseNumber();
|
final String value = parseNumber();
|
||||||
return Double.valueOf(value).intValue();
|
return Integer.valueOf(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Long parseLong() {
|
public Long parseLong() {
|
||||||
|
|
@ -125,6 +125,10 @@ public class Parser extends Lexer {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<?, ?> parseObject() {
|
public Map<?, ?> parseObject() {
|
||||||
|
return parseObject(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<?, ?> parseObject(Class<?> type) {
|
||||||
final HashMap<Object, Object> map = new HashMap<>();
|
final HashMap<Object, Object> map = new HashMap<>();
|
||||||
skipWhitespace();
|
skipWhitespace();
|
||||||
if (current != '{') {
|
if (current != '{') {
|
||||||
|
|
@ -142,8 +146,13 @@ public class Parser extends Lexer {
|
||||||
throw new JsonParseException("expected colon");
|
throw new JsonParseException("expected colon");
|
||||||
}
|
}
|
||||||
skipWhitespace();
|
skipWhitespace();
|
||||||
final Maybe<Object> maybeValue = parseValue();
|
final Maybe<Object> maybeValue;
|
||||||
|
try {
|
||||||
|
maybeValue = type == null ? parseValue() : parseValue(type.getDeclaredField(key).getType());
|
||||||
maybeValue.ifPresent(value -> map.put(key, value));
|
maybeValue.ifPresent(value -> map.put(key, value));
|
||||||
|
} catch (NoSuchFieldException e) {
|
||||||
|
throw new JsonParseException(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
advance();
|
advance();
|
||||||
skipWhitespace();
|
skipWhitespace();
|
||||||
|
|
@ -181,8 +190,8 @@ public class Parser extends Lexer {
|
||||||
break;
|
break;
|
||||||
default: String numeric = parseNumber();
|
default: String numeric = parseNumber();
|
||||||
double doubleValue = Double.parseDouble(numeric);
|
double doubleValue = Double.parseDouble(numeric);
|
||||||
if ((int) doubleValue == doubleValue) {
|
if ((long) doubleValue == doubleValue) {
|
||||||
value = (int) doubleValue;
|
value = (long) doubleValue;
|
||||||
} else {
|
} else {
|
||||||
value = doubleValue;
|
value = doubleValue;
|
||||||
}
|
}
|
||||||
|
|
@ -190,6 +199,20 @@ public class Parser extends Lexer {
|
||||||
return Maybe.of(value);
|
return Maybe.of(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Maybe<Object> parseValue(Class<?> type) {
|
||||||
|
final Object value;
|
||||||
|
skipWhitespace();
|
||||||
|
|
||||||
|
JsonValueReader<?> reader = ReaderFactory.getReader(type);
|
||||||
|
if (reader != null) {
|
||||||
|
value = reader.read(this);
|
||||||
|
} else {
|
||||||
|
value = parseObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Maybe.of(value);
|
||||||
|
}
|
||||||
|
|
||||||
private Object readNull() {
|
private Object readNull() {
|
||||||
expect(() -> new JsonParseException("Expected 'null', encountered " + (char) current), 'n', 'u', 'l', 'l');
|
expect(() -> new JsonParseException("Expected 'null', encountered " + (char) current), 'n', 'u', 'l', 'l');
|
||||||
return null;
|
return null;
|
||||||
|
|
|
||||||
66
src/main/java/nl/sander/jsontoy2/ReaderFactory.java
Normal file
66
src/main/java/nl/sander/jsontoy2/ReaderFactory.java
Normal file
|
|
@ -0,0 +1,66 @@
|
||||||
|
package nl.sander.jsontoy2;
|
||||||
|
|
||||||
|
import nl.sander.jsontoy2.readers.*;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.ConcurrentMap;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
public class ReaderFactory {
|
||||||
|
static final ConcurrentMap<Class<?>, Supplier<JsonValueReader<?>>> readerSuppliers = new ConcurrentHashMap<>();
|
||||||
|
private static final ConcurrentMap<Class<?>, JsonValueReader<?>> readers = new ConcurrentHashMap<>();
|
||||||
|
private final static MapReader MAPREADER = new MapReader();
|
||||||
|
private final static ListReader LISTREADER = new ListReader();
|
||||||
|
|
||||||
|
static {
|
||||||
|
registerPrimitiveTypeReaders();
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> void registerCustomReader(Class<T> type, JsonValueReader<T> reader) {
|
||||||
|
readers.put(type, reader);
|
||||||
|
}
|
||||||
|
|
||||||
|
static <T> void register(Class<T> type, Supplier<JsonValueReader<?>> objectReader) {
|
||||||
|
readerSuppliers.put(type, objectReader);
|
||||||
|
}
|
||||||
|
|
||||||
|
static <T> JsonValueReader<?> getReader(Class<T> type) {
|
||||||
|
if (Map.class.isAssignableFrom(type)) {
|
||||||
|
return MAPREADER;
|
||||||
|
} else if (List.class.isAssignableFrom(type) || Set.class.isAssignableFrom(type)) {
|
||||||
|
return LISTREADER;
|
||||||
|
} else {
|
||||||
|
return readers.computeIfAbsent(type, k -> {
|
||||||
|
Supplier<JsonValueReader<?>> jsonValueReaderSupplier = readerSuppliers.get(k);
|
||||||
|
|
||||||
|
return Optional.ofNullable(jsonValueReaderSupplier)
|
||||||
|
.orElseGet(() -> () -> JavaObjectReaderFactory.createReaderInstance(type))
|
||||||
|
.get();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void registerPrimitiveTypeReaders() {
|
||||||
|
register(Boolean.class, BooleanReader::new);
|
||||||
|
register(boolean.class, BooleanReader::new);
|
||||||
|
register(Integer.class, IntegerReader::new);
|
||||||
|
register(int.class, IntegerReader::new);
|
||||||
|
register(Long.class, LongReader::new);
|
||||||
|
register(long.class, LongReader::new);
|
||||||
|
register(Byte.class, ByteReader::new);
|
||||||
|
register(byte.class, ByteReader::new);
|
||||||
|
register(Short.class, ShortReader::new);
|
||||||
|
register(short.class, ShortReader::new);
|
||||||
|
register(Double.class, DoubleReader::new);
|
||||||
|
register(double.class, DoubleReader::new);
|
||||||
|
register(Float.class, FloatReader::new);
|
||||||
|
register(float.class, FloatReader::new);
|
||||||
|
register(Date.class, DateReader::new);
|
||||||
|
register(Character.class, CharReader::new);
|
||||||
|
register(char.class, CharReader::new);
|
||||||
|
register(String.class, StringReader::new);
|
||||||
|
register(LocalDateTime.class, LocalDateTimeReader::new);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
package nl.sander.jsontoy2.javassist;
|
||||||
|
|
||||||
|
public class ClassCreationException extends RuntimeException {
|
||||||
|
public ClassCreationException(Throwable e) {
|
||||||
|
super(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClassCreationException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
183
src/main/java/nl/sander/jsontoy2/javassist/Javassist.java
Normal file
183
src/main/java/nl/sander/jsontoy2/javassist/Javassist.java
Normal file
|
|
@ -0,0 +1,183 @@
|
||||||
|
package nl.sander.jsontoy2.javassist;
|
||||||
|
|
||||||
|
import javassist.*;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import static java.util.Arrays.asList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Facade for javassist functions
|
||||||
|
*/
|
||||||
|
public class Javassist {
|
||||||
|
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<>(asList(BOOLEAN, CHARACTER, BYTE, DOUBLE, FLOAT, LONG, SHORT, INTEGER, STRING));
|
||||||
|
private final static Set<String> wrappers = new HashSet<>(asList(BOOLEAN, CHARACTER, BYTE, DOUBLE, FLOAT, LONG, SHORT, INTEGER));
|
||||||
|
|
||||||
|
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 final static ClassPool pool = ClassPool.getDefault();
|
||||||
|
|
||||||
|
public static CtClass getTypeDefinition(Class<?> type) {
|
||||||
|
try {
|
||||||
|
return pool.get(type.getName());
|
||||||
|
} catch (NotFoundException e) {
|
||||||
|
throw new ClassCreationException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public static CtClass getTypeDefinition(String type) {
|
||||||
|
try {
|
||||||
|
return pool.get(type);
|
||||||
|
} catch (NotFoundException e) {
|
||||||
|
throw new ClassCreationException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CtClass createClass(String className, CtClass baseClass) {
|
||||||
|
return pool.makeClass(className, baseClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isPrimitiveOrWrapperOrString(CtClass beanClass) {
|
||||||
|
return beanClass.isPrimitive() || wrappersAndString.contains(beanClass.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isBasicType(CtClass beanClass) {
|
||||||
|
return isPrimitiveOrWrapperOrString(beanClass) || isList(beanClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isList(CtClass type) {
|
||||||
|
try {
|
||||||
|
List<CtClass> interfaces = new ArrayList<>(asList(type.getInterfaces()));
|
||||||
|
interfaces.add(type);
|
||||||
|
for (CtClass interfaze : interfaces) {
|
||||||
|
if (interfaze.getName().equals(COLLECTION) || interfaze.getName().equals(LIST) || interfaze.getName().equals(SET)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
} catch (NotFoundException e) {
|
||||||
|
throw new IllegalStateException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isCollection(CtClass type) {
|
||||||
|
try {
|
||||||
|
List<CtClass> interfaces = new ArrayList<>(asList(type.getInterfaces()));
|
||||||
|
interfaces.add(type);
|
||||||
|
for (CtClass interfaze : interfaces) {
|
||||||
|
if (interfaze.getName().equals(COLLECTION) || interfaze.getName().equals(LIST) || interfaze.getName().equals(SET) || interfaze.getName().equals(MAP)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
} catch (NotFoundException e) {
|
||||||
|
throw new IllegalStateException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isMap(CtClass type) throws NotFoundException {
|
||||||
|
List<CtClass> interfaces = new ArrayList<>(asList(type.getInterfaces()));
|
||||||
|
interfaces.add(type);
|
||||||
|
for (CtClass interfaze : interfaces) {
|
||||||
|
if (interfaze.getName().equals(MAP)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Retrieves getter methods from a class
|
||||||
|
*/
|
||||||
|
public static List<CtMethod> getGetters(CtClass type) {
|
||||||
|
List<CtMethod> methods = new ArrayList<>();
|
||||||
|
List<CtField> fields = getAllFields(type);
|
||||||
|
for (CtField field : fields) {
|
||||||
|
try {
|
||||||
|
CtMethod method = type.getMethod(getGetterMethod(field), getDescription(field));
|
||||||
|
if (Modifier.isPublic(method.getModifiers())) {
|
||||||
|
methods.add(method);
|
||||||
|
}
|
||||||
|
} catch (NotFoundException n) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return methods;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String getGetterMethod(CtField field) {
|
||||||
|
return "get" + field.getName().substring(0, 1).toUpperCase() + field.getName().substring(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<CtField> getAllFields(CtClass beanClass) {
|
||||||
|
try {
|
||||||
|
List<CtField> allfields = new ArrayList<>(asList(beanClass.getDeclaredFields()));
|
||||||
|
if (beanClass.getSuperclass() != null) {
|
||||||
|
return getAllFields(beanClass.getSuperclass(), allfields);
|
||||||
|
}
|
||||||
|
return allfields;
|
||||||
|
} catch (NotFoundException e) {
|
||||||
|
throw new ClassCreationException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<CtField> getAllFields(CtClass beanClass, List<CtField> allfields) {
|
||||||
|
allfields.addAll(asList(beanClass.getDeclaredFields()));
|
||||||
|
|
||||||
|
return allfields;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static 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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String innerClassName(String name) {
|
||||||
|
return "L" + name.replaceAll("\\.", "/").replaceAll("\\[]", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static 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 "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
package nl.sander.jsontoy2.readers;
|
package nl.sander.jsontoy2.readers;
|
||||||
|
|
||||||
|
import nl.sander.jsontoy2.JsonValueReader;
|
||||||
|
|
||||||
import java.time.ZoneId;
|
import java.time.ZoneId;
|
||||||
import java.time.ZonedDateTime;
|
import java.time.ZonedDateTime;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
|
|
@ -7,7 +9,7 @@ import java.time.format.DateTimeFormatterBuilder;
|
||||||
import java.time.temporal.ChronoField;
|
import java.time.temporal.ChronoField;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
public abstract class AbstractDatesReader<T> {
|
public abstract class AbstractDatesReader<T> extends JsonValueReader<T> {
|
||||||
|
|
||||||
private static final ZoneId zone = ZoneId.systemDefault();
|
private static final ZoneId zone = ZoneId.systemDefault();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ package nl.sander.jsontoy2.readers;
|
||||||
import nl.sander.jsontoy2.JsonValueReader;
|
import nl.sander.jsontoy2.JsonValueReader;
|
||||||
import nl.sander.jsontoy2.Parser;
|
import nl.sander.jsontoy2.Parser;
|
||||||
|
|
||||||
public class BooleanReader implements JsonValueReader<Boolean> {
|
public class BooleanReader extends JsonValueReader<Boolean> {
|
||||||
@Override
|
@Override
|
||||||
public Boolean read(Parser parser) {
|
public Boolean read(Parser parser) {
|
||||||
return parser.parseBoolean();
|
return parser.parseBoolean();
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ package nl.sander.jsontoy2.readers;
|
||||||
import nl.sander.jsontoy2.JsonValueReader;
|
import nl.sander.jsontoy2.JsonValueReader;
|
||||||
import nl.sander.jsontoy2.Parser;
|
import nl.sander.jsontoy2.Parser;
|
||||||
|
|
||||||
public class ByteReader implements JsonValueReader<Byte> {
|
public class ByteReader extends JsonValueReader<Byte> {
|
||||||
@Override
|
@Override
|
||||||
public Byte read(Parser parser) {
|
public Byte read(Parser parser) {
|
||||||
return parser.parseByte();
|
return parser.parseByte();
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ package nl.sander.jsontoy2.readers;
|
||||||
import nl.sander.jsontoy2.JsonValueReader;
|
import nl.sander.jsontoy2.JsonValueReader;
|
||||||
import nl.sander.jsontoy2.Parser;
|
import nl.sander.jsontoy2.Parser;
|
||||||
|
|
||||||
public class CharReader implements JsonValueReader<Character> {
|
public class CharReader extends JsonValueReader<Character> {
|
||||||
@Override
|
@Override
|
||||||
public Character read(Parser parser) {
|
public Character read(Parser parser) {
|
||||||
return parser.parseCharacter();
|
return parser.parseCharacter();
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,11 @@
|
||||||
package nl.sander.jsontoy2.readers;
|
package nl.sander.jsontoy2.readers;
|
||||||
|
|
||||||
import nl.sander.jsontoy2.JsonValueReader;
|
|
||||||
import nl.sander.jsontoy2.Parser;
|
import nl.sander.jsontoy2.Parser;
|
||||||
|
|
||||||
import java.time.ZonedDateTime;
|
import java.time.ZonedDateTime;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
public class DateReader extends AbstractDatesReader<Date> implements JsonValueReader<Date> {
|
public class DateReader extends AbstractDatesReader<Date> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Date read(Parser parser) {
|
public Date read(Parser parser) {
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ package nl.sander.jsontoy2.readers;
|
||||||
import nl.sander.jsontoy2.JsonValueReader;
|
import nl.sander.jsontoy2.JsonValueReader;
|
||||||
import nl.sander.jsontoy2.Parser;
|
import nl.sander.jsontoy2.Parser;
|
||||||
|
|
||||||
public class DoubleReader implements JsonValueReader<Double> {
|
public class DoubleReader extends JsonValueReader<Double> {
|
||||||
@Override
|
@Override
|
||||||
public Double read(Parser parser) {
|
public Double read(Parser parser) {
|
||||||
return parser.parseDouble();
|
return parser.parseDouble();
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ package nl.sander.jsontoy2.readers;
|
||||||
import nl.sander.jsontoy2.JsonValueReader;
|
import nl.sander.jsontoy2.JsonValueReader;
|
||||||
import nl.sander.jsontoy2.Parser;
|
import nl.sander.jsontoy2.Parser;
|
||||||
|
|
||||||
public class FloatReader implements JsonValueReader<Float> {
|
public class FloatReader extends JsonValueReader<Float> {
|
||||||
@Override
|
@Override
|
||||||
public Float read(Parser parser) {
|
public Float read(Parser parser) {
|
||||||
return parser.parseFloat();
|
return parser.parseFloat();
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ package nl.sander.jsontoy2.readers;
|
||||||
import nl.sander.jsontoy2.JsonValueReader;
|
import nl.sander.jsontoy2.JsonValueReader;
|
||||||
import nl.sander.jsontoy2.Parser;
|
import nl.sander.jsontoy2.Parser;
|
||||||
|
|
||||||
public class IntegerReader implements JsonValueReader<Integer> {
|
public class IntegerReader extends JsonValueReader<Integer> {
|
||||||
@Override
|
@Override
|
||||||
public Integer read(Parser parser) {
|
public Integer read(Parser parser) {
|
||||||
return parser.parseInteger();
|
return parser.parseInteger();
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ import nl.sander.jsontoy2.Parser;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@SuppressWarnings("rawtypes")
|
@SuppressWarnings("rawtypes")
|
||||||
public class ListReader implements JsonValueReader<List> {
|
public class ListReader extends JsonValueReader<List> {
|
||||||
@Override
|
@Override
|
||||||
public List<?> read(Parser parser) {
|
public List<?> read(Parser parser) {
|
||||||
return parser.parseArray();
|
return parser.parseArray();
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,11 @@
|
||||||
package nl.sander.jsontoy2.readers;
|
package nl.sander.jsontoy2.readers;
|
||||||
|
|
||||||
import nl.sander.jsontoy2.JsonValueReader;
|
|
||||||
import nl.sander.jsontoy2.Parser;
|
import nl.sander.jsontoy2.Parser;
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.time.ZonedDateTime;
|
import java.time.ZonedDateTime;
|
||||||
|
|
||||||
public class LocalDateTimeReader extends AbstractDatesReader<LocalDateTime> implements JsonValueReader<LocalDateTime> {
|
public class LocalDateTimeReader extends AbstractDatesReader<LocalDateTime> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public LocalDateTime read(Parser parser) {
|
public LocalDateTime read(Parser parser) {
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ package nl.sander.jsontoy2.readers;
|
||||||
import nl.sander.jsontoy2.JsonValueReader;
|
import nl.sander.jsontoy2.JsonValueReader;
|
||||||
import nl.sander.jsontoy2.Parser;
|
import nl.sander.jsontoy2.Parser;
|
||||||
|
|
||||||
public class LongReader implements JsonValueReader<Long> {
|
public class LongReader extends JsonValueReader<Long> {
|
||||||
@Override
|
@Override
|
||||||
public Long read(Parser parser) {
|
public Long read(Parser parser) {
|
||||||
return parser.parseLong();
|
return parser.parseLong();
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ import nl.sander.jsontoy2.Parser;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@SuppressWarnings("rawtypes")
|
@SuppressWarnings("rawtypes")
|
||||||
public class MapReader implements JsonValueReader<Map> {
|
public class MapReader extends JsonValueReader<Map> {
|
||||||
@Override
|
@Override
|
||||||
public Map read(Parser parser) {
|
public Map read(Parser parser) {
|
||||||
return parser.parseObject();
|
return parser.parseObject();
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ package nl.sander.jsontoy2.readers;
|
||||||
import nl.sander.jsontoy2.JsonValueReader;
|
import nl.sander.jsontoy2.JsonValueReader;
|
||||||
import nl.sander.jsontoy2.Parser;
|
import nl.sander.jsontoy2.Parser;
|
||||||
|
|
||||||
public class ShortReader implements JsonValueReader<Short> {
|
public class ShortReader extends JsonValueReader<Short> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Short read(Parser parser) {
|
public Short read(Parser parser) {
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ package nl.sander.jsontoy2.readers;
|
||||||
import nl.sander.jsontoy2.JsonValueReader;
|
import nl.sander.jsontoy2.JsonValueReader;
|
||||||
import nl.sander.jsontoy2.Parser;
|
import nl.sander.jsontoy2.Parser;
|
||||||
|
|
||||||
public class StringReader implements JsonValueReader<String> {
|
public class StringReader extends JsonValueReader<String> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String read(Parser parser) {
|
public String read(Parser parser) {
|
||||||
|
|
|
||||||
13
src/test/java/nl/sander/jsontoy2/BeanWithBoolean.java
Normal file
13
src/test/java/nl/sander/jsontoy2/BeanWithBoolean.java
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
package nl.sander.jsontoy2;
|
||||||
|
|
||||||
|
import nl.sander.jsontoy2.beans.BooleanBean;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
|
public class BeanWithBoolean {
|
||||||
|
@Test
|
||||||
|
public void testTrue() {
|
||||||
|
assertEquals(new BooleanBean(true, true), JsonReader.read(BooleanBean.class, "{\"value\": true, \"value2\": true}"));
|
||||||
|
}
|
||||||
|
}
|
||||||
147
src/test/java/nl/sander/jsontoy2/WrapperObjectTests.java
Normal file
147
src/test/java/nl/sander/jsontoy2/WrapperObjectTests.java
Normal file
|
|
@ -0,0 +1,147 @@
|
||||||
|
package nl.sander.jsontoy2;
|
||||||
|
|
||||||
|
import nl.sander.jsontoy2.beans.*;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashSet;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
|
|
||||||
|
public class WrapperObjectTests {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNested() {
|
||||||
|
SimpleBean bean = JsonReader.read(SimpleBean.class, "{\"data1\": \"value1\",\"data2\": \"value2\"}");
|
||||||
|
assertEquals(SimpleBean.class, bean.getClass());
|
||||||
|
|
||||||
|
assertEquals("value1", bean.getData1());
|
||||||
|
assertEquals("value2", bean.getData2());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBoolean() {
|
||||||
|
// BooleanBean trueBean = JsonReader.read(BooleanBean.class, "{\"value\": true}");
|
||||||
|
// assertTrue(trueBean.isValue());
|
||||||
|
// second call to read, must not recreate class definition, would not compile
|
||||||
|
// so this test implicitly tests caching function too
|
||||||
|
BooleanBean falseBean = JsonReader.read(BooleanBean.class, "{\"value2\": false}");
|
||||||
|
assertFalse(falseBean.isValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testString() {
|
||||||
|
StringBean stringBean = JsonReader.read(StringBean.class, "{\"value\": \"haha\"}");
|
||||||
|
assertEquals("haha", stringBean.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInteger() {
|
||||||
|
IntegerBean integerBean = JsonReader.read(IntegerBean.class, "{\"value\": 1,\"value2\": 2}");
|
||||||
|
assertEquals(1, integerBean.getValue());
|
||||||
|
assertEquals(Integer.valueOf(2), integerBean.getValue2());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLong() {
|
||||||
|
LongBean longBean = JsonReader.read(LongBean.class, "{\"value\": 100000000000,\"value2\": 100000000000}");
|
||||||
|
assertEquals(100000000000L, longBean.getValue());
|
||||||
|
assertEquals(Long.valueOf(100000000000L), longBean.getValue2());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFloat() {
|
||||||
|
FloatBean floatBean = JsonReader.read(FloatBean.class, "{\"value\": 1.0,\"value2\": 100000000000}");
|
||||||
|
assertEquals(1.0F, floatBean.getValue(), 0.1F);
|
||||||
|
assertEquals(100000000000.0F, floatBean.getValue2(), 0.1F);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDouble() {
|
||||||
|
DoubleBean doubleBean = JsonReader.read(DoubleBean.class, "{\"value\": 1.0,\"value2\": 100000000000}");
|
||||||
|
assertEquals(1.0D, doubleBean.getValue(), 0.1D);
|
||||||
|
assertEquals(100000000000.0D, doubleBean.getValue2(), 0.1D);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testShort() {
|
||||||
|
ShortBean shortBean = JsonReader.read(ShortBean.class, "{\"value\": 1,\"value2\": -11}");
|
||||||
|
assertEquals(1, shortBean.getValue());
|
||||||
|
assertEquals((short) -11, shortBean.getValue2().shortValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testByte() {
|
||||||
|
ByteBean byteBean = JsonReader.read(ByteBean.class, "{\"value\": 1,\"value2\": -11}");
|
||||||
|
assertEquals(1, byteBean.getValue());
|
||||||
|
assertEquals((byte) -11, byteBean.getValue2().shortValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testStringList() {
|
||||||
|
StringListBean listBean = JsonReader.read(StringListBean.class, "{\"value\": [\"a\",\"b\"]}");
|
||||||
|
assertEquals(Arrays.asList("a", "b"), listBean.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testStringSet() {
|
||||||
|
StringSetBean listBean = JsonReader.read(StringSetBean.class, "{\"value\": [\"a\",\"b\"]}");
|
||||||
|
assertEquals(new HashSet<>(Arrays.asList("a", "b")), listBean.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Test
|
||||||
|
// public void testIntegerList() {
|
||||||
|
// IntegerListBean listBean = JsonReader.read(IntegerListBean.class, "{\"value\": [1,22]}");
|
||||||
|
// assertEquals(Arrays.asList(1, 22), listBean.getValue());
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Test
|
||||||
|
// public void testCharacterList() {
|
||||||
|
// CharacterListBean listBean = JsonReader.read(CharacterListBean.class, "{\"value\": [\"a\", \"[\", \"^\"]}");
|
||||||
|
// assertEquals(Arrays.asList('a', '[', '^'), listBean.getValue());
|
||||||
|
// }
|
||||||
|
|
||||||
|
// @Test
|
||||||
|
// public void testShortList() {
|
||||||
|
// ShortListBean listBean = JsonReader.read(ShortListBean.class, "{\"value\": [-1,0,1]}");
|
||||||
|
// assertEquals(Arrays.asList((short) -1, (short) 0, (short) 1), listBean.getValue());
|
||||||
|
// }
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBooleanList() {
|
||||||
|
BooleanListBean listBean = JsonReader.read(BooleanListBean.class, "{\"value\": [true,false]}");
|
||||||
|
assertEquals(Arrays.asList(true, false), listBean.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Test
|
||||||
|
// public void testFloatList() {
|
||||||
|
// FloatListBean listBean = JsonReader.read(FloatListBean.class, "{\"value\": [-100.156,78.0]}");
|
||||||
|
// assertEquals(Arrays.asList(-100.156F, 78.0F), listBean.getValue());
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Test
|
||||||
|
// public void testByteList() {
|
||||||
|
// ByteListBean listBean = JsonReader.read(ByteListBean.class, "{\"value\": [-100,78]}");
|
||||||
|
// assertEquals(Arrays.asList((byte) -100, (byte) 78), listBean.getValue());
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Test
|
||||||
|
// public void testDoubleList() {
|
||||||
|
// DoubleListBean listBean = JsonReader.read(DoubleListBean.class, "{\"value\": [-100.156,78.0]}");
|
||||||
|
// assertEquals(Arrays.asList(-100.156D, 78.0D), listBean.getValue());
|
||||||
|
// }
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNestedBean() {
|
||||||
|
NestedBean nestedBean = JsonReader.read(NestedBean.class, "{\"value\": {\"value\": \"nested\"}}");
|
||||||
|
assertEquals(new NestedBean(new InnerBean("nested")), nestedBean);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testStringMap() {
|
||||||
|
StringMapBean actual = JsonReader.read(StringMapBean.class, "{\"map\": {\"a:\": \"b\", \"c:\" : \"d\" }}");
|
||||||
|
StringMapBean expected = new StringMapBean("a:", "b", "c:", "d");
|
||||||
|
assertEquals(expected, actual);
|
||||||
|
}
|
||||||
|
}
|
||||||
48
src/test/java/nl/sander/jsontoy2/beans/BooleanBean.java
Normal file
48
src/test/java/nl/sander/jsontoy2/beans/BooleanBean.java
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
package nl.sander.jsontoy2.beans;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public class BooleanBean {
|
||||||
|
private boolean value;
|
||||||
|
private Boolean value2;
|
||||||
|
|
||||||
|
public BooleanBean() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public BooleanBean(boolean value, Boolean value2) {
|
||||||
|
this.value = value;
|
||||||
|
this.value2 = value2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValue(boolean value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getValue2() {
|
||||||
|
return value2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValue2(Boolean value2) {
|
||||||
|
this.value2 = value2;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
BooleanBean that = (BooleanBean) o;
|
||||||
|
return value == that.value &&
|
||||||
|
value2.equals(that.value2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(value, value2);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
22
src/test/java/nl/sander/jsontoy2/beans/BooleanListBean.java
Normal file
22
src/test/java/nl/sander/jsontoy2/beans/BooleanListBean.java
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
package nl.sander.jsontoy2.beans;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class BooleanListBean {
|
||||||
|
private List<Boolean> value;
|
||||||
|
|
||||||
|
public List<Boolean> getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValue(List<Boolean> value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "BooleanListBean{" +
|
||||||
|
"value=" + value +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
||||||
25
src/test/java/nl/sander/jsontoy2/beans/ByteBean.java
Normal file
25
src/test/java/nl/sander/jsontoy2/beans/ByteBean.java
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
package nl.sander.jsontoy2.beans;
|
||||||
|
|
||||||
|
public class ByteBean {
|
||||||
|
private byte value;
|
||||||
|
private Byte value2;
|
||||||
|
|
||||||
|
public ByteBean() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValue(byte value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Byte getValue2() {
|
||||||
|
return value2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValue2(Byte value2) {
|
||||||
|
this.value2 = value2;
|
||||||
|
}
|
||||||
|
}
|
||||||
15
src/test/java/nl/sander/jsontoy2/beans/ByteListBean.java
Normal file
15
src/test/java/nl/sander/jsontoy2/beans/ByteListBean.java
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
package nl.sander.jsontoy2.beans;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class ByteListBean {
|
||||||
|
private List<Byte> value;
|
||||||
|
|
||||||
|
public List<Byte> getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValue(List<Byte> value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
package nl.sander.jsontoy2.beans;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class CharacterListBean {
|
||||||
|
private List<Character> value;
|
||||||
|
|
||||||
|
public List<Character> getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValue(List<Character> value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
25
src/test/java/nl/sander/jsontoy2/beans/DoubleBean.java
Normal file
25
src/test/java/nl/sander/jsontoy2/beans/DoubleBean.java
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
package nl.sander.jsontoy2.beans;
|
||||||
|
|
||||||
|
public class DoubleBean {
|
||||||
|
private double value;
|
||||||
|
private Double value2;
|
||||||
|
|
||||||
|
public DoubleBean() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValue(double value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Double getValue2() {
|
||||||
|
return value2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValue2(Double value2) {
|
||||||
|
this.value2 = value2;
|
||||||
|
}
|
||||||
|
}
|
||||||
25
src/test/java/nl/sander/jsontoy2/beans/DoubleListBean.java
Normal file
25
src/test/java/nl/sander/jsontoy2/beans/DoubleListBean.java
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
package nl.sander.jsontoy2.beans;
|
||||||
|
|
||||||
|
import nl.sander.jsontoy2.JsonReader;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
|
public class DoubleListBean {
|
||||||
|
private List<Double> value;
|
||||||
|
|
||||||
|
public List<Double> getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValue(List<Double> value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTrue() {
|
||||||
|
assertEquals(true, JsonReader.read(Boolean.class, "true"));
|
||||||
|
}
|
||||||
|
}
|
||||||
25
src/test/java/nl/sander/jsontoy2/beans/FloatBean.java
Normal file
25
src/test/java/nl/sander/jsontoy2/beans/FloatBean.java
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
package nl.sander.jsontoy2.beans;
|
||||||
|
|
||||||
|
public class FloatBean {
|
||||||
|
private float value;
|
||||||
|
private Float value2;
|
||||||
|
|
||||||
|
public FloatBean() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValue(float value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Float getValue2() {
|
||||||
|
return value2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValue2(Float value2) {
|
||||||
|
this.value2 = value2;
|
||||||
|
}
|
||||||
|
}
|
||||||
15
src/test/java/nl/sander/jsontoy2/beans/FloatListBean.java
Normal file
15
src/test/java/nl/sander/jsontoy2/beans/FloatListBean.java
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
package nl.sander.jsontoy2.beans;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class FloatListBean {
|
||||||
|
private List<Float> value;
|
||||||
|
|
||||||
|
public List<Float> getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValue(List<Float> value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
42
src/test/java/nl/sander/jsontoy2/beans/InnerBean.java
Normal file
42
src/test/java/nl/sander/jsontoy2/beans/InnerBean.java
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
package nl.sander.jsontoy2.beans;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public class InnerBean {
|
||||||
|
private String value;
|
||||||
|
|
||||||
|
public InnerBean() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public InnerBean(String value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValue(String value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
InnerBean innerBean = (InnerBean) o;
|
||||||
|
return value.equals(innerBean.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "InnerBean{" +
|
||||||
|
"value='" + value + '\'' +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
||||||
25
src/test/java/nl/sander/jsontoy2/beans/IntegerBean.java
Normal file
25
src/test/java/nl/sander/jsontoy2/beans/IntegerBean.java
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
package nl.sander.jsontoy2.beans;
|
||||||
|
|
||||||
|
public class IntegerBean {
|
||||||
|
private int value;
|
||||||
|
private Integer value2;
|
||||||
|
|
||||||
|
public IntegerBean() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValue(int value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getValue2() {
|
||||||
|
return value2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValue2(Integer value2) {
|
||||||
|
this.value2 = value2;
|
||||||
|
}
|
||||||
|
}
|
||||||
15
src/test/java/nl/sander/jsontoy2/beans/IntegerListBean.java
Normal file
15
src/test/java/nl/sander/jsontoy2/beans/IntegerListBean.java
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
package nl.sander.jsontoy2.beans;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class IntegerListBean {
|
||||||
|
private List<Integer> value;
|
||||||
|
|
||||||
|
public List<Integer> getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValue(List<Integer> value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
25
src/test/java/nl/sander/jsontoy2/beans/LongBean.java
Normal file
25
src/test/java/nl/sander/jsontoy2/beans/LongBean.java
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
package nl.sander.jsontoy2.beans;
|
||||||
|
|
||||||
|
public class LongBean {
|
||||||
|
private long value;
|
||||||
|
private Long value2;
|
||||||
|
|
||||||
|
public LongBean() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValue(long value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getValue2() {
|
||||||
|
return value2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValue2(Long value2) {
|
||||||
|
this.value2 = value2;
|
||||||
|
}
|
||||||
|
}
|
||||||
48
src/test/java/nl/sander/jsontoy2/beans/NestedBean.java
Normal file
48
src/test/java/nl/sander/jsontoy2/beans/NestedBean.java
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
package nl.sander.jsontoy2.beans;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public class NestedBean {
|
||||||
|
|
||||||
|
private InnerBean value;
|
||||||
|
private String empty;
|
||||||
|
|
||||||
|
public NestedBean() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public NestedBean(InnerBean value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public InnerBean getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValue(InnerBean value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEmpty(String empty) {
|
||||||
|
this.empty = empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
NestedBean that = (NestedBean) o;
|
||||||
|
return value.equals(that.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "NestedBean{" +
|
||||||
|
"value=" + value +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
||||||
25
src/test/java/nl/sander/jsontoy2/beans/ShortBean.java
Normal file
25
src/test/java/nl/sander/jsontoy2/beans/ShortBean.java
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
package nl.sander.jsontoy2.beans;
|
||||||
|
|
||||||
|
public class ShortBean {
|
||||||
|
private short value;
|
||||||
|
private Short value2;
|
||||||
|
|
||||||
|
public ShortBean() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public short getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValue(short value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Short getValue2() {
|
||||||
|
return value2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValue2(Short value2) {
|
||||||
|
this.value2 = value2;
|
||||||
|
}
|
||||||
|
}
|
||||||
15
src/test/java/nl/sander/jsontoy2/beans/ShortListBean.java
Normal file
15
src/test/java/nl/sander/jsontoy2/beans/ShortListBean.java
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
package nl.sander.jsontoy2.beans;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class ShortListBean {
|
||||||
|
private List<Short> value;
|
||||||
|
|
||||||
|
public List<Short> getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValue(List<Short> value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
22
src/test/java/nl/sander/jsontoy2/beans/SimpleBean.java
Normal file
22
src/test/java/nl/sander/jsontoy2/beans/SimpleBean.java
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
package nl.sander.jsontoy2.beans;
|
||||||
|
|
||||||
|
public class SimpleBean {
|
||||||
|
String data1;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
13
src/test/java/nl/sander/jsontoy2/beans/StringBean.java
Normal file
13
src/test/java/nl/sander/jsontoy2/beans/StringBean.java
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
package nl.sander.jsontoy2.beans;
|
||||||
|
|
||||||
|
public class StringBean {
|
||||||
|
private String value;
|
||||||
|
|
||||||
|
public String getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValue(String value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
15
src/test/java/nl/sander/jsontoy2/beans/StringListBean.java
Normal file
15
src/test/java/nl/sander/jsontoy2/beans/StringListBean.java
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
package nl.sander.jsontoy2.beans;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class StringListBean {
|
||||||
|
private List<String> value;
|
||||||
|
|
||||||
|
public List<String> getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValue(List<String> value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
46
src/test/java/nl/sander/jsontoy2/beans/StringMapBean.java
Normal file
46
src/test/java/nl/sander/jsontoy2/beans/StringMapBean.java
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
package nl.sander.jsontoy2.beans;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public class StringMapBean {
|
||||||
|
|
||||||
|
private Map<String, String> map = new HashMap<>();
|
||||||
|
|
||||||
|
public StringMapBean() {
|
||||||
|
this.map = new HashMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public StringMapBean(String... keysAndValues) {
|
||||||
|
if (keysAndValues.length % 2 == 1) {
|
||||||
|
throw new IllegalArgumentException("uneven number of arguments is not allowed here");
|
||||||
|
}
|
||||||
|
for (int i = 0; i < keysAndValues.length; ) {
|
||||||
|
String key = keysAndValues[i++];
|
||||||
|
String value = keysAndValues[i++];
|
||||||
|
map.put(key, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMap(Map<String, String> map) {
|
||||||
|
this.map = map;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, String> getMap() {
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
StringMapBean that = (StringMapBean) o;
|
||||||
|
return map.equals(that.map);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(map);
|
||||||
|
}
|
||||||
|
}
|
||||||
15
src/test/java/nl/sander/jsontoy2/beans/StringSetBean.java
Normal file
15
src/test/java/nl/sander/jsontoy2/beans/StringSetBean.java
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
package nl.sander.jsontoy2.beans;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class StringSetBean {
|
||||||
|
private Set<String> value;
|
||||||
|
|
||||||
|
public Set<String> getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValue(Set<String> value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue