Compare commits
10 commits
3522416622
...
0a02524d86
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0a02524d86 | ||
|
|
f483844d65 | ||
|
|
b3687452f6 | ||
|
|
06a15f3feb | ||
|
|
4522f36e67 | ||
|
|
6417930897 | ||
|
|
3ca89dadb5 | ||
|
|
514702a40d | ||
|
|
899bcb16ca | ||
|
|
680106597b |
11 changed files with 254 additions and 330 deletions
|
|
@ -5,12 +5,12 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>nl.sander</groupId>
|
<groupId>nl.sander</groupId>
|
||||||
<artifactId>jsonthingy-pom</artifactId>
|
<artifactId>jsonthingy-pom</artifactId>
|
||||||
<version>0.1-SNAPSHOT</version>
|
<version>1.7</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<name>JsonToy-JMH</name>
|
<name>JsonToy-JMH</name>
|
||||||
<artifactId>jsonthingy-jmhtests</artifactId>
|
<artifactId>jsonthingy-jmhtests</artifactId>
|
||||||
<version>0.1-SNAPSHOT</version>
|
<version>1.7</version>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
|
|
@ -19,7 +19,6 @@
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>${project.groupId}</groupId>
|
<groupId>${project.groupId}</groupId>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,79 @@
|
||||||
|
package nl.sanderhautvast.json.jmh;
|
||||||
|
|
||||||
|
import org.openjdk.jmh.annotations.*;
|
||||||
|
|
||||||
|
import java.lang.reflect.Array;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
@State(Scope.Thread)
|
||||||
|
@BenchmarkMode(Mode.AverageTime)
|
||||||
|
@OutputTimeUnit(TimeUnit.NANOSECONDS)
|
||||||
|
public class ArrayReflectionBenchmarks {
|
||||||
|
|
||||||
|
private static final int ITERATIONS = 10;
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
new ArrayReflectionBenchmarks().testReflectiveArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
public void testReflectiveArray() {
|
||||||
|
int[] r1 = {1};
|
||||||
|
int[] r2 = {1, 2};
|
||||||
|
int[][] table1 = {r1, r2};
|
||||||
|
int[][] table2 = {r1, r2};
|
||||||
|
int[][][] schema = {table1, table2};
|
||||||
|
for (int i = 0; i < ITERATIONS; i++) {
|
||||||
|
addArrayElements(schema);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
public void testNonReflectiveArray() {
|
||||||
|
int[] r1 = {1};
|
||||||
|
int[] r2 = {1, 2};
|
||||||
|
int[][] table1 = {r1, r2};
|
||||||
|
int[][] table2 = {r1, r2};
|
||||||
|
int[][][] schema = {table1, table2};
|
||||||
|
for (int i = 0; i < ITERATIONS; i++) {
|
||||||
|
addIntegerArray(schema);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int addArrayElements(Object o) {
|
||||||
|
int sum = 0;
|
||||||
|
if (o.getClass().isArray()) {
|
||||||
|
int length = Array.getLength(o);
|
||||||
|
for (int i = 0; i < length; i++) {
|
||||||
|
sum += addArrayElements(Array.get(o, i));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sum += (Integer) o;
|
||||||
|
}
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int addIntegerArray(int[][][] o) {
|
||||||
|
int sum = 0;
|
||||||
|
for (int[][] ints : o) {
|
||||||
|
sum += addIntegerArray2(ints);
|
||||||
|
}
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int addIntegerArray2(int[][] o) {
|
||||||
|
int sum = 0;
|
||||||
|
for (int[] ints : o) {
|
||||||
|
sum += addIntegerArray3(ints);
|
||||||
|
}
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int addIntegerArray3(int[] o) {
|
||||||
|
int sum = 0;
|
||||||
|
for (int j : o) {
|
||||||
|
sum += j;
|
||||||
|
}
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -8,14 +8,14 @@ import org.openjdk.jmh.annotations.*;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
@State(Scope.Thread)
|
//@State(Scope.Thread)
|
||||||
@BenchmarkMode(Mode.AverageTime)
|
//@BenchmarkMode(Mode.AverageTime)
|
||||||
@OutputTimeUnit(TimeUnit.NANOSECONDS)
|
//@OutputTimeUnit(TimeUnit.NANOSECONDS)
|
||||||
public class Benchmarks {
|
public class Benchmarks {
|
||||||
|
|
||||||
private static final int ITERATIONS = 10;
|
private static final int ITERATIONS = 10;
|
||||||
|
|
||||||
@Benchmark
|
// @Benchmark
|
||||||
public void testJson() {
|
public void testJson() {
|
||||||
Bean1 bean1;
|
Bean1 bean1;
|
||||||
Bean2 bean2;
|
Bean2 bean2;
|
||||||
|
|
@ -30,7 +30,7 @@ public class Benchmarks {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Benchmark
|
// @Benchmark
|
||||||
public void testJackson() throws JsonProcessingException {
|
public void testJackson() throws JsonProcessingException {
|
||||||
Bean1 bean1;
|
Bean1 bean1;
|
||||||
Bean2 bean2;
|
Bean2 bean2;
|
||||||
|
|
|
||||||
|
|
@ -5,12 +5,12 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>nl.sander</groupId>
|
<groupId>nl.sander</groupId>
|
||||||
<artifactId>jsonthingy-pom</artifactId>
|
<artifactId>jsonthingy-pom</artifactId>
|
||||||
<version>0.1-SNAPSHOT</version>
|
<version>1.7</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<name>JsonToy</name>
|
<name>JsonToy</name>
|
||||||
<artifactId>jsonthingy</artifactId>
|
<artifactId>jsonthingy</artifactId>
|
||||||
<version>0.1-SNAPSHOT</version>
|
<version>1.7</version>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
|
|
|
||||||
|
|
@ -4,25 +4,32 @@ import org.objectweb.asm.ClassReader;
|
||||||
import org.objectweb.asm.ClassWriter;
|
import org.objectweb.asm.ClassWriter;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.lang.reflect.Array;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.time.temporal.Temporal;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mapper.json(StringBuilder b, ...)
|
||||||
|
* TODO write to outputstream
|
||||||
|
*/
|
||||||
public class Mapper {
|
public class Mapper {
|
||||||
private static final Map<Class<?>, BaseMapper<?>> mappers = new ConcurrentHashMap<>();
|
private static final Map<Class<?>, BaseMapper<?>> mappers = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
private static final ByteClassLoader generatedClassesLoader = new ByteClassLoader();
|
private static final ByteClassLoader generatedClassesLoader = new ByteClassLoader();
|
||||||
private static final StringMapper stringMapper = new StringMapper();
|
public static final char[] TAB = {'\\', 't'};
|
||||||
private static final BooleanMapper booleanMapper = new BooleanMapper();
|
public static final char[] DOUBLEQUOTE = {'\\', '\"'};
|
||||||
|
public static final char[] SLASH = {'\\', '/'};
|
||||||
private static final IntegerMapper integerMapper = new IntegerMapper();
|
public static final char[] RETURN = {'\\', 'r'};
|
||||||
private static final LongMapper longMapper = new LongMapper();
|
public static final char[] BACKSLASH = {'\\', '\\'};
|
||||||
private static final ShortMapper shortMapper = new ShortMapper();
|
public static final char[] NEWLINE = {'\\', 'n'};
|
||||||
private static final ByteMapper byteMapper = new ByteMapper();
|
public static final char[] BELL = {'\\', 'b'};
|
||||||
private static final CharMapper charMapper = new CharMapper();
|
public static final char[] FORMFEED = {'\\', 'f'};
|
||||||
private static final FloatMapper floatMapper = new FloatMapper();
|
private static final char[][] MAP = createEscapeMap();
|
||||||
private static final DoubleMapper doubleMapper = new DoubleMapper();
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -45,56 +52,42 @@ public class Mapper {
|
||||||
return b.toString();
|
return b.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
@SuppressWarnings({"unchecked", "rawtypes", "UnnecessaryToStringCall"})
|
||||||
public static void json(StringBuilder b, Object value) {
|
public static void json(StringBuilder b, Object value) {
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
b.append("null");
|
b.append("null");
|
||||||
} else {
|
} else {
|
||||||
Class<?> type = value.getClass();
|
Class<?> type = value.getClass();
|
||||||
if (type.isArray()) {
|
if (type.isArray()) {
|
||||||
if (value instanceof byte[]) {
|
array(b, value);
|
||||||
array(b, (byte[]) value);
|
|
||||||
} else if (value instanceof int[]) {
|
|
||||||
array(b, (int[]) value);
|
|
||||||
} else if (value instanceof short[]) {
|
|
||||||
array(b, (short[]) value);
|
|
||||||
} else if (value instanceof boolean[]) {
|
|
||||||
array(b, (boolean[]) value);
|
|
||||||
} else if (value instanceof char[]) {
|
|
||||||
array(b, (char[]) value);
|
|
||||||
} else if (value instanceof long[]) {
|
|
||||||
array(b, (long[]) value);
|
|
||||||
} else if (value instanceof float[]) {
|
|
||||||
array(b, (float[]) value);
|
|
||||||
} else if (value instanceof double[]) {
|
|
||||||
array(b, (double[]) value);
|
|
||||||
} else {
|
|
||||||
array(b, (Object[]) value);
|
|
||||||
}
|
|
||||||
} else if (value instanceof Collection) {
|
} else if (value instanceof Collection) {
|
||||||
list(b, (Collection) value);
|
list(b, (Collection) value);
|
||||||
} else if (value instanceof Map) {
|
} else if (value instanceof Map) {
|
||||||
object(b, (Map) value);
|
object(b, (Map) value);
|
||||||
} else {
|
} else {
|
||||||
if (type.equals(String.class)) {
|
if (type == String.class) {
|
||||||
stringMapper.json(b, (String) value);
|
b.append("\"");
|
||||||
} else if (type.equals(Boolean.class)) {
|
Mapper.escape(b, (String) value);
|
||||||
|
b.append("\"");
|
||||||
booleanMapper.json(b, (Boolean) value);
|
} else if (type == Character.class) {
|
||||||
} else if (type.equals(Integer.class)) {
|
b.append("\"");
|
||||||
integerMapper.json(b, (Integer) value);
|
Mapper.escape(b, (Character) value);
|
||||||
} else if (type.equals(Long.class)) {
|
b.append("\"");
|
||||||
longMapper.json(b, (Long) value);
|
} else if (type == UUID.class || value instanceof Temporal || type.isEnum()) {
|
||||||
} else if (type.equals(Short.class)) {
|
b.append("\"");
|
||||||
shortMapper.json(b, (Short) value);
|
b.append(value.toString());
|
||||||
} else if (type.equals(Byte.class)) {
|
b.append("\"");
|
||||||
byteMapper.json(b, (Byte) value);
|
} else if (type == Boolean.class
|
||||||
} else if (type.equals(Character.class)) {
|
|| type == Integer.class
|
||||||
charMapper.json(b, (Character) value);
|
|| type == Long.class
|
||||||
} else if (type.equals(Float.class)) {
|
|| type == Float.class
|
||||||
floatMapper.json(b, (Float) value);
|
|| type == Double.class
|
||||||
} else if (type.equals(Double.class)) {
|
|| type == Byte.class
|
||||||
doubleMapper.json(b, (Double) value);
|
|| type == Short.class
|
||||||
|
|| type == BigInteger.class
|
||||||
|
|| type == BigDecimal.class
|
||||||
|
) {
|
||||||
|
b.append(value.toString()); // prevents another nullcheck
|
||||||
} else {
|
} else {
|
||||||
BaseMapper mapper = mappers.computeIfAbsent(type, key -> createObjectMapper(type));
|
BaseMapper mapper = mappers.computeIfAbsent(type, key -> createObjectMapper(type));
|
||||||
mapper.json(b, value);
|
mapper.json(b, value);
|
||||||
|
|
@ -103,140 +96,16 @@ public class Mapper {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void array(StringBuilder b, Object[] array) {
|
//TODO make this more performant
|
||||||
if (array.length == 0) {
|
private static void array(StringBuilder b, Object value) {
|
||||||
b.append("[]");
|
b.append("[");
|
||||||
} else {
|
StringJoiner joiner = new StringJoiner(",");
|
||||||
Object first = array[0];
|
for (int i = 0; i < Array.getLength(value); i++) {
|
||||||
b.append("[");
|
Object arrayElement = Array.get(value, i);
|
||||||
Mapper.json(b, first);
|
joiner.add(Mapper.json(arrayElement)); // recursie
|
||||||
Arrays.stream(array).skip(1)
|
|
||||||
.forEach(element -> {
|
|
||||||
b.append(",");
|
|
||||||
Mapper.json(b, element);
|
|
||||||
});
|
|
||||||
b.append("]");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void array(StringBuilder b, byte[] array) {
|
|
||||||
if (array.length == 0) {
|
|
||||||
b.append("[]");
|
|
||||||
} else {
|
|
||||||
byte first = array[0];
|
|
||||||
b.append("[");
|
|
||||||
json(b, first);
|
|
||||||
for (int i = 1; i < array.length; i++) {
|
|
||||||
b.append(",");
|
|
||||||
json(b, array[i]);
|
|
||||||
}
|
|
||||||
b.append("]");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void array(StringBuilder b, short[] array) {
|
|
||||||
if (array.length == 0) {
|
|
||||||
b.append("[]");
|
|
||||||
} else {
|
|
||||||
short first = array[0];
|
|
||||||
b.append("[");
|
|
||||||
json(b, first);
|
|
||||||
for (int i = 1; i < array.length; i++) {
|
|
||||||
b.append(",");
|
|
||||||
json(b, array[i]);
|
|
||||||
}
|
|
||||||
b.append("]");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void array(StringBuilder b, long[] array) {
|
|
||||||
if (array.length == 0) {
|
|
||||||
b.append("[]");
|
|
||||||
} else {
|
|
||||||
long first = array[0];
|
|
||||||
b.append("[");
|
|
||||||
json(b, first);
|
|
||||||
for (int i = 1; i < array.length; i++) {
|
|
||||||
b.append(",");
|
|
||||||
json(b, array[i]);
|
|
||||||
}
|
|
||||||
b.append("]");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void array(StringBuilder b, boolean[] array) {
|
|
||||||
if (array.length == 0) {
|
|
||||||
b.append("[]");
|
|
||||||
} else {
|
|
||||||
boolean first = array[0];
|
|
||||||
b.append("[");
|
|
||||||
json(b, first);
|
|
||||||
for (int i = 1; i < array.length; i++) {
|
|
||||||
b.append(",");
|
|
||||||
json(b, array[i]);
|
|
||||||
}
|
|
||||||
b.append("]");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void array(StringBuilder b, double[] array) {
|
|
||||||
if (array.length == 0) {
|
|
||||||
b.append("[]");
|
|
||||||
} else {
|
|
||||||
double first = array[0];
|
|
||||||
b.append("[");
|
|
||||||
json(b, first);
|
|
||||||
for (int i = 1; i < array.length; i++) {
|
|
||||||
b.append(",");
|
|
||||||
json(b, array[i]);
|
|
||||||
}
|
|
||||||
b.append("]");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void array(StringBuilder b, char[] array) {
|
|
||||||
if (array.length == 0) {
|
|
||||||
b.append("[]");
|
|
||||||
} else {
|
|
||||||
char first = array[0];
|
|
||||||
b.append("[");
|
|
||||||
json(b, first);
|
|
||||||
for (int i = 1; i < array.length; i++) {
|
|
||||||
b.append(",");
|
|
||||||
json(b, array[i]);
|
|
||||||
}
|
|
||||||
b.append("]");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void array(StringBuilder b, float[] array) {
|
|
||||||
if (array.length == 0) {
|
|
||||||
b.append("[]");
|
|
||||||
} else {
|
|
||||||
float first = array[0];
|
|
||||||
b.append("[");
|
|
||||||
json(b, first);
|
|
||||||
for (int i = 1; i < array.length; i++) {
|
|
||||||
b.append(",");
|
|
||||||
json(b, array[i]);
|
|
||||||
}
|
|
||||||
b.append("]");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void array(StringBuilder b, int[] array) {
|
|
||||||
if (array.length == 0) {
|
|
||||||
b.append("[]");
|
|
||||||
} else {
|
|
||||||
int first = array[0];
|
|
||||||
b.append("[");
|
|
||||||
json(b, first);
|
|
||||||
for (int i = 1; i < array.length; i++) {
|
|
||||||
b.append(",");
|
|
||||||
json(b, array[i]);
|
|
||||||
}
|
|
||||||
b.append("]");
|
|
||||||
}
|
}
|
||||||
|
b.append(joiner);
|
||||||
|
b.append("]");
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||||
|
|
@ -341,134 +210,64 @@ public class Mapper {
|
||||||
escape(b, String.valueOf(c));
|
escape(b, String.valueOf(c));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void escape(StringBuilder b, String value) {
|
private static char[][] createEscapeMap() {
|
||||||
int offset = b.length();
|
char[][] charmap = new char[0x2100][];
|
||||||
b.append(value);
|
for (int i = 0; i < 0x2100; i++) {
|
||||||
int i = offset;
|
char c = (char) i;
|
||||||
while (i < b.length()) {
|
char[] replacement;
|
||||||
char c = b.charAt(i);
|
if (c == '\t') {
|
||||||
switch (c) {
|
replacement = TAB;
|
||||||
case '\t':
|
} else if (c == '\"') {
|
||||||
b.replace(i, i + 1, "\\");
|
replacement = DOUBLEQUOTE;
|
||||||
b.insert(i + 1, "t");
|
} else if (c == '/') {
|
||||||
break;
|
replacement = SLASH;
|
||||||
case '\"':
|
} else if (c == '\r') {
|
||||||
b.replace(i, i + 1, "\\");
|
replacement = RETURN;
|
||||||
b.insert(++i, "\"");
|
} else if (c == '\\') {
|
||||||
break;
|
replacement = BACKSLASH;
|
||||||
case '/':
|
} else if (c == '\n') {
|
||||||
b.replace(i, i + 1, "\\");
|
replacement = NEWLINE;
|
||||||
b.insert(++i, "/");
|
} else if (c == '\b') {
|
||||||
break;
|
replacement = BELL;
|
||||||
case '\r':
|
} else if (c == '\f') {
|
||||||
b.replace(i, i + 1, "\\");
|
replacement = FORMFEED;
|
||||||
b.insert(++i, "r");
|
} else if ((c <= '\u001F') || (c >= '\u007F' && c <= '\u009F') || (c >= '\u2000')) {
|
||||||
break;
|
replacement = new char[6];
|
||||||
case '\n':
|
replacement[0] = '\\';
|
||||||
b.replace(i, i + 1, "\\");
|
replacement[1] = 'u';
|
||||||
b.insert(++i, "n");
|
|
||||||
break;
|
String hex = Integer.toHexString(c).toUpperCase();
|
||||||
case '\b':
|
int hexlen = hex.length();
|
||||||
b.replace(i, i + 1, "\\");
|
for (int k = 0; k < 4 - hexlen; k++) {
|
||||||
b.insert(++i, "b");
|
replacement[k + 2] = '0';
|
||||||
break;
|
}
|
||||||
case '\f':
|
for (int k = 0; k < hexlen; k++) {
|
||||||
b.replace(i, i + 1, "\\");
|
replacement[6 - hexlen + k] = hex.charAt(k);
|
||||||
b.insert(++i, "f");
|
}
|
||||||
break;
|
} else {
|
||||||
case '\\':
|
replacement = new char[]{c};
|
||||||
b.replace(i, i + 1, "\\");
|
}
|
||||||
b.insert(++i, "\\");
|
charmap[i] = replacement;
|
||||||
break;
|
}
|
||||||
case '\'':
|
|
||||||
break;
|
return charmap;
|
||||||
default:
|
}
|
||||||
if ((c <= '\u001F') || (c >= '\u007F' && c <= '\u009F') || (c >= '\u2000' && c <= '\u20FF')) {
|
|
||||||
String ss = Integer.toHexString(c);
|
//both methods are equally slow it seems
|
||||||
b.replace(i, i + 1, "\\");
|
//mainly because we can't do a batch copy into the stringbuilder and have to map every character individually
|
||||||
b.insert(++i, "u");
|
static void escape(StringBuilder b, String value) {
|
||||||
for (int k = 0; k < 4 - ss.length(); k++) {
|
for (int i = 0; i < value.length(); i++) {
|
||||||
b.insert(++i, '0');
|
int c = value.charAt(i);
|
||||||
}
|
|
||||||
b.insert(++i, ss.toUpperCase());
|
if (c < 0x2100) {
|
||||||
}
|
b.append(MAP[c]);
|
||||||
|
} else {
|
||||||
|
b.append((char) c);
|
||||||
}
|
}
|
||||||
i++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class BooleanMapper extends BaseMapper<Boolean> {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void json(StringBuilder b, Boolean value) {
|
|
||||||
b.append(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ShortMapper extends BaseMapper<Short> {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void json(StringBuilder b, Short value) {
|
|
||||||
b.append(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class StringMapper extends BaseMapper<String> {
|
|
||||||
@Override
|
|
||||||
public void json(StringBuilder b, String value) {
|
|
||||||
b.append("\"");
|
|
||||||
Mapper.escape(b, value);
|
|
||||||
b.append("\"");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class IntegerMapper extends BaseMapper<Integer> {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void json(StringBuilder b, Integer value) {
|
|
||||||
b.append(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class LongMapper extends BaseMapper<Long> {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void json(StringBuilder b, Long value) {
|
|
||||||
b.append(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ByteMapper extends BaseMapper<Byte> {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void json(StringBuilder b, Byte value) {
|
|
||||||
b.append(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class CharMapper extends BaseMapper<Character> {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void json(StringBuilder b, Character value) {
|
|
||||||
b.append("\"");
|
|
||||||
Mapper.escape(b, value);
|
|
||||||
b.append("\"");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class FloatMapper extends BaseMapper<Float> {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void json(StringBuilder b, Float value) {
|
|
||||||
b.append(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class DoubleMapper extends BaseMapper<Double> {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void json(StringBuilder b, Double value) {
|
|
||||||
b.append(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -92,7 +92,7 @@ public class MapperFactory extends ClassVisitor {
|
||||||
}
|
}
|
||||||
|
|
||||||
getterInsnList.add(new VarInsnNode(ALOAD, 1));
|
getterInsnList.add(new VarInsnNode(ALOAD, 1));
|
||||||
getterInsnList.add(new LdcInsnNode("\"" + getterMethodName.substring(startIndex).toLowerCase() + "\":"));
|
getterInsnList.add(new LdcInsnNode("\"" + correctName(getterMethodName, startIndex) + "\":"));
|
||||||
getterInsnList.add(new MethodInsnNode(INVOKEVIRTUAL, STRINGBUILDER, APPEND, APPEND_SIGNATURE));
|
getterInsnList.add(new MethodInsnNode(INVOKEVIRTUAL, STRINGBUILDER, APPEND, APPEND_SIGNATURE));
|
||||||
getterInsnList.add(new InsnNode(POP));
|
getterInsnList.add(new InsnNode(POP));
|
||||||
getterInsnList.add(new VarInsnNode(ALOAD, 1));
|
getterInsnList.add(new VarInsnNode(ALOAD, 1));
|
||||||
|
|
@ -101,6 +101,11 @@ public class MapperFactory extends ClassVisitor {
|
||||||
getterInsnList.add(new MethodInsnNode(INVOKESTATIC, MAPPER, "json", "(Ljava/lang/StringBuilder;" + genericReturnType(returnType) + ")V"));
|
getterInsnList.add(new MethodInsnNode(INVOKESTATIC, MAPPER, "json", "(Ljava/lang/StringBuilder;" + genericReturnType(returnType) + ")V"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String correctName(String getterMethodName, int startIndex) {
|
||||||
|
String tmp = getterMethodName.substring(startIndex);
|
||||||
|
return tmp.substring(0, 1).toLowerCase() + tmp.substring(1);
|
||||||
|
}
|
||||||
|
|
||||||
private static String genericReturnType(String returnType) {
|
private static String genericReturnType(String returnType) {
|
||||||
char firstChar = returnType.charAt(0);
|
char firstChar = returnType.charAt(0);
|
||||||
if (firstChar == 'L' || firstChar == '[') {
|
if (firstChar == 'L' || firstChar == '[') {
|
||||||
|
|
|
||||||
17
lib/src/test/java/nl/sanderhautvast/json/ser/EnumTest.java
Normal file
17
lib/src/test/java/nl/sanderhautvast/json/ser/EnumTest.java
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
package nl.sanderhautvast.json.ser;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
|
class EnumTest {
|
||||||
|
|
||||||
|
enum Answer {
|
||||||
|
YES, NO
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testEnums() {
|
||||||
|
assertEquals("\"YES\"", Mapper.json(Answer.YES));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -22,7 +22,7 @@ public class JacksonComparisonTest {
|
||||||
ObjectMapper objectMapper = new ObjectMapper();
|
ObjectMapper objectMapper = new ObjectMapper();
|
||||||
Bean1 bean1 = new Bean1();
|
Bean1 bean1 = new Bean1();
|
||||||
Bean2 bean2 = new Bean2();
|
Bean2 bean2 = new Bean2();
|
||||||
bean1.setData1(UUID.randomUUID().toString());
|
bean1.setData1(UUID.randomUUID());
|
||||||
bean1.setBean2(bean2);
|
bean1.setBean2(bean2);
|
||||||
bean2.setData2(UUID.randomUUID().toString());
|
bean2.setData2(UUID.randomUUID().toString());
|
||||||
String valueAsString;
|
String valueAsString;
|
||||||
|
|
@ -34,7 +34,7 @@ public class JacksonComparisonTest {
|
||||||
for (int i = 0; i < INNERLOOP_COUNT; i++) {
|
for (int i = 0; i < INNERLOOP_COUNT; i++) {
|
||||||
bean1 = new Bean1();
|
bean1 = new Bean1();
|
||||||
bean2 = new Bean2();
|
bean2 = new Bean2();
|
||||||
bean1.setData1(UUID.randomUUID().toString());
|
bean1.setData1(UUID.randomUUID());
|
||||||
bean1.setBean2(bean2);
|
bean1.setBean2(bean2);
|
||||||
bean2.setData2(UUID.randomUUID().toString());
|
bean2.setData2(UUID.randomUUID().toString());
|
||||||
valueAsString = objectMapper.writeValueAsString(bean1);
|
valueAsString = objectMapper.writeValueAsString(bean1);
|
||||||
|
|
@ -47,7 +47,7 @@ public class JacksonComparisonTest {
|
||||||
for (int i = 0; i < INNERLOOP_COUNT; i++) {
|
for (int i = 0; i < INNERLOOP_COUNT; i++) {
|
||||||
bean1 = new Bean1();
|
bean1 = new Bean1();
|
||||||
bean2 = new Bean2();
|
bean2 = new Bean2();
|
||||||
bean1.setData1(UUID.randomUUID().toString());
|
bean1.setData1(UUID.randomUUID());
|
||||||
bean1.setBean2(bean2);
|
bean1.setBean2(bean2);
|
||||||
bean2.setData2(UUID.randomUUID().toString());
|
bean2.setData2(UUID.randomUUID().toString());
|
||||||
jsonString = Mapper.json(bean1);
|
jsonString = Mapper.json(bean1);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
package nl.sanderhautvast.json.ser;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
|
class LocalDateTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testLocalDate() {
|
||||||
|
assertEquals("\"2023-10-11\"", Mapper.json(LocalDate.of(2023, 10, 11)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testLocalDateTime() {
|
||||||
|
assertEquals("\"2023-10-11T13:15:27\"", Mapper.json(LocalDateTime.of(2023, 10, 11,13,15,27)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,16 +1,18 @@
|
||||||
package nl.sanderhautvast.json.ser.nested;
|
package nl.sanderhautvast.json.ser.nested;
|
||||||
|
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public class Bean1 {
|
public class Bean1 {
|
||||||
private String data1;
|
private UUID data1;
|
||||||
private Bean2 bean2;
|
private Bean2 bean2;
|
||||||
|
|
||||||
public String getData1() {
|
public UUID getData1() {
|
||||||
return data1;
|
return data1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setData1(String data1) {
|
public void setData1(UUID data1) {
|
||||||
this.data1 = data1;
|
this.data1 = data1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
16
pom.xml
16
pom.xml
|
|
@ -5,20 +5,22 @@
|
||||||
<name>JsonToy</name>
|
<name>JsonToy</name>
|
||||||
<groupId>nl.sander</groupId>
|
<groupId>nl.sander</groupId>
|
||||||
<artifactId>jsonthingy-pom</artifactId>
|
<artifactId>jsonthingy-pom</artifactId>
|
||||||
<version>0.1-SNAPSHOT</version>
|
<version>1.7</version>
|
||||||
<packaging>pom</packaging>
|
<packaging>pom</packaging>
|
||||||
|
|
||||||
<properties>
|
|
||||||
<maven.compiler.source>9</maven.compiler.source>
|
|
||||||
<maven.compiler.target>9</maven.compiler.target>
|
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
|
||||||
</properties>
|
|
||||||
|
|
||||||
<modules>
|
<modules>
|
||||||
<module>lib</module>
|
<module>lib</module>
|
||||||
<module>jmh</module>
|
<module>jmh</module>
|
||||||
</modules>
|
</modules>
|
||||||
|
|
||||||
|
<distributionManagement>
|
||||||
|
<repository>
|
||||||
|
<id>github</id>
|
||||||
|
<name>GitHub OWNER Apache Maven Packages</name>
|
||||||
|
<url>https://maven.pkg.github.com/shautvast/JsonToy</url>
|
||||||
|
</repository>
|
||||||
|
</distributionManagement>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
<pluginManagement>
|
<pluginManagement>
|
||||||
<plugins>
|
<plugins>
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue