Added AbstractJSONDatabaseHandler<T>

This commit is contained in:
Florian CUNY 2018-10-28 15:28:43 +01:00
parent f0c4cb710c
commit 77258b2770
3 changed files with 64 additions and 55 deletions

View File

@ -0,0 +1,52 @@
package world.bentobox.bentobox.database;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.potion.PotionEffectType;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.flags.Flag;
import world.bentobox.bentobox.database.mysql.adapters.FlagAdapter;
import world.bentobox.bentobox.database.mysql.adapters.LocationAdapter;
import world.bentobox.bentobox.database.mysql.adapters.PotionEffectTypeAdapter;
import world.bentobox.bentobox.database.mysql.adapters.WorldAdapter;
/**
* Abstract class that handles insert/select-operations into/from a database.
* It also provides {@link #getGson()}.
*
* @author Poslovitch
*
* @param <T>
*/
public abstract class AbstractJSONDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
/**
* Constructor
*
* @param plugin
* @param type The type of the objects that should be created and filled with
* values from the database or inserted into the database
* @param databaseConnector Contains the settings to create a connection to the database
*/
protected AbstractJSONDatabaseHandler(BentoBox plugin, Class<T> type, DatabaseConnector databaseConnector) {
super(plugin, type, databaseConnector);
}
protected Gson getGson() {
// 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();
// Register adapters
builder.registerTypeAdapter(Location.class, new LocationAdapter(plugin)) ;
builder.registerTypeAdapter(World.class, new WorldAdapter(plugin));
builder.registerTypeAdapter(Flag.class, new FlagAdapter(plugin));
builder.registerTypeAdapter(PotionEffectType.class, new PotionEffectTypeAdapter());
// Keep null in the database
builder.serializeNulls();
// Allow characters like < or > without escaping them
builder.disableHtmlEscaping();
return builder.create();
}
}

View File

@ -5,12 +5,8 @@ import java.util.List;
import org.bson.Document; import org.bson.Document;
import org.bson.conversions.Bson; import org.bson.conversions.Bson;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.potion.PotionEffectType;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.mongodb.client.MongoCollection; import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase; import com.mongodb.client.MongoDatabase;
import com.mongodb.client.model.FindOneAndReplaceOptions; import com.mongodb.client.model.FindOneAndReplaceOptions;
@ -19,13 +15,8 @@ import com.mongodb.client.model.Indexes;
import com.mongodb.util.JSON; import com.mongodb.util.JSON;
import world.bentobox.bentobox.BentoBox; import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.flags.Flag; import world.bentobox.bentobox.database.AbstractJSONDatabaseHandler;
import world.bentobox.bentobox.database.AbstractDatabaseHandler;
import world.bentobox.bentobox.database.DatabaseConnector; import world.bentobox.bentobox.database.DatabaseConnector;
import world.bentobox.bentobox.database.mysql.adapters.FlagAdapter;
import world.bentobox.bentobox.database.mysql.adapters.LocationAdapter;
import world.bentobox.bentobox.database.mysql.adapters.PotionEffectTypeAdapter;
import world.bentobox.bentobox.database.mysql.adapters.WorldAdapter;
import world.bentobox.bentobox.database.objects.DataObject; import world.bentobox.bentobox.database.objects.DataObject;
/** /**
@ -37,7 +28,7 @@ import world.bentobox.bentobox.database.objects.DataObject;
* @param <T> * @param <T>
*/ */
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
public class MongoDBDatabaseHandler<T> extends AbstractDatabaseHandler<T> { public class MongoDBDatabaseHandler<T> extends AbstractJSONDatabaseHandler<T> {
private static final String UNIQUEID = "uniqueId"; private static final String UNIQUEID = "uniqueId";
private static final String MONGO_ID = "_id"; private static final String MONGO_ID = "_id";
@ -56,36 +47,18 @@ public class MongoDBDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
public MongoDBDatabaseHandler(BentoBox plugin, Class<T> type, DatabaseConnector dbConnecter) { public MongoDBDatabaseHandler(BentoBox plugin, Class<T> type, DatabaseConnector dbConnecter) {
super(plugin, type, dbConnecter); super(plugin, type, dbConnecter);
this.dbConnecter = dbConnecter; this.dbConnecter = dbConnecter;
/*
Connection to the database // Connection to the database
*/
MongoDatabase database = (MongoDatabase) dbConnecter.createConnection(); MongoDatabase database = (MongoDatabase) dbConnecter.createConnection();
collection = database.getCollection(dataObject.getCanonicalName()); collection = database.getCollection(dataObject.getCanonicalName());
IndexOptions indexOptions = new IndexOptions().unique(true); IndexOptions indexOptions = new IndexOptions().unique(true);
collection.createIndex(Indexes.text(UNIQUEID), indexOptions); collection.createIndex(Indexes.text(UNIQUEID), indexOptions);
} }
// Gets the GSON builder
private Gson getGSON() {
// 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();
// Register adapters
builder.registerTypeAdapter(Location.class, new LocationAdapter(plugin)) ;
builder.registerTypeAdapter(World.class, new WorldAdapter(plugin));
builder.registerTypeAdapter(Flag.class, new FlagAdapter(plugin));
builder.registerTypeAdapter(PotionEffectType.class, new PotionEffectTypeAdapter());
// Keep null in the database
builder.serializeNulls();
// Allow characters like < or > without escaping them
builder.disableHtmlEscaping();
return builder.create();
}
@Override @Override
public List<T> loadObjects() { public List<T> loadObjects() {
List<T> list = new ArrayList<>(); List<T> list = new ArrayList<>();
Gson gson = getGSON(); Gson gson = getGson();
for (Document document : collection.find(new Document())) { for (Document document : collection.find(new Document())) {
// The deprecated serialize option does not have a viable alternative without involving a huge amount of custom code // The deprecated serialize option does not have a viable alternative without involving a huge amount of custom code
String json = JSON.serialize(document); String json = JSON.serialize(document);
@ -98,7 +71,7 @@ public class MongoDBDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
@Override @Override
public T loadObject(String uniqueId) { public T loadObject(String uniqueId) {
Document doc = collection.find(new Document(MONGO_ID, uniqueId)).limit(1).first(); Document doc = collection.find(new Document(MONGO_ID, uniqueId)).limit(1).first();
Gson gson = getGSON(); Gson gson = getGson();
String json = JSON.serialize(doc).replaceFirst(MONGO_ID, UNIQUEID); String json = JSON.serialize(doc).replaceFirst(MONGO_ID, UNIQUEID);
// load single object // load single object
return gson.fromJson(json, dataObject); return gson.fromJson(json, dataObject);
@ -112,7 +85,7 @@ public class MongoDBDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
} }
DataObject dataObj = (DataObject)instance; DataObject dataObj = (DataObject)instance;
try { try {
Gson gson = getGSON(); Gson gson = getGson();
String toStore = gson.toJson(instance); String toStore = gson.toJson(instance);
// Change uniqueId to _id // Change uniqueId to _id
toStore = toStore.replaceFirst(UNIQUEID, MONGO_ID); toStore = toStore.replaceFirst(UNIQUEID, MONGO_ID);

View File

@ -19,6 +19,7 @@ import com.google.gson.GsonBuilder;
import world.bentobox.bentobox.BentoBox; import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.flags.Flag; import world.bentobox.bentobox.api.flags.Flag;
import world.bentobox.bentobox.database.AbstractDatabaseHandler; import world.bentobox.bentobox.database.AbstractDatabaseHandler;
import world.bentobox.bentobox.database.AbstractJSONDatabaseHandler;
import world.bentobox.bentobox.database.DatabaseConnector; import world.bentobox.bentobox.database.DatabaseConnector;
import world.bentobox.bentobox.database.mysql.adapters.FlagAdapter; import world.bentobox.bentobox.database.mysql.adapters.FlagAdapter;
import world.bentobox.bentobox.database.mysql.adapters.LocationAdapter; import world.bentobox.bentobox.database.mysql.adapters.LocationAdapter;
@ -34,7 +35,7 @@ import world.bentobox.bentobox.database.objects.DataObject;
* *
* @param <T> * @param <T>
*/ */
public class MySQLDatabaseHandler<T> extends AbstractDatabaseHandler<T> { public class MySQLDatabaseHandler<T> extends AbstractJSONDatabaseHandler<T> {
/** /**
* Connection to the database * Connection to the database
@ -71,23 +72,6 @@ public class MySQLDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
} }
} }
// Gets the GSON builder
private Gson getGSON() {
// 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();
// Register adapters
builder.registerTypeAdapter(Location.class, new LocationAdapter(plugin)) ;
builder.registerTypeAdapter(World.class, new WorldAdapter(plugin));
builder.registerTypeAdapter(Flag.class, new FlagAdapter(plugin));
builder.registerTypeAdapter(PotionEffectType.class, new PotionEffectTypeAdapter());
// Keep null in the database
builder.serializeNulls();
// Allow characters like < or > without escaping them
builder.disableHtmlEscaping();
return builder.create();
}
@Override @Override
public List<T> loadObjects() { public List<T> loadObjects() {
List<T> list = new ArrayList<>(); List<T> list = new ArrayList<>();
@ -98,7 +82,7 @@ public class MySQLDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
try (Statement preparedStatement = connection.createStatement()) { try (Statement preparedStatement = connection.createStatement()) {
try (ResultSet resultSet = preparedStatement.executeQuery(sb.toString())) { try (ResultSet resultSet = preparedStatement.executeQuery(sb.toString())) {
// Load all the results // Load all the results
Gson gson = getGSON(); Gson gson = getGson();
while (resultSet.next()) { while (resultSet.next()) {
list.add(gson.fromJson(resultSet.getString("json"), dataObject)); list.add(gson.fromJson(resultSet.getString("json"), dataObject));
} }
@ -120,7 +104,7 @@ public class MySQLDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
try (ResultSet resultSet = preparedStatement.executeQuery()) { try (ResultSet resultSet = preparedStatement.executeQuery()) {
if (resultSet.next()) { if (resultSet.next()) {
// If there is a result, we only want/need the first one // If there is a result, we only want/need the first one
Gson gson = getGSON(); Gson gson = getGson();
return gson.fromJson(resultSet.getString("json"), dataObject); return gson.fromJson(resultSet.getString("json"), dataObject);
} }
} }
@ -143,7 +127,7 @@ public class MySQLDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
// Replace into is used so that any data in the table will be replaced with updated data // Replace into is used so that any data in the table will be replaced with updated data
// The table name is the canonical name, so that add-ons can be sure of a unique table in the database // The table name is the canonical name, so that add-ons can be sure of a unique table in the database
try (PreparedStatement preparedStatement = connection.prepareStatement(sb)) { try (PreparedStatement preparedStatement = connection.prepareStatement(sb)) {
Gson gson = getGSON(); Gson gson = getGson();
String toStore = gson.toJson(instance); String toStore = gson.toJson(instance);
preparedStatement.setString(1, toStore); preparedStatement.setString(1, toStore);
preparedStatement.setString(2, toStore); preparedStatement.setString(2, toStore);