Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
package top.focess.util.yaml;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.thoughtworks.xstream.converters.reflection.PureJavaReflectionProvider;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.yaml.snakeyaml.Yaml;
import top.focess.util.SectionMap;
import top.focess.util.serialize.FocessSerializable;
import top.focess.util.serialize.NotFocessSerializableException;
import top.focess.util.serialize.SerializationParseException;
import top.focess.util.serialize.SimpleFocessReader;
import java.io.*;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.stream.Collectors;
/**
* This class is used to define a YAML configuration.
*/
public class YamlConfiguration implements SectionMap {
private static final Yaml YAML = new Yaml();
private static final PureJavaReflectionProvider PROVIDER = new PureJavaReflectionProvider();
private static final Map, ReservedHandler>> CLASS_RESERVED_HANDLER_MAP = Maps.newHashMap();
static {
CLASS_RESERVED_HANDLER_MAP.put(Class.class, new ReservedHandler() {
@Override
public Object write(final Class value) {
return value.getName();
}
@Override
public Class read(final Object value) {
try {
final String cls = value.toString();
switch (cls) {
case "byte":
return byte.class;
case "short":
return short.class;
case "int":
return int.class;
case "long":
return long.class;
case "float":
return float.class;
case "double":
return double.class;
case "boolean":
return boolean.class;
case "char":
return char.class;
case "void":
return void.class;
default:
return SimpleFocessReader.getDefaultClassFinder().forName(cls);
}
} catch (final ClassNotFoundException e) {
throw new SerializationParseException(e);
}
}
});
CLASS_RESERVED_HANDLER_MAP.put(ArrayList.class, new ReservedHandler() {
@Override
public Object write(final ArrayList list) {
return list.stream().map(YamlConfiguration::write).collect(Collectors.toList());
}
@Override
public ArrayList read(final Object value) {
final List list = (List) value;
final ArrayList ret = Lists.newArrayList();
for (final Object o : list) ret.add(YamlConfiguration.read(o));
return ret;
}
});
CLASS_RESERVED_HANDLER_MAP.put(HashSet.class, new ReservedHandler() {
@Override
public Object write(final HashSet set) {
return set.stream().map(YamlConfiguration::write).collect(Collectors.toList());
}
@Override
public HashSet read(final Object value) {
final List list = (List) value;
final HashSet ret = new HashSet();
for (final Object o : list) ret.add(YamlConfiguration.read(o));
return ret;
}
});
CLASS_RESERVED_HANDLER_MAP.put(ConcurrentHashMap.class, new ReservedHandler() {
@Override
public Object write(final ConcurrentHashMap map) {
return map;
}
@Override
public ConcurrentHashMap read(final Object value) {
final Map map = (Map) value;
return new ConcurrentHashMap(map);
}
});
CLASS_RESERVED_HANDLER_MAP.put(ConcurrentHashMap.KeySetView.class, new ReservedHandler() {
@Override
public Object write(final ConcurrentHashMap.KeySetView set) {
return set.stream().map(YamlConfiguration::write).collect(Collectors.toList());
}
@Override
public ConcurrentHashMap.KeySetView read(final Object value) {
final List list = (List) value;
final ConcurrentHashMap.KeySetView ret = ConcurrentHashMap.newKeySet();
for (final Object o : list) ret.add(YamlConfiguration.read(o));
return ret;
}
});
CLASS_RESERVED_HANDLER_MAP.put(CopyOnWriteArrayList.class, new ReservedHandler() {
@Override
public Object write(final CopyOnWriteArrayList value) {
return value.stream().map(YamlConfiguration::write).collect(Collectors.toList());
}
@Override
public CopyOnWriteArrayList read(final Object value) {
final List list = (List) value;
final CopyOnWriteArrayList ret = new CopyOnWriteArrayList();
for (final Object o : list) ret.add(YamlConfiguration.read(o));
return ret;
}
});
CLASS_RESERVED_HANDLER_MAP.put(HashMap.class, new ReservedHandler() {
@Override
public Object write(final HashMap map) {
return map;
}
@Override
public HashMap read(final Object value) {
return (HashMap) value;
}
});
}
private final Map values;
/**
* Initializes the YamlConfiguration with existed key-value pairs
*
* @param values the YAML configuration key-value pairs
*/
public YamlConfiguration(@Nullable final Map values) {
this.values = values == null ? Maps.newHashMap() : values;
}
/**
* Load the file as a YAML configuration
*
* @param file where to load
* @return YAML configuration
* @throws YamlLoadException if there is any io exception in loading the file
*/
@NotNull
public static YamlConfiguration loadFile(@NonNull final File file) throws YamlLoadException {
try {
final FileReader reader = new FileReader(file);
final YamlConfiguration yamlConfiguration = new YamlConfiguration(YAML.load(reader));
reader.close();
return yamlConfiguration;
} catch (final IOException e) {
throw new YamlLoadException(e);
}
}
@NotNull
@Contract("_ -> new")
public static YamlConfiguration load(@Nullable final InputStream inputStream) {
if (inputStream == null) return new YamlConfiguration(null);
return new YamlConfiguration(YAML.load(inputStream));
}
@Nullable
private static Object write(@Nullable final Object value) {
if (value == null)
return null;
if (value instanceof Byte || value instanceof Short || value instanceof Integer || value instanceof Long || value instanceof Float || value instanceof Double || value instanceof Character || value instanceof Boolean || value instanceof String)
return value;
if (value.getClass().isEnum()) {
final Map ret = Maps.newHashMap();
ret.put("class", "!!" + value.getClass().getName());
ret.put("value", ((Enum>)value).name());
return ret;
}
if (value.getClass().isArray()) {
final Map ret = Maps.newHashMap();
ret.put("class", "!!" + value.getClass().getComponentType().getName());
final List list = Lists.newArrayList();
for (int i = 0; i < Array.getLength(value); i++)
list.add(write(Array.get(value, i)));
ret.put("value", list);
ret.put("array", true);
return ret;
}
if (value instanceof FocessSerializable) {
final Map ret = Maps.newHashMap();
ret.put("class", "!!" + value.getClass().getName());
Map data = ((FocessSerializable) value).serialize();
if (data != null) {
ret.put("value", data);
ret.put("serialize", true);
return ret;
}
data = Maps.newHashMap();
for (final Field field : value.getClass().getDeclaredFields()) {
if ((field.getModifiers() & (Modifier.STATIC | Modifier.TRANSIENT)) == 0) {
field.setAccessible(true);
try {
data.put(field.getName(), write(field.get(value)));
} catch (final IllegalAccessException e) {
throw new NotFocessSerializableException(value.getClass().getName());
}
}
}
ret.put("value", data);
return ret;
}
if (CLASS_RESERVED_HANDLER_MAP.containsKey(value.getClass())) {
final Map ret = Maps.newHashMap();
final T t = (T) value;
final ReservedHandler handler = (ReservedHandler) CLASS_RESERVED_HANDLER_MAP.get(value.getClass());
ret.put("value", handler.write(t));
ret.put("class", "!!" + value.getClass().getName());
return ret;
}
throw new NotFocessSerializableException(value.getClass().getName());
}
@Nullable
private static > Object read(final Object value) {
if (value == null)
return null;
if (value instanceof Byte || value instanceof Short || value instanceof Integer || value instanceof Long || value instanceof Float || value instanceof Double || value instanceof Character || value instanceof Boolean || value instanceof String)
return value;
if (value instanceof Map) {
final Map map = (Map) value;
if (map.containsKey("class") && map.containsKey("value")) {
final String className = map.get("class").toString().substring(2);
try {
final Class> cls = SimpleFocessReader.getDefaultClassFinder().forName(className);
final Object v = map.get("value");
if (cls.isEnum()) {
Class enumClass = (Class) cls;
return Enum.valueOf(enumClass, ((Enum>)v).name());
}
if (v instanceof List && Boolean.parseBoolean(String.valueOf(map.get("array")))) {
final List list = (List) v;
final Object array = Array.newInstance(cls, list.size());
for (int i = 0; i < list.size(); i++)
Array.set(array, i, read(list.get(i)));
return array;
}
if (v instanceof Map && FocessSerializable.class.isAssignableFrom(cls)) {
final Map data = (Map) v;
if (Boolean.parseBoolean(String.valueOf(map.get("serialize")))) {
final Method method = cls.getMethod("deserialize", Map.class);
return method.invoke(null, data);
}
final Object o = PROVIDER.newInstance(cls);
for (final String key : data.keySet()) {
final Field f = cls.getDeclaredField(key);
f.setAccessible(true);
f.set(o, read(data.get(key)));
}
return o;
}
if (CLASS_RESERVED_HANDLER_MAP.containsKey(cls)) {
final ReservedHandler handler = (ReservedHandler) CLASS_RESERVED_HANDLER_MAP.get(cls);
return handler.read(v);
}
} catch (final Exception e) {
throw new SerializationParseException(e);
}
}
}
throw new SerializationParseException("Unknown class: " + value.getClass().getName());
}
@Override
public YamlConfigurationSection createSection(final String key) {
final Map values = Maps.newHashMap();
this.set(key, values);
return new YamlConfigurationSection(this, values);
}
@Override
public void set(final String key, @Nullable final Object value) {
this.values.put(key, write(value));
}
/**
* Get the value of the key-value pair as list
* @param key the key
* @return the value of the key-value pair as list, or null if the key does not exist
*/
@Nullable
public List getList(final String key) {
final List value;
try {
value = SectionMap.super.get(key);
} catch (final Exception e) {
return Lists.newArrayList(Collections.singleton((T)YamlConfiguration.read(SectionMap.super.get(key))));
}
if (value == null)
return null;
return value.stream().map(i -> (T)YamlConfiguration.read(i)).collect(Collectors.toList());
}
/**
* Get the value of the key-value pair as list
* @param key the key
* @return the value of the key-value pair as list or an empty list if the key-value pair does not exist
*/
public List getListOrEmpty(final String key) {
try {
List ret = getList(key);
return ret == null ? Lists.newArrayList() : ret;
}catch (final Exception e) {
return Lists.newArrayList();
}
}
/**
* Set the list value of the key-value pair
* @param key the key
* @param value the list value
*/
public void setList(final String key, final List> value) {
this.values.put(key, value.stream().map(YamlConfiguration::write).collect(Collectors.toList()));
}
@Nullable
@Override
public T get(final String key) {
final Object value = SectionMap.super.get(key);
return (T) read(value);
}
@Override
public Map getValues() {
return this.values;
}
/**
* Save the YAML configuration as a file
*
* @param file where to save
*/
public void save(final File file) {
try {
YAML.dump(this.values, new FileWriter(file));
} catch (final IOException e) {
throw new YamlSaveException(e);
}
}
@Override
public YamlConfigurationSection getSection(final String key) {
final Object value = this.get(key);
if (value == null)
return this.createSection(key);
if (value instanceof Map)
return new YamlConfigurationSection(this, (Map) value);
throw new IllegalStateException("This " + key + " is not a valid section.");
}
@Override
public boolean containsSection(final String key) {
return this.get(key) instanceof Map;
}
@Override
public String toString() {
return this.values.toString();
}
private interface ReservedHandler {
Object write(T value);
T read(Object value);
}
}