mirror of
https://github.com/BentoBoxWorld/BentoBox.git
synced 2024-11-27 13:15:28 +01:00
Added a generic GSON Type Adapter for ConfigurationSerializabale objects
Bukkit has built-in serialization that can be used. Kept legacy serialization for backwards compatibility and compactness.
This commit is contained in:
parent
91b650bdee
commit
779c370b6a
@ -1,24 +1,11 @@
|
||||
package world.bentobox.bentobox.database.json;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.potion.PotionEffectType;
|
||||
import org.bukkit.util.BoundingBox;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
|
||||
import world.bentobox.bentobox.BentoBox;
|
||||
import world.bentobox.bentobox.api.flags.Flag;
|
||||
import world.bentobox.bentobox.database.AbstractDatabaseHandler;
|
||||
import world.bentobox.bentobox.database.DatabaseConnector;
|
||||
import world.bentobox.bentobox.database.json.adapters.BoundingBoxTypeAdapter;
|
||||
import world.bentobox.bentobox.database.json.adapters.FlagTypeAdapter;
|
||||
import world.bentobox.bentobox.database.json.adapters.ItemStackTypeAdapter;
|
||||
import world.bentobox.bentobox.database.json.adapters.LocationTypeAdapter;
|
||||
import world.bentobox.bentobox.database.json.adapters.PotionEffectTypeAdapter;
|
||||
import world.bentobox.bentobox.database.json.adapters.WorldTypeAdapter;
|
||||
|
||||
/**
|
||||
* Abstract class that handles insert/select-operations into/from a database.
|
||||
@ -48,13 +35,8 @@ public abstract class AbstractJSONDatabaseHandler<T> extends AbstractDatabaseHan
|
||||
// excludeFieldsWithoutExposeAnnotation - this means that every field to be stored should use @Expose
|
||||
// enableComplexMapKeySerialization - forces GSON to use TypeAdapters even for Map keys
|
||||
GsonBuilder builder = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().enableComplexMapKeySerialization().setPrettyPrinting();
|
||||
// Register adapters
|
||||
builder.registerTypeAdapter(Location.class, new LocationTypeAdapter()) ;
|
||||
builder.registerTypeAdapter(World.class, new WorldTypeAdapter());
|
||||
builder.registerTypeAdapter(Flag.class, new FlagTypeAdapter(plugin));
|
||||
builder.registerTypeAdapter(PotionEffectType.class, new PotionEffectTypeAdapter());
|
||||
builder.registerTypeAdapter(ItemStack.class, new ItemStackTypeAdapter());
|
||||
builder.registerTypeAdapter(BoundingBox.class, new BoundingBoxTypeAdapter());
|
||||
// Register adapter factory
|
||||
builder.registerTypeAdapterFactory(new BentoboxTypeAdapterFactory(plugin));
|
||||
// Keep null in the database
|
||||
builder.serializeNulls();
|
||||
// Allow characters like < or > without escaping them
|
||||
|
@ -0,0 +1,71 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package world.bentobox.bentobox.database.json;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.configuration.serialization.ConfigurationSerializable;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.potion.PotionEffectType;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.TypeAdapter;
|
||||
import com.google.gson.TypeAdapterFactory;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
|
||||
import world.bentobox.bentobox.BentoBox;
|
||||
import world.bentobox.bentobox.api.flags.Flag;
|
||||
import world.bentobox.bentobox.database.json.adapters.BukkitObjectTypeAdapter;
|
||||
import world.bentobox.bentobox.database.json.adapters.FlagTypeAdapter;
|
||||
import world.bentobox.bentobox.database.json.adapters.ItemStackTypeAdapter;
|
||||
import world.bentobox.bentobox.database.json.adapters.LocationTypeAdapter;
|
||||
import world.bentobox.bentobox.database.json.adapters.PotionEffectTypeAdapter;
|
||||
import world.bentobox.bentobox.database.json.adapters.WorldTypeAdapter;
|
||||
|
||||
/**
|
||||
* Allocates type adapters based on class type.
|
||||
*
|
||||
* @author tastybento
|
||||
*
|
||||
*/
|
||||
public class BentoboxTypeAdapterFactory implements TypeAdapterFactory {
|
||||
|
||||
BentoBox plugin;
|
||||
|
||||
/**
|
||||
* @param plugin
|
||||
*/
|
||||
public BentoboxTypeAdapterFactory(BentoBox plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see com.google.gson.TypeAdapterFactory#create(com.google.gson.Gson, com.google.gson.reflect.TypeToken)
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
|
||||
Class<?> rawType = type.getRawType();
|
||||
if (Location.class.isAssignableFrom(rawType)) {
|
||||
// Use our current location adapter for backward compatibility
|
||||
return (TypeAdapter<T>) new LocationTypeAdapter();
|
||||
} else if (ItemStack.class.isAssignableFrom(rawType)) {
|
||||
// Use our current location adapter for backward compatibility
|
||||
return (TypeAdapter<T>) new ItemStackTypeAdapter();
|
||||
} else if (Flag.class.isAssignableFrom(rawType)) {
|
||||
return (TypeAdapter<T>) new FlagTypeAdapter(plugin);
|
||||
} else if (PotionEffectType.class.isAssignableFrom(rawType)) {
|
||||
return (TypeAdapter<T>) new PotionEffectTypeAdapter();
|
||||
} else if (World.class.isAssignableFrom(rawType)) {
|
||||
return (TypeAdapter<T>) new WorldTypeAdapter();
|
||||
} else if (ConfigurationSerializable.class.isAssignableFrom(rawType)) {
|
||||
// This covers a lot of Bukkit objects
|
||||
return (TypeAdapter<T>) new BukkitObjectTypeAdapter(gson.getAdapter(Map.class));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
@ -1,46 +0,0 @@
|
||||
package world.bentobox.bentobox.database.json.adapters;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.bukkit.util.BoundingBox;
|
||||
|
||||
import com.google.gson.TypeAdapter;
|
||||
import com.google.gson.stream.JsonReader;
|
||||
import com.google.gson.stream.JsonToken;
|
||||
import com.google.gson.stream.JsonWriter;
|
||||
|
||||
public class BoundingBoxTypeAdapter extends TypeAdapter<BoundingBox> {
|
||||
|
||||
@Override
|
||||
public void write(JsonWriter out, BoundingBox box) throws IOException {
|
||||
if (box == null) {
|
||||
out.nullValue();
|
||||
return;
|
||||
}
|
||||
out.beginArray();
|
||||
out.value(box.getMinX());
|
||||
out.value(box.getMinY());
|
||||
out.value(box.getMinZ());
|
||||
out.value(box.getMaxX());
|
||||
out.value(box.getMaxY());
|
||||
out.value(box.getMaxZ());
|
||||
out.endArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BoundingBox read(JsonReader in) throws IOException {
|
||||
if (in.peek() == JsonToken.NULL) {
|
||||
in.nextNull();
|
||||
return null;
|
||||
}
|
||||
in.beginArray();
|
||||
double minX = in.nextDouble();
|
||||
double minY = in.nextDouble();
|
||||
double minZ = in.nextDouble();
|
||||
double maxX = in.nextDouble();
|
||||
double maxY = in.nextDouble();
|
||||
double maxZ = in.nextDouble();
|
||||
in.endArray();
|
||||
return new BoundingBox(minX, minY, minZ, maxX, maxY, maxZ);
|
||||
}
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
package world.bentobox.bentobox.database.json.adapters;
|
||||
|
||||
import static org.bukkit.configuration.serialization.ConfigurationSerialization.SERIALIZED_TYPE_KEY;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.bukkit.configuration.serialization.ConfigurationSerializable;
|
||||
import org.bukkit.configuration.serialization.ConfigurationSerialization;
|
||||
|
||||
import com.google.gson.TypeAdapter;
|
||||
import com.google.gson.stream.JsonReader;
|
||||
import com.google.gson.stream.JsonWriter;
|
||||
|
||||
/**
|
||||
* Handles {@link ConfigurationSerializable} types
|
||||
* @author tastybento
|
||||
* @since 1.5.0
|
||||
*/
|
||||
|
||||
public class BukkitObjectTypeAdapter extends TypeAdapter<ConfigurationSerializable> {
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
private final TypeAdapter<Map> map;
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public BukkitObjectTypeAdapter(TypeAdapter<Map> mapAdapter) {
|
||||
this.map = mapAdapter;
|
||||
}
|
||||
|
||||
public static Map<String, Object> serializeObject(ConfigurationSerializable serializable) {
|
||||
Map<String, Object> serialized = new HashMap<>();
|
||||
serialized.putAll(serializable.serialize());
|
||||
serialized.entrySet().stream()
|
||||
.filter(e -> e.getValue() instanceof ConfigurationSerializable)
|
||||
.forEach(e -> serialized.put(e.getKey(), serializeObject((ConfigurationSerializable) e.getValue())));
|
||||
serialized.put(SERIALIZED_TYPE_KEY, ConfigurationSerialization.getAlias(serializable.getClass()));
|
||||
return serialized;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public ConfigurationSerializable deserializeObject(Map<String, Object> map) {
|
||||
if (map == null) {
|
||||
return null;
|
||||
}
|
||||
// Iteratively expand maps until the Bukkit ConfigurationSerialization can deserialize the base object
|
||||
map.forEach((k,v) -> {
|
||||
if (v instanceof Map) {
|
||||
Map<String, Object> nestedMap = (Map<String, Object>)v;
|
||||
if (nestedMap.containsKey(SERIALIZED_TYPE_KEY)) {
|
||||
map.put(k, deserializeObject(nestedMap));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return ConfigurationSerialization.deserializeObject(map);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public ConfigurationSerializable read(JsonReader in) throws IOException {
|
||||
return deserializeObject(map.read(in));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(JsonWriter out, ConfigurationSerializable value) throws IOException {
|
||||
if (value == null) {
|
||||
out.nullValue();
|
||||
}
|
||||
map.write(out, serializeObject(value));
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user