Skip to content

Commit

Permalink
specs!
Browse files Browse the repository at this point in the history
  • Loading branch information
KrLite committed May 2, 2024
1 parent 32b8ee9 commit d45dff1
Show file tree
Hide file tree
Showing 7 changed files with 158 additions and 29 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package band.kessokuteatime.nightautoconfig.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.List;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface SpecInRangeByte {
byte min() default 0;
byte max() default Byte.MAX_VALUE;

List<Class<?>> associatedTypes = List.of(Byte.class, byte.class);
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,13 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.List;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface SpecInRangeDouble {
double min() default 0;
double max() default Double.MAX_VALUE;

List<Class<?>> associatedTypes = List.of(Double.class, double.class, Float.class, float.class);
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,13 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.List;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface SpecInRangeInt {
int min() default 0;
int max() default Integer.MAX_VALUE;

List<Class<?>> associatedTypes = List.of(Integer.class, int.class);
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,13 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.List;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface SpecInRangeLong {
long min() default 0;
long max() default Integer.MAX_VALUE;

List<Class<?>> associatedTypes = List.of(Long.class, long.class);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package band.kessokuteatime.nightautoconfig.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.List;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface SpecInRangeShort {
short min() default 0;
short max() default Short.MAX_VALUE;

List<Class<?>> associatedTypes = List.of(Short.class, short.class);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import com.electronwill.nightconfig.core.conversion.Converter;

@Deprecated
public class FloatToDoubleConverter implements Converter<Float, Double> {
@Override
public Float convertToField(Double value) {
Expand Down
145 changes: 117 additions & 28 deletions src/main/java/band/kessokuteatime/nightautoconfig/spec/SpecBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,18 @@

import band.kessokuteatime.nightautoconfig.annotation.*;
import com.electronwill.nightconfig.core.ConfigSpec;
import com.electronwill.nightconfig.core.conversion.AdvancedPath;
import com.electronwill.nightconfig.core.conversion.Path;
import com.electronwill.nightconfig.core.utils.StringUtils;

import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.function.Function;
import java.util.function.Predicate;

public record SpecBuilder<T>(T t) {
Expand All @@ -19,10 +26,47 @@ public ConfigSpec build() {
return spec;
}

public void appendBasicSpecs(ConfigSpec spec) {
Field[] fields = t.getClass().getDeclaredFields();
/**
* Gets the path of a field: returns the annotated path, or the field's name if there is no
* annotated path.
*
* @return the annotated path, if any, or the field name
*/
static List<String> getPath(Field field) {
List<String> annotatedPath = getPath((AnnotatedElement)field);
return (annotatedPath == null) ? Collections.singletonList(field.getName()) : annotatedPath;
}
/**
* Gets the annotated path (specified with @Path or @AdvancedPath) of an annotated element.
*
* @return the annotated path, or {@code null} if there is none.
*/
static List<String> getPath(AnnotatedElement annotatedElement) {
Path path = annotatedElement.getDeclaredAnnotation(Path.class);
if (path != null) {
return StringUtils.split(path.value(), '.');
}
AdvancedPath advancedPath = annotatedElement.getDeclaredAnnotation(AdvancedPath.class);
if (advancedPath != null) {
return Arrays.asList(advancedPath.value());
}
return null;
}

Arrays.stream(fields)
static Double safeDouble(Object floatObject) {
return ((Float) floatObject).doubleValue();
}

static Predicate<? super Field> typeChecker(List<Class<?>> availableTypes) {
return field -> availableTypes.contains(field.getType());
}

private Field[] fields() {
return t.getClass().getDeclaredFields();
}

private void appendBasicSpecs(ConfigSpec spec) {
Arrays.stream(fields())
.forEach(field -> {
try {
field.setAccessible(true);
Expand All @@ -35,17 +79,17 @@ public void appendBasicSpecs(ConfigSpec spec) {
Predicate<Object> validator = annotation.value().getDeclaredConstructor().newInstance();

if (isFloat) {
spec.define(field.getName(), ((Float) value).doubleValue(), validator);
// Store float as double
spec.define(getPath(field), safeDouble(value), validator);
} else {
spec.define(field.getName(), value, validator);
spec.define(getPath(field), value, validator);
}
} else {
System.out.println(field.getName() + ", " + value);

if (isFloat) {
spec.define(field.getName(), ((Float) value).doubleValue());
// Store float as double
spec.define(getPath(field), safeDouble(value));
} else {
spec.define(field.getName(), value);
spec.define(getPath(field), value);
}
}
} catch (IllegalAccessException | InvocationTargetException | InstantiationException |
Expand All @@ -55,52 +99,97 @@ public void appendBasicSpecs(ConfigSpec spec) {
});
}

public void appendInRangeSpecs(ConfigSpec spec) {
private <V extends Comparable<? super V>> void appendInRangeSpec(
ConfigSpec spec, Field field,
V min, V max
) throws IllegalAccessException {
field.setAccessible(true);
appendInRangeSpec(spec, field, (V) field.get(t), min, max);
}

private <V extends Comparable<? super V>> void appendInRangeSpec(
ConfigSpec spec, Field field,
V value, V min, V max
) {
spec.defineInRange(getPath(field), value, min, max);
}

private void appendInRangeSpecs(ConfigSpec spec) {
Field[] fields = t.getClass().getDeclaredFields();

// Byte
Arrays.stream(fields)
.filter(typeChecker(SpecInRangeByte.associatedTypes))
.filter(field -> field.isAnnotationPresent(SpecInRangeByte.class))
.forEach(field -> {
SpecInRangeByte annotation = field.getAnnotation(SpecInRangeByte.class);
try {
appendInRangeSpec(spec, field, annotation.min(), annotation.max());
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
});

// Short
Arrays.stream(fields)
.filter(typeChecker(SpecInRangeShort.associatedTypes))
.filter(field -> field.isAnnotationPresent(SpecInRangeShort.class))
.forEach(field -> {
SpecInRangeShort annotation = field.getAnnotation(SpecInRangeShort.class);
try {
appendInRangeSpec(spec, field, annotation.min(), annotation.max());
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
});

// Int
Arrays.stream(fields)
.filter(field -> List.of(int.class, Integer.class).contains(field.getType()))
.filter(typeChecker(SpecInRangeInt.associatedTypes))
.filter(field -> field.isAnnotationPresent(SpecInRangeInt.class))
.forEach(field -> {
SpecInRangeInt annotation = field.getAnnotation(SpecInRangeInt.class);
try {
field.setAccessible(true);
SpecInRangeInt annotation = field.getAnnotation(SpecInRangeInt.class);
spec.defineInRange(field.getName(), (int) field.get(t), annotation.min(), annotation.max());
appendInRangeSpec(spec, field, annotation.min(), annotation.max());
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
});

// Long
Arrays.stream(fields)
.filter(field -> List.of(long.class, Long.class).contains(field.getType()))
.filter(typeChecker(SpecInRangeLong.associatedTypes))
.filter(field -> field.isAnnotationPresent(SpecInRangeLong.class))
.forEach(field -> {
SpecInRangeLong annotation = field.getAnnotation(SpecInRangeLong.class);
try {
field.setAccessible(true);
SpecInRangeLong annotation = field.getAnnotation(SpecInRangeLong.class);
spec.defineInRange(field.getName(), (long) field.get(t), annotation.min(), annotation.max());
appendInRangeSpec(spec, field, annotation.min(), annotation.max());
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
});

// Floating points
// Float
Arrays.stream(fields)
.filter(field -> List.of(double.class, Double.class, float.class, Float.class).contains(field.getType()))
.filter(typeChecker(List.of(Float.class, float.class)))
.filter(field -> field.isAnnotationPresent(SpecInRangeDouble.class))
.forEach(field -> {
SpecInRangeDouble annotation = field.getAnnotation(SpecInRangeDouble.class);
try {
field.setAccessible(true);
SpecInRangeDouble annotation = field.getAnnotation(SpecInRangeDouble.class);
Object obj = field.get(t);
appendInRangeSpec(spec, field, safeDouble(field.get(t)), annotation.min(), annotation.max());
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
});

if (List.of(double.class, Double.class).contains(field.getType())) {
spec.defineInRange(field.getName(), (double) obj, annotation.min(), annotation.max());
} else if (List.of(float.class, Float.class).contains(field.getType())) {
spec.defineInRange(field.getName(), ((Float) obj).doubleValue(), annotation.min(), annotation.max());
}
// Double
Arrays.stream(fields)
.filter(typeChecker(List.of(Double.class, double.class)))
.filter(field -> field.isAnnotationPresent(SpecInRangeDouble.class))
.forEach(field -> {
SpecInRangeDouble annotation = field.getAnnotation(SpecInRangeDouble.class);
try {
appendInRangeSpec(spec, field, (double) field.get(t), annotation.min(), annotation.max());
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
Expand Down

0 comments on commit d45dff1

Please sign in to comment.