LibJF/libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/impl/dsl/DslEntryInfo.java

201 lines
6.9 KiB
Java

package io.gitlab.jfronny.libjf.config.impl.dsl;
import io.gitlab.jfronny.commons.serialize.gson.api.GsonHolder;
import io.gitlab.jfronny.commons.throwable.ThrowingConsumer;
import io.gitlab.jfronny.commons.throwable.ThrowingSupplier;
import io.gitlab.jfronny.gson.JsonElement;
import io.gitlab.jfronny.gson.stream.JsonWriter;
import io.gitlab.jfronny.libjf.LibJf;
import io.gitlab.jfronny.libjf.config.api.v1.Entry;
import io.gitlab.jfronny.libjf.config.api.v1.EntryInfo;
import io.gitlab.jfronny.libjf.config.api.v1.type.Type;
import io.gitlab.jfronny.libjf.config.impl.entrypoint.JfConfigSafe;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Objects;
import java.util.stream.Collectors;
public class DslEntryInfo<T> implements EntryInfo<T> {
private final String name;
private final T defaultValue;
private final ThrowingSupplier<T, IllegalAccessException> get;
private final ThrowingConsumer<T, IllegalAccessException> set;
private final Type type;
private final int width;
private final double minValue;
private final double maxValue;
public DslEntryInfo(String name,
T defaultValue,
ThrowingSupplier<T, IllegalAccessException> get,
ThrowingConsumer<T, IllegalAccessException> set,
Type type,
int width,
double minValue,
double maxValue) {
this.name = name;
this.defaultValue = defaultValue;
this.get = get;
this.set = set;
this.type = type;
this.width = width;
this.minValue = minValue;
this.maxValue = maxValue;
}
public DslEntryInfo(String name,
T def,
ThrowingSupplier<T, IllegalAccessException> get,
ThrowingConsumer<T, IllegalAccessException> set,
Type type) {
this(name, def, get, set, type, 100, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);
}
public static DslEntryInfo<Object> ofField(Field field) {
Entry entry = field.getAnnotation(Entry.class);
Object defaultValue = null;
try {
defaultValue = field.get(null);
} catch (IllegalAccessException ignored) {
}
//noinspection unchecked,rawtypes
return new DslEntryInfo<Object>(
field.getName(),
defaultValue,
() -> field.get(null),
v -> field.set(null, v),
(Type) Type.ofClass(field.getGenericType()),
entry == null ? 100 : entry.width(),
entry == null ? Double.NEGATIVE_INFINITY : entry.min(),
entry == null ? Double.POSITIVE_INFINITY : entry.max()
);
}
@Override
public String getName() {
return name;
}
@Override
public T getDefault() {
return defaultValue;
}
@Override
public T getValue() throws IllegalAccessException {
return get.get();
}
@Override
public void setValue(T value) throws IllegalAccessException {
set.accept(value);
}
@Override
public Type getValueType() {
return type;
}
@Override
public void fix() {
Object value;
try {
value = getValue();
} catch (IllegalAccessException e) {
LibJf.LOGGER.error("Could not read value", e);
return;
}
final Object valueOriginal = value;
if (value instanceof final Integer v) {
if (v < minValue) value = (int)minValue;
if (v > maxValue) value = (int)maxValue;
} else if (value instanceof final Float v) {
if (v < minValue) value = (float)minValue;
if (v > maxValue) value = (float)maxValue;
} else if (value instanceof final Double v) {
if (v < minValue) value = minValue;
if (v > maxValue) value = maxValue;
}
if (valueOriginal != value) {
try {
setUnchecked(value);
} catch (IllegalAccessException e) {
LibJf.LOGGER.error("Could not write value", e);
}
}
}
@Override
public void loadFromJson(JsonElement element) throws IllegalAccessException {
if (type.isBool()) {
if (element.isJsonPrimitive() && element.getAsJsonPrimitive().isBoolean()) {
setUnchecked(element.getAsBoolean());
}
} else if (type.isString()) {
if (element.isJsonPrimitive()) {
setUnchecked(element.getAsString());
}
} else if (type.isInt()) {
if (element.isJsonPrimitive() && element.getAsJsonPrimitive().isNumber()) {
setUnchecked(element.getAsNumber().intValue());
}
} else if (type.isLong()) {
if (element.isJsonPrimitive() && element.getAsJsonPrimitive().isNumber()) {
setUnchecked(element.getAsNumber().longValue());
}
} else if (type.isDouble()) {
if (element.isJsonPrimitive() && element.getAsJsonPrimitive().isNumber()) {
setUnchecked(element.getAsNumber().doubleValue());
}
} else if (type.isFloat()) {
if (element.isJsonPrimitive() && element.getAsJsonPrimitive().isNumber()) {
setUnchecked(element.getAsNumber().floatValue());
}
} else if (type.isEnum()) {
Type.TEnum<T> e = (Type.TEnum<T>) type;
if (element.isJsonPrimitive() && element.getAsJsonPrimitive().isString()) {
setUnchecked(e.optionForString(element.getAsString()));
}
} else {
setValue(GsonHolder.getGson().fromJson(element, type.asClass()));
}
}
@SuppressWarnings("unchecked")
private void setUnchecked(Object object) throws IllegalAccessException {
if (object == null) return;
setValue((T) object);
}
@Override
public void writeTo(JsonWriter writer, String translationPrefix) throws IOException, IllegalAccessException {
T value = getValue();
String val;
if ((val = JfConfigSafe.TRANSLATION_SUPPLIER.apply(translationPrefix + getName() + ".tooltip")) != null) {
writer.comment(val);
}
if (type.isEnum()) {
writer.comment("Valid: [" + Arrays.stream(((Type.TEnum<T>)type).options()).map(Objects::toString).collect(Collectors.joining(", ")) + "]");
}
writer.name(name);
GsonHolder.getGson().toJson(value, Objects.requireNonNullElse(type.asClass(), String.class), writer);
}
@Override
public int getWidth() {
return width;
}
@Override
public double getMinValue() {
return minValue;
}
@Override
public double getMaxValue() {
return maxValue;
}
}