some cleanup and added javadocs, upgrade to junit5
This commit is contained in:
parent
a8a364b557
commit
c650834d3b
5 changed files with 60 additions and 49 deletions
|
|
@ -7,12 +7,15 @@ import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 class JavaObjectReaderFactory {
|
||||||
public static final String ROOT_PACKAGE = "serializer.";
|
public static final String ROOT_PACKAGE = "serializer.";
|
||||||
private final static CtClass DESERIALIZER_BASE = Javassist.getTypeDefinition(JsonValueReader.class);
|
private final static CtClass DESERIALIZER_BASE = Javassist.getTypeDefinition(JsonValueReader.class);
|
||||||
|
|
@ -21,13 +24,6 @@ public class JavaObjectReaderFactory {
|
||||||
private static final Class<?>[] NO_PARAMS = {};
|
private static final Class<?>[] NO_PARAMS = {};
|
||||||
private static final CtClass[] CT_NO_PARAMS = {};
|
private static final CtClass[] CT_NO_PARAMS = {};
|
||||||
private final static CtClass OBJECT_CLASS = Javassist.getTypeDefinition(Object.class);
|
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")
|
@SuppressWarnings("unchecked")
|
||||||
static <T> JsonValueReader<T> createReaderInstance(Class<T> type) {
|
static <T> JsonValueReader<T> createReaderInstance(Class<T> type) {
|
||||||
|
|
@ -56,7 +52,7 @@ public class JavaObjectReaderFactory {
|
||||||
private static CtMethod createReadJsonMethod(CtClass serializerClass, Class<?> type) {
|
private static CtMethod createReadJsonMethod(CtClass serializerClass, Class<?> type) {
|
||||||
try {
|
try {
|
||||||
String readMethodBodySource = createReadMethodBodySource(type);
|
String readMethodBodySource = createReadMethodBodySource(type);
|
||||||
System.out.println(readMethodBodySource);
|
// System.out.println(readMethodBodySource);
|
||||||
return CtNewMethod.make(Modifier.PUBLIC, OBJECT_CLASS, "read", PARSER_PARAM, NO_EXCEPTIONS, readMethodBodySource, serializerClass);
|
return CtNewMethod.make(Modifier.PUBLIC, OBJECT_CLASS, "read", PARSER_PARAM, NO_EXCEPTIONS, readMethodBodySource, serializerClass);
|
||||||
} catch (CannotCompileException e) {
|
} catch (CannotCompileException e) {
|
||||||
throw new ClassCreationException(e);
|
throw new ClassCreationException(e);
|
||||||
|
|
@ -110,7 +106,7 @@ public class JavaObjectReaderFactory {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//should be reinstated
|
||||||
private static String genericType(CtField field) {
|
private static String genericType(CtField field) {
|
||||||
try {
|
try {
|
||||||
if (!Javassist.isCollection(field.getType())) {
|
if (!Javassist.isCollection(field.getType())) {
|
||||||
|
|
@ -138,10 +134,6 @@ public class JavaObjectReaderFactory {
|
||||||
return lowercase.substring(0, 1).toUpperCase() + lowercase.substring(1);
|
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
|
* custom root package is prepended to avoid the java.lang class in which it's illegal to create new classes
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,16 @@
|
||||||
package nl.sander.jsontoy2;
|
package nl.sander.jsontoy2;
|
||||||
|
|
||||||
import java.io.BufferedInputStream;
|
import java.io.BufferedInputStream;
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.lang.ref.SoftReference;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* public api
|
* public api
|
||||||
*/
|
*/
|
||||||
public class JsonReader {
|
public class JsonReader {
|
||||||
|
|
||||||
|
private JsonReader() {
|
||||||
private final static ThreadLocal<SoftReference<Parser>> PARSERS = new ThreadLocal<>();
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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
|
||||||
|
|
@ -32,7 +27,7 @@ public class JsonReader {
|
||||||
*/
|
*/
|
||||||
public static Object read(InputStream inputStream) {
|
public static Object read(InputStream inputStream) {
|
||||||
final InputStream in = ensureBufferedStream(inputStream);
|
final InputStream in = ensureBufferedStream(inputStream);
|
||||||
try (Parser parser = getParser(in)) {
|
try (Parser parser = ParserFactory.getParser(in)) {
|
||||||
return read(parser);
|
return read(parser);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -44,7 +39,7 @@ public class JsonReader {
|
||||||
* @return @see read(InputStream stream)
|
* @return @see read(InputStream stream)
|
||||||
*/
|
*/
|
||||||
public static Object read(String jsonString) {
|
public static Object read(String jsonString) {
|
||||||
return read(getParser(jsonString));
|
return read(ParserFactory.getParser(jsonString));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -56,7 +51,7 @@ public class JsonReader {
|
||||||
* @return Object the specified type
|
* @return Object the specified type
|
||||||
*/
|
*/
|
||||||
public static <T> T read(Class<T> type, InputStream inputStream) {
|
public static <T> T read(Class<T> type, InputStream inputStream) {
|
||||||
Parser parser = getParser(inputStream);
|
Parser parser = ParserFactory.getParser(inputStream);
|
||||||
T value = read(type, parser);
|
T value = read(type, parser);
|
||||||
parser.close();
|
parser.close();
|
||||||
return value;
|
return value;
|
||||||
|
|
@ -71,31 +66,15 @@ public class JsonReader {
|
||||||
* @return Object the specified type
|
* @return Object the specified type
|
||||||
*/
|
*/
|
||||||
public static <T> T read(Class<T> type, String jsonString) {
|
public static <T> T read(Class<T> type, String jsonString) {
|
||||||
return read(type, getParser(jsonString));
|
return read(type, ParserFactory.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) {
|
static Object read(Parser parser) {
|
||||||
return parser.parseAny();
|
return parser.parseAny();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//TODO should not be public
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public static <T> T read(Class<T> type, Parser parser) {
|
public static <T> T read(Class<T> type, Parser parser) {
|
||||||
return (T) ReaderFactory.getReader(type).read(parser);
|
return (T) ReaderFactory.getReader(type).read(parser);
|
||||||
|
|
|
||||||
38
src/main/java/nl/sander/jsontoy2/ParserFactory.java
Normal file
38
src/main/java/nl/sander/jsontoy2/ParserFactory.java
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -18,7 +18,10 @@ public class ReaderFactory {
|
||||||
registerPrimitiveTypeReaders();
|
registerPrimitiveTypeReaders();
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T> void registerCustomReader(Class<T> type, JsonValueReader<T> reader) {
|
private ReaderFactory() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> void registerCustomReader(Class<T> type, JsonValueReader<T> reader) {
|
||||||
readers.put(type, reader);
|
readers.put(type, reader);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,7 @@ import org.junit.jupiter.api.Test;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
|
||||||
|
|
||||||
public class WrapperObjectTests {
|
public class WrapperObjectTests {
|
||||||
|
|
||||||
|
|
@ -22,9 +21,9 @@ public class WrapperObjectTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testBoolean() {
|
public void testBoolean() {
|
||||||
// BooleanBean trueBean = JsonReader.read(BooleanBean.class, "{\"value\": true}");
|
BooleanBean trueBean = JsonReader.read(BooleanBean.class, "{\"value\": true}");
|
||||||
// assertTrue(trueBean.isValue());
|
assertTrue(trueBean.isValue());
|
||||||
// second call to read, must not recreate class definition, would not compile
|
// second call to read, must not recreate class definition, (it would not compile)
|
||||||
// so this test implicitly tests caching function too
|
// so this test implicitly tests caching function too
|
||||||
BooleanBean falseBean = JsonReader.read(BooleanBean.class, "{\"value2\": false}");
|
BooleanBean falseBean = JsonReader.read(BooleanBean.class, "{\"value2\": false}");
|
||||||
assertFalse(falseBean.isValue());
|
assertFalse(falseBean.isValue());
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue