diff options
Diffstat (limited to 'src/main/java/cc/polyfrost')
14 files changed, 68 insertions, 1160 deletions
diff --git a/src/main/java/cc/polyfrost/oneconfig/config/Config.java b/src/main/java/cc/polyfrost/oneconfig/config/Config.java index 87ade90..fe7d7f7 100644 --- a/src/main/java/cc/polyfrost/oneconfig/config/Config.java +++ b/src/main/java/cc/polyfrost/oneconfig/config/Config.java @@ -34,9 +34,9 @@ import cc.polyfrost.oneconfig.config.data.PageLocation; import cc.polyfrost.oneconfig.config.elements.BasicOption; import cc.polyfrost.oneconfig.config.elements.OptionPage; import cc.polyfrost.oneconfig.config.elements.OptionSubcategory; +import cc.polyfrost.oneconfig.config.gson.InstanceSupplier; import cc.polyfrost.oneconfig.config.gson.exclusion.NonProfileSpecificExclusionStrategy; import cc.polyfrost.oneconfig.config.gson.exclusion.ProfileExclusionStrategy; -import cc.polyfrost.oneconfig.config.gson.gsoninterface.InterfaceAdapterFactory; import cc.polyfrost.oneconfig.gui.elements.config.ConfigKeyBind; import cc.polyfrost.oneconfig.gui.OneConfigGui; import cc.polyfrost.oneconfig.gui.elements.config.ConfigPageButton; @@ -45,14 +45,10 @@ import cc.polyfrost.oneconfig.hud.HUDUtils; import cc.polyfrost.oneconfig.internal.config.annotations.Option; import cc.polyfrost.oneconfig.internal.config.core.ConfigCore; import cc.polyfrost.oneconfig.internal.config.core.KeyBindHandler; -import cc.polyfrost.oneconfig.utils.JsonUtils; import cc.polyfrost.oneconfig.utils.gui.GuiUtils; import com.google.gson.*; -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.InputStreamReader; -import java.io.OutputStreamWriter; +import java.io.*; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.nio.charset.StandardCharsets; @@ -64,19 +60,12 @@ import java.util.function.Supplier; public class Config { public final transient HashMap<String, BasicOption> optionNames = new HashMap<>(); transient protected final String configFile; - transient protected final Gson gson = new GsonBuilder() - .setExclusionStrategies(new ProfileExclusionStrategy()) - .registerTypeAdapterFactory(new InterfaceAdapterFactory()) - .excludeFieldsWithModifiers(Modifier.TRANSIENT) - .setPrettyPrinting() + transient protected final Gson gson = addGsonOptions(new GsonBuilder() + .setExclusionStrategies(new ProfileExclusionStrategy())) .create(); - transient protected final Gson nonProfileSpecificGson = new GsonBuilder() - .setExclusionStrategies(new NonProfileSpecificExclusionStrategy()) - .registerTypeAdapterFactory(new InterfaceAdapterFactory()) - .excludeFieldsWithModifiers(Modifier.TRANSIENT) - .setPrettyPrinting() + transient protected final Gson nonProfileSpecificGson = addGsonOptions(new GsonBuilder() + .setExclusionStrategies(new NonProfileSpecificExclusionStrategy())) .create(); - transient protected final HashMap<Field, Object> defaults = new HashMap<>(); transient public Mod mod; public boolean enabled; @@ -138,12 +127,12 @@ public class Config { */ public void load() { try (BufferedReader reader = new BufferedReader(new InputStreamReader(Files.newInputStream(ConfigUtils.getProfileFile(configFile).toPath()), StandardCharsets.UTF_8))) { - deserializePart(JsonUtils.PARSER.parse(reader).getAsJsonObject(), this); + gson.fromJson(reader, this.getClass()); } catch (Exception e) { e.printStackTrace(); } try (BufferedReader reader = new BufferedReader(new InputStreamReader(Files.newInputStream(ConfigUtils.getNonProfileSpecificFile(configFile).toPath()), StandardCharsets.UTF_8))) { - deserializePart(JsonUtils.PARSER.parse(reader).getAsJsonObject(), this); + nonProfileSpecificGson.fromJson(reader, this.getClass()); } catch (Exception e) { e.printStackTrace(); } @@ -157,7 +146,7 @@ public class Config { * @param mod data about the mod * @param migrate whether the migrator should be run */ - protected void generateOptionList(Object instance, OptionPage page, Mod mod, boolean migrate) { + protected final void generateOptionList(Object instance, OptionPage page, Mod mod, boolean migrate) { String pagePath = page.equals(mod.defaultPage) ? "" : page.name + "."; for (Field field : instance.getClass().getDeclaredFields()) { Option option = ConfigUtils.findAnnotation(field, Option.class); @@ -214,45 +203,11 @@ public class Config { return null; } - /** - * Deserialize part of config and load values - * - * @param json json to deserialize - * @param instance instance of target class - */ - protected void deserializePart(JsonObject json, Object instance) { - Class<?> clazz = instance.getClass(); - ArrayList<Field> fields = ConfigUtils.getClassFields(clazz); - for (Map.Entry<String, JsonElement> element : json.entrySet()) { - String name = element.getKey(); - JsonElement value = element.getValue(); - if (value.isJsonObject()) { - Optional<Class<?>> innerClass = Arrays.stream(clazz.getClasses()).filter(aClass -> aClass.getSimpleName().equals(name)).findFirst(); - if (innerClass.isPresent()) { - deserializePart(value.getAsJsonObject(), innerClass.get()); - continue; - } - } - try { - Field field = null; - for (Field f : fields) { - if (f.getName().equals(name)) { - field = f; - break; - } - } - if (field != null) { - TypeAdapter<?> adapter = gson.getAdapter(field.getType()); - Object object = adapter.fromJsonTree(value); - field.setAccessible(true); - field.set(instance, object); - } else { - System.out.println("Could not deserialize " + name + " in class " + clazz.getSimpleName()); - } - } catch (Exception ignored) { - System.out.println("Could not deserialize " + name + " in class " + clazz.getSimpleName()); - } - } + protected GsonBuilder addGsonOptions(GsonBuilder builder) { + return builder + .registerTypeAdapter(this.getClass(), new InstanceSupplier<>(this)) + .excludeFieldsWithModifiers(Modifier.TRANSIENT) + .setPrettyPrinting(); } /** @@ -269,7 +224,7 @@ public class Config { * @param option The name of the field, or if the field is in a page "pageName.fieldName" * @param condition The condition that has to be met for the option to be enabled */ - protected void addDependency(String option, Supplier<Boolean> condition) { + protected final void addDependency(String option, Supplier<Boolean> condition) { if (!optionNames.containsKey(option)) return; optionNames.get(option).addDependency(condition); } @@ -280,7 +235,7 @@ public class Config { * @param option The name of the field, or if the field is in a page "pageName.fieldName" * @param dependentOption The option that has to be enabled */ - protected void addDependency(String option, String dependentOption) { + protected final void addDependency(String option, String dependentOption) { if (!optionNames.containsKey(option) || !optionNames.containsKey(dependentOption)) return; optionNames.get(option).addDependency(() -> { try { @@ -297,7 +252,7 @@ public class Config { * @param option The name of the field, or if the field is in a page "pageName.fieldName" * @param value The value of the dependency */ - protected void addDependency(String option, boolean value) { + protected final void addDependency(String option, boolean value) { if (!optionNames.containsKey(option)) return; optionNames.get(option).addDependency(() -> value); } @@ -308,7 +263,7 @@ public class Config { * @param option The name of the field, or if the field is in a page "pageName.fieldName" * @param condition The condition that has to be met for the option to be hidden */ - protected void hideIf(String option, Supplier<Boolean> condition) { + protected final void hideIf(String option, Supplier<Boolean> condition) { if (!optionNames.containsKey(option)) return; optionNames.get(option).addHideCondition(condition); } @@ -319,7 +274,7 @@ public class Config { * @param option The name of the field, or if the field is in a page "pageName.fieldName" * @param dependentOption The option that has to be hidden */ - protected void hideIf(String option, String dependentOption) { + protected final void hideIf(String option, String dependentOption) { if (!optionNames.containsKey(option) || !optionNames.containsKey(dependentOption)) return; optionNames.get(option).addHideCondition(() -> { try { @@ -336,7 +291,7 @@ public class Config { * @param option The name of the field, or if the field is in a page "pageName.fieldName" * @param value The value of the condition */ - protected void hideIf(String option, boolean value) { + protected final void hideIf(String option, boolean value) { if (!optionNames.containsKey(option)) return; optionNames.get(option).addHideCondition(() -> value); } @@ -347,7 +302,7 @@ public class Config { * @param option The name of the field, or if the field is in a page "pageName.fieldName" * @param runnable What should be executed after the option is changed */ - protected void addListener(String option, Runnable runnable) { + protected final void addListener(String option, Runnable runnable) { if (!optionNames.containsKey(option)) return; optionNames.get(option).addListener(runnable); } @@ -358,7 +313,7 @@ public class Config { * @param keyBind The keybind * @param runnable The code to be executed */ - protected void registerKeyBind(OneKeyBind keyBind, Runnable runnable) { + protected final void registerKeyBind(OneKeyBind keyBind, Runnable runnable) { Field field = null; Object instance = null; for (BasicOption option : optionNames.values()) { @@ -379,23 +334,6 @@ public class Config { } /** - * @param field The field to get the default value from - * @return The default value of the given field - */ - public Object getDefault(Field field) { - return defaults.get(field); - } - - /** - * Reset this config file to its defaults. - */ - public void reset() { - for (BasicOption option : optionNames.values()) { - option.reset(this); - } - } - - /** * @return If this mod supports profiles, false for compatibility mode */ public boolean supportsProfiles() { diff --git a/src/main/java/cc/polyfrost/oneconfig/config/elements/BasicOption.java b/src/main/java/cc/polyfrost/oneconfig/config/elements/BasicOption.java index 82d8b31..3394c52 100644 --- a/src/main/java/cc/polyfrost/oneconfig/config/elements/BasicOption.java +++ b/src/main/java/cc/polyfrost/oneconfig/config/elements/BasicOption.java @@ -102,7 +102,7 @@ public abstract class BasicOption { * @param x x position * @param y y position */ - public void drawLast(long vg, int x, int y , InputHandler inputHandler) { + public void drawLast(long vg, int x, int y, InputHandler inputHandler) { } /** @@ -115,20 +115,6 @@ public abstract class BasicOption { } /** - * Reset the field to its default value - * - * @param config The config the field is in - */ - public void reset(Config config) { - Object object = config.getDefault(field); - if (object == null) return; - try { - set(object); - } catch (IllegalAccessException ignored) { - } - } - - /** * @return If the option is enabled, based on the dependencies */ public boolean isEnabled() { diff --git a/src/main/java/cc/polyfrost/oneconfig/config/elements/OptionCategory.java b/src/main/java/cc/polyfrost/oneconfig/config/elements/OptionCategory.java index d3da143..4daefca 100644 --- a/src/main/java/cc/polyfrost/oneconfig/config/elements/OptionCategory.java +++ b/src/main/java/cc/polyfrost/oneconfig/config/elements/OptionCategory.java @@ -32,10 +32,4 @@ import java.util.ArrayList; public class OptionCategory { public final ArrayList<OptionSubcategory> subcategories = new ArrayList<>(); - - public void reset(Config config) { - for (OptionSubcategory subcategory : subcategories) { - subcategory.reset(config); - } - } } diff --git a/src/main/java/cc/polyfrost/oneconfig/config/elements/OptionPage.java b/src/main/java/cc/polyfrost/oneconfig/config/elements/OptionPage.java index 9ac7c14..7a1dfb0 100644 --- a/src/main/java/cc/polyfrost/oneconfig/config/elements/OptionPage.java +++ b/src/main/java/cc/polyfrost/oneconfig/config/elements/OptionPage.java @@ -40,10 +40,4 @@ public class OptionPage { this.name = name; this.mod = mod; } - - public void reset(Config config) { - for (OptionCategory subcategory : categories.values()) { - subcategory.reset(config); - } - } } diff --git a/src/main/java/cc/polyfrost/oneconfig/config/elements/OptionSubcategory.java b/src/main/java/cc/polyfrost/oneconfig/config/elements/OptionSubcategory.java index 282f30f..08c59b8 100644 --- a/src/main/java/cc/polyfrost/oneconfig/config/elements/OptionSubcategory.java +++ b/src/main/java/cc/polyfrost/oneconfig/config/elements/OptionSubcategory.java @@ -132,10 +132,4 @@ public class OptionSubcategory { public String getName() { return name; } - - public void reset(Config config) { - for (BasicOption option : options) { - options.remove(config); - } - } } diff --git a/src/main/java/cc/polyfrost/oneconfig/config/gson/InstanceSupplier.java b/src/main/java/cc/polyfrost/oneconfig/config/gson/InstanceSupplier.java new file mode 100644 index 0000000..f20b527 --- /dev/null +++ b/src/main/java/cc/polyfrost/oneconfig/config/gson/InstanceSupplier.java @@ -0,0 +1,44 @@ +/* + * This file is part of OneConfig. + * OneConfig - Next Generation Config Library for Minecraft: Java Edition + * Copyright (C) 2021, 2022 Polyfrost. + * <https://polyfrost.cc> <https://github.com/Polyfrost/> + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * OneConfig is licensed under the terms of version 3 of the GNU Lesser + * General Public License as published by the Free Software Foundation, AND + * under the Additional Terms Applicable to OneConfig, as published by Polyfrost, + * either version 1.0 of the Additional Terms, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License. If not, see <https://www.gnu.org/licenses/>. You should + * have also received a copy of the Additional Terms Applicable + * to OneConfig, as published by Polyfrost. If not, see + * <https://polyfrost.cc/legal/oneconfig/additional-terms> + */ + +package cc.polyfrost.oneconfig.config.gson; + +import com.google.gson.InstanceCreator; + +import java.lang.reflect.Type; + +public class InstanceSupplier<T> implements InstanceCreator<T> { + private final T instance; + + public InstanceSupplier(T instance) { + this.instance = instance; + } + + @Override + public T createInstance(Type type) { + return instance; + } +}
\ No newline at end of file diff --git a/src/main/java/cc/polyfrost/oneconfig/config/gson/gsoninterface/GsonContext.java b/src/main/java/cc/polyfrost/oneconfig/config/gson/gsoninterface/GsonContext.java deleted file mode 100644 index e27a362..0000000 --- a/src/main/java/cc/polyfrost/oneconfig/config/gson/gsoninterface/GsonContext.java +++ /dev/null @@ -1,123 +0,0 @@ -package cc.polyfrost.oneconfig.config.gson.gsoninterface; - -/* - * This file is part of OneConfig. - * OneConfig - Next Generation Config Library for Minecraft: Java Edition - * Copyright (C) 2021, 2022 Polyfrost. - * - * <https://polyfrost.cc> <https://github.com/Polyfrost/> - * - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * OneConfig is licensed under the terms of version 3 of the GNU Lesser - * General Public License as published by the Free Software Foundation, AND - * under the Additional Terms Applicable to OneConfig, as published by Polyfrost, - * either version 1.0 of the Additional Terms, or (at your option) any later - * version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License. If not, see <https://www.gnu.org/licenses/>. You should - * have also received a copy of the Additional Terms Applicable - * to OneConfig, as published by Polyfrost. If not, see - * <https://polyfrost.cc/legal/oneconfig/additional-terms> - - * This file contains an adaptation of code from gson-interface - * Project found at <https://github.com/mintern/gson-interface> - * For the avoidance of doubt, this file is still licensed under the terms - * of OneConfig's Licensing. - * - * LICENSE NOTICE FOR ADAPTED CODE - * - * Copyright (C) 2012, Brandon Mintern, EasyESI, Berkeley, CA - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither gson-interface nor the names of its contributors may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BRANDON MINTERN OR EASYESI BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -import com.google.gson.Gson; -import com.google.gson.JsonElement; -import com.google.gson.JsonIOException; -import com.google.gson.TypeAdapter; -import com.google.gson.internal.bind.JsonTreeReader; -import com.google.gson.internal.bind.JsonTreeWriter; - -import java.io.IOException; -import java.lang.reflect.Type; - -/** - * @author mintern - */ -public class GsonContext<T> { - private final Gson gson; - private final InterfaceAdapterFactory.InterfaceTypeAdapter<T> constructingAdapter; - - public GsonContext(Gson g, InterfaceAdapterFactory.InterfaceTypeAdapter<T> ita) { - gson = g; - constructingAdapter = ita; - } - - public JsonElement toJsonTree(Object obj) { - return gson.toJsonTree(obj); - } - - public JsonElement thisToJsonTree(T obj) throws JsonIOException { - JsonTreeWriter writer = new JsonTreeWriter(); - try { - constructingAdapter.getDelegate().write(writer, obj); - } catch (IOException e) { - throw new JsonIOException(e); - } - return writer.get(); - } - - public <C> C fromJsonTree(JsonElement json, Class<C> type) { - return gson.fromJson(json, type); - } - - public <C> C fromJsonTree(JsonElement json, Type typeOfC) { - return (C) gson.fromJson(json, typeOfC); - } - - public T thisFromJsonTree(JsonElement json) throws JsonIOException { - try { - return constructingAdapter.getDelegate().read(new JsonTreeReader(json)); - } catch (IOException e) { - throw new JsonIOException(e); - } - } - - public <C extends T> C thisFromJsonTree(JsonElement json, Type typeOfC) { - TypeAdapter<C> adapter = constructingAdapter.getNextAdapter(typeOfC); - try { - return adapter.read(new JsonTreeReader(json)); - } catch (IOException e) { - throw new JsonIOException(e); - } - } -} diff --git a/src/main/java/cc/polyfrost/oneconfig/config/gson/gsoninterface/InterfaceAdapterFactory.java b/src/main/java/cc/polyfrost/oneconfig/config/gson/gsoninterface/InterfaceAdapterFactory.java deleted file mode 100644 index 8f7d9d6..0000000 --- a/src/main/java/cc/polyfrost/oneconfig/config/gson/gsoninterface/InterfaceAdapterFactory.java +++ /dev/null @@ -1,192 +0,0 @@ -package cc.polyfrost.oneconfig.config.gson.gsoninterface; - -/* - * This file is part of OneConfig. - * OneConfig - Next Generation Config Library for Minecraft: Java Edition - * Copyright (C) 2021, 2022 Polyfrost. - * - * <https://polyfrost.cc> <https://github.com/Polyfrost/> - * - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * OneConfig is licensed under the terms of version 3 of the GNU Lesser - * General Public License as published by the Free Software Foundation, AND - * under the Additional Terms Applicable to OneConfig, as published by Polyfrost, - * either version 1.0 of the Additional Terms, or (at your option) any later - * version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License. If not, see <https://www.gnu.org/licenses/>. You should - * have also received a copy of the Additional Terms Applicable - * to OneConfig, as published by Polyfrost. If not, see - * <https://polyfrost.cc/legal/oneconfig/additional-terms> - - * This file contains an adaptation of code from gson-interface - * Project found at <https://github.com/mintern/gson-interface> - * For the avoidance of doubt, this file is still licensed under the terms - * of OneConfig's Licensing. - * - * LICENSE NOTICE FOR ADAPTED CODE - * - * Copyright (C) 2012, Brandon Mintern, EasyESI, Berkeley, CA - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither gson-interface nor the names of its contributors may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BRANDON MINTERN OR EASYESI BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -import com.google.gson.*; -import com.google.gson.internal.Streams; -import com.google.gson.reflect.TypeToken; -import com.google.gson.stream.JsonReader; -import com.google.gson.stream.JsonWriter; - -import java.io.IOException; -import java.lang.reflect.Constructor; -import java.lang.reflect.Type; -import java.util.HashMap; -import java.util.Map; - -/** - * @author mintern - */ -public class InterfaceAdapterFactory implements TypeAdapterFactory { - @Override - public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> tt) { - Class<T> rawType = Reflection.classOfType(tt.getRawType()); - boolean serializes = JsonSerialization.class.isAssignableFrom(rawType); - Constructor<JsonDeserializes<T>> deserializerConstructor = null; - Class<JsonDeserializes<T>>[] typeParameters = Reflection.getTypeParameters(rawType, JsonDeserialization.class); - if (typeParameters != null) { - deserializerConstructor = Reflection.getConstructor(typeParameters[0]); - } - if (serializes || deserializerConstructor != null) { - return new InterfaceTypeAdapter(serializes, deserializerConstructor, gson, tt, this); - } - return null; - } - - public static class InterfaceTypeAdapter<T> extends TypeAdapter<T> { - // This map ensures that only one deserializer of each type exists. - private static final Map<Class, JsonDeserializes<?>> deserializerInstances = new HashMap(); - - // Fields set in the constructor - private final boolean selfSerializing; - private final Constructor<JsonDeserializes<T>> deserializerConstructor; - private final Gson gson; - private final TypeToken<T> typeToken; - private final TypeAdapterFactory thisFactory; - - // Adapters that follow this one in the chain for the indicated type - private final Map<Type, TypeAdapter> nextAdapters = new HashMap(); - - // Lazily-initialized fields. Call their corresponding getters in - // order to access them. - private TypeAdapter<T> delegate; - private GsonContext gsonContext; - - private InterfaceTypeAdapter( - boolean serializes, - Constructor<JsonDeserializes<T>> dsc, - Gson g, - TypeToken<T> tt, - TypeAdapterFactory factory) { - selfSerializing = serializes; - if (dsc != null) { - dsc.setAccessible(true); - } - deserializerConstructor = dsc; - gson = g; - typeToken = tt; - thisFactory = factory; - } - - @Override - public void write(JsonWriter writer, T value) throws IOException { - if (!selfSerializing) { - getDelegate().write(writer, value); - } else if (value == null) { - writer.nullValue(); - } else { - JsonElement tree = ((JsonSerialization) value).toJsonTree(gsonContext()); - Streams.write(tree, writer); - } - } - - @Override - public T read(JsonReader reader) throws IOException { - if (deserializerConstructor == null) { - return getDelegate().read(reader); - } - JsonElement json = Streams.parse(reader); - if (json.isJsonNull()) { - return null; - } - return (T) deserializer().fromJsonTree(json, typeToken.getType(), gsonContext()); - } - - synchronized TypeAdapter<T> getDelegate() { - if (delegate == null) { - delegate = gson.getDelegateAdapter(thisFactory, typeToken); - } - return delegate; - } - - private synchronized GsonContext gsonContext() { - if (gsonContext == null) { - gsonContext = new GsonContext(gson, this); - } - return gsonContext; - } - - synchronized <C extends T> TypeAdapter<C> getNextAdapter(Type typeOfC) { - TypeAdapter<C> nextAdapter = nextAdapters.get(typeOfC); - if (nextAdapter == null) { - nextAdapter = gson.getDelegateAdapter(thisFactory, (TypeToken<C>) TypeToken.get(typeOfC)); - nextAdapters.put(typeOfC, nextAdapter); - } - return nextAdapter; - } - - private JsonDeserializes<T> deserializer() { - synchronized (deserializerInstances) { - Class<JsonDeserializes<T>> c = deserializerConstructor.getDeclaringClass(); - JsonDeserializes<T> deserializer = (JsonDeserializes<T>) deserializerInstances.get(c); - if (deserializer == null) { - try { - deserializer = deserializerConstructor.newInstance(); - } catch (Exception e) { - throw new JsonParseException(e); - } - deserializerInstances.put(c, deserializer); - } - return deserializer; - } - } - } -} diff --git a/src/main/java/cc/polyfrost/oneconfig/config/gson/gsoninterface/JsonDeserialization.java b/src/main/java/cc/polyfrost/oneconfig/config/gson/gsoninterface/JsonDeserialization.java deleted file mode 100644 index 436d897..0000000 --- a/src/main/java/cc/polyfrost/oneconfig/config/gson/gsoninterface/JsonDeserialization.java +++ /dev/null @@ -1,63 +0,0 @@ -package cc.polyfrost.oneconfig.config.gson.gsoninterface; - -/* - * This file is part of OneConfig. - * OneConfig - Next Generation Config Library for Minecraft: Java Edition - * Copyright (C) 2021, 2022 Polyfrost. - * - * <https://polyfrost.cc> <https://github.com/Polyfrost/> - * - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * OneConfig is licensed under the terms of version 3 of the GNU Lesser - * General Public License as published by the Free Software Foundation, AND - * under the Additional Terms Applicable to OneConfig, as published by Polyfrost, - * either version 1.0 of the Additional Terms, or (at your option) any later - * version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License. If not, see <https://www.gnu.org/licenses/>. You should - * have also received a copy of the Additional Terms Applicable - * to OneConfig, as published by Polyfrost. If not, see - * <https://polyfrost.cc/legal/oneconfig/additional-terms> - - * This file contains an adaptation of code from gson-interface - * Project found at <https://github.com/mintern/gson-interface> - * For the avoidance of doubt, this file is still licensed under the terms - * of OneConfig's Licensing. - * - * LICENSE NOTICE FOR ADAPTED CODE - * - * Copyright (C) 2012, Brandon Mintern, EasyESI, Berkeley, CA - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither gson-interface nor the names of its contributors may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BRANDON MINTERN OR EASYESI BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ -public interface JsonDeserialization<D extends JsonDeserializes<? extends JsonDeserialization<D>>> { -} diff --git a/src/main/java/cc/polyfrost/oneconfig/config/gson/gsoninterface/JsonDeserializes.java b/src/main/java/cc/polyfrost/oneconfig/config/gson/gsoninterface/JsonDeserializes.java deleted file mode 100644 index ecdf8e5..0000000 --- a/src/main/java/cc/polyfrost/oneconfig/config/gson/gsoninterface/JsonDeserializes.java +++ /dev/null @@ -1,72 +0,0 @@ -package cc.polyfrost.oneconfig.config.gson.gsoninterface; - -/* - * This file is part of OneConfig. - * OneConfig - Next Generation Config Library for Minecraft: Java Edition - * Copyright (C) 2021, 2022 Polyfrost. - * - * <https://polyfrost.cc> <https://github.com/Polyfrost/> - * - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * OneConfig is licensed under the terms of version 3 of the GNU Lesser - * General Public License as published by the Free Software Foundation, AND - * under the Additional Terms Applicable to OneConfig, as published by Polyfrost, - * either version 1.0 of the Additional Terms, or (at your option) any later - * version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License. If not, see <https://www.gnu.org/licenses/>. You should - * have also received a copy of the Additional Terms Applicable - * to OneConfig, as published by Polyfrost. If not, see - * <https://polyfrost.cc/legal/oneconfig/additional-terms> - - * This file contains an adaptation of code from gson-interface - * Project found at <https://github.com/mintern/gson-interface> - * For the avoidance of doubt, this file is still licensed under the terms - * of OneConfig's Licensing. - * - * LICENSE NOTICE FOR ADAPTED CODE - * - * Copyright (C) 2012, Brandon Mintern, EasyESI, Berkeley, CA - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither gson-interface nor the names of its contributors may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BRANDON MINTERN OR EASYESI BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -import com.google.gson.JsonElement; - -import java.lang.reflect.Type; - -/** - * @author mintern - */ -public interface JsonDeserializes<T> { - T fromJsonTree(JsonElement json, Type type, GsonContext<T> context); -} diff --git a/src/main/java/cc/polyfrost/oneconfig/config/gson/gsoninterface/JsonSerialization.java b/src/main/java/cc/polyfrost/oneconfig/config/gson/gsoninterface/JsonSerialization.java deleted file mode 100644 index 3cae64d..0000000 --- a/src/main/java/cc/polyfrost/oneconfig/config/gson/gsoninterface/JsonSerialization.java +++ /dev/null @@ -1,70 +0,0 @@ -package cc.polyfrost.oneconfig.config.gson.gsoninterface; - -/* - * This file is part of OneConfig. - * OneConfig - Next Generation Config Library for Minecraft: Java Edition - * Copyright (C) 2021, 2022 Polyfrost. - * - * <https://polyfrost.cc> <https://github.com/Polyfrost/> - * - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * OneConfig is licensed under the terms of version 3 of the GNU Lesser - * General Public License as published by the Free Software Foundation, AND - * under the Additional Terms Applicable to OneConfig, as published by Polyfrost, - * either version 1.0 of the Additional Terms, or (at your option) any later - * version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License. If not, see <https://www.gnu.org/licenses/>. You should - * have also received a copy of the Additional Terms Applicable - * to OneConfig, as published by Polyfrost. If not, see - * <https://polyfrost.cc/legal/oneconfig/additional-terms> - - * This file contains an adaptation of code from gson-interface - * Project found at <https://github.com/mintern/gson-interface> - * For the avoidance of doubt, this file is still licensed under the terms - * of OneConfig's Licensing. - * - * LICENSE NOTICE FOR ADAPTED CODE - * - * Copyright (C) 2012, Brandon Mintern, EasyESI, Berkeley, CA - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither gson-interface nor the names of its contributors may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BRANDON MINTERN OR EASYESI BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -import com.google.gson.JsonElement; - -/** - * @author mintern - */ -public interface JsonSerialization<T extends JsonSerialization<T>> { - public JsonElement toJsonTree(GsonContext<T> context); -} diff --git a/src/main/java/cc/polyfrost/oneconfig/config/gson/gsoninterface/Reflection.java b/src/main/java/cc/polyfrost/oneconfig/config/gson/gsoninterface/Reflection.java deleted file mode 100644 index ee50b64..0000000 --- a/src/main/java/cc/polyfrost/oneconfig/config/gson/gsoninterface/Reflection.java +++ /dev/null @@ -1,513 +0,0 @@ -package cc.polyfrost.oneconfig.config.gson.gsoninterface; - -/* - * This file is part of OneConfig. - * OneConfig - Next Generation Config Library for Minecraft: Java Edition - * Copyright (C) 2021, 2022 Polyfrost. - * - * <https://polyfrost.cc> <https://github.com/Polyfrost/> - * - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * OneConfig is licensed under the terms of version 3 of the GNU Lesser - * General Public License as published by the Free Software Foundation, AND - * under the Additional Terms Applicable to OneConfig, as published by Polyfrost, - * either version 1.0 of the Additional Terms, or (at your option) any later - * version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License. If not, see <https://www.gnu.org/licenses/>. You should - * have also received a copy of the Additional Terms Applicable - * to OneConfig, as published by Polyfrost. If not, see - * <https://polyfrost.cc/legal/oneconfig/additional-terms> - - * This file contains an adaptation of code from gson-interface - * Project found at <https://github.com/mintern/gson-interface> - * For the avoidance of doubt, this file is still licensed under the terms - * of OneConfig's Licensing. - * - * LICENSE NOTICE FOR ADAPTED CODE - * - * Copyright (C) 2012, Brandon Mintern, EasyESI, Berkeley, CA - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither gson-interface nor the names of its contributors may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BRANDON MINTERN OR EASYESI BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -import java.lang.reflect.*; -import java.util.ArrayList; -import java.util.EmptyStackException; - -/** - * Provides various static helper methods that add a high-level interface to - * introspection and reflection. - * - * @author mintern - */ -public class Reflection { - /** - * A wrapper for Class.newInstance() that throws an unchecked Exception. - * It also ensures that even private constructors can be called. - * - * @param c the class on which to call newInstance() - * @return the object returned from c.newInstance() - * @throws IllegalArgumentException if there was an exception - * constructing the instance - */ - public static <T> T newInstance(Class<T> c) { - try { - return constructAnyway(c.getDeclaredConstructor()); - } catch (Exception e) { - throw new IllegalArgumentException(e); - } - } - - /** - * Gets the aClass constructor with the given paramaters, throwing an - * unchecked exception in the case of errors. - * - * @param aClass the class whose constructor should be fetched. - * @param params the parameters to the desired constructor - * @return the constructor for aClass that accepts params, or null if - * there is no such constructor - */ - public static <T> Constructor<T> getConstructor(Class<T> aClass, Class... params) { - try { - return aClass.getDeclaredConstructor(params); - } catch (Exception e) { - return null; - } - } - - /** - * Invokes the given constructor with the given args even if it's not - * accessible. - * - * @param <T> the type of value to be constructed - * @param constructor the constructor to invoke (see getConstructor) - * @param args the args to send to the constructor - * @return a new instance of type T - * @throws IllegalArgumentException if there was an exception while - * setting the constructor to be accessible or invoking it - */ - public static <T> T constructAnyway(Constructor<T> constructor, Object... args) - throws IllegalArgumentException { - try { - boolean wasAccessible = constructor.isAccessible(); - constructor.setAccessible(true); - try { - T instance = constructor.newInstance(args); - return instance; - } finally { - constructor.setAccessible(wasAccessible); - } - } catch (Exception e) { - throw new IllegalArgumentException(e); - } - } - - /** - * Checks whether a class is abstract. - * - * @param c the class to check - * @return true iff c is an interface or abstract class - */ - public static boolean isAbstract(Class c) { - return c.isInterface() || Modifier.isAbstract(c.getModifiers()); - } - - /** - * Obtain the value of a field even if it is not public. - * - * @param field the field value to obtain - * @param fieldObj an instantiated object which defines field - * @return the value of field in fieldObj - * @throws IllegalArgumentException on any error - */ - public static Object getFieldValue(Field field, Object fieldObj) - throws IllegalArgumentException { - try { - boolean wasAccessible = field.isAccessible(); - field.setAccessible(true); - try { - return field.get(fieldObj); - } finally { - field.setAccessible(wasAccessible); - } - } catch (IllegalAccessException e) { - throw new IllegalArgumentException(e); - } - } - - /** - * Returns a field on which field.get(...) can be called, even if the field - * is private. - * - * @param aClass the class defining the desired field - * @param fieldName the name of the desired field - * @return a field that is accessible regardless of its modifiers - * @throws IllegalArgumentException on any error - */ - public static Field getAccessibleField(Class aClass, String fieldName) - throws IllegalArgumentException { - try { - Field field = aClass.getDeclaredField(fieldName); - field.setAccessible(true); - return field; - } catch (Exception e) { - // NoSuchFieldException, SecurityException - throw new IllegalArgumentException(e); - } - } - - /** - * For a class implClass that instantiates a generic class or interface - * genClass, return the types that genClass is instantiated with. This - * method has a runtime linear in the size of the type hierarchy, so if - * the results are used at runtime, it is recommended to cache them. - * <p> - * An example of its usage: - * <p> - * import java.util.*; - * public class IdToNameMap extends HashMap<Integer, String> { - * public static void main (String[] args) { - * for (Class c: getTypeParameters(IdToNameMap.class, Map.class) { - * System.out.println(c); - * } - * } - * } - * <p> - * Calling main() would print out: - * <p> - * Integer.class - * String.class - * <p> - * Note that this method ascends and descends the class hierarchy to - * determine the best bounds possible on all type parameters. For - * example, even if the class hierarchy is: - * <p> - * public class IdMap<V> extends HashMap<Integer, V> {} - * public class IdToNameMap extends IdMap<String> {} - * <p> - * the main() call would print the same thing. For type parameters that - * remain unbounded, the tightest bound available is printed. So: - * <p> - * getTypeParameters(EnumSet.class, Set.class) - * <p> - * would return Enum.class. Sometimes the tightest bound available is - * Object.class. - * <p> - * This method should NOT be called with implClass or genClass as a - * primitive class. This is not sensible, anyway. - * - * @param implClass a class instantiating a generic class or interface - * @param genClass the generic class or interface which has type - * parameters you want to know - * @return the array of instantiated parameters. If implClass does not - * extend or implement genClass, null is returned. For any genClass - * type parameters not instantiated by implClass, we return the - * parameters' upper bounds. - */ - public static Class[] getTypeParameters(Class implClass, Class genClass) { - return getTypeParameters(implClass, genClass, new Stack()); - } - - /** - * @param genClass typically a Class with generic type parameters - * @return the array of Class bounds on those parameters, or an empty - * Class array if genClass is not generic. - */ - public static Class[] getParameterBounds(Class genClass) { - Type[] parameters = genClass.getTypeParameters(); - Class[] paramClasses = new Class[parameters.length]; - for (int i = 0; i < parameters.length; i++) { - paramClasses[i] = classOfType(parameters[i]); - } - return paramClasses; - } - - /** - * @param type any Type object - * @return the most specific class of type that we can determine - */ - public static Class classOfType(Type type) { - if (type instanceof Class) { - return (Class) type; - } else if (type instanceof ParameterizedType) { - return classOfType(((ParameterizedType) type).getRawType()); - } else if (type instanceof TypeVariable) { - return classOfType(((TypeVariable) type).getBounds()[0]); - } else if (type instanceof WildcardType) { - return classOfType(((WildcardType) type).getUpperBounds()[0]); - } else { - // this should never happen in principle, but just in case... - return Object.class; - } - } - - // Internal helper methods used above. - - /** - * See public ... getTypeParameters. This method and the others below - * that implement it work by ascending and descending the type hierarchy - * in order to gather the desired information. As we ascend the type - * hierarchy looking for genClass, we push the classes that have led us - * there onto classStack. Later, if we find genClass but the associated - * implClass is generic, we descend the classStack to figure out how - * implClass is instantiated. Eventually, each type parameter is either - * fully instantiated, in which case we use the instantiation class, or - * the type parameter is not instantiated, in which case we return its - * upper bound, which in some cases will be Object.class. @param - * implClass the class extending/implementing genClass @param genClass - * a class with generic type parameters - * - * @param classStack the stack of subclasses we've visited before - * reaching this implClass - * @return the tightest bounds implClass places on those type - * parameters - */ - private static Class[] getTypeParameters(Class implClass, Class genClass, Stack<Class> classStack) { - if (genClass.isInterface()) { - return getInterfaceParameters(implClass, genClass, classStack); - } - return getSuperParameters(implClass, genClass, classStack); - } - - /** - * This method implements getTypeParameters when genClass is an - * interface. Since a class can implement multiple interfaces and since - * they must be retrieved differently than with a superclass, we keep - * the functions separate. - * <p> - * At each level, we check each interface against genClass. If none of - * them match, we look at any interface's implemented interfaces, and so - * on all the way up until we reach an interface with no implemented - * interfaces. - * <p> - * If we still haven't found genClass at this point, we ascend into - * implClass's superclass and perform the same work. - * <p> - * As mentioned in private ... getTypeParameters, any time we ascend the - * type hierarchy, we push the implClass onto the classStack so that we - * can later descend the class hierarchy to resolve type parameters - * which are set further down the tree. - */ - private static Class[] getInterfaceParameters(Class implClass, Class genClass, Stack<Class> classStack) { - Type[] interfaces = implClass.getGenericInterfaces(); - // Check each of the interfaces implemented by implClass to see if - // one matches genClass. - for (Type iface : interfaces) { - Class[] result = getParametersIfMatches(iface, implClass, genClass, classStack); - if (result != null) { - // We found it. - return result; - } - } - // None of the implemented interfaces matched genClass. Ascend each - // interface's type hierarchy looking for genClass. - for (Type iface : interfaces) { - Class interfaceClass = classOfType(iface); - classStack.push(implClass); - Class[] result = getInterfaceParameters(interfaceClass, genClass, classStack); - classStack.pop(); - if (result != null) { - return result; - } - } - // We visited the entire interface hierarchy of implClass. Ascend to - // implClass's superclass and look for the interface there. - Class superclass = implClass.getSuperclass(); - if (superclass == null) { - // implClass is an interface or Object, so it has no superclass. - // We didn't find genClass along this path. - return null; - } - // The ascent. - classStack.push(implClass); - Class[] result = getInterfaceParameters(superclass, genClass, classStack); - classStack.pop(); - // The result may still be null at this point, but we've visited the - // entire type hierarchy and haven't found genClass. In these cases, we - // want to return null, anyway. - return result; - } - - /** - * This method implements getTypeParameters when genClass is not an - * interface, and therefore should be found as a superclass of - * implClass. Since a class can only have one superclass, we simply - * check that superclass and then ascend the type hierarchy if it is not - * a match. - */ - private static Class[] getSuperParameters(Class implClass, Class genClass, Stack<Class> classStack) { - Type supertype = implClass.getGenericSuperclass(); - if (supertype == null) { - // Base case; implClass is Object; we didn't find genClass. - return null; - } - Class[] result = getParametersIfMatches(supertype, implClass, genClass, classStack); - if (result != null) { - // We found it. - return result; - } - // The superclass of implClass didn't match genClass. Ascend class - // hierarchy. - classStack.push(implClass); - result = getSuperParameters(classOfType(supertype), genClass, classStack); - classStack.pop(); - // We either have our result or null. Return. - return result; - } - - /** - * If the Class represented by type matches genClass, return the - * genClass type parameters. If it is not a match, returns null. - * - * @param type the type being considered, with all information present - * in implClass - * @param implClass the current class, for which type was a superclass - * or an implemented interface - * @param genClass the class we are looking for (to be compared against - * type) - * @param classStack - * @return null if type is not of Class genClass, genClass - * instantiated type parameters otherwise. Class[0] if genClasses has - * no type parameters - */ - private static Class[] getParametersIfMatches(Type type, Class implClass, Class genClass, Stack<Class> classStack) { - if (type == genClass) { - // type matches genClass and it's a Class Type; if genClass has - // type parameters, they have not been instantiated by - // implClass. Simply return the bounds on genClass's - // parameters, if it has any parameters. If it doesn't have - // parameters, we'll return Class[0] - return getParameterBounds(genClass); - } - if (type instanceof ParameterizedType && classOfType(type) == genClass) { - // We've found our parameterized genClass. For each type, - // convert it to its corresponding class. If it's a TypeVariable - // and it matches a type argument in implClass, descend down the - // classStack to determine THAT parameter type. Otherwise, or - // if the TypeVariable can't be resolved, simply perform a dumb - // conversion on the type. - Type[] types = ((ParameterizedType) type).getActualTypeArguments(); - Class[] classes = new Class[types.length]; - // The following two types declared here to avoid repeated work - Type[] implParams = null; - Class[] implInstantiatedParams = null; - // This loop is probably the most complex bit in the code. An - // instructive example is where we have a class hierarchy like: - // IdNameMap extends IdMap<String> - // IdMap<E> extends HashMap<Integer, E> - // getTypeParameters(IdNameMap.class, HashMap.class) - // When we reach this point: - // types = [Integer, E] - // implClass = IdMap - // classes = [] - // classStack = [IdNameMap] - // The outer loop iterates over types. After its first iteration - // (for which the if-test fails), classes=[Integer]. In the - // second iteration, E is a TypeVariable and the classStack is - // not empty. We fetch IdMap's TypeParameters: - // implParams = [E] - // The inner loop iterates over implParams, finding that when j - // = 0, implParams[j] matches types[i] (both are E). We then - // call getTypeParameters(IdNameMap, IdMap, []) to determine the - // type of E, which turns out to be String: - // implInstantiatedParams = [String] - // We update classes: - // classes = [Integer, String] - // and we continue to the next iteration of the outer loop, - // where it turns out to terminate. Finally, we return classes. - types: - for (int i = 0; i < types.length; i++) { - if (types[i] instanceof TypeVariable && !classStack.isEmpty()) { - if (implParams == null) { - implParams = implClass.getTypeParameters(); - } - for (int j = 0; j < implParams.length; j++) { - if (((TypeVariable) types[i]).equals(implParams[j])) { - if (implInstantiatedParams == null) { - Class subClass = classStack.pop(); - // the descent - implInstantiatedParams = getTypeParameters(subClass, implClass, classStack); - classStack.push(subClass); - } - classes[i] = implInstantiatedParams[j]; - continue types; - } - } - // If we reach this point (we were unable to resolve the - // parameter), type[i] will be resolved to its bound in the - // line below. - } - classes[i] = classOfType(types[i]); - } - return classes; - } - // type did not match genClass - return null; - } - - /** - * A non-threadsafe alternative to java.util.Stack. - * Since the Reflection code is single threaded, using this should be - * faster. - * - * @param E the type of elements in the stack - */ - public static class Stack<E> extends ArrayList<E> { - /** - * Push an item onto the stack. The next call to pop() will return - * the most-recently push()ed item. - * - * @param elt the element to add to the stack - * @return this; convenient for chaining: stack.push(...).push(...) - */ - public Stack<E> push(E elt) { - add(elt); - return this; - } - - /** - * Pop from this and return the item that was most recently pushed - * onto this. This should never be called on an empty stack. - * - * @return the item that was pop()ed - * @throws EmptyStackException if this is empty - */ - public E pop() { - try { - return remove(size() - 1); - } catch (IndexOutOfBoundsException e) { - throw new EmptyStackException(); - } - } - } -} diff --git a/src/main/java/cc/polyfrost/oneconfig/internal/config/InternalConfig.java b/src/main/java/cc/polyfrost/oneconfig/internal/config/InternalConfig.java index b3f59ba..0d1ab3e 100644 --- a/src/main/java/cc/polyfrost/oneconfig/internal/config/InternalConfig.java +++ b/src/main/java/cc/polyfrost/oneconfig/internal/config/InternalConfig.java @@ -64,7 +64,7 @@ public abstract class InternalConfig extends Config { @Override public void load() { try (BufferedReader reader = new BufferedReader(new InputStreamReader(Files.newInputStream(Paths.get("OneConfig/" + configFile)), StandardCharsets.UTF_8))) { - deserializePart(JsonUtils.PARSER.parse(reader).getAsJsonObject(), this); + gson.fromJson(reader, this.getClass()); } catch (IOException e) { e.printStackTrace(); } diff --git a/src/main/java/cc/polyfrost/oneconfig/internal/config/compatibility/forge/ForgeCompat.java b/src/main/java/cc/polyfrost/oneconfig/internal/config/compatibility/forge/ForgeCompat.java index 238355e..665a9f3 100644 --- a/src/main/java/cc/polyfrost/oneconfig/internal/config/compatibility/forge/ForgeCompat.java +++ b/src/main/java/cc/polyfrost/oneconfig/internal/config/compatibility/forge/ForgeCompat.java @@ -35,15 +35,6 @@ public class ForgeCompat { } @Override - public Object getDefault(Field field) { - return null; - } - - @Override - public void reset() { - } - - @Override public boolean supportsProfiles() { return false; } |