Compare commits

..

No commits in common. "3a756a1dade91309d6632b41a74db4deaa89af19" and "0763ad1fd67fde064c71b2ec79f566924f0a8239" have entirely different histories.

64 changed files with 233 additions and 1882 deletions

View file

@ -1,4 +0,0 @@
# JsonToy-2
my second (or third) go at writing a java json reader/writer
Toy project, aiming for a low-latency tool, optimizing on memory usage

View file

@ -59,9 +59,9 @@
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.6.2</version>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
<scope>test</scope>
</dependency>
<dependency>
@ -80,7 +80,7 @@
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.10.5.1</version>
<version>2.10.3</version>
<scope>test</scope>
</dependency>
<dependency>

View file

@ -1,157 +0,0 @@
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.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Responsible for generating classes that parse into java beans.
* <p>
* TODO remove javassist both for analysing java beans and for generating bytecode
*/
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);
@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 {
String fieldTypeName = field.getType().getName();
if (Set.class.isAssignableFrom(fieldType)) {
return "(" + fieldTypeName + ")getSet(\"" + fieldName + "\"," + fieldTypeName + ".class,object)";
} else if (List.class.isAssignableFrom(fieldType)) {
return "(" + fieldTypeName + ")getList(\"" + fieldName + "\"," + fieldTypeName + ".class,object)";
} else if (fieldType.isArray()) {
return "(" + format(fieldTypeName) + "[])getArray(\"" + fieldName + "\"," + format(fieldTypeName) + ".class,object)";
} else {
return "(" + fieldTypeName + ")(object.get(\"" + fieldName + "\"))";
}
}
}
private static String format(String arrayTypeExpr) {
return arrayTypeExpr.substring(2).substring(0, arrayTypeExpr.length() - 3);
}
//should be reinstated
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);
}
/*
* 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";
}
}

View file

@ -1,15 +1,32 @@
package nl.sander.jsontoy2;
import nl.sander.jsontoy2.readers.*;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.lang.ref.SoftReference;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.function.Supplier;
/**
* public api
*/
public class JsonReader {
private static final ConcurrentMap<Class<?>, Supplier<JsonValueReader<?>>> readSuppliers = new ConcurrentHashMap<>();
private static final ConcurrentMap<Class<?>, JsonValueReader<?>> readers = new ConcurrentHashMap<>();
private JsonReader() {
private final static ThreadLocal<SoftReference<Parser>> PARSERS = new ThreadLocal<>();
static {
registerPrimitiveTypeReaders();
}
/**
@ -26,12 +43,21 @@ public class JsonReader {
* array => List
*/
public static Object read(InputStream inputStream) {
final InputStream in = ensureBufferedStream(inputStream);
try (Parser parser = ParserFactory.getParser(in)) {
InputStream in = ensureBuffered(inputStream);
try (Parser parser = getParser(in)) {
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
*
@ -39,7 +65,29 @@ public class JsonReader {
* @return @see read(InputStream stream)
*/
public static Object read(String jsonString) {
return read(ParserFactory.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();
}
/**
@ -51,7 +99,7 @@ public class JsonReader {
* @return Object the specified type
*/
public static <T> T read(Class<T> type, InputStream inputStream) {
Parser parser = ParserFactory.getParser(inputStream);
Parser parser = getParser(inputStream);
T value = read(type, parser);
parser.close();
return value;
@ -66,34 +114,44 @@ public class JsonReader {
* @return Object the specified type
*/
public static <T> T read(Class<T> type, String jsonString) {
return read(type, ParserFactory.getParser(jsonString));
return read(type, getParser(jsonString));
}
static Object read(Parser parser) {
return parser.parseAny();
}
//TODO should not be public
@SuppressWarnings("unchecked")
public static <T> T read(Class<T> type, Parser parser) {
return (T) ReaderFactory.getReader(type).read(parser);
private static <T> T read(Class<T> type, Parser parser) {
return (T) getReader(type).read(parser);
// class.cast() does not work well for primitives;
}
@SuppressWarnings("unused")
public static Map<?, ?> readJavaObject(Class<?> type, Parser parser) {
return parser.parseObject(type);
private static <T> JsonValueReader<?> getReader(Class<T> type) {
return readers.computeIfAbsent(type, k -> readSuppliers.get(k).get());
}
private static InputStream ensureBufferedStream(InputStream inputStream) {
if (inputStream instanceof BufferedInputStream) {
return inputStream;
} else {
return new BufferedInputStream(inputStream);
}
private static <T> void register(Class<T> type, Supplier<JsonValueReader<?>> objectReader) {
readSuppliers.put(type, objectReader);
}
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);
}
}

View file

@ -1,112 +1,5 @@
package nl.sander.jsontoy2;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.*;
/**
* 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;
}
/*
* Creates a Set type for any implementation of it (that the containing bean needs),
* unless it has no constructor using a java.util.Collection as single parameter.
*
* returntype is generic Set, object needs cast afterwards in generated code
*/
protected Set<?> getSet(String fieldName, Class<? extends Set<?>> type, Map<String, ?> values) {
List<?> value = (List<?>) values.get(fieldName);
if (value == null) {
return null;
} else {
try {
if (type.equals(Set.class)) {
return new HashSet<>(value);
} else {
Constructor<? extends Set<?>> constructor = type.getConstructor(Collection.class);
return constructor.newInstance(value);
}
} catch (NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) {
throw new JsonParseException(e);
}
}
}
/*
* Creates a List type for any implementation of it (that the containing bean needs),
* unless it has no constructor using a java.util.Collection as single parameter.
*
* returntype is generic List, needs cast afterwards in generated code
*/
protected List<?> getList(String fieldName, Class<?> listImplType, Map<String, ?> values) {
List<?> value = (List<?>) values.get(fieldName);
if (value == null) {
return null;
} else if (listImplType == ArrayList.class || listImplType.equals(List.class)) {
return value;
} else {
try {
Constructor<?> constructor = listImplType.getConstructor(Collection.class);
return (List<?>) constructor.newInstance(value);
} catch (NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) {
throw new JsonParseException(e);
}
}
}
protected Object getArray(String fieldName, Class<?> arrayType, Map<String, ?> values) {
List<?> value = (List<?>) values.get(fieldName);
if (value == null) {
return new Object[]{};
} else {
Object[] array = (Object[]) Array.newInstance(arrayType, value.size());
int index = 0;
for (Object element : value) {
array[index] = value.get(index++);
}
//TODO this can probably be done smarter
return array;
}
}
public interface JsonValueReader<T> {
T read(Parser parser);
}

View file

@ -37,10 +37,6 @@ public class Lexer implements AutoCloseable {
}
}
void eatUntil(char until) {
eatUntil(new char[]{until});
}
void eatUntil(char... until) {
while (current > -1 && (!contains(until, current) | Character.isWhitespace(current))) {
advance();
@ -71,9 +67,4 @@ public class Lexer implements AutoCloseable {
throw new JsonParseException(e);
}
}
@SuppressWarnings("unused")
public byte current() {
return current;
}
}

View file

@ -37,37 +37,37 @@ public class Parser extends Lexer {
}
public Integer parseInteger() {
final String value = parseNumber();
String value = parseNumber();
return Double.valueOf(value).intValue();
}
public Long parseLong() {
final String value = parseNumber();
String value = parseNumber();
return Long.parseLong(value);
}
public Float parseFloat() {
final String value = parseNumber();
String value = parseNumber();
return Float.parseFloat(value);
}
public Double parseDouble() {
final String value = parseNumber();
String value = parseNumber();
return Double.parseDouble(value);
}
public Short parseShort() {
final String value = parseNumber();
String value = parseNumber();
return Short.parseShort(value);
}
public Byte parseByte() {
final String value = parseNumber();
String value = parseNumber();
return Byte.parseByte(value);
}
public Character parseCharacter() {
final String string = parseString();
String string = parseString();
return string.charAt(0);
}
@ -78,7 +78,7 @@ public class Parser extends Lexer {
advance();
}
final String maybeBoolean = characterBuffer.toString();
String maybeBoolean = characterBuffer.toString();
boolean returnValue;
if ((returnValue = maybeBoolean.equals("true")) || maybeBoolean.equals("false")) {
return returnValue;
@ -105,18 +105,14 @@ public class Parser extends Lexer {
}
public List<?> parseArray() {
return parseArray(null);
}
public List<?> parseArray(Class<?> genericType) {
skipWhitespace();
if (current != '[') {
throw new JsonParseException("no list found");
}
final List<Object> list = new ArrayList<>();
List<Object> list = new ArrayList<>();
advance();
while (current != -1 && current != ']') {
final Maybe<Object> maybeValue = genericType == null ? parseValue() : parseValue(genericType);
Maybe<Object> maybeValue = parseValue();
if (!maybeValue.isPresent()) {
break;
} else {
@ -129,11 +125,7 @@ public class Parser extends Lexer {
}
public Map<?, ?> parseObject() {
return parseObject(null);
}
public Map<?, ?> parseObject(Class<?> type) {
final HashMap<Object, Object> map = new HashMap<>();
HashMap<Object, Object> map = new HashMap<>();
skipWhitespace();
if (current != '{') {
throw new JsonParseException("no map found");
@ -142,7 +134,7 @@ public class Parser extends Lexer {
while (current != -1 && current != '}') {
skipWhitespace();
if (current == '"') {
final String key = parseString();
String key = parseString();
skipWhitespace();
if (current == ':') {
advance();
@ -150,13 +142,8 @@ public class Parser extends Lexer {
throw new JsonParseException("expected colon");
}
skipWhitespace();
final Maybe<Object> maybeValue;
try {
maybeValue = type == null ? parseValue() : Maybe.of(JsonReader.read(type.getDeclaredField(key).getType(), this));
maybeValue.ifPresent(value -> map.put(key, value));
} catch (NoSuchFieldException e) {
throw new JsonParseException(e);
}
Maybe<Object> maybeValue = parseValue();
maybeValue.ifPresent(value -> map.put(key, value));
}
advance();
skipWhitespace();
@ -165,7 +152,7 @@ public class Parser extends Lexer {
}
public Object parseAny() {
final Maybe<Object> maybe = parseValue();
Maybe<Object> maybe = parseValue();
if (maybe.isPresent()) {
return maybe.get();
} else {
@ -174,7 +161,7 @@ public class Parser extends Lexer {
}
private Maybe<Object> parseValue() {
final Object value;
Object value;
skipWhitespace();
switch (current) {
case ']':
@ -194,8 +181,8 @@ public class Parser extends Lexer {
break;
default: String numeric = parseNumber();
double doubleValue = Double.parseDouble(numeric);
if ((long) doubleValue == doubleValue) {
value = (long) doubleValue;
if ((int) doubleValue == doubleValue) {
value = (int) doubleValue;
} else {
value = doubleValue;
}
@ -203,20 +190,6 @@ public class Parser extends Lexer {
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() {
expect(() -> new JsonParseException("Expected 'null', encountered " + (char) current), 'n', 'u', 'l', 'l');
return null;
@ -278,8 +251,8 @@ public class Parser extends Lexer {
}
private void parseEncoded() {
final StringBuilder buf = new StringBuilder();
final char codePoint = parseCodePoint();
StringBuilder buf = new StringBuilder();
char codePoint = parseCodePoint();
buf.append(codePoint);
if (Character.isHighSurrogate(codePoint)) {
expect(() -> new JsonParseException("Invalid unicode codepoint at line " + linecount), '\\', 'u');

View file

@ -1,38 +0,0 @@
package nl.sander.jsontoy2;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.lang.ref.SoftReference;
import java.nio.charset.StandardCharsets;
import java.util.Objects;
/**
* Keeps a Threadlocal parser that can be (re)used by clients.
* <p>
* The parser is not kept indefinitely, but garbage collected when the JVM considers necessary.
*/
public class ParserFactory {
private final static ThreadLocal<SoftReference<Parser>> PARSERS = new ThreadLocal<>();
private ParserFactory() {
}
static Parser getParser(String jsonString) {
return getParser(new ByteArrayInputStream(jsonString.getBytes(StandardCharsets.UTF_8)));
}
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;
}
}

View file

@ -1,69 +0,0 @@
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();
}
private ReaderFactory() {
}
public static <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) || type.isArray()) {
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);
}
}

View file

@ -2,28 +2,17 @@ package nl.sander.jsontoy2.java;
import nl.sander.jsontoy2.java.constantpool.ConstantPoolEntry;
import nl.sander.jsontoy2.java.constantpool.Utf8Entry;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
/**
* Contains info from parsed bytecode
*/
public class ClassObject {
private final ConstantPoolEntry[] constantPool;
private final Info[] fieldInfos;
private final Info[] methodInfos;
public class ClassObject<T> {
private ClassObject(ConstantPoolEntry[] constantPool, Info[] fieldInfos, Info[] methodInfos) {
this.constantPool = constantPool;
this.fieldInfos = fieldInfos;
this.methodInfos = methodInfos;
}
private ConstantPoolEntry[] constantPool;
private Info[] fieldInfos;
private Info[] methodInfos;
private String getUtf8(int index) {
return ((Utf8Entry) constantPool[index - 1]).getUtf8();
@ -37,50 +26,10 @@ public class ClassObject {
public Set<Method> getMethods() {
return Arrays.stream(methodInfos)
.map(this::createMethod)
.map(mi -> new Method(getUtf8(mi.getNameIndex()), getUtf8(mi.getDescriptorIndex())))
.collect(Collectors.toSet());
}
@NotNull
private Method createMethod(Info mi) {
final String descriptor = getUtf8(mi.getDescriptorIndex());
final int split = descriptor.indexOf(')');
final List<String> parameters = getParameterTypes(descriptor.substring(0, split));
String returnType = descriptor.substring(split + 1);
returnType = returnType.substring(0, returnType.length() - 1);
return new Method(getUtf8(mi.getNameIndex()), parameters, returnType);
}
private List<String> getParameterTypes(String parameterDescriptor) {
List<String> result = new ArrayList<>();
boolean array = false;
for (int i = 1; i < parameterDescriptor.length(); i++) {
if (parameterDescriptor.charAt(i) == '[') {
array = true;
} else {
if (parameterDescriptor.charAt(i) == 'L') {
int i2 = i;
while (i2 < parameterDescriptor.length() && parameterDescriptor.charAt(i2) != ';') {
i2++;
}
result.add(getArrayIndicator(array) + parameterDescriptor.substring(i, i2));
array = false;
i = i2;
} else {
result.add(getArrayIndicator(array) + parameterDescriptor.charAt(i));
array = false;
}
}
}
return result;
}
@NotNull
private String getArrayIndicator(boolean array) {
return array ? "[" : "";
}
public String toString() {
StringBuilder builder = new StringBuilder();
for (ConstantPoolEntry entry : constantPool) {
@ -92,44 +41,41 @@ public class ClassObject {
public static class Builder<T> {
private final ClassObject<T> classObject = new ClassObject<>();
private int constantPoolIndex = 0;
private int fieldInfoIndex = 0;
private int methodInfoIndex = 0;
private ConstantPoolEntry[] constantPool;
private Info[] fieldInfos;
private Info[] methodInfos;
public ClassObject build() {
return new ClassObject(constantPool, fieldInfos, methodInfos);
public ClassObject<T> build() {
return classObject;
}
public Builder<T> constantPoolCount(int constantPoolCount) {
constantPool = new ConstantPoolEntry[constantPoolCount - 1];
classObject.constantPool = new ConstantPoolEntry[constantPoolCount - 1];
return this;
}
void constantPoolEntry(ConstantPoolEntry entry) {
constantPool[constantPoolIndex++] = entry;
classObject.constantPool[constantPoolIndex++] = entry;
}
public Builder<T> fieldInfoCount(int fieldInfoCount) {
fieldInfos = new Info[fieldInfoCount];
classObject.fieldInfos = new Info[fieldInfoCount];
return this;
}
public Builder<T> fieldInfo(Info fieldInfo) {
fieldInfos[fieldInfoIndex++] = fieldInfo;
classObject.fieldInfos[fieldInfoIndex++] = fieldInfo;
return this;
}
public Builder<T> methodInfoCount(int methodInfoCount) {
methodInfos = new Info[methodInfoCount];
classObject.methodInfos = new Info[methodInfoCount];
return this;
}
public Builder<T> methodInfo(Info methodInfo) {
methodInfos[methodInfoIndex++] = methodInfo;
classObject.methodInfos[methodInfoIndex++] = methodInfo;
return this;
}
}

View file

@ -8,8 +8,8 @@ import java.io.IOException;
public class ClassReader extends DataReader {
public <T> ClassObject parse(Class<T> type) {
final DataInputStream in = new DataInputStream(new BufferedInputStream(type.getResourceAsStream(getResourceName(type))));
public <T> ClassObject<T> parse(Class<T> type) {
DataInputStream in = new DataInputStream(new BufferedInputStream(type.getResourceAsStream(getResourceName(type))));
expect(in, 0xCAFEBABE);
ClassObject.Builder<T> builder = new ClassObject.Builder<>();
@ -19,8 +19,8 @@ public class ClassReader extends DataReader {
readConstantPool(in, builder);
skip(in, 6); // u2 access_flags, u2 this_class, u2 super_class
final int interfacesCount = readUnsignedShort(in);
skip(in, interfacesCount * 2); // interfaces[u2;]
int interfacesCount = readUnsignedShort(in);
skip(in, interfacesCount * 2); // interfaces[]
readFields(in, builder);
readMethods(in, builder);
@ -29,7 +29,7 @@ public class ClassReader extends DataReader {
}
private <T> void readConstantPool(DataInputStream in, ClassObject.Builder<T> builder) {
final int constantPoolCount = readUnsignedShort(in);
int constantPoolCount = readUnsignedShort(in);
builder.constantPoolCount(constantPoolCount);
for (int i = 1; i < constantPoolCount; i++) {
builder.constantPoolEntry(readConstantPoolEntry(in));
@ -37,7 +37,7 @@ public class ClassReader extends DataReader {
}
private <T> void readFields(DataInputStream in, ClassObject.Builder<T> builder) {
final int fieldInfoCount = readUnsignedShort(in);
int fieldInfoCount = readUnsignedShort(in);
builder.fieldInfoCount(fieldInfoCount);
for (int i = 0; i < fieldInfoCount; i++) {
builder.fieldInfo(readField(in));
@ -45,7 +45,7 @@ public class ClassReader extends DataReader {
}
private <T> void readMethods(DataInputStream in, ClassObject.Builder<T> builder) {
final int methodInfoCount = readUnsignedShort(in);
int methodInfoCount = readUnsignedShort(in);
builder.methodInfoCount(methodInfoCount);
for (int i = 0; i < methodInfoCount; i++) {
builder.methodInfo(readMethod(in));
@ -53,7 +53,7 @@ public class ClassReader extends DataReader {
}
private <T> Info readField(DataInputStream in) {
final Info fieldInfo = new Info(readUnsignedShort(in), readUnsignedShort(in), readUnsignedShort(in), readUnsignedShort(in));
Info fieldInfo = new Info(readUnsignedShort(in), readUnsignedShort(in), readUnsignedShort(in), readUnsignedShort(in));
for (int i = 0; i < fieldInfo.getAttributesCount(); i++) {
fieldInfo.add(readAttribute(in));
}
@ -62,7 +62,7 @@ public class ClassReader extends DataReader {
}
private <T> Info readMethod(DataInputStream in) {
final Info methodInfo = new Info(readUnsignedShort(in), readUnsignedShort(in), readUnsignedShort(in), readUnsignedShort(in));
Info methodInfo = new Info(readUnsignedShort(in), readUnsignedShort(in), readUnsignedShort(in), readUnsignedShort(in));
for (int i = 0; i < methodInfo.getAttributesCount(); i++) {
methodInfo.add(readAttribute(in));
}
@ -71,9 +71,9 @@ public class ClassReader extends DataReader {
}
private AttributeInfo readAttribute(DataInputStream in) {
final int attributeNameIndex = readUnsignedShort(in);
final int attributeLength = readS32(in);
final byte[] info;
int attributeNameIndex = readUnsignedShort(in);
int attributeLength = readInt(in);
byte[] info;
if (attributeLength > 0) {
info = new byte[attributeLength];
try {
@ -87,32 +87,30 @@ public class ClassReader extends DataReader {
return new AttributeInfo(attributeNameIndex, info);
}
private ConstantPoolEntry readConstantPoolEntry(DataInputStream in) {
final byte tag = readByte(in);
private <T> ConstantPoolEntry readConstantPoolEntry(DataInputStream in) {
byte tag = readByte(in);
switch (tag) {
case 1: return new Utf8Entry(readString(in, readUnsignedShort(in)));
case 1: return readUtf8Entry(in);
case 2: throw new IllegalStateException("2: invalid classpool tag");
case 3: return new IntEntry(readS32(in));
case 4: return new FloatEntry(readF32(in));
case 5: return new LongEntry(readS64(in));
case 6: return new DoubleEntry(readF64(in));
case 3: return new IntEntry(readInt(in));
case 4: return new FloatEntry(readFloat(in));
case 5: return new LongEntry(readLong(in));
case 6: return new DoubleEntry(readDouble(in));
case 7: return new ClassEntry(readUnsignedShort(in));
case 8: return new StringEntry(readUnsignedShort(in));
case 9: return new FieldRefEntry(readUnsignedShort(in), readUnsignedShort(in));
case 9: return new FieldRefEntry(readShort(in), readShort(in));
case 10: return new MethodRefEntry(readUnsignedShort(in), readUnsignedShort(in));
case 11: return new InterfaceMethodRefEntry(readUnsignedShort(in), readUnsignedShort(in));
case 12: return new NameAndTypeEntry(readUnsignedShort(in), readUnsignedShort(in));
case 15: return new MethodHandleEntry(readUnsignedShort(in), readUnsignedShort(in));
case 16: return new MethodTypeEntry(readUnsignedShort(in));
case 18: return new InvokeDynamicEntry(readUnsignedShort(in), readUnsignedShort(in));
case 19: return new ModuleEntry(readUnsignedShort(in));
case 20: return new PackageEntry(readUnsignedShort(in));
default: throw new IllegalStateException("invalid classpool");
}
}
protected <T> String getResourceName(Class<T> type) {
final StringBuilder typeName = new StringBuilder("/" + type.getName());
StringBuilder typeName = new StringBuilder("/" + type.getName());
for (int i = 0; i < typeName.length(); i++) {
if (typeName.charAt(i) == '.') {

View file

@ -1,24 +1,15 @@
package nl.sander.jsontoy2.java;
import nl.sander.jsontoy2.java.constantpool.Utf8Entry;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
/**
* basic IO operations with runtime exceptions
*/
public class DataReader {
protected long readS64(DataInputStream in) {
try {
return in.readLong();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
protected float readF32(DataInputStream in) {
protected float readFloat(DataInputStream in) {
try {
return in.readFloat();
} catch (IOException e) {
@ -26,7 +17,29 @@ public class DataReader {
}
}
protected double readF64(DataInputStream in) {
protected Utf8Entry readUtf8Entry(DataInputStream in) {
short length = readShort(in);
return new Utf8Entry(readString(in, length));
}
protected String readString(DataInputStream in, short length) {
try {
byte[] bytes = in.readNBytes(length);
return new String(bytes, StandardCharsets.UTF_8);
} catch (IOException e) {
throw new RuntimeException();
}
}
protected long readLong(DataInputStream in) {
try {
return in.readLong();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
protected double readDouble(DataInputStream in) {
try {
return in.readDouble();
} catch (IOException e) {
@ -34,6 +47,14 @@ public class DataReader {
}
}
protected short readShort(DataInputStream in) {
try {
return in.readShort();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
protected int readUnsignedShort(DataInputStream in) {
try {
return in.readUnsignedShort();
@ -42,7 +63,7 @@ public class DataReader {
}
}
protected int readS32(DataInputStream in) {
protected int readInt(DataInputStream in) {
try {
return in.readInt();
} catch (IOException e) {
@ -50,15 +71,6 @@ public class DataReader {
}
}
protected String readString(DataInputStream in, int length) {
try {
byte[] bytes = in.readNBytes(length);
return new String(bytes, StandardCharsets.UTF_8);
} catch (IOException e) {
throw new RuntimeException();
}
}
protected byte readByte(DataInputStream in) {
try {
return in.readByte();

View file

@ -1,28 +1,23 @@
package nl.sander.jsontoy2.java;
import org.jetbrains.annotations.NotNull;
import java.util.List;
import java.util.Objects;
public class Method implements Comparable<Method> {
public class Method {
private final String name;
private final List<String> parameterTypes;
private final String returnType;
private final String type;
public Method(String name, List<String> parameterTypes, String returnType) {
public Method(String name, String type) {
this.name = name;
this.parameterTypes = parameterTypes;
this.returnType = returnType;
this.type = type;
}
public String getName() {
return name;
}
public String getReturnType() {
return returnType;
public String getType() {
return type;
}
@Override
@ -31,25 +26,19 @@ public class Method implements Comparable<Method> {
if (o == null || getClass() != o.getClass()) return false;
Method field = (Method) o;
return name.equals(field.name) &&
returnType.equals(field.returnType);
type.equals(field.type);
}
@Override
public int hashCode() {
return Objects.hash(name, returnType);
return Objects.hash(name, type);
}
@Override
public String toString() {
return "Method{" +
"name='" + name + '\'' +
", parameterTypes=" + parameterTypes +
", returnType='" + returnType + '\'' +
", type='" + type + '\'' +
'}';
}
@Override
public int compareTo(@NotNull Method o) {
return name.compareTo(o.name);
}
}

View file

@ -1,19 +1,19 @@
package nl.sander.jsontoy2.java.constantpool;
public class FieldRefEntry extends ConstantPoolEntry {
private final int classIndex;
private final int nameAndTypeIndex;
private final short classIndex;
private final short nameAndTypeIndex;
public FieldRefEntry(int classIndex, int nameAndTypeIndex) {
public FieldRefEntry(short classIndex, short nameAndTypeIndex) {
this.classIndex = classIndex;
this.nameAndTypeIndex = nameAndTypeIndex;
}
public int getClassIndex() {
public short getClassIndex() {
return classIndex;
}
public int getNameAndTypeIndex() {
public short getNameAndTypeIndex() {
return nameAndTypeIndex;
}

View file

@ -1,11 +0,0 @@
package nl.sander.jsontoy2.java.constantpool;
import nl.sander.jsontoy2.java.constantpool.ConstantPoolEntry;
public class ModuleEntry extends ConstantPoolEntry {
private final int nameIndex;
public ModuleEntry(int nameIndex) {
this.nameIndex = nameIndex;
}
}

View file

@ -1,9 +0,0 @@
package nl.sander.jsontoy2.java.constantpool;
public class PackageEntry extends ConstantPoolEntry {
private final int nameIndex;
public PackageEntry(int nameIndex) {
this.nameIndex = nameIndex;
}
}

View file

@ -1,11 +0,0 @@
package nl.sander.jsontoy2.javassist;
public class ClassCreationException extends RuntimeException {
public ClassCreationException(Throwable e) {
super(e);
}
public ClassCreationException(String message) {
super(message);
}
}

View file

@ -1,183 +0,0 @@
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);
}
}
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 "";
}
}

View file

@ -1,7 +1,5 @@
package nl.sander.jsontoy2.readers;
import nl.sander.jsontoy2.JsonValueReader;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
@ -9,7 +7,7 @@ import java.time.format.DateTimeFormatterBuilder;
import java.time.temporal.ChronoField;
import java.util.function.Supplier;
public abstract class AbstractDatesReader<T> extends JsonValueReader<T> {
public abstract class AbstractDatesReader<T> {
private static final ZoneId zone = ZoneId.systemDefault();

View file

@ -3,7 +3,7 @@ package nl.sander.jsontoy2.readers;
import nl.sander.jsontoy2.JsonValueReader;
import nl.sander.jsontoy2.Parser;
public class BooleanReader extends JsonValueReader<Boolean> {
public class BooleanReader implements JsonValueReader<Boolean> {
@Override
public Boolean read(Parser parser) {
return parser.parseBoolean();

View file

@ -3,7 +3,7 @@ package nl.sander.jsontoy2.readers;
import nl.sander.jsontoy2.JsonValueReader;
import nl.sander.jsontoy2.Parser;
public class ByteReader extends JsonValueReader<Byte> {
public class ByteReader implements JsonValueReader<Byte> {
@Override
public Byte read(Parser parser) {
return parser.parseByte();

View file

@ -3,7 +3,7 @@ package nl.sander.jsontoy2.readers;
import nl.sander.jsontoy2.JsonValueReader;
import nl.sander.jsontoy2.Parser;
public class CharReader extends JsonValueReader<Character> {
public class CharReader implements JsonValueReader<Character> {
@Override
public Character read(Parser parser) {
return parser.parseCharacter();

View file

@ -1,11 +1,12 @@
package nl.sander.jsontoy2.readers;
import nl.sander.jsontoy2.JsonValueReader;
import nl.sander.jsontoy2.Parser;
import java.time.ZonedDateTime;
import java.util.Date;
public class DateReader extends AbstractDatesReader<Date> {
public class DateReader extends AbstractDatesReader<Date> implements JsonValueReader<Date> {
@Override
public Date read(Parser parser) {

View file

@ -3,7 +3,7 @@ package nl.sander.jsontoy2.readers;
import nl.sander.jsontoy2.JsonValueReader;
import nl.sander.jsontoy2.Parser;
public class DoubleReader extends JsonValueReader<Double> {
public class DoubleReader implements JsonValueReader<Double> {
@Override
public Double read(Parser parser) {
return parser.parseDouble();

View file

@ -3,7 +3,7 @@ package nl.sander.jsontoy2.readers;
import nl.sander.jsontoy2.JsonValueReader;
import nl.sander.jsontoy2.Parser;
public class FloatReader extends JsonValueReader<Float> {
public class FloatReader implements JsonValueReader<Float> {
@Override
public Float read(Parser parser) {
return parser.parseFloat();

View file

@ -3,7 +3,7 @@ package nl.sander.jsontoy2.readers;
import nl.sander.jsontoy2.JsonValueReader;
import nl.sander.jsontoy2.Parser;
public class IntegerReader extends JsonValueReader<Integer> {
public class IntegerReader implements JsonValueReader<Integer> {
@Override
public Integer read(Parser parser) {
return parser.parseInteger();

View file

@ -6,7 +6,7 @@ import nl.sander.jsontoy2.Parser;
import java.util.List;
@SuppressWarnings("rawtypes")
public class ListReader extends JsonValueReader<List> {
public class ListReader implements JsonValueReader<List> {
@Override
public List<?> read(Parser parser) {
return parser.parseArray();

View file

@ -1,11 +1,12 @@
package nl.sander.jsontoy2.readers;
import nl.sander.jsontoy2.JsonValueReader;
import nl.sander.jsontoy2.Parser;
import java.time.LocalDateTime;
import java.time.ZonedDateTime;
public class LocalDateTimeReader extends AbstractDatesReader<LocalDateTime> {
public class LocalDateTimeReader extends AbstractDatesReader<LocalDateTime> implements JsonValueReader<LocalDateTime> {
@Override
public LocalDateTime read(Parser parser) {

View file

@ -3,7 +3,7 @@ package nl.sander.jsontoy2.readers;
import nl.sander.jsontoy2.JsonValueReader;
import nl.sander.jsontoy2.Parser;
public class LongReader extends JsonValueReader<Long> {
public class LongReader implements JsonValueReader<Long> {
@Override
public Long read(Parser parser) {
return parser.parseLong();

View file

@ -6,7 +6,7 @@ import nl.sander.jsontoy2.Parser;
import java.util.Map;
@SuppressWarnings("rawtypes")
public class MapReader extends JsonValueReader<Map> {
public class MapReader implements JsonValueReader<Map> {
@Override
public Map read(Parser parser) {
return parser.parseObject();

View file

@ -3,7 +3,7 @@ package nl.sander.jsontoy2.readers;
import nl.sander.jsontoy2.JsonValueReader;
import nl.sander.jsontoy2.Parser;
public class ShortReader extends JsonValueReader<Short> {
public class ShortReader implements JsonValueReader<Short> {
@Override
public Short read(Parser parser) {

View file

@ -3,7 +3,7 @@ package nl.sander.jsontoy2.readers;
import nl.sander.jsontoy2.JsonValueReader;
import nl.sander.jsontoy2.Parser;
public class StringReader extends JsonValueReader<String> {
public class StringReader implements JsonValueReader<String> {
@Override
public String read(Parser parser) {

View file

@ -1,33 +0,0 @@
package nl.sander.jsontoy2;
import nl.sander.jsontoy2.testobjects.BooleanBean;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
public class BeanWithBoolean {
@Test
public void testTrue() {
// Arrange
BooleanBean booleanBean = JsonReader.read(BooleanBean.class, "{\"value\": true, \"value2\": true}");
// Assert
assertEquals(new BooleanBean(true, Boolean.TRUE), booleanBean);
}
@Test
public void testFalse() {
// Arrange
BooleanBean booleanBean = JsonReader.read(BooleanBean.class, "{\"value\": false, \"value2\": false}");
// Assert
assertEquals(new BooleanBean(false, Boolean.FALSE), booleanBean);
}
@Test
public void testIllegalValues() {
// Assert
assertThrows(JsonParseException.class, () -> JsonReader.read(BooleanBean.class, "{\"value\": true, \"value2\": True}"));
}
}

View file

@ -7,23 +7,23 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
public class Ints {
@Test
public void testSimpleInt() {
assertEquals(1, JsonReader.read(Integer.class, "1"));
public void testSimpleInt(){
assertEquals(1,JsonReader.read(Integer.class,"1"));
}
@Test
public void testSimplePrimitiveInt() {
assertEquals(1, JsonReader.read(int.class, "1"));
public void testSimplePrimitiveInt(){
assertEquals(1,JsonReader.read(int.class,"1"));
}
@Test
public void testSimpleNegativeInt() {
assertEquals(-20001, JsonReader.read(Integer.class, "-20001"));
public void testSimpleNegativeInt(){
assertEquals(-20001,JsonReader.read(Integer.class,"-20001"));
}
@Test
public void testSimpleNegativePrimitiveInt() {
assertEquals(Integer.MIN_VALUE, JsonReader.read(int.class, "-2147483684"));
public void testSimpleNegativePrimitiveInt(){
assertEquals(Integer.MIN_VALUE,JsonReader.read(int.class,"-2147483684"));
}
@Test

View file

@ -38,23 +38,23 @@ public class Lists {
}
@Test
public void singleLong() {
List<Long> list = JsonReader.read(List.class, " [ 1 ]");
List<Long> expected = List.of(1L);
public void singleInt() {
List<Integer> list = JsonReader.read(List.class, " [ 1 ]");
List<Integer> expected = List.of(1);
assertEquals(expected, list);
}
@Test
public void multipleLongs() {
List<Long> list = JsonReader.read(List.class, "[1,2]");
List<Long> expected = List.of(1L, 2L);
public void multipleInts() {
List<Integer> list = JsonReader.read(List.class, "[1,2]");
List<Integer> expected = List.of(1, 2);
assertEquals(expected, list);
}
@Test
public void longDoubleBooleanString() {
public void intDoubleBooleanString() {
List<Integer> list = JsonReader.read(List.class, "[1, 2.5,false, \"hello jason\"]");
List<?> expected = List.of(1L, 2.5, false, "hello jason");
List<?> expected = List.of(1, 2.5, false, "hello jason");
assertEquals(expected, list);
}

View file

@ -30,7 +30,7 @@ public class Maps {
Map<String, Object> map = JsonReader.read(Map.class, "{\"value1\" : \"jason\" ,\n \"value2\":1}");
Map<String, Object> expected = new HashMap<>();
expected.put("value1", "jason");
expected.put("value2", 1L);
expected.put("value2", 1);
assertEquals(expected, map);
}
@ -40,9 +40,9 @@ public class Maps {
}
@Test
public void singleLongs() {
Map<String, Long> map = JsonReader.read(Map.class, " { \"1\":2 }");
Map<String, Long> expected = Collections.singletonMap("1", 2L);
public void singleInts() {
Map<String, Integer> map = JsonReader.read(Map.class, " { \"1\":2 }");
Map<String, Integer> expected = Collections.singletonMap("1", 2);
assertEquals(expected, map);
}
@ -63,7 +63,7 @@ public class Maps {
public void listInMap() {
Map<String, List> list = JsonReader.read(Map.class, " { \"list\" : [ 1 ] } ");
Map<String, List> expected = new HashMap<>();
expected.put("list", List.of(1L));
expected.put("list", List.of(1));
assertEquals(expected, list);
}

View file

@ -1,34 +0,0 @@
package nl.sander.jsontoy2;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
class ParserFactoryTest {
Parser parser1;
Parser parser2;
@Test
public void differentThreadsHaveTheirOwnParser() throws InterruptedException {
Thread t1 = new Thread(() -> parser1 = ParserFactory.getParser(""));
Thread t2 = new Thread(() -> parser2 = ParserFactory.getParser(""));
t1.start();
t2.start();
t1.join();
t2.join();
assertNotSame(parser1, parser2);
}
@Test
public void sameThreadCanReuseParser() {
Parser parser1 = ParserFactory.getParser("1");
Integer value1 = parser1.parseInteger();
Parser parser2 = ParserFactory.getParser("2");
Integer value2 = parser2.parseInteger();
assertSame(parser1, parser2);
assertEquals(1, value1);
assertEquals(2, value2);
}
}

View file

@ -1,87 +0,0 @@
package nl.sander.jsontoy2;
import org.junit.jupiter.api.Test;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
class ParserTest {
@Test
public void testFloat() {
assertEquals(31.415927F, new Parser(getInputStream("31.415927")).parseFloat());
}
@Test
public void testDouble() {
assertEquals(3.1415927D, new Parser(getInputStream("3.1415927")).parseDouble());
}
@Test
public void testInt() {
assertEquals(31415927, new Parser(getInputStream("31415927")).parseInteger());
}
@Test
public void testShort() {
assertEquals((short) 31415, new Parser(getInputStream("31415")).parseShort());
}
@Test
public void testByte() {
assertEquals((byte) 31, new Parser(getInputStream("31")).parseByte());
}
@Test
public void testBooleanTrue() {
assertEquals(true, new Parser(getInputStream("true")).parseBoolean());
}
@Test
public void testBooleanFalse() {
assertEquals(false, new Parser(getInputStream("false")).parseBoolean());
}
@Test
public void testBooleanInvalid() {
assertThrows(JsonParseException.class, () -> new Parser(getInputStream("falsy")).parseBoolean());
}
@Test
public void testArray() {
assertEquals(List.of("3", "1", "4", "1"), new Parser(getInputStream("[\"3\",\"1\",\"4\",\"1\"]")).parseArray());
}
@Test
public void testArrayWithType() {
assertEquals(List.of(3D, 1D, 4D, 1D), new Parser(getInputStream("[3,1,4,1]")).parseArray(Double.class));
}
@Test
public void testObject() {
assertEquals(Map.of("pi", 3.1415927D), new Parser(getInputStream("{\"pi\":3.1415927}")).parseObject());
}
@Test
public void testObjectWithType() {
assertEquals(Map.of("pi", 3.1415927F), new Parser(getInputStream("{\"pi\":3.1415927}")).parseObject(PiBean.class));
}
@Test
public void testChar() {
assertEquals('3', new Parser(getInputStream("\"3\"")).parseCharacter());
}
private InputStream getInputStream(String jsonString) {
return new ByteArrayInputStream(jsonString.getBytes(StandardCharsets.UTF_8));
}
static class PiBean {
private float pi;
}
}

View file

@ -1,169 +0,0 @@
package nl.sander.jsontoy2;
import nl.sander.jsontoy2.testobjects.*;
import org.junit.jupiter.api.Test;
import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
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, (it 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
//TODO enable and fix code
public void testIntegerList() {
IntegerListBean listBean = JsonReader.read(IntegerListBean.class, "{\"value\": [1,22]}");
assertEquals(Arrays.asList(1, 22), listBean.getValue());
}
// @Test
//TODO enable and fix code
public void testCharacterList() {
CharacterListBean listBean = JsonReader.read(CharacterListBean.class, "{\"value\": [\"a\", \"[\", \"^\"]}");
assertEquals(Arrays.asList('a', '[', '^'), listBean.getValue());
}
// @Test
//TODO enable and fix code
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
//TODO enable and fix code
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);
}
@Test
public void testLinkedList() {
LinkedListBean actual = JsonReader.read(LinkedListBean.class, "{\"list\": [\"a\"]}");
LinkedList<String> actualList = actual.getList();
assertEquals(List.of("a"), actualList);
}
@Test
public void testArray() {
ArrayBean actual = JsonReader.read(ArrayBean.class, "{\"array\": [\"a\"]}");
assertEquals(1, actual.getArray().length);
assertEquals("a", actual.getArray()[0]);
}
}

View file

@ -2,30 +2,18 @@ package nl.sander.jsontoy2.java;
import org.junit.jupiter.api.Test;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class ClassReaderTest {
//part of the test
public int field;
public String method(String value, int[] value2, int value3) {
return value;
}
//
@Test
public void testReadClass() {
ClassObject object = new ClassReader().parse(ClassReaderTest.class);
ClassObject<ClassReaderTest> object = new ClassReader().parse(ClassReaderTest.class);
assertEquals(Set.of(new Field("field", "I")), object.getFields());
assertEquals(new TreeSet<>(Set.of(
new Method("method", List.of("Ljava/lang/String", "[I", "I"), "Ljava/lang/String"),
new Method("testReadClass", null, "V"),
new Method("<init>", null, "V"))
), new TreeSet<>(object.getMethods()));
assertEquals(Set.of(new Method("<init>", "()V"), new Method("testReadClass", "()V")), object.getMethods());
}
}

View file

@ -1,69 +0,0 @@
package nl.sander.jsontoy2.javassist;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.NotFoundException;
import nl.sander.jsontoy2.testobjects.BooleanBean;
import nl.sander.jsontoy2.testobjects.SimpleBean;
import org.junit.jupiter.api.Test;
import java.util.HashMap;
import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
public class JavassistTest {
@Test
public void getTypeDefinitionForClass() throws NotFoundException {
// Act
CtClass typeDefinition = Javassist.getTypeDefinition(BooleanBean.class);
// Assert
assertEquals("setValue", typeDefinition.getDeclaredMethod("setValue").getName());
}
@Test
public void getTypeDefinitionForClassname() throws NotFoundException {
// Act
CtClass typeDefinition = Javassist.getTypeDefinition("nl.sander.jsontoy2.testobjects.BooleanBean");
// Assert
assertNotNull(typeDefinition);
assertEquals("BooleanBean", typeDefinition.getSimpleName());
assertEquals("nl.sander.jsontoy2.testobjects.BooleanBean", typeDefinition.getName());
assertEquals("value", typeDefinition.getDeclaredField("value").getName());
assertEquals("setValue", typeDefinition.getDeclaredMethod("setValue").getName());
}
@Test
public void createClass() {
// Act
CtClass newClass = Javassist.createClass("UberClass", Javassist.getTypeDefinition(Object.class));
// Assert
assertEquals("UberClass", newClass.getName());
}
@Test
public void isCollection() {
// Act/ Assert
assertTrue(Javassist.isCollection(Javassist.getTypeDefinition(List.class)));
assertTrue(Javassist.isCollection(Javassist.getTypeDefinition(HashMap.class)));
assertFalse(Javassist.isCollection(Javassist.getTypeDefinition(String.class)));
}
@Test
public void getGetterMethod() {
// Arrange
CtClass typeDefinition = Javassist.getTypeDefinition(SimpleBean.class);
// Act
List<CtMethod> getterMethods = Javassist.getGetters(typeDefinition);
// Assert
assertEquals(2, getterMethods.size());
assertEquals("getData1", getterMethods.get(0).getName());
assertEquals("getData2", getterMethods.get(1).getName());
}
}

View file

@ -1,16 +0,0 @@
package nl.sander.jsontoy2.testobjects;
/*
* test object
*/
public class ArrayBean {
private String[] array;
public void setArray(String[] array) {
this.array = array;
}
public String[] getArray() {
return array;
}
}

View file

@ -1,51 +0,0 @@
package nl.sander.jsontoy2.testobjects;
import java.util.Objects;
/*
* test object
*/
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);
}
}

View file

@ -1,25 +0,0 @@
package nl.sander.jsontoy2.testobjects;
import java.util.List;
/*
* test object
*/
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 +
'}';
}
}

View file

@ -1,28 +0,0 @@
package nl.sander.jsontoy2.testobjects;
/*
* test object
*/
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;
}
}

View file

@ -1,18 +0,0 @@
package nl.sander.jsontoy2.testobjects;
import java.util.List;
/*
* test object
*/
public class ByteListBean {
private List<Byte> value;
public List<Byte> getValue() {
return value;
}
public void setValue(List<Byte> value) {
this.value = value;
}
}

View file

@ -1,18 +0,0 @@
package nl.sander.jsontoy2.testobjects;
import java.util.List;
/*
* test object
*/
public class CharacterListBean {
private List<Character> value;
public List<Character> getValue() {
return value;
}
public void setValue(List<Character> value) {
this.value = value;
}
}

View file

@ -1,28 +0,0 @@
package nl.sander.jsontoy2.testobjects;
/*
* test object
*/
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;
}
}

View file

@ -1,28 +0,0 @@
package nl.sander.jsontoy2.testobjects;
import nl.sander.jsontoy2.JsonReader;
import org.junit.jupiter.api.Test;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
/*
* test object
*/
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"));
}
}

View file

@ -1,33 +0,0 @@
package nl.sander.jsontoy2.testobjects;
/*
* test object
*/
public class FloatBean {
private float value;
private Float value2;
public FloatBean() {
}
public FloatBean(float value, Float value2) {
this.value = value;
this.value2 = value2;
}
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;
}
}

View file

@ -1,18 +0,0 @@
package nl.sander.jsontoy2.testobjects;
import java.util.List;
/*
* test object
*/
public class FloatListBean {
private List<Float> value;
public List<Float> getValue() {
return value;
}
public void setValue(List<Float> value) {
this.value = value;
}
}

View file

@ -1,45 +0,0 @@
package nl.sander.jsontoy2.testobjects;
import java.util.Objects;
/*
* test object
*/
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 + '\'' +
'}';
}
}

View file

@ -1,28 +0,0 @@
package nl.sander.jsontoy2.testobjects;
/*
* test object
*/
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;
}
}

View file

@ -1,18 +0,0 @@
package nl.sander.jsontoy2.testobjects;
import java.util.List;
/*
* test object
*/
public class IntegerListBean {
private List<Integer> value;
public List<Integer> getValue() {
return value;
}
public void setValue(List<Integer> value) {
this.value = value;
}
}

View file

@ -1,18 +0,0 @@
package nl.sander.jsontoy2.testobjects;
import java.util.LinkedList;
/*
* test object
*/
public class LinkedListBean {
private LinkedList<String> list;
public LinkedList<String> getList() {
return list;
}
public void setList(LinkedList<String> list) {
this.list = list;
}
}

View file

@ -1,28 +0,0 @@
package nl.sander.jsontoy2.testobjects;
/*
* test object
*/
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;
}
}

View file

@ -1,51 +0,0 @@
package nl.sander.jsontoy2.testobjects;
import java.util.Objects;
/*
* test object
*/
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 +
'}';
}
}

View file

@ -1,28 +0,0 @@
package nl.sander.jsontoy2.testobjects;
/*
* test object
*/
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;
}
}

View file

@ -1,18 +0,0 @@
package nl.sander.jsontoy2.testobjects;
import java.util.List;
/*
* test object
*/
public class ShortListBean {
private List<Short> value;
public List<Short> getValue() {
return value;
}
public void setValue(List<Short> value) {
this.value = value;
}
}

View file

@ -1,25 +0,0 @@
package nl.sander.jsontoy2.testobjects;
/*
* test object
*/
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;
}
}

View file

@ -1,16 +0,0 @@
package nl.sander.jsontoy2.testobjects;
/*
* test object
*/
public class StringBean {
private String value;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}

View file

@ -1,18 +0,0 @@
package nl.sander.jsontoy2.testobjects;
import java.util.List;
/*
* test object
*/
public class StringListBean {
private List<String> value;
public List<String> getValue() {
return value;
}
public void setValue(List<String> value) {
this.value = value;
}
}

View file

@ -1,49 +0,0 @@
package nl.sander.jsontoy2.testobjects;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
/*
* test object
*/
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);
}
}

View file

@ -1,18 +0,0 @@
package nl.sander.jsontoy2.testobjects;
import java.util.Set;
/*
* test object
*/
public class StringSetBean {
private Set<String> value;
public Set<String> getValue() {
return value;
}
public void setValue(Set<String> value) {
this.value = value;
}
}