diff options
author | nea <nea@nea.moe> | 2023-05-25 01:37:03 +0200 |
---|---|---|
committer | nea <nea@nea.moe> | 2023-05-25 01:37:03 +0200 |
commit | f91a246e41042f35f55c7b77ff7c0a3fb67f5937 (patch) | |
tree | 73e780825ded1da745d90180e5f3f885c3cac50d /src/main/java/io | |
parent | dba771fdbd96fa5ab68e9a817429dc3f8411eec8 (diff) | |
download | neurepoparsing-f91a246e41042f35f55c7b77ff7c0a3fb67f5937.tar.gz neurepoparsing-f91a246e41042f35f55c7b77ff7c0a3fb67f5937.tar.bz2 neurepoparsing-f91a246e41042f35f55c7b77ff7c0a3fb67f5937.zip |
Some clean up
Diffstat (limited to 'src/main/java/io')
-rw-r--r-- | src/main/java/io/github/moulberry/repo/NEUConstants.java | 6 | ||||
-rw-r--r-- | src/main/java/io/github/moulberry/repo/NEUItems.java | 5 | ||||
-rw-r--r-- | src/main/java/io/github/moulberry/repo/NEURecipeCache.java | 5 | ||||
-rw-r--r-- | src/main/java/io/github/moulberry/repo/NEURepository.java | 2 | ||||
-rw-r--r-- | src/main/java/io/github/moulberry/repo/constants/EssenceCosts.java | 3 | ||||
-rw-r--r-- | src/main/java/io/github/moulberry/repo/constants/Leveling.java (renamed from src/main/java/io/github/moulberry/repo/Leveling.java) | 2 | ||||
-rw-r--r-- | src/main/java/io/github/moulberry/repo/data/NEUIngredient.java | 3 | ||||
-rw-r--r-- | src/main/java/io/github/moulberry/repo/data/NEUItem.java | 3 | ||||
-rw-r--r-- | src/main/java/io/github/moulberry/repo/util/NEUId.java | 14 | ||||
-rw-r--r-- | src/main/java/io/github/moulberry/repo/vendored/RuntimeTypeAdapterFactory.java | 283 |
10 files changed, 312 insertions, 14 deletions
diff --git a/src/main/java/io/github/moulberry/repo/NEUConstants.java b/src/main/java/io/github/moulberry/repo/NEUConstants.java index de614f7..ba71f9e 100644 --- a/src/main/java/io/github/moulberry/repo/NEUConstants.java +++ b/src/main/java/io/github/moulberry/repo/NEUConstants.java @@ -3,11 +3,7 @@ package io.github.moulberry.repo; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.reflect.TypeToken; -import io.github.moulberry.repo.constants.Parents; -import io.github.moulberry.repo.constants.Bonuses; -import io.github.moulberry.repo.constants.Enchants; -import io.github.moulberry.repo.constants.EssenceCosts; -import io.github.moulberry.repo.constants.FairySouls; +import io.github.moulberry.repo.constants.*; import lombok.Getter; import java.util.List; diff --git a/src/main/java/io/github/moulberry/repo/NEUItems.java b/src/main/java/io/github/moulberry/repo/NEUItems.java index 650e67d..1c958ec 100644 --- a/src/main/java/io/github/moulberry/repo/NEUItems.java +++ b/src/main/java/io/github/moulberry/repo/NEUItems.java @@ -1,6 +1,7 @@ package io.github.moulberry.repo; import io.github.moulberry.repo.data.NEUItem; +import io.github.moulberry.repo.util.NEUId; import io.github.moulberry.repo.util.StreamIt; import lombok.Getter; import org.checkerframework.checker.nullness.qual.Nullable; @@ -13,7 +14,7 @@ import java.util.stream.Stream; public class NEUItems implements IReloadable { @Getter - Map<String, NEUItem> items; + Map<@NEUId String, NEUItem> items; @Override public void reload(NEURepository repository) throws NEURepositoryException { @@ -29,7 +30,7 @@ public class NEUItems implements IReloadable { } @Nullable - public NEUItem getItemBySkyblockId(String itemId) { + public NEUItem getItemBySkyblockId(@NEUId String itemId) { return items.get(itemId.toUpperCase(Locale.ROOT)); } } diff --git a/src/main/java/io/github/moulberry/repo/NEURecipeCache.java b/src/main/java/io/github/moulberry/repo/NEURecipeCache.java index 50e0481..33ec60e 100644 --- a/src/main/java/io/github/moulberry/repo/NEURecipeCache.java +++ b/src/main/java/io/github/moulberry/repo/NEURecipeCache.java @@ -3,6 +3,7 @@ package io.github.moulberry.repo; import io.github.moulberry.repo.data.NEUIngredient; import io.github.moulberry.repo.data.NEUItem; import io.github.moulberry.repo.data.NEURecipe; +import io.github.moulberry.repo.util.NEUId; import lombok.Getter; import java.util.HashMap; @@ -31,9 +32,9 @@ public class NEURecipeCache implements IReloadable { @Getter - Map<String, Set<NEURecipe>> recipes = new HashMap<>(); + Map<@NEUId String, Set<NEURecipe>> recipes = new HashMap<>(); @Getter - Map<String, Set<NEURecipe>> usages = new HashMap<>(); + Map<@NEUId String, Set<NEURecipe>> usages = new HashMap<>(); @Override diff --git a/src/main/java/io/github/moulberry/repo/NEURepository.java b/src/main/java/io/github/moulberry/repo/NEURepository.java index 122ef24..1fbac5f 100644 --- a/src/main/java/io/github/moulberry/repo/NEURepository.java +++ b/src/main/java/io/github/moulberry/repo/NEURepository.java @@ -3,7 +3,7 @@ package io.github.moulberry.repo; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.reflect.TypeToken; -import com.google.gson.typeadapters.RuntimeTypeAdapterFactory; +import io.github.moulberry.repo.vendored.RuntimeTypeAdapterFactory; import io.github.moulberry.repo.data.*; import lombok.Getter; import lombok.NonNull; diff --git a/src/main/java/io/github/moulberry/repo/constants/EssenceCosts.java b/src/main/java/io/github/moulberry/repo/constants/EssenceCosts.java index 2280b13..474b152 100644 --- a/src/main/java/io/github/moulberry/repo/constants/EssenceCosts.java +++ b/src/main/java/io/github/moulberry/repo/constants/EssenceCosts.java @@ -4,6 +4,7 @@ import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import io.github.moulberry.repo.NEURepositoryException; +import io.github.moulberry.repo.util.NEUId; import lombok.Data; import lombok.Getter; @@ -34,7 +35,7 @@ public class EssenceCosts { } @Getter - Map<String, EssenceCost> costs; + Map<@NEUId String, EssenceCost> costs; public EssenceCosts(JsonObject json) throws NEURepositoryException { costs = new HashMap<>(); diff --git a/src/main/java/io/github/moulberry/repo/Leveling.java b/src/main/java/io/github/moulberry/repo/constants/Leveling.java index 093ef43..687b3fc 100644 --- a/src/main/java/io/github/moulberry/repo/Leveling.java +++ b/src/main/java/io/github/moulberry/repo/constants/Leveling.java @@ -1,4 +1,4 @@ -package io.github.moulberry.repo; +package io.github.moulberry.repo.constants; import com.google.gson.annotations.SerializedName; import lombok.Getter; diff --git a/src/main/java/io/github/moulberry/repo/data/NEUIngredient.java b/src/main/java/io/github/moulberry/repo/data/NEUIngredient.java index 9f7d62c..6e86c4d 100644 --- a/src/main/java/io/github/moulberry/repo/data/NEUIngredient.java +++ b/src/main/java/io/github/moulberry/repo/data/NEUIngredient.java @@ -1,13 +1,14 @@ package io.github.moulberry.repo.data; import com.google.gson.*; +import io.github.moulberry.repo.util.NEUId; import lombok.Getter; import java.lang.reflect.Type; @Getter public class NEUIngredient { - String itemId; + @NEUId String itemId; int amount; public static final String NEU_SENTINEL_EMPTY = "NEU_SENTINEL_EMPTY"; public static final NEUIngredient SENTINEL_EMPTY = new NEUIngredient(); diff --git a/src/main/java/io/github/moulberry/repo/data/NEUItem.java b/src/main/java/io/github/moulberry/repo/data/NEUItem.java index 94de529..26e1760 100644 --- a/src/main/java/io/github/moulberry/repo/data/NEUItem.java +++ b/src/main/java/io/github/moulberry/repo/data/NEUItem.java @@ -1,6 +1,7 @@ package io.github.moulberry.repo.data; import com.google.gson.annotations.SerializedName; +import io.github.moulberry.repo.util.NEUId; import lombok.AccessLevel; import lombok.Getter; @@ -17,7 +18,7 @@ public class NEUItem { int damage; List<String> lore; @SerializedName("internalname") - String skyblockItemId; + @NEUId String skyblockItemId; String crafttext; String clickcommand; String modver; diff --git a/src/main/java/io/github/moulberry/repo/util/NEUId.java b/src/main/java/io/github/moulberry/repo/util/NEUId.java new file mode 100644 index 0000000..15423af --- /dev/null +++ b/src/main/java/io/github/moulberry/repo/util/NEUId.java @@ -0,0 +1,14 @@ +package io.github.moulberry.repo.util; + +import java.lang.annotation.*; + +/** + * Indicates that this string is a neu internalname / neu id. + * When applied to a method, indicates the return type is a neu id. + * When applied to a parameter, field, or local variable indicated that the variable type is a neu id. + */ +@Documented +@Target({ElementType.PARAMETER, ElementType.FIELD, ElementType.LOCAL_VARIABLE, ElementType.METHOD, ElementType.TYPE_USE}) +@Retention(RetentionPolicy.CLASS) +public @interface NEUId { +} diff --git a/src/main/java/io/github/moulberry/repo/vendored/RuntimeTypeAdapterFactory.java b/src/main/java/io/github/moulberry/repo/vendored/RuntimeTypeAdapterFactory.java new file mode 100644 index 0000000..1c67f02 --- /dev/null +++ b/src/main/java/io/github/moulberry/repo/vendored/RuntimeTypeAdapterFactory.java @@ -0,0 +1,283 @@ +/* + * Copyright (C) 2011 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.github.moulberry.repo.vendored; + +import com.google.gson.*; +import com.google.gson.reflect.TypeToken; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; + +import java.io.IOException; +import java.util.LinkedHashMap; +import java.util.Map; + + +/** + * Adapts values whose runtime type may differ from their declaration type. This is necessary when a field's type is not + * the same type that GSON should create when deserializing that field. For example, consider these types: + * <pre> {@code + * abstract class Shape { + * int x; + * int y; + * } + * class Circle extends Shape { + * int radius; + * } + * class Rectangle extends Shape { + * int width; + * int height; + * } + * class Diamond extends Shape { + * int width; + * int height; + * } + * class Drawing { + * Shape bottomShape; + * Shape topShape; + * } + * }</pre> + * <p>Without additional type information, the serialized JSON is ambiguous. Is + * the bottom shape in this drawing a rectangle or a diamond? <pre> {@code + * { + * "bottomShape": { + * "width": 10, + * "height": 5, + * "x": 0, + * "y": 0 + * }, + * "topShape": { + * "radius": 2, + * "x": 4, + * "y": 1 + * } + * }}</pre> + * This class addresses this problem by adding type information to the serialized JSON and honoring that type + * information when the JSON is + * deserialized: <pre> {@code + * { + * "bottomShape": { + * "type": "Diamond", + * "width": 10, + * "height": 5, + * "x": 0, + * "y": 0 + * }, + * "topShape": { + * "type": "Circle", + * "radius": 2, + * "x": 4, + * "y": 1 + * } + * }}</pre> + * Both the type field name ({@code "type"}) and the type labels ({@code "Rectangle"}) are configurable. + * <h2></h2> + * <h3>Registering Types</h3> + * Create a {@code RuntimeTypeAdapterFactory} by passing the base type and type field name to the {@link #of} factory + * method. If you don't supply an explicit type + * field name, {@code "type"} will be used. <pre> {@code + * RuntimeTypeAdapterFactory<Shape> shapeAdapterFactory + * = RuntimeTypeAdapterFactory.of(Shape.class, "type"); + * }</pre> + * Next register all of your subtypes. Every subtype must be explicitly registered. This protects your application from + * injection attacks. If you don't supply an explicit type label, the type's simple name will be used. + * <pre> {@code + * shapeAdapterFactory.registerSubtype(Rectangle.class, "Rectangle"); + * shapeAdapterFactory.registerSubtype(Circle.class, "Circle"); + * shapeAdapterFactory.registerSubtype(Diamond.class, "Diamond"); + * }</pre> + * Finally, register the type adapter factory in your application's GSON builder: + * <pre> {@code + * Gson gson = new GsonBuilder() + * .registerTypeAdapterFactory(shapeAdapterFactory) + * .create(); + * }</pre> + * Like {@code GsonBuilder}, this API supports chaining: <pre> {@code + * RuntimeTypeAdapterFactory<Shape> shapeAdapterFactory = RuntimeTypeAdapterFactory.of(Shape.class) + * .registerSubtype(Rectangle.class) + * .registerSubtype(Circle.class) + * .registerSubtype(Diamond.class); + * }</pre> + * + * <h3>Serialization and deserialization</h3> + * In order to serialize and deserialize a polymorphic object, you must specify the base type explicitly. + * <pre> {@code + * Diamond diamond = new Diamond(); + * String json = gson.toJson(diamond, Shape.class); + * }</pre> + * And then: + * <pre> {@code + * Shape shape = gson.fromJson(json, Shape.class); + * }</pre> + */ +public final class RuntimeTypeAdapterFactory<T> implements TypeAdapterFactory { + private final Class<?> baseType; + private final String typeFieldName; + private final Map<String, Class<?>> labelToSubtype = new LinkedHashMap<>(); + private final Map<Class<?>, String> subtypeToLabel = new LinkedHashMap<>(); + private final boolean maintainType; + private String defaultType; // NEU modification + + // NEU modification + public RuntimeTypeAdapterFactory<T> setDefaultTypeTag(String defaultTag) { + this.defaultType = defaultTag; + return this; + } + + private RuntimeTypeAdapterFactory(Class<?> baseType, String typeFieldName, boolean maintainType) { + if (typeFieldName == null || baseType == null) { + throw new NullPointerException(); + } + this.baseType = baseType; + this.typeFieldName = typeFieldName; + this.maintainType = maintainType; + } + + /** + * Creates a new runtime type adapter using for {@code baseType} using {@code typeFieldName} as the type field name. + * Type field names are case sensitive. {@code maintainType} flag decide if the type will be stored in pojo or not. + */ + public static <T> RuntimeTypeAdapterFactory<T> of(Class<T> baseType, String typeFieldName, boolean maintainType) { + return new RuntimeTypeAdapterFactory<>(baseType, typeFieldName, maintainType); + } + + /** + * Creates a new runtime type adapter using for {@code baseType} using {@code typeFieldName} as the type field name. + * Type field names are case sensitive. + */ + public static <T> RuntimeTypeAdapterFactory<T> of(Class<T> baseType, String typeFieldName) { + return new RuntimeTypeAdapterFactory<>(baseType, typeFieldName, false); + } + + /** + * Creates a new runtime type adapter for {@code baseType} using {@code "type"} as the type field name. + */ + public static <T> RuntimeTypeAdapterFactory<T> of(Class<T> baseType) { + return new RuntimeTypeAdapterFactory<>(baseType, "type", false); + } + + /** + * Registers {@code type} identified by {@code label}. Labels are case sensitive. + * + * @throws IllegalArgumentException if either {@code type} or {@code label} have already been registered on this + * type adapter. + */ + public RuntimeTypeAdapterFactory<T> registerSubtype(Class<? extends T> type, String label) { + if (type == null || label == null) { + throw new NullPointerException(); + } + if (subtypeToLabel.containsKey(type) || labelToSubtype.containsKey(label)) { + throw new IllegalArgumentException("types and labels must be unique"); + } + labelToSubtype.put(label, type); + subtypeToLabel.put(type, label); + return this; + } + + /** + * Registers {@code type} identified by its {@link Class#getSimpleName simple name}. Labels are case sensitive. + * + * @throws IllegalArgumentException if either {@code type} or its simple name have already been registered on this + * type adapter. + */ + public RuntimeTypeAdapterFactory<T> registerSubtype(Class<? extends T> type) { + return registerSubtype(type, type.getSimpleName()); + } + + @Override + public <R> TypeAdapter<R> create(Gson gson, TypeToken<R> type) { + if (type == null || !baseType.isAssignableFrom(type.getRawType())) { + return null; + } + + final TypeAdapter<JsonElement> jsonElementAdapter = gson.getAdapter(JsonElement.class); + final Map<String, TypeAdapter<?>> labelToDelegate = new LinkedHashMap<>(); + final Map<Class<?>, TypeAdapter<?>> subtypeToDelegate = new LinkedHashMap<>(); + for (Map.Entry<String, Class<?>> entry : labelToSubtype.entrySet()) { + TypeAdapter<?> delegate = gson.getDelegateAdapter(this, TypeToken.get(entry.getValue())); + labelToDelegate.put(entry.getKey(), delegate); + subtypeToDelegate.put(entry.getValue(), delegate); + } + + // NEU modification + if (defaultType != null && !labelToDelegate.containsKey(defaultType)) { + throw new IllegalStateException("RuntimeTypeAdapterFactory has default type '" + defaultType + "' but does not have that listed as a regular type."); + } + + return new TypeAdapter<R>() { + @Override + public R read(JsonReader in) throws IOException { + JsonElement jsonElement = jsonElementAdapter.read(in); + JsonElement labelJsonElement; + if (maintainType) { + labelJsonElement = jsonElement.getAsJsonObject().get(typeFieldName); + } else { + labelJsonElement = jsonElement.getAsJsonObject().remove(typeFieldName); + } + + // NEU modification + if (defaultType != null && labelJsonElement == null) { + labelJsonElement = new JsonPrimitive(defaultType); + } + + + if (labelJsonElement == null) { + throw new JsonParseException("cannot deserialize " + baseType + + " because it does not define a field named " + typeFieldName); + } + String label = labelJsonElement.getAsString(); + @SuppressWarnings("unchecked") // registration requires that subtype extends T + TypeAdapter<R> delegate = (TypeAdapter<R>) labelToDelegate.get(label); + if (delegate == null) { + throw new JsonParseException("cannot deserialize " + baseType + " subtype named " + + label + "; did you forget to register a subtype?"); + } + return delegate.fromJsonTree(jsonElement); + } + + @Override + public void write(JsonWriter out, R value) throws IOException { + Class<?> srcType = value.getClass(); + String label = subtypeToLabel.get(srcType); + @SuppressWarnings("unchecked") // registration requires that subtype extends T + TypeAdapter<R> delegate = (TypeAdapter<R>) subtypeToDelegate.get(srcType); + if (delegate == null) { + throw new JsonParseException("cannot serialize " + srcType.getName() + + "; did you forget to register a subtype?"); + } + JsonObject jsonObject = delegate.toJsonTree(value).getAsJsonObject(); + + if (maintainType) { + jsonElementAdapter.write(out, jsonObject); + return; + } + + JsonObject clone = new JsonObject(); + + if (jsonObject.has(typeFieldName)) { + throw new JsonParseException("cannot serialize " + srcType.getName() + + " because it already defines a field named " + typeFieldName); + } + clone.add(typeFieldName, new JsonPrimitive(label)); + + for (Map.Entry<String, JsonElement> e : jsonObject.entrySet()) { + clone.add(e.getKey(), e.getValue()); + } + jsonElementAdapter.write(out, clone); + } + }.nullSafe(); + } +} |