Gson now deserializes numbers to the appropriate Number subclass
This commit is contained in:
parent
db06ab1be9
commit
a24eab67b6
@ -2,10 +2,14 @@ package fr.pandacube.lib.core.json;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonParseException;
|
||||
import com.google.gson.ToNumberStrategy;
|
||||
import com.google.gson.TypeAdapter;
|
||||
import com.google.gson.TypeAdapterFactory;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import com.google.gson.stream.MalformedJsonException;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
@ -16,6 +20,52 @@ import java.util.function.Function;
|
||||
*/
|
||||
public class Json {
|
||||
|
||||
/**
|
||||
* Makes Gson deserialize numbers to Number subclasses the same way SnakeYAML does
|
||||
*/
|
||||
private static final ToNumberStrategy YAML_EQUIVALENT_NUMBER_STRATEGY = in -> {
|
||||
String value = in.nextString();
|
||||
|
||||
// YAML uses Regex to resolve values as INT or FLOAT (see org.yaml.snakeyaml.resolver.Resolver), trying FLOAT first.
|
||||
// We see in the regex that FLOAT MUST have a "." in the string, but INT must not, so we try that.
|
||||
boolean isFloat = value.contains(".");
|
||||
|
||||
if (isFloat) {
|
||||
// if float, will only parse to Double
|
||||
// (see org.yaml.snakeyaml.constructor.SafeConstructor.ConstructYamlFloat)
|
||||
try {
|
||||
Double d = Double.valueOf(value);
|
||||
if ((d.isInfinite() || d.isNaN()) && !in.isLenient()) {
|
||||
throw new MalformedJsonException("JSON forbids NaN and infinities: " + d + "; at path " + in.getPreviousPath());
|
||||
}
|
||||
return d;
|
||||
} catch (NumberFormatException e) {
|
||||
throw new JsonParseException("Cannot parse " + value + "; at path " + in.getPreviousPath(), e);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// if integer, will try to parse int, then long, then BigDecimal
|
||||
// (see org.yaml.snakeyaml.constructor.SafeConstructor.ConstructYamlInt
|
||||
// then org.yaml.snakeyaml.constructor.SafeConstructor.createNumber)
|
||||
try {
|
||||
return Integer.valueOf(value);
|
||||
} catch (NumberFormatException e) {
|
||||
try {
|
||||
return Long.valueOf(value);
|
||||
} catch (NumberFormatException e2) {
|
||||
try {
|
||||
return new BigInteger(value);
|
||||
} catch (NumberFormatException e3) {
|
||||
throw new JsonParseException("Cannot parse " + value + "; at path " + in.getPreviousPath(), e3);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* {@link Gson} instance with {@link GsonBuilder#setLenient()} and support for Java records and additional
|
||||
* {@link TypeAdapterFactory} provided with {@link #registerTypeAdapterFactory(TypeAdapterFactory)}.
|
||||
@ -53,6 +103,7 @@ public class Json {
|
||||
GsonBuilder base = new GsonBuilder()
|
||||
.registerTypeAdapterFactory(new CustomAdapterFactory())
|
||||
.disableHtmlEscaping()
|
||||
.setObjectToNumberStrategy(YAML_EQUIVALENT_NUMBER_STRATEGY)
|
||||
.setLenient();
|
||||
return builderModifier.apply(base).create();
|
||||
}
|
||||
@ -95,4 +146,19 @@ public class Json {
|
||||
registerTypeAdapterFactory(ThrowableAdapter.FACTORY);
|
||||
}
|
||||
|
||||
|
||||
/*public static void main(String[] args) {
|
||||
TypeToken<Map<String, Object>> MAP_STR_OBJ_TYPE = new TypeToken<>() { };
|
||||
Map<String, Object> map = gson.fromJson("{" +
|
||||
"\"int\":34," +
|
||||
"\"long\":3272567356876864," +
|
||||
"\"bigint\":-737868677777837833757846576245765," +
|
||||
"\"float\":34.0" +
|
||||
"}", MAP_STR_OBJ_TYPE.getType());
|
||||
for (String key : map.keySet()) {
|
||||
Object v = map.get(key);
|
||||
System.out.println(key + ": " + v + " (type " + v.getClass() + ")");
|
||||
}
|
||||
}*/
|
||||
|
||||
}
|
||||
|
@ -10,13 +10,11 @@ import com.google.gson.JsonSerializer;
|
||||
import com.google.gson.TypeAdapterFactory;
|
||||
import com.google.gson.internal.bind.TreeTypeAdapter;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import fr.pandacube.lib.core.json.Json;
|
||||
import org.bukkit.configuration.InvalidConfigurationException;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.configuration.serialization.ConfigurationSerializable;
|
||||
import org.bukkit.configuration.serialization.ConfigurationSerialization;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.util.BlockVector;
|
||||
import org.yaml.snakeyaml.Yaml;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
@ -68,12 +66,12 @@ import java.util.Map;
|
||||
}
|
||||
|
||||
|
||||
public static void main(String[] args) {
|
||||
/*public static void main(String[] args) {
|
||||
PaperJson.init();
|
||||
BlockVector bv = new BlockVector(12, 24, 48);
|
||||
String json = Json.gson.toJson(bv);
|
||||
System.out.println(json);
|
||||
BlockVector bv2 = Json.gson.fromJson(json, BlockVector.class);
|
||||
System.out.println(bv.equals(bv2));
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user