com.mstiles92.plugins.stileslib.config.ConfigObject.java Source code

Java tutorial

Introduction

Here is the source code for com.mstiles92.plugins.stileslib.config.ConfigObject.java

Source

/*
 * This document is a part of the source code and related artifacts for StilesLib, an open source library that
 * provides a set of commonly-used functions for Bukkit plugins.
 *
 * http://github.com/mstiles92/StilesLib
 *
 * Copyright (c) 2014 Matthew Stiles (mstiles92)
 *
 * Licensed under the Common Development and Distribution License Version 1.0
 * You may not use this file except in compliance with this License.
 *
 * You may obtain a copy of the CDDL-1.0 License at http://opensource.org/licenses/CDDL-1.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
 * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations under the license.
 */

package com.mstiles92.plugins.stileslib.config;

import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.util.Vector;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.*;

/*
* SuperEasyConfig - ConfigObject
*
* Based off of codename_Bs EasyConfig v2.1
* which was inspired by md_5
*
* An even awesomer super-duper-lazy Config lib!
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* @author MrFigg
* @version 1.2
*/

public abstract class ConfigObject {

    /*
      * loading and saving
      */

    protected void onLoad(ConfigurationSection cs) throws Exception {
        for (Field field : getClass().getDeclaredFields()) {
            String path = field.getName().replaceAll("_", ".");
            if (doSkip(field)) {
                // Do nothing
            } else if (cs.isSet(path)) {
                field.set(this, loadObject(field, cs, path));
            } else {
                cs.set(path, saveObject(field.get(this), field, cs, path));
            }
        }
    }

    protected void onSave(ConfigurationSection cs) throws Exception {
        for (Field field : getClass().getDeclaredFields()) {
            String path = field.getName().replaceAll("_", ".");
            if (doSkip(field)) {
                // Do nothing
            } else {
                cs.set(path, saveObject(field.get(this), field, cs, path));
            }
        }
    }

    protected Object loadObject(Field field, ConfigurationSection cs, String path) throws Exception {
        return loadObject(field, cs, path, 0);
    }

    protected Object saveObject(Object obj, Field field, ConfigurationSection cs, String path) throws Exception {
        return saveObject(obj, field, cs, path, 0);
    }

    @SuppressWarnings("rawtypes")
    protected Object loadObject(Field field, ConfigurationSection cs, String path, int depth) throws Exception {
        Class clazz = getClassAtDepth(field.getGenericType(), depth);
        if (ConfigObject.class.isAssignableFrom(clazz) && isConfigurationSection(cs.get(path))) {
            return getConfigObject(clazz, cs.getConfigurationSection(path));
        } else if (Location.class.isAssignableFrom(clazz) && isJSON(cs.get(path))) {
            return getLocation((String) cs.get(path));
        } else if (Vector.class.isAssignableFrom(clazz) && isJSON(cs.get(path))) {
            return getVector((String) cs.get(path));
        } else if (Map.class.isAssignableFrom(clazz) && isConfigurationSection(cs.get(path))) {
            return getMap(field, cs.getConfigurationSection(path), path, depth);
        } else if (clazz.isEnum() && isString(cs.get(path))) {
            return getEnum(clazz, (String) cs.get(path));
        } else if (List.class.isAssignableFrom(clazz) && isConfigurationSection(cs.get(path))) {
            Class subClazz = getClassAtDepth(field.getGenericType(), depth + 1);
            if (ConfigObject.class.isAssignableFrom(subClazz) || Location.class.isAssignableFrom(subClazz)
                    || Vector.class.isAssignableFrom(subClazz) || Map.class.isAssignableFrom(subClazz)
                    || List.class.isAssignableFrom(subClazz) || subClazz.isEnum()) {
                return getList(field, cs.getConfigurationSection(path), path, depth);
            } else {
                return cs.get(path);
            }
        } else {
            return cs.get(path);
        }
    }

    @SuppressWarnings("rawtypes")
    protected Object saveObject(Object obj, Field field, ConfigurationSection cs, String path, int depth)
            throws Exception {
        Class clazz = getClassAtDepth(field.getGenericType(), depth);
        if (ConfigObject.class.isAssignableFrom(clazz) && isConfigObject(obj)) {
            return getConfigObject((ConfigObject) obj, path, cs);
        } else if (Location.class.isAssignableFrom(clazz) && isLocation(obj)) {
            return getLocation((Location) obj);
        } else if (Vector.class.isAssignableFrom(clazz) && isVector(obj)) {
            return getVector((Vector) obj);
        } else if (Map.class.isAssignableFrom(clazz) && isMap(obj)) {
            return getMap((Map) obj, field, cs, path, depth);
        } else if (clazz.isEnum() && isEnum(clazz, obj)) {
            return getEnum((Enum) obj);
        } else if (List.class.isAssignableFrom(clazz) && isList(obj)) {
            Class subClazz = getClassAtDepth(field.getGenericType(), depth + 1);
            if (ConfigObject.class.isAssignableFrom(subClazz) || Location.class.isAssignableFrom(subClazz)
                    || Vector.class.isAssignableFrom(subClazz) || Map.class.isAssignableFrom(subClazz)
                    || List.class.isAssignableFrom(subClazz) || subClazz.isEnum()) {
                return getList((List) obj, field, cs, path, depth);
            } else {
                return obj;
            }
        } else {
            return obj;
        }
    }

    /*
      * class detection
      */

    @SuppressWarnings("rawtypes")
    protected Class getClassAtDepth(Type type, int depth) throws Exception {
        if (depth <= 0) {
            String className = type.toString();
            if (className.length() >= 6 && className.substring(0, 6).equalsIgnoreCase("class ")) {
                className = className.substring(6);
            }
            if (className.indexOf("<") >= 0) {
                className = className.substring(0, className.indexOf("<"));
            }
            try {
                return Class.forName(className);
            } catch (ClassNotFoundException ex) {
                // ugly fix for primitive data types
                if (className.equalsIgnoreCase("byte"))
                    return Byte.class;
                if (className.equalsIgnoreCase("short"))
                    return Short.class;
                if (className.equalsIgnoreCase("int"))
                    return Integer.class;
                if (className.equalsIgnoreCase("long"))
                    return Long.class;
                if (className.equalsIgnoreCase("float"))
                    return Float.class;
                if (className.equalsIgnoreCase("double"))
                    return Double.class;
                if (className.equalsIgnoreCase("char"))
                    return Character.class;
                if (className.equalsIgnoreCase("boolean"))
                    return Boolean.class;
                throw ex;
            }
        }
        depth--;
        ParameterizedType pType = (ParameterizedType) type;
        Type[] typeArgs = pType.getActualTypeArguments();
        return getClassAtDepth(typeArgs[typeArgs.length - 1], depth);
    }

    protected boolean isString(Object obj) {
        if (obj instanceof String) {
            return true;
        }
        return false;
    }

    protected boolean isConfigurationSection(Object o) {
        try {
            return (ConfigurationSection) o != null;
        } catch (Exception e) {
            return false;
        }
    }

    protected boolean isJSON(Object obj) {
        try {
            if (obj instanceof String) {
                String str = (String) obj;
                if (str.startsWith("{")) {
                    return new JSONParser().parse(str) != null;
                }
            }
            return false;
        } catch (Exception e) {
            return false;
        }
    }

    protected boolean isConfigObject(Object obj) {
        try {
            return (ConfigObject) obj != null;
        } catch (Exception e) {
            return false;
        }
    }

    protected boolean isLocation(Object obj) {
        try {
            return (Location) obj != null;
        } catch (Exception e) {
            return false;
        }
    }

    protected boolean isVector(Object obj) {
        try {
            return (Vector) obj != null;
        } catch (Exception e) {
            return false;
        }
    }

    @SuppressWarnings("rawtypes")
    protected boolean isMap(Object obj) {
        try {
            return (Map) obj != null;
        } catch (Exception e) {
            return false;
        }
    }

    @SuppressWarnings("rawtypes")
    protected boolean isList(Object obj) {
        try {
            return (List) obj != null;
        } catch (Exception e) {
            return false;
        }
    }

    @SuppressWarnings("rawtypes")
    protected boolean isEnum(Class clazz, Object obj) {
        if (!clazz.isEnum())
            return false;
        for (Object constant : clazz.getEnumConstants()) {
            if (constant.equals(obj)) {
                return true;
            }
        }
        return false;
    }

    /*
      * loading conversion
      */

    @SuppressWarnings("rawtypes")
    protected ConfigObject getConfigObject(Class clazz, ConfigurationSection cs) throws Exception {
        ConfigObject obj = (ConfigObject) clazz.newInstance();
        obj.onLoad(cs);
        return obj;
    }

    protected Location getLocation(String json) throws Exception {
        JSONObject data = (JSONObject) new JSONParser().parse(json);
        // world
        World world = Bukkit.getWorld((String) data.get("world"));
        // x, y, z
        double x = Double.parseDouble((String) data.get("x"));
        double y = Double.parseDouble((String) data.get("y"));
        double z = Double.parseDouble((String) data.get("z"));
        // pitch, yaw
        float pitch = Float.parseFloat((String) data.get("pitch"));
        float yaw = Float.parseFloat((String) data.get("yaw"));
        // generate Location
        Location loc = new Location(world, x, y, z);
        loc.setPitch(pitch);
        loc.setYaw(yaw);
        return loc;
    }

    protected Vector getVector(String json) throws Exception {
        JSONObject data = (JSONObject) new JSONParser().parse(json);
        // x, y, z
        double x = Double.parseDouble((String) data.get("x"));
        double y = Double.parseDouble((String) data.get("y"));
        double z = Double.parseDouble((String) data.get("z"));
        // generate Vector
        return new Vector(x, y, z);
    }

    @SuppressWarnings({ "rawtypes", "unchecked" })
    protected Map getMap(Field field, ConfigurationSection cs, String path, int depth) throws Exception {
        depth++;
        Set<String> keys = cs.getKeys(false);
        Map map = new HashMap();
        if (keys != null && keys.size() > 0) {
            for (String key : keys) {
                Object in = cs.get(key);
                in = loadObject(field, cs, key, depth);
                map.put(key, in);
            }
        }
        return map;
    }

    @SuppressWarnings({ "rawtypes", "unchecked" })
    protected List getList(Field field, ConfigurationSection cs, String path, int depth) throws Exception {
        depth++;
        int listSize = cs.getKeys(false).size();
        String key = path;
        if (key.lastIndexOf(".") >= 0) {
            key = key.substring(key.lastIndexOf("."));
        }
        List list = new ArrayList();
        if (listSize > 0) {
            int loaded = 0;
            int i = 0;
            while (loaded < listSize) {
                if (cs.isSet(key + i)) {
                    Object in = cs.get(key + i);
                    in = loadObject(field, cs, key + i, depth);
                    list.add(in);
                    loaded++;
                }
                i++;
                // ugly overflow guard... should only be needed if config was manually edited very badly
                if (i > (listSize * 3))
                    loaded = listSize;
            }
        }
        return list;
    }

    @SuppressWarnings("rawtypes")
    protected Enum getEnum(Class clazz, String string) throws Exception {
        if (!clazz.isEnum())
            throw new Exception("Class " + clazz.getName() + " is not an enum.");
        for (Object constant : clazz.getEnumConstants()) {
            if (((Enum) constant).toString().equals(string)) {
                return (Enum) constant;
            }
        }
        throw new Exception("String " + string + " not a valid enum constant for " + clazz.getName());
    }

    /*
      * saving conversion
      */

    protected ConfigurationSection getConfigObject(ConfigObject obj, String path, ConfigurationSection cs)
            throws Exception {
        ConfigurationSection subCS = cs.createSection(path);
        obj.onSave(subCS);
        return subCS;
    }

    protected String getLocation(Location loc) {
        String ret = "{";
        ret += "\"world\":\"" + loc.getWorld().getName() + "\"";
        ret += ",\"x\":\"" + loc.getX() + "\"";
        ret += ",\"y\":\"" + loc.getY() + "\"";
        ret += ",\"z\":\"" + loc.getZ() + "\"";
        ret += ",\"pitch\":\"" + loc.getPitch() + "\"";
        ret += ",\"yaw\":\"" + loc.getYaw() + "\"";
        ret += "}";
        if (!isJSON(ret))
            return getLocationJSON(loc);
        try {
            getLocation(ret);
        } catch (Exception ex) {
            return getLocationJSON(loc);
        }
        return ret;
    }

    @SuppressWarnings("unchecked")
    protected String getLocationJSON(Location loc) {
        JSONObject data = new JSONObject();
        // world
        data.put("world", loc.getWorld().getName());
        // x, y, z
        data.put("x", String.valueOf(loc.getX()));
        data.put("y", String.valueOf(loc.getY()));
        data.put("z", String.valueOf(loc.getZ()));
        // pitch, yaw
        data.put("pitch", String.valueOf(loc.getPitch()));
        data.put("yaw", String.valueOf(loc.getYaw()));
        return data.toJSONString();
    }

    protected String getVector(Vector vec) {
        String ret = "{";
        ret += "\"x\":\"" + vec.getX() + "\"";
        ret += ",\"y\":\"" + vec.getY() + "\"";
        ret += ",\"z\":\"" + vec.getZ() + "\"";
        ret += "}";
        if (!isJSON(ret))
            return getVectorJSON(vec);
        try {
            getVector(ret);
        } catch (Exception ex) {
            return getVectorJSON(vec);
        }
        return ret;
    }

    @SuppressWarnings("unchecked")
    protected String getVectorJSON(Vector vec) {
        JSONObject data = new JSONObject();
        // x, y, z
        data.put("x", String.valueOf(vec.getX()));
        data.put("y", String.valueOf(vec.getY()));
        data.put("z", String.valueOf(vec.getZ()));
        return data.toJSONString();
    }

    @SuppressWarnings({ "rawtypes", "unchecked" })
    protected ConfigurationSection getMap(Map map, Field field, ConfigurationSection cs, String path, int depth)
            throws Exception {
        depth++;
        ConfigurationSection subCS = cs.createSection(path);
        Set<String> keys = map.keySet();
        if (keys != null && keys.size() > 0) {
            for (String key : keys) {
                Object out = map.get(key);
                out = saveObject(out, field, cs, path + "." + key, depth);
                subCS.set(key, out);
            }
        }
        return subCS;
    }

    @SuppressWarnings("rawtypes")
    protected ConfigurationSection getList(List list, Field field, ConfigurationSection cs, String path, int depth)
            throws Exception {
        depth++;
        ConfigurationSection subCS = cs.createSection(path);
        String key = path;
        if (key.lastIndexOf(".") >= 0) {
            key = key.substring(key.lastIndexOf("."));
        }
        if (list != null && list.size() > 0) {
            for (int i = 0; i < list.size(); i++) {
                Object out = list.get(i);
                out = saveObject(out, field, cs, path + "." + key + (i + 1), depth);
                subCS.set(key + (i + 1), out);
            }
        }
        return subCS;
    }

    @SuppressWarnings("rawtypes")
    protected String getEnum(Enum enumObj) {
        return enumObj.toString();
    }

    /*
      * utility
      */

    protected boolean doSkip(Field field) {
        return Modifier.isTransient(field.getModifiers()) || Modifier.isStatic(field.getModifiers())
                || Modifier.isFinal(field.getModifiers()) || Modifier.isProtected(field.getModifiers())
                || Modifier.isPrivate(field.getModifiers());
    }
}