Package greed.conf

Source Code of greed.conf.ConfigParser

package greed.conf;

import greed.conf.meta.*;

import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;

import com.typesafe.config.Config;
import com.typesafe.config.ConfigObject;
import com.typesafe.config.ConfigValue;
import greed.conf.parser.IParser;
import greed.util.reflect.ReflectionUtil;

/**
* Greed is good! Cheers!
*/
public class ConfigParser {

    public ConfigParser() {}

    @SuppressWarnings("unchecked")
    public <T> T parseAndCheck(String path, Object obj, Class<T> configClass) throws ConfigException {
        if (String.class.equals(configClass)) {
            return (T) parseString(obj);
        }
        else if (Integer.TYPE.equals(configClass) || Integer.class.equals(configClass)) {
            return (T) parseInt(path, obj);
        }
        else if (Boolean.TYPE.equals(configClass) || Boolean.class.equals(configClass)) {
            return (T) parseBoolean(obj);
        }
        else if (configClass.isEnum()) {
            return (T) parseEnum(obj, configClass);
        }

        if (!(obj instanceof Config) && !(obj instanceof ConfigObject)) {
            throw new ConfigException(String.format("Config object needed, %s found", obj.getClass().getSimpleName()));
        }

        Config rawConf = (obj instanceof ConfigObject) ? ((ConfigObject) obj).toConfig() : (Config) obj;
        HashSet<String> hasSet = new HashSet<String>();
        try {
            T configObject = configClass.newInstance();
            for (Field field: configClass.getDeclaredFields()) {

                if (field.isSynthetic()) {
                    // ignore synthetic fields (e.g. eclEmma)
                    continue;
                }

                if (!rawConf.hasPath(field.getName())) {
                    if (field.isAnnotationPresent(Required.class))
                        throw new ConfigException(String.format("Missing required config key at %s.%s", path, field.getName()));
                    continue;
                }

                Method setter = ReflectionUtil.findSetter(configClass, field);
                if (setter == null) {
                    throw new ConfigException(String.format("FATAL: Unable to find setter for %s in class %s", field.getName(), configClass.getName()));
                }

                IParser parser = null;
                if (field.isAnnotationPresent(Parser.class)) {
                    Class<? extends IParser> parserClass = field.getAnnotation(Parser.class).value();
                    parser = parserClass.newInstance();
                }

                Class<?> fieldType = field.getType();
                hasSet.add(field.getName());
                if (fieldType.isPrimitive() || String.class.equals(fieldType) || fieldType.isEnum()) {
                    setter.invoke(configObject,
                            parser != null ? parser.apply(rawConf.getAnyRef(field.getName())) : parseAndCheck(path + "." + field.getName(), rawConf.getAnyRef(field.getName()), fieldType));
                }
                else if (fieldType.isArray()) {
                    Class<?> elementType = fieldType.getComponentType();
                    List<?> rawValues = rawConf.getAnyRefList(field.getName());
                    Object values = Array.newInstance(elementType, rawValues.size());
                    int idx = 0;
                    for (Object rv: rawValues) {
                        Array.set(values, idx,
                                parser != null ? parser.apply(rv) : parseAndCheck(String.format("%s.[%d]", path, idx), rv, elementType));
                        idx++;
                    }
                    setter.invoke(configObject, values);
                }
                else if (field.isAnnotationPresent(MapParam.class)) {
                    HashMap<Object, Object> map = new HashMap<Object, Object>();
                    Class<?> valueClass = field.getAnnotation(MapParam.class).value();
                    for (Map.Entry<String, ConfigValue> entry : rawConf.getObject(field.getName()).entrySet()) {
                        map.put(entry.getKey(),
                                parser != null ? parser.apply(entry.getValue()) : parseAndCheck(path + "." + field.getName() + "." + entry.getKey(), entry.getValue(), valueClass));
                    }
                    setter.invoke(configObject, map);
                }
                else if (fieldType.isAnnotationPresent(ConfigObjectClass.class)) {
                    setter.invoke(configObject, parseAndCheck(path + "." + field.getName(), rawConf.getConfig(field.getName()), fieldType));
                }
                else if (parser != null) {
                    setter.invoke(configObject, parser.apply(rawConf.getAnyRef(field.getName())));
                }
                else {
                    throw new ConfigException(String.format("Field %s with unknown type %s at path %s", field.getName(), fieldType.getSimpleName(), path));
                }
            }

            // Check for conflict
            for (Field field: configClass.getDeclaredFields()) {
                if (!hasSet.contains(field.getName()))
                    continue;

                if (field.isAnnotationPresent(Conflict.class)) {
                    for (String conflictField: field.getAnnotation(Conflict.class).withField()) {
                        if (hasSet.contains(conflictField)) {
                            throw new ConfigException(String.format("Conflict fields of %s and %s at path %s", field.getName(), conflictField, path));
                        }
                    }
                }
            }

            return configObject;
        } catch (InstantiationException e) {
            throw new ConfigException("FATAL: Exception while reflecting on " + configClass.getName(), e);
        } catch (ReflectiveOperationException e) {
            throw new ConfigException("FATAL: Exception while reflecting on " + configClass.getName(), e);
        }
    }

    private Object parseEnum(Object obj, Class<?> enumClass) throws ConfigException {
        String enumStr = ReflectionUtil.normalizeEnumName(obj.toString());
        Object enumValue = null;
        for (Object ev: enumClass.getEnumConstants())
            if (ev.toString().equals(enumStr)) {
                enumValue = ev;
                break;
            }
        if (enumValue == null)
            throw new ConfigException("No such value of " + enumStr + " for enum type " + enumClass.getName());
        return enumValue;
    }

    private Boolean parseBoolean(Object obj) {
        return Boolean.parseBoolean(obj.toString());
    }

    private Integer parseInt(String path, Object obj) throws ConfigException {
        try {
            return Integer.parseInt(obj.toString());
        }
        catch (NumberFormatException e) {
            throw new ConfigException(String.format("Cannot parse integer for %s from %s", path, obj.toString()), e);
        }
    }

    private String parseString(Object obj) {
        if (obj instanceof ConfigValue) {
            String  s = ((ConfigValue)obj).render() ;
            if (s != null && s.length() >= 2 && s.charAt(0) == '"' && s.charAt(s.length()-1)=='"') {
                s = s.substring(1, s.length() - 1);
            }
            return s;
        } else {
            return obj.toString();
        }
    }
}
TOP

Related Classes of greed.conf.ConfigParser

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.