Added annotation handling to the flatfile database handler.

Currently it handles the @ConfigEntry path and specificTo fields.

Experimental: There is a class called Setting2.java. It has an
annotation that defines its filename as config.yml. Currently, it is
using the database folder as its location, but it could be the plugin's
datafolder in the future. By placing the config.yml file in the database
folder, it will be read. See the code in BSkyBlock onEnable() for how
that is done.

The main differences between Settings2.java and Settings.java are that
all fields are NOT static and therefore it is an object and uses getters
and setters. This is because it is a JavaBean. In other code, settings
should be queried using this config object.
This commit is contained in:
Tastybento 2018-01-05 19:58:08 -08:00
parent 478968dac7
commit 2d447afa88
12 changed files with 1308 additions and 72 deletions

View File

@ -45,6 +45,16 @@ public class BSkyBlock extends JavaPlugin {
public void onEnable(){
plugin = this;
// Load config - EXPERIMENTAL
Settings2 config = new Settings2();
try {
//config.saveConfig(); // works, but will wipe out comments
config = config.loadConfig();
getLogger().info("DEBUG: island distance = " + config.getIslandDistance());
} catch (Exception e) {
e.printStackTrace();
}
// Load configuration and locales. If there are no errors, load the plugin.
if(PluginConfig.loadPluginConfig(this)){

View File

@ -10,6 +10,7 @@ import org.bukkit.inventory.ItemStack;
import org.bukkit.potion.PotionEffectType;
import us.tastybento.bskyblock.api.configuration.ConfigEntry;
import us.tastybento.bskyblock.api.configuration.ConfigEntry.GameType;
import us.tastybento.bskyblock.api.configuration.ISettings;
import us.tastybento.bskyblock.api.flags.Flag;
import us.tastybento.bskyblock.database.BSBDatabase.DatabaseType;
@ -21,10 +22,6 @@ import us.tastybento.bskyblock.database.BSBDatabase.DatabaseType;
public class Settings implements ISettings {
// ----------------- Constants -----------------
// Game Type BSKYBLOCK or ACIDISLAND
public enum GameType {
BSKYBLOCK, ACIDISLAND, BOTH
}
/*
public final static GameType GAMETYPE = GameType.ACIDISLAND;
// The spawn command (Essentials spawn for example)

File diff suppressed because it is too large Load Diff

View File

@ -5,8 +5,6 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import us.tastybento.bskyblock.Settings.GameType;
/**
*
*
@ -25,4 +23,9 @@ public @interface ConfigEntry {
Class<?> adapter() default NoAdapter.class;
public class NoAdapter {}
// Game Type BSKYBLOCK or ACIDISLAND
public enum GameType {
BSKYBLOCK, ACIDISLAND, BOTH
}
}

View File

@ -1,8 +1,36 @@
package us.tastybento.bskyblock.api.configuration;
import java.beans.IntrospectionException;
import java.lang.reflect.InvocationTargetException;
import java.sql.SQLException;
import us.tastybento.bskyblock.BSkyBlock;
import us.tastybento.bskyblock.Settings2;
import us.tastybento.bskyblock.database.flatfile.FlatFileDatabase;
import us.tastybento.bskyblock.database.managers.AbstractDatabaseHandler;
/**
* Simple interface for tagging all classes containing ConfigEntries.
*
* @author Poslovitch
* @param <T>
*/
public interface ISettings {}
public interface ISettings<T> {
// ----------------Saver-------------------
@SuppressWarnings("unchecked")
public default void saveConfig(T instance) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, SecurityException, InstantiationException, NoSuchMethodException, IntrospectionException, SQLException {
// Get the handler
AbstractDatabaseHandler<T> configHandler = (AbstractDatabaseHandler<T>) new FlatFileDatabase().getHandler(BSkyBlock.getInstance(), instance.getClass());
// Load every field in the config class
configHandler.saveObject(instance); // The string parameter can be anything
}
// --------------- Loader ------------------
@SuppressWarnings("unchecked")
public default Settings2 loadConfig() throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, SecurityException, ClassNotFoundException, IntrospectionException, SQLException {
// Get the handler
AbstractDatabaseHandler<Settings2> configHandler = (AbstractDatabaseHandler<Settings2>) new FlatFileDatabase().getHandler(BSkyBlock.getInstance(), Settings2.class);
// Load every field in the config class
return configHandler.loadObject("config");
}
}

View File

@ -8,8 +8,8 @@ import org.bukkit.Bukkit;
import us.tastybento.bskyblock.BSkyBlock;
import us.tastybento.bskyblock.Settings;
import us.tastybento.bskyblock.Settings.GameType;
import us.tastybento.bskyblock.api.configuration.ConfigEntry;
import us.tastybento.bskyblock.api.configuration.ConfigEntry.GameType;
import us.tastybento.bskyblock.api.configuration.ConfigEntry.NoAdapter;
public class ConfigLoader {

View File

@ -0,0 +1,27 @@
package us.tastybento.bskyblock.config;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Defines where this data object will be stored.
* @author tastybento
*
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface StoreAt {
/**
* Path where this will be stored. If blank, it will be the BSkyBlock database folder.
*/
String path() default "";
/**
* Filename
*/
String filename() default "";
}

View File

@ -77,11 +77,11 @@ public class FlatFileDatabaseConnecter implements DatabaseConnecter {
/**
* Saves a YAML file
*
* @param yamlFile
* @param yamlConfig
* @param fileName
*/
@Override
public void saveYamlFile(YamlConfiguration yamlFile, String tableName, String fileName) {
public void saveYamlFile(YamlConfiguration yamlConfig, String tableName, String fileName) {
if (!fileName.endsWith(".yml")) {
fileName = fileName + ".yml";
}
@ -91,7 +91,7 @@ public class FlatFileDatabaseConnecter implements DatabaseConnecter {
tableFolder.mkdirs();
}
try {
yamlFile.save(file);
yamlConfig.save(file);
} catch (Exception e) {
e.printStackTrace();
}

View File

@ -17,12 +17,18 @@ import java.util.Map.Entry;
import java.util.Set;
import java.util.UUID;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.configuration.MemorySection;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.plugin.Plugin;
import us.tastybento.bskyblock.Settings;
import us.tastybento.bskyblock.api.configuration.ConfigEntry;
import us.tastybento.bskyblock.api.configuration.ConfigEntry.GameType;
import us.tastybento.bskyblock.api.configuration.ConfigEntry.NoAdapter;
import us.tastybento.bskyblock.config.StoreAt;
import us.tastybento.bskyblock.database.DatabaseConnecter;
import us.tastybento.bskyblock.database.managers.AbstractDatabaseHandler;
import us.tastybento.bskyblock.util.Util;
@ -39,6 +45,7 @@ public class FlatFileDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
private static final String DATABASE_FOLDER_NAME = "database";
private static final boolean DEBUG = false;
public FlatFileDatabaseHandler(Plugin plugin, Class<T> type, DatabaseConnecter databaseConnecter) {
super(plugin, type, databaseConnecter);
}
@ -70,13 +77,20 @@ public class FlatFileDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
*/
@Override
public T loadObject(String key) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, IntrospectionException, ClassNotFoundException {
YamlConfiguration config = databaseConnecter.loadYamlFile(type.getSimpleName(), key);
String path = dataObject.getSimpleName();
String fileName = key;
StoreAt storeAt = dataObject.getAnnotation(StoreAt.class);
if (storeAt != null) {
path = storeAt.path();
fileName = storeAt.filename();
}
YamlConfiguration config = databaseConnecter.loadYamlFile(path, fileName);
return createObject(config);
}
@Override
public boolean objectExits(String key) {
return databaseConnecter.uniqueIdExists(type.getSimpleName(), key);
return databaseConnecter.uniqueIdExists(dataObject.getSimpleName(), key);
}
/**
@ -103,14 +117,23 @@ public class FlatFileDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
}
}
};
String path = dataObject.getSimpleName();
StoreAt storeAt = dataObject.getAnnotation(StoreAt.class);
if (storeAt != null) {
path = storeAt.path();
}
File dataFolder = new File(plugin.getDataFolder(), DATABASE_FOLDER_NAME);
File tableFolder = new File(dataFolder, type.getSimpleName());
File tableFolder = new File(dataFolder, path);
if (!tableFolder.exists()) {
// Nothing there...
tableFolder.mkdirs();
}
for (File file: tableFolder.listFiles(ymlFilter)) {
YamlConfiguration config = databaseConnecter.loadYamlFile(type.getSimpleName(), file.getName());
String fileName = file.getName();
if (storeAt != null) {
fileName = storeAt.filename();
}
YamlConfiguration config = databaseConnecter.loadYamlFile(dataObject.getSimpleName(), fileName);
list.add(createObject(config));
}
return list;
@ -131,15 +154,33 @@ public class FlatFileDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
* @throws ClassNotFoundException
*/
private T createObject(YamlConfiguration config) throws InstantiationException, IllegalAccessException, IntrospectionException, IllegalArgumentException, InvocationTargetException, ClassNotFoundException {
T instance = type.newInstance();
T instance = dataObject.newInstance();
for (Field field : type.getDeclaredFields()) {
PropertyDescriptor propertyDescriptor = new PropertyDescriptor(field.getName(), type);
// Run through all the fields in the object
for (Field field : dataObject.getDeclaredFields()) {
// Gets the getter and setters for this field
PropertyDescriptor propertyDescriptor = new PropertyDescriptor(field.getName(), dataObject);
// Get the write method
Method method = propertyDescriptor.getWriteMethod();
if (DEBUG)
plugin.getLogger().info("DEBUG: " + field.getName() + ": " + propertyDescriptor.getPropertyType().getTypeName());
if (config.contains(field.getName())) {
String storageLocation = field.getName();
// Check if there is an annotation on the field
ConfigEntry configEntry = field.getAnnotation(ConfigEntry.class);
// If there is a config annotation then do something
if (configEntry != null) {
if (!configEntry.path().isEmpty()) {
storageLocation = configEntry.path();
}
if (!configEntry.specificTo().equals(GameType.BOTH) && !configEntry.specificTo().equals(Settings.GAMETYPE)) {
Bukkit.getLogger().info(field.getName() + " not applicable to this game type");
continue;
}
}
// Look in the YAML Config to see if this field exists (it should)
if (config.contains(storageLocation)) {
// Handle storage of maps. Check if this type is a Map
if (Map.class.isAssignableFrom(propertyDescriptor.getPropertyType())) {
// Note that we have no idea what type this is
List<Type> collectionTypes = Util.getCollectionParameterTypes(method);
@ -150,9 +191,9 @@ public class FlatFileDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
plugin.getLogger().info("DEBUG: is Map or HashMap<" + keyType.getTypeName() + ", " + valueType.getTypeName() + ">");
// TODO: this may not work with all keys. Further serialization may be required.
Map<Object,Object> value = new HashMap<Object, Object>();
for (String key : config.getConfigurationSection(field.getName()).getKeys(false)) {
for (String key : config.getConfigurationSection(storageLocation).getKeys(false)) {
Object mapKey = deserialize(key,Class.forName(keyType.getTypeName()));
Object mapValue = deserialize(config.get(field.getName() + "." + key), Class.forName(valueType.getTypeName()));
Object mapValue = deserialize(config.get(storageLocation + "." + key), Class.forName(valueType.getTypeName()));
if (DEBUG) {
plugin.getLogger().info("DEBUG: mapKey = " + mapKey + " (" + mapKey.getClass().getCanonicalName() + ")");
plugin.getLogger().info("DEBUG: mapValue = " + mapValue + " (" + mapValue.getClass().getCanonicalName() + ")");
@ -177,13 +218,13 @@ public class FlatFileDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
plugin.getLogger().info("DEBUG: collection type argument = " + collectionTypes);
plugin.getLogger().info("DEBUG: setType = " + setType.getTypeName());
}
for (Object listValue: config.getList(field.getName())) {
for (Object listValue: config.getList(storageLocation)) {
//plugin.getLogger().info("DEBUG: collectionResultSet size = " + collectionResultSet.getFetchSize());
((Set<Object>) value).add(deserialize(listValue,Class.forName(setType.getTypeName())));
}
// TODO: this may not work with all keys. Further serialization may be required.
//Set<Object> value = new HashSet((List<Object>) config.getList(field.getName()));
//Set<Object> value = new HashSet((List<Object>) config.getList(storageLocation));
method.invoke(instance, value);
} else if (List.class.isAssignableFrom(propertyDescriptor.getPropertyType())) {
//plugin.getLogger().info("DEBUG: is Set " + propertyDescriptor.getReadMethod().getGenericReturnType().getTypeName());
@ -197,18 +238,18 @@ public class FlatFileDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
List<Object> value = new ArrayList<Object>();
//plugin.getLogger().info("DEBUG: collection type argument = " + collectionTypes);
//plugin.getLogger().info("DEBUG: setType = " + setType.getTypeName());
for (Object listValue: config.getList(field.getName())) {
for (Object listValue: config.getList(storageLocation)) {
//plugin.getLogger().info("DEBUG: collectionResultSet size = " + collectionResultSet.getFetchSize());
((List<Object>) value).add(deserialize(listValue,Class.forName(setType.getTypeName())));
}
// TODO: this may not work with all keys. Further serialization may be required.
//Set<Object> value = new HashSet((List<Object>) config.getList(field.getName()));
//Set<Object> value = new HashSet((List<Object>) config.getList(storageLocation));
method.invoke(instance, value);
} else {
// Not a collection
if (DEBUG)
plugin.getLogger().info("DEBUG: not a collection");
Object value = config.get(field.getName());
Object value = config.get(storageLocation);
if (DEBUG) {
plugin.getLogger().info("DEBUG: value = " + value);
plugin.getLogger().info("DEBUG: property type = " + propertyDescriptor.getPropertyType());
@ -238,17 +279,33 @@ public class FlatFileDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
public void saveObject(T instance) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, IntrospectionException {
// This is the Yaml Configuration that will be used and saved at the end
YamlConfiguration config = new YamlConfiguration();
// The file name of the Yaml file.
String filename = "";
String path = dataObject.getSimpleName();
StoreAt storeAt = instance.getClass().getAnnotation(StoreAt.class);
if (storeAt != null) {
path = storeAt.path();
filename = storeAt.filename();
}
// Run through all the fields in the class that is being stored. EVERY field must have a get and set method
for (Field field : type.getDeclaredFields()) {
for (Field field : dataObject.getDeclaredFields()) {
String storageLocation = field.getName();
// Check if there is an annotation on the field
ConfigEntry configEntry = field.getAnnotation(ConfigEntry.class);
// If there is a config path annotation then do something
if (configEntry != null && !configEntry.path().isEmpty()) {
storageLocation = configEntry.path();
}
// Get the property descriptor for this field
PropertyDescriptor propertyDescriptor = new PropertyDescriptor(field.getName(), type);
PropertyDescriptor propertyDescriptor = new PropertyDescriptor(field.getName(), dataObject);
// Get the read method, i.e., getXXXX();
Method method = propertyDescriptor.getReadMethod();
// Invoke the read method to get the value. We have no idea what type of value it is.
Object value = method.invoke(instance);
//plugin.getLogger().info("DEBUG: writing " + field.getName());
//plugin.getLogger().info("DEBUG: property desc = " + propertyDescriptor.getPropertyType().getTypeName());
// Depending on the vale type, it'll need serializing differenty
// Check if this field is the mandatory UniqueId field. This is used to identify this instantiation of the class
@ -257,17 +314,18 @@ public class FlatFileDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
//plugin.getLogger().info("DEBUG: uniqueId = " + value);
String id = (String)value;
if (id.isEmpty()) {
id = databaseConnecter.getUniqueId(type.getSimpleName());
id = databaseConnecter.getUniqueId(dataObject.getSimpleName());
// Set it in the class so that it will be used next time
propertyDescriptor.getWriteMethod().invoke(instance, id);
}
// Save the name for when the file is saved
filename = id;
if (filename.isEmpty())
filename = id;
}
// Collections need special serialization
if (propertyDescriptor.getPropertyType().equals(HashMap.class) || propertyDescriptor.getPropertyType().equals(Map.class)) {
if (Map.class.isAssignableFrom(propertyDescriptor.getPropertyType())) {
// Maps need to have keys serialized
//plugin.getLogger().info("DEBUG: Map for " + field.getName());
//plugin.getLogger().info("DEBUG: Map for " + storageLocation);
if (value != null) {
Map<Object, Object> result = new HashMap<Object, Object>();
for (Entry<Object, Object> object : ((Map<Object,Object>)value).entrySet()) {
@ -276,31 +334,29 @@ public class FlatFileDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
result.put(serialize(object.getKey()), object.getValue());
}
// Save the list in the config file
config.set(field.getName(), result);
config.set(storageLocation, result);
}
} else if (propertyDescriptor.getPropertyType().equals(Set.class)) {
} else if (Set.class.isAssignableFrom(propertyDescriptor.getPropertyType())) {
// Sets need to be serialized as string lists
if (DEBUG)
plugin.getLogger().info("DEBUG: Set for " + field.getName());
plugin.getLogger().info("DEBUG: Set for " + storageLocation);
if (value != null) {
List<Object> list = new ArrayList<Object>();
for (Object object : (Set<Object>)value) {
list.add(serialize(object));
}
// Save the list in the config file
config.set(field.getName(), list);
config.set(storageLocation, list);
}
} else {
// For all other data that doesn't need special serialization
config.set(field.getName(), serialize(value));
config.set(storageLocation, serialize(value));
}
}
if (filename.isEmpty()) {
throw new IllegalArgumentException("No uniqueId in class");
}
// Save the file in the right folder
databaseConnecter.saveYamlFile(config, type.getSimpleName(), filename);
databaseConnecter.saveYamlFile(config, path, filename);
}
/**
@ -379,14 +435,14 @@ public class FlatFileDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
@Override
public void deleteObject(T instance) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, IntrospectionException {
// The file name of the Yaml file.
PropertyDescriptor propertyDescriptor = new PropertyDescriptor("uniqueId", type);
PropertyDescriptor propertyDescriptor = new PropertyDescriptor("uniqueId", dataObject);
Method method = propertyDescriptor.getReadMethod();
String fileName = (String) method.invoke(instance);
if (!fileName.endsWith(".yml")) {
fileName = fileName + ".yml";
}
File dataFolder = new File(plugin.getDataFolder(), DATABASE_FOLDER_NAME);
File tableFolder = new File(dataFolder, type.getSimpleName());
File tableFolder = new File(dataFolder, dataObject.getSimpleName());
if (tableFolder.exists()) {
File file = new File(tableFolder, fileName);
file.delete();

View File

@ -19,10 +19,10 @@ import us.tastybento.bskyblock.database.DatabaseConnecter;
public abstract class AbstractDatabaseHandler<T> {
/**
* The type of the objects that should be created and filled with values
* The data object that should be created and filled with values
* from the database or inserted into the database
*/
protected Class<T> type;
protected Class<T> dataObject;
/**
* Contains the settings to create a connection to the database like
@ -52,7 +52,7 @@ public abstract class AbstractDatabaseHandler<T> {
protected AbstractDatabaseHandler(Plugin plugin, Class<T> type, DatabaseConnecter databaseConnecter) {
this.plugin = plugin;
this.databaseConnecter = databaseConnecter;
this.type = type;
this.dataObject = type;
this.selectQuery = createSelectQuery();
this.insertQuery = createInsertQuery();
this.deleteQuery = createDeleteQuery();

View File

@ -125,11 +125,11 @@ public class MySQLDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
private void createSchema() throws IntrospectionException, SQLException {
PreparedStatement pstmt = null;
try {
String sql = "CREATE TABLE IF NOT EXISTS `" + type.getCanonicalName() + "` (";
String sql = "CREATE TABLE IF NOT EXISTS `" + dataObject.getCanonicalName() + "` (";
// Run through the fields of the class using introspection
for (Field field : type.getDeclaredFields()) {
for (Field field : dataObject.getDeclaredFields()) {
// Get the description of the field
PropertyDescriptor propertyDescriptor = new PropertyDescriptor(field.getName(), type);
PropertyDescriptor propertyDescriptor = new PropertyDescriptor(field.getName(), dataObject);
//plugin.getLogger().info("DEBUG: Field = " + field.getName() + "(" + propertyDescriptor.getPropertyType().getTypeName() + ")");
// Get default SQL mappings
// Get the write method for this field. This method will take an argument of the type of this field.
@ -152,7 +152,7 @@ public class MySQLDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
propertyDescriptor.getPropertyType().equals(HashMap.class) ||
propertyDescriptor.getPropertyType().equals(ArrayList.class)) {
// The ID in this table relates to the parent table and is unique
String setSql = "CREATE TABLE IF NOT EXISTS `" + type.getCanonicalName() + "." + field.getName() + "` ("
String setSql = "CREATE TABLE IF NOT EXISTS `" + dataObject.getCanonicalName() + "." + field.getName() + "` ("
+ "uniqueId VARCHAR(36) NOT NULL, ";
// Get columns separated by commas
setSql += getCollectionColumnString(writeMethod,false,true);
@ -207,7 +207,7 @@ public class MySQLDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
boolean first = true;
/* Iterate the column-names */
for (Field f : type.getDeclaredFields()) {
for (Field f : dataObject.getDeclaredFields()) {
if (first)
first = false;
else
@ -321,7 +321,7 @@ public class MySQLDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
sb.append(getColumns(false));
sb.append(" FROM ");
sb.append("`");
sb.append(type.getCanonicalName());
sb.append(dataObject.getCanonicalName());
sb.append("`");
return sb.toString();
@ -339,7 +339,7 @@ public class MySQLDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
sb.append("REPLACE INTO ");
sb.append("`");
// The table name is the canonical name, so that add-ons can be sure of a unique table in the database
sb.append(type.getCanonicalName());
sb.append(dataObject.getCanonicalName());
sb.append("`");
sb.append("(");
sb.append(getColumns(false));
@ -388,7 +388,7 @@ public class MySQLDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
// insertQuery is created in super from the createInsertQuery() method
preparedStatement = connection.prepareStatement(insertQuery);
// Get the uniqueId. As each class extends DataObject, it must have this method in it.
PropertyDescriptor propertyDescriptor = new PropertyDescriptor("uniqueId", type);
PropertyDescriptor propertyDescriptor = new PropertyDescriptor("uniqueId", dataObject);
Method getUniqueId = propertyDescriptor.getReadMethod();
final String uniqueId = (String) getUniqueId.invoke(instance);
if (DEBUG) {
@ -402,9 +402,9 @@ public class MySQLDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
if (DEBUG)
plugin.getLogger().info("DEBUG: insert Query " + insertQuery);
// Run through the fields in the class using introspection
for (Field field : type.getDeclaredFields()) {
for (Field field : dataObject.getDeclaredFields()) {
// Get the field's property descriptor
propertyDescriptor = new PropertyDescriptor(field.getName(), type);
propertyDescriptor = new PropertyDescriptor(field.getName(), dataObject);
// Get the read method for this field
Method method = propertyDescriptor.getReadMethod();
if (DEBUG)
@ -421,14 +421,14 @@ public class MySQLDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
propertyDescriptor.getPropertyType().equals(ArrayList.class)) {
// Collection
// The table is cleared for this uniqueId every time the data is stored
String clearTableSql = "DELETE FROM `" + type.getCanonicalName() + "." + field.getName() + "` WHERE uniqueId = ?";
String clearTableSql = "DELETE FROM `" + dataObject.getCanonicalName() + "." + field.getName() + "` WHERE uniqueId = ?";
PreparedStatement collStatement = connection.prepareStatement(clearTableSql);
collStatement.setString(1, uniqueId);
collStatement.execute();
if (DEBUG)
plugin.getLogger().info("DEBUG: collStatement " + collStatement.toString());
// Insert into the table
String setSql = "INSERT INTO `" + type.getCanonicalName() + "." + field.getName() + "` (uniqueId, ";
String setSql = "INSERT INTO `" + dataObject.getCanonicalName() + "." + field.getName() + "` (uniqueId, ";
// Get the columns we are going to insert, just the names of them
setSql += getCollectionColumnString(propertyDescriptor.getWriteMethod(), false, false) + ") ";
// Get all the ?'s for the columns
@ -602,7 +602,7 @@ public class MySQLDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
plugin.getLogger().info("DEBUG: loading object for " + uniqueId);
try {
connection = databaseConnecter.createConnection();
String query = "SELECT " + getColumns(false) + " FROM `" + type.getCanonicalName() + "` WHERE uniqueId = ? LIMIT 1";
String query = "SELECT " + getColumns(false) + " FROM `" + dataObject.getCanonicalName() + "` WHERE uniqueId = ? LIMIT 1";
PreparedStatement preparedStatement = connection.prepareStatement(query);
preparedStatement.setString(1, uniqueId);
if (DEBUG)
@ -653,18 +653,18 @@ public class MySQLDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
// Run through them one by one
while (resultSet.next()) {
// Create a new instance of this type
T instance = type.newInstance();
T instance = dataObject.newInstance();
// Get the unique ID from the results
String uniqueId = resultSet.getString("uniqueId");
if (uniqueId == null) {
throw new SQLException("No unique ID in the results!");
}
// Use introspection to run through all the fields in this type class
for (Field field : type.getDeclaredFields()) {
for (Field field : dataObject.getDeclaredFields()) {
/* We assume the table-column-names exactly match the variable-names of T */
Object value = resultSet.getObject(field.getName());
// Get the property descriptor of this type
PropertyDescriptor propertyDescriptor = new PropertyDescriptor(field.getName(), type);
PropertyDescriptor propertyDescriptor = new PropertyDescriptor(field.getName(), dataObject);
// Get the write method for this field, because we are going to use it to write the value
// once we get the value from the database
Method method = propertyDescriptor.getWriteMethod();
@ -677,7 +677,7 @@ public class MySQLDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
String setSql = "SELECT ";
// Get the columns, just the names of them, no ?'s or types
setSql += getCollectionColumnString(method, false, false) + " ";
setSql += "FROM `" + type.getCanonicalName() + "." + field.getName() + "` ";
setSql += "FROM `" + dataObject.getCanonicalName() + "." + field.getName() + "` ";
// We will need to fill in the ? later with the unique id of the class from the database
setSql += "WHERE uniqueId = ?";
// Prepare the statement
@ -832,7 +832,7 @@ public class MySQLDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
// Try to connect to the database
connection = databaseConnecter.createConnection();
// Get the uniqueId. As each class extends DataObject, it must have this method in it.
Method getUniqueId = type.getMethod("getUniqueId");
Method getUniqueId = dataObject.getMethod("getUniqueId");
String uniqueId = (String) getUniqueId.invoke(instance);
//plugin.getLogger().info("DEBUG: Unique Id = " + uniqueId);
if (uniqueId.isEmpty()) {
@ -841,7 +841,7 @@ public class MySQLDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
// Delete from the main table
// First substitution is the table name
// deleteQuery is created in super from the createInsertQuery() method
preparedStatement = connection.prepareStatement(deleteQuery.replace("[table_name]", "`" + type.getCanonicalName() + "`"));
preparedStatement = connection.prepareStatement(deleteQuery.replace("[table_name]", "`" + dataObject.getCanonicalName() + "`"));
// Second is the unique ID
preparedStatement.setString(1, uniqueId);
preparedStatement.addBatch();
@ -850,16 +850,16 @@ public class MySQLDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
preparedStatement.executeBatch();
// Delete from any sub tables created from the object
// Run through the fields in the class using introspection
for (Field field : type.getDeclaredFields()) {
for (Field field : dataObject.getDeclaredFields()) {
// Get the field's property descriptor
PropertyDescriptor propertyDescriptor = new PropertyDescriptor(field.getName(), type);
PropertyDescriptor propertyDescriptor = new PropertyDescriptor(field.getName(), dataObject);
// Delete Collection tables
if (propertyDescriptor.getPropertyType().equals(Set.class) ||
propertyDescriptor.getPropertyType().equals(Map.class) ||
propertyDescriptor.getPropertyType().equals(HashMap.class) ||
propertyDescriptor.getPropertyType().equals(ArrayList.class)) {
// First substitution is the table name
preparedStatement = connection.prepareStatement(deleteQuery.replace("[table_name]", "`" + type.getCanonicalName() + "." + field.getName() + "`"));
preparedStatement = connection.prepareStatement(deleteQuery.replace("[table_name]", "`" + dataObject.getCanonicalName() + "." + field.getName() + "`"));
// Second is the unique ID
preparedStatement.setString(1, uniqueId);
preparedStatement.addBatch();
@ -886,7 +886,7 @@ public class MySQLDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
String query = "SELECT IF ( EXISTS( SELECT * FROM `" + type.getCanonicalName() + "` WHERE `uniqueId` = ?), 1, 0)";
String query = "SELECT IF ( EXISTS( SELECT * FROM `" + dataObject.getCanonicalName() + "` WHERE `uniqueId` = ?), 1, 0)";
//String query = "SELECT * FROM `" + type.getCanonicalName() + "` WHERE uniqueId = ?";
try {
connection = databaseConnecter.createConnection();

View File

@ -16,9 +16,9 @@ import org.bukkit.inventory.InventoryHolder;
import org.bukkit.inventory.ItemStack;
import org.bukkit.material.Chest;
import us.tastybento.bskyblock.api.commands.User;
import us.tastybento.bskyblock.Settings;
import us.tastybento.bskyblock.Settings.GameType;
import us.tastybento.bskyblock.api.commands.User;
import us.tastybento.bskyblock.api.configuration.ConfigEntry.GameType;
import us.tastybento.bskyblock.database.objects.Island;
import us.tastybento.bskyblock.generators.IslandWorld;