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.Gson;
|
||||||
import com.google.gson.GsonBuilder;
|
import com.google.gson.GsonBuilder;
|
||||||
|
import com.google.gson.JsonParseException;
|
||||||
|
import com.google.gson.ToNumberStrategy;
|
||||||
import com.google.gson.TypeAdapter;
|
import com.google.gson.TypeAdapter;
|
||||||
import com.google.gson.TypeAdapterFactory;
|
import com.google.gson.TypeAdapterFactory;
|
||||||
import com.google.gson.reflect.TypeToken;
|
import com.google.gson.reflect.TypeToken;
|
||||||
|
import com.google.gson.stream.MalformedJsonException;
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
@ -16,6 +20,52 @@ import java.util.function.Function;
|
|||||||
*/
|
*/
|
||||||
public class Json {
|
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 Gson} instance with {@link GsonBuilder#setLenient()} and support for Java records and additional
|
||||||
* {@link TypeAdapterFactory} provided with {@link #registerTypeAdapterFactory(TypeAdapterFactory)}.
|
* {@link TypeAdapterFactory} provided with {@link #registerTypeAdapterFactory(TypeAdapterFactory)}.
|
||||||
@ -53,6 +103,7 @@ public class Json {
|
|||||||
GsonBuilder base = new GsonBuilder()
|
GsonBuilder base = new GsonBuilder()
|
||||||
.registerTypeAdapterFactory(new CustomAdapterFactory())
|
.registerTypeAdapterFactory(new CustomAdapterFactory())
|
||||||
.disableHtmlEscaping()
|
.disableHtmlEscaping()
|
||||||
|
.setObjectToNumberStrategy(YAML_EQUIVALENT_NUMBER_STRATEGY)
|
||||||
.setLenient();
|
.setLenient();
|
||||||
return builderModifier.apply(base).create();
|
return builderModifier.apply(base).create();
|
||||||
}
|
}
|
||||||
@ -95,4 +146,19 @@ public class Json {
|
|||||||
registerTypeAdapterFactory(ThrowableAdapter.FACTORY);
|
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.TypeAdapterFactory;
|
||||||
import com.google.gson.internal.bind.TreeTypeAdapter;
|
import com.google.gson.internal.bind.TreeTypeAdapter;
|
||||||
import com.google.gson.reflect.TypeToken;
|
import com.google.gson.reflect.TypeToken;
|
||||||
import fr.pandacube.lib.core.json.Json;
|
|
||||||
import org.bukkit.configuration.InvalidConfigurationException;
|
import org.bukkit.configuration.InvalidConfigurationException;
|
||||||
import org.bukkit.configuration.file.YamlConfiguration;
|
import org.bukkit.configuration.file.YamlConfiguration;
|
||||||
import org.bukkit.configuration.serialization.ConfigurationSerializable;
|
import org.bukkit.configuration.serialization.ConfigurationSerializable;
|
||||||
import org.bukkit.configuration.serialization.ConfigurationSerialization;
|
import org.bukkit.configuration.serialization.ConfigurationSerialization;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
import org.bukkit.util.BlockVector;
|
|
||||||
import org.yaml.snakeyaml.Yaml;
|
import org.yaml.snakeyaml.Yaml;
|
||||||
|
|
||||||
import java.lang.reflect.Type;
|
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();
|
PaperJson.init();
|
||||||
BlockVector bv = new BlockVector(12, 24, 48);
|
BlockVector bv = new BlockVector(12, 24, 48);
|
||||||
String json = Json.gson.toJson(bv);
|
String json = Json.gson.toJson(bv);
|
||||||
System.out.println(json);
|
System.out.println(json);
|
||||||
BlockVector bv2 = Json.gson.fromJson(json, BlockVector.class);
|
BlockVector bv2 = Json.gson.fromJson(json, BlockVector.class);
|
||||||
System.out.println(bv.equals(bv2));
|
System.out.println(bv.equals(bv2));
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user