Added Json util file to avoid multiple identical instances of Gson object

This commit is contained in:
Marc Baloup 2021-09-09 23:31:54 +02:00
parent f2bd13a18d
commit 218010e910
Signed by: marcbal
GPG Key ID: BBC0FE3ABC30B893
4 changed files with 110 additions and 11 deletions

View File

@ -19,10 +19,10 @@ import java.util.UUID;
import com.google.common.base.MoreObjects;
import com.google.common.base.MoreObjects.ToStringHelper;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import fr.pandacube.lib.core.util.EnumUtil;
import fr.pandacube.lib.core.util.Json;
import fr.pandacube.lib.core.util.Log;
public abstract class SQLElement<E extends SQLElement<E>> {
@ -398,7 +398,7 @@ public abstract class SQLElement<E extends SQLElement<E>> {
public JsonObject asJsonObject() {
JsonObject json = new JsonObject();
for (SQLField<E, ?> f : getFields().values()) {
json.add(f.getName(), new Gson().toJsonTree(get(f)));
json.add(f.getName(), Json.gson.toJsonTree(get(f)));
}
return json;
}

View File

@ -0,0 +1,104 @@
package fr.pandacube.lib.core.util;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.RecordComponent;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.TypeAdapter;
import com.google.gson.TypeAdapterFactory;
import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
import com.google.gson.stream.JsonWriter;
public class Json {
public static final Gson gson = build(b -> b);
public static final Gson gsonPrettyPrinting = build(b -> b.setPrettyPrinting());
public static final Gson gsonSerializeNulls = build(b -> b.serializeNulls());
public static final Gson gsonSerializeNullsPrettyPrinting = build(b -> b.serializeNulls().setPrettyPrinting());
private static Gson build(Function<GsonBuilder, GsonBuilder> builderModifier) {
return builderModifier
.apply(new GsonBuilder().registerTypeAdapterFactory(new RecordAdapterFactory()).setLenient()).create();
}
// from https://github.com/google/gson/issues/1794#issuecomment-812964421
private static class RecordAdapterFactory implements TypeAdapterFactory {
@Override
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
@SuppressWarnings("unchecked")
Class<T> clazz = (Class<T>) type.getRawType();
if (!clazz.isRecord() || clazz == Record.class) {
return null;
}
return new RecordTypeAdapter<>(gson, this, type);
}
}
private static class RecordTypeAdapter<T> extends TypeAdapter<T> {
private Gson gson;
private TypeAdapterFactory factory;
private TypeToken<T> type;
public RecordTypeAdapter(Gson gson, TypeAdapterFactory factory, TypeToken<T> type) {
this.gson = gson;
this.factory = factory;
this.type = type;
}
@Override
public void write(JsonWriter out, T value) throws IOException {
gson.getDelegateAdapter(factory, type).write(out, value);
}
@Override
public T read(JsonReader reader) throws IOException {
if (reader.peek() == JsonToken.NULL) {
reader.nextNull();
return null;
} else {
@SuppressWarnings("unchecked")
Class<T> clazz = (Class<T>) type.getRawType();
RecordComponent[] recordComponents = clazz.getRecordComponents();
Map<String, TypeToken<?>> typeMap = new HashMap<>();
for (int i = 0; i < recordComponents.length; i++) {
typeMap.put(recordComponents[i].getName(), TypeToken.get(recordComponents[i].getGenericType()));
}
var argsMap = new HashMap<String, Object>();
reader.beginObject();
while (reader.hasNext()) {
String name = reader.nextName();
argsMap.put(name, gson.getAdapter(typeMap.get(name)).read(reader));
}
reader.endObject();
var argTypes = new Class<?>[recordComponents.length];
var args = new Object[recordComponents.length];
for (int i = 0; i < recordComponents.length; i++) {
argTypes[i] = recordComponents[i].getType();
args[i] = argsMap.get(recordComponents[i].getName());
}
Constructor<T> constructor;
try {
constructor = clazz.getDeclaredConstructor(argTypes);
constructor.setAccessible(true);
return constructor.newInstance(args);
} catch (NoSuchMethodException | InstantiationException | SecurityException | IllegalAccessException
| IllegalArgumentException | InvocationTargetException e) {
throw new RuntimeException(e);
}
}
}
}
}

View File

@ -7,13 +7,9 @@ import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonSyntaxException;
public class ServerPropertyFile {
private static final Gson SERIALIZER = new GsonBuilder().setPrettyPrinting().create();
private transient File file;
@ -39,7 +35,7 @@ public class ServerPropertyFile {
public boolean loadFromFile() {
try (BufferedReader in = new BufferedReader(new FileReader(file))) {
ServerPropertyFile dataFile = SERIALIZER.fromJson(in, getClass());
ServerPropertyFile dataFile = Json.gsonPrettyPrinting.fromJson(in, getClass());
name = dataFile.name;
memory = dataFile.memory;
@ -61,7 +57,7 @@ public class ServerPropertyFile {
public boolean save() {
try (BufferedWriter out = new BufferedWriter(new FileWriter(file, false))) {
SERIALIZER.toJson(this, out);
Json.gsonPrettyPrinting.toJson(this, out);
out.flush();
return true;
} catch (IOException e) {

View File

@ -5,7 +5,6 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.google.gson.Gson;
import com.google.gson.JsonElement;
/**
@ -128,7 +127,7 @@ public class TypeConverter {
}
if (o instanceof JsonElement) {
o = new Gson().fromJson((JsonElement)o, Object.class);
o = Json.gson.fromJson((JsonElement)o, Object.class);
}
if (o instanceof Map) {
@ -175,7 +174,7 @@ public class TypeConverter {
}
if (o instanceof JsonElement) {
o = new Gson().fromJson((JsonElement)o, Object.class);
o = Json.gson.fromJson((JsonElement)o, Object.class);
}