[gson] Separate API and CONFIG gson holders

This commit is contained in:
Johannes Frohnmeyer 2022-09-25 12:01:45 +02:00
parent 8fa03efbda
commit a8ab56c9f4
Signed by: Johannes
GPG Key ID: E76429612C2929F4
5 changed files with 138 additions and 57 deletions

View File

@ -1,74 +1,32 @@
package io.gitlab.jfronny.commons.serialize.gson.api;
import io.gitlab.jfronny.commons.*;
import io.gitlab.jfronny.commons.serialize.*;
import io.gitlab.jfronny.commons.serialize.gson.impl.*;
import com.google.gson.*;
import java.io.*;
import java.lang.reflect.*;
import java.util.function.*;
/**
* Holds a common instance of the Gson object.
* Supports registering type adapters/etc. as needed
*/
@Deprecated
public class GsonHolder {
private static final GsonBuilder builder = new GsonBuilder()
.registerTypeAdapter(ComparableVersion.class, new ComparableVersionAdapter())
.excludeFieldsWithModifiers(Modifier.TRANSIENT, Modifier.PRIVATE)
.setExclusionStrategies(new GsonIgnoreExclusionStrategy())
.setLenient()
.serializeNulls()
.setPrettyPrinting();
private static boolean clean = false;
private static Gson gson;
/**
* Get the current gson instance or build it if needed
* @return The Gson instance
*/
private static final io.gitlab.jfronny.commons.serialize.gson.api.v1.GsonHolder BACKEND = new io.gitlab.jfronny.commons.serialize.gson.api.v1.GsonHolder();
public static Gson getGson() {
if (!clean) {
gson = builder.create();
clean = true;
}
return gson;
return BACKEND.getGson();
}
/**
* Register a type adapter and mark the gson instance as unclean
* @param type The type for which to register the adapter
* @param typeAdapter The adapter type
*/
public static void registerTypeAdapter(Type type, Object typeAdapter) {
builder.registerTypeAdapter(type, typeAdapter);
clean = false;
BACKEND.registerTypeAdapter(type, typeAdapter);
}
/**
* Register a type adapter factory and mark the gson instance as unclean
* @param factory The factory to register
*/
public static void registerTypeAdapterFactory(TypeAdapterFactory factory) {
builder.registerTypeAdapterFactory(factory);
clean = false;
BACKEND.registerTypeAdapterFactory(factory);
}
/**
* Run a function on the builder for modifying it and mark the gson instance as unclean
* @param func The function to run
*/
public static void modifyBuilder(Consumer<GsonBuilder> func) {
func.accept(builder);
clean = false;
BACKEND.modifyBuilder(func);
}
/**
* Register this in {@code SerializerHolder}
*/
public static void register() {
Serializer.setInstance(new GsonHolderSerializer());
Serializer.setInstance(new GsonHolderSerializer(BACKEND));
}
}

View File

@ -0,0 +1,75 @@
package io.gitlab.jfronny.commons.serialize.gson.api.v1;
import com.google.gson.*;
import io.gitlab.jfronny.commons.ComparableVersion;
import io.gitlab.jfronny.commons.serialize.gson.impl.ComparableVersionAdapter;
import io.gitlab.jfronny.commons.serialize.gson.impl.GsonIgnoreExclusionStrategy;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.util.function.Consumer;
/**
* Holds a common instance of the Gson object.
* Supports registering type adapters/etc. as needed
*/
public class GsonHolder {
private final GsonBuilder builder = new GsonBuilder()
.registerTypeAdapter(ComparableVersion.class, new ComparableVersionAdapter())
.excludeFieldsWithModifiers(Modifier.TRANSIENT, Modifier.PRIVATE)
.setExclusionStrategies(new GsonIgnoreExclusionStrategy())
.setLenient();
private boolean clean = false;
private Gson gson;
public GsonHolder() {
synchronized (GsonHolders.KNOWN_INSTANCES) {
GsonHolders.KNOWN_INSTANCES.add(this);
for (Consumer<GsonBuilder> modification : GsonHolders.KNOWN_MODIFICATIONS) modification.accept(builder);
}
}
/**
* Get the current gson instance or build it if needed
* @return The Gson instance
*/
public Gson getGson() {
if (!clean) {
gson = builder.create();
clean = true;
}
return gson;
}
/**
* Register a type adapter and mark the gson instance as unclean
* @param type The type for which to register the adapter
* @param typeAdapter The adapter type
*/
public GsonHolder registerTypeAdapter(Type type, Object typeAdapter) {
builder.registerTypeAdapter(type, typeAdapter);
clean = false;
return this;
}
/**
* Register a type adapter factory and mark the gson instance as unclean
* @param factory The factory to register
*/
public GsonHolder registerTypeAdapterFactory(TypeAdapterFactory factory) {
builder.registerTypeAdapterFactory(factory);
clean = false;
return this;
}
/**
* Run a function on the builder for modifying it and mark the gson instance as unclean
* @param func The function to run
*/
public GsonHolder modifyBuilder(Consumer<GsonBuilder> func) {
func.accept(builder);
clean = false;
return this;
}
}

View File

@ -0,0 +1,46 @@
package io.gitlab.jfronny.commons.serialize.gson.api.v1;
import com.google.gson.GsonBuilder;
import com.google.gson.TypeAdapterFactory;
import io.gitlab.jfronny.commons.ref.WeakSet;
import io.gitlab.jfronny.commons.serialize.Serializer;
import io.gitlab.jfronny.commons.serialize.gson.impl.GsonHolderSerializer;
import org.jetbrains.annotations.ApiStatus;
import java.lang.reflect.Type;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.function.Consumer;
public class GsonHolders {
@ApiStatus.Internal
static final Set<Consumer<GsonBuilder>> KNOWN_MODIFICATIONS = new LinkedHashSet<>();
@ApiStatus.Internal
static final WeakSet<GsonHolder> KNOWN_INSTANCES = new WeakSet<>();
public static final GsonHolder API = new GsonHolder();
public static final GsonHolder CONFIG = new GsonHolder().modifyBuilder(b -> b
.setOmitQuotes()
.serializeSpecialFloatingPointValues()
.serializeNulls()
.setPrettyPrinting()
);
public static void registerTypeAdapter(Type type, Object typeAdapter) {
synchronized (KNOWN_INSTANCES) {
KNOWN_MODIFICATIONS.add(b -> b.registerTypeAdapter(type, typeAdapter));
for (GsonHolder holder : KNOWN_INSTANCES) holder.registerTypeAdapter(type, typeAdapter);
}
}
public static void registerTypeAdapterFactory(TypeAdapterFactory factory) {
synchronized (KNOWN_INSTANCES) {
KNOWN_MODIFICATIONS.add(b -> b.registerTypeAdapterFactory(factory));
for (GsonHolder holder : KNOWN_INSTANCES) holder.registerTypeAdapterFactory(factory);
}
}
public static void registerSerializer() {
Serializer.setInstance(new GsonHolderSerializer(API));
}
}

View File

@ -2,13 +2,13 @@ package io.gitlab.jfronny.commons.serialize.gson.impl;
import com.google.gson.*;
import io.gitlab.jfronny.commons.serialize.Serializer;
import io.gitlab.jfronny.commons.serialize.gson.api.GsonHolder;
import io.gitlab.jfronny.commons.serialize.gson.api.v1.GsonHolder;
import java.io.IOException;
import java.io.Reader;
import java.lang.reflect.Type;
public class GsonHolderSerializer implements Serializer {
public record GsonHolderSerializer(GsonHolder holder) implements Serializer {
@Override
public String serialize(Object object) throws IOException {
try {
@ -89,7 +89,7 @@ public class GsonHolderSerializer implements Serializer {
}
private Gson getGson() {
return GsonHolder.getGson();
return holder.getGson();
}
@Override

View File

@ -1,9 +1,11 @@
package io.gitlab.jfronny.commons.test;
import io.gitlab.jfronny.commons.*;
import io.gitlab.jfronny.commons.serialize.*;
import io.gitlab.jfronny.commons.serialize.gson.api.*;
import org.junit.jupiter.api.*;
import io.gitlab.jfronny.commons.ComparableVersion;
import io.gitlab.jfronny.commons.serialize.Serializer;
import io.gitlab.jfronny.commons.serialize.gson.api.Ignore;
import io.gitlab.jfronny.commons.serialize.gson.api.v1.GsonHolders;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import java.io.IOException;
@ -12,7 +14,7 @@ import static org.junit.jupiter.api.Assertions.*;
public class GsonTest {
@BeforeAll
static void setup() {
GsonHolder.register();
GsonHolders.registerSerializer();
}
@Test