diff --git a/commons-gson/src/main/java/io/gitlab/jfronny/commons/serialize/gson/api/GsonHolder.java b/commons-gson/src/main/java/io/gitlab/jfronny/commons/serialize/gson/api/GsonHolder.java index 78e7014..7d68193 100644 --- a/commons-gson/src/main/java/io/gitlab/jfronny/commons/serialize/gson/api/GsonHolder.java +++ b/commons-gson/src/main/java/io/gitlab/jfronny/commons/serialize/gson/api/GsonHolder.java @@ -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 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)); } } diff --git a/commons-gson/src/main/java/io/gitlab/jfronny/commons/serialize/gson/api/v1/GsonHolder.java b/commons-gson/src/main/java/io/gitlab/jfronny/commons/serialize/gson/api/v1/GsonHolder.java new file mode 100644 index 0000000..aaa4b4d --- /dev/null +++ b/commons-gson/src/main/java/io/gitlab/jfronny/commons/serialize/gson/api/v1/GsonHolder.java @@ -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 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 func) { + func.accept(builder); + clean = false; + return this; + } +} diff --git a/commons-gson/src/main/java/io/gitlab/jfronny/commons/serialize/gson/api/v1/GsonHolders.java b/commons-gson/src/main/java/io/gitlab/jfronny/commons/serialize/gson/api/v1/GsonHolders.java new file mode 100644 index 0000000..c51dfbb --- /dev/null +++ b/commons-gson/src/main/java/io/gitlab/jfronny/commons/serialize/gson/api/v1/GsonHolders.java @@ -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> KNOWN_MODIFICATIONS = new LinkedHashSet<>(); + @ApiStatus.Internal + static final WeakSet 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)); + } +} diff --git a/commons-gson/src/main/java/io/gitlab/jfronny/commons/serialize/gson/impl/GsonHolderSerializer.java b/commons-gson/src/main/java/io/gitlab/jfronny/commons/serialize/gson/impl/GsonHolderSerializer.java index eea98d9..87095c2 100644 --- a/commons-gson/src/main/java/io/gitlab/jfronny/commons/serialize/gson/impl/GsonHolderSerializer.java +++ b/commons-gson/src/main/java/io/gitlab/jfronny/commons/serialize/gson/impl/GsonHolderSerializer.java @@ -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 diff --git a/commons-gson/src/test/java/io/gitlab/jfronny/commons/test/GsonTest.java b/commons-gson/src/test/java/io/gitlab/jfronny/commons/test/GsonTest.java index 0807adc..638c669 100644 --- a/commons-gson/src/test/java/io/gitlab/jfronny/commons/test/GsonTest.java +++ b/commons-gson/src/test/java/io/gitlab/jfronny/commons/test/GsonTest.java @@ -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