diff --git a/TeamCode/src/main/java/org/firstinspires/ftc/teamcode/hardware/HardwareMapper.java b/TeamCode/src/main/java/org/firstinspires/ftc/teamcode/hardware/HardwareMapper.java
index e4a605b764b..ef03775690a 100644
--- a/TeamCode/src/main/java/org/firstinspires/ftc/teamcode/hardware/HardwareMapper.java
+++ b/TeamCode/src/main/java/org/firstinspires/ftc/teamcode/hardware/HardwareMapper.java
@@ -4,12 +4,80 @@
import com.qualcomm.robotcore.hardware.DcMotorSimple;
import com.qualcomm.robotcore.hardware.HardwareMap;
+import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
/**
* Annotation processor for hardware map things.
*/
public abstract class HardwareMapper {
+ /**
+ * Represents an annotation processor for hardware devices.
+ * Internals are a bit of a mess right now.
+ *
+ * HardwareName is hardcoded because it provides the value of the field.
+ */
+ static final class DeviceAnnotation {
+ private final Class annotationClass;
+ private final Class targetClass;
+ private final Action action;
+
+ @FunctionalInterface
+ interface Action {
+ void use(AnnotationT annotation, TargetType target);
+ }
+
+ DeviceAnnotation(Class annotationClass, Class targetClass, Action action) {
+ this.annotationClass = annotationClass;
+ this.targetClass = targetClass;
+ this.action = action;
+ }
+
+ private boolean check(Field t, Object value) {
+ if (!t.isAnnotationPresent(annotationClass)) return false;
+ AnnotationT annotation = t.getAnnotation(annotationClass);
+ if (annotation == null)
+ throw new NullPointerException("Annotation is null! (isAnnotationPresent is true but getAnnotation returned null)");
+ if (!targetClass.isAssignableFrom(value.getClass())) {
+ throw new ClassCastException("Annotation " + annotationClass.getName() + " can only be used on " + targetClass.getName() + " (or subclasses)");
+ }
+ return true;
+ }
+
+ void use(Field t, Object value) {
+ if (!check(t, value)) return;
+ AnnotationT annotation = t.getAnnotation(annotationClass);
+ if (annotation == null)
+ throw new NullPointerException("Annotation disappeared between check and use");
+ action.use(annotation, targetClass.cast(value));
+ }
+ }
+
+ static final DeviceAnnotation reversed =
+ new DeviceAnnotation<>(
+ Reversed.class,
+ DcMotorSimple.class,
+ (annotation, target) -> target.setDirection(DcMotorSimple.Direction.REVERSE)
+ );
+
+ static final DeviceAnnotation zeroPower =
+ new DeviceAnnotation<>(
+ ZeroPower.class,
+ DcMotor.class,
+ (annotation, target) -> target.setZeroPowerBehavior(annotation.value())
+ );
+
+ static final DeviceAnnotation autoClearEncoder =
+ new DeviceAnnotation<>(
+ AutoClearEncoder.class,
+ DcMotor.class,
+ (annotation, target) -> {
+ DcMotor.RunMode current = target.getMode();
+ target.setMode(DcMotor.RunMode.STOP_AND_RESET_ENCODER);
+ target.setMode(current);
+ }
+ );
+
public HardwareMapper(HardwareMap map) {
Field[] fields = this.getClass().getDeclaredFields();
for (Field field : fields) {
@@ -22,12 +90,7 @@ public HardwareMapper(HardwareMap map) {
Object result = map.tryGet(targetType, field.getName());
if (result == null) {
- throw new RuntimeException(
- "Hardware: '" +
- field.getName() + "' not found, expected type " +
- targetType.getName() + " for field " +
- field.getName() + " in " + this.getClass().getName()
- );
+ throw new RuntimeException("Hardware: '" + field.getName() + "' not found, expected type " + targetType.getName() + " for field " + field.getName() + " in " + this.getClass().getName());
}
try {
field.set(this, result);
@@ -35,34 +98,9 @@ public HardwareMapper(HardwareMap map) {
throw new RuntimeException("Field " + field.getName() + " assign failed: " + result.getClass().getName() + " to " + field.getType().getName());
}
- if (field.isAnnotationPresent(Reversed.class)) {
- if (targetType.isAssignableFrom(DcMotorSimple.class)) {
- DcMotorSimple motor = (DcMotorSimple) result;
- motor.setDirection(DcMotorSimple.Direction.REVERSE);
- } else {
- throw new RuntimeException("@Reversed annotation can only be used on DcMotorSimple (or subclasses)");
- }
- }
- if (field.isAnnotationPresent(ZeroPower.class)) {
- if (targetType.isAssignableFrom(DcMotor.class)) {
- DcMotor motor = (DcMotor) result;
- ZeroPower zeroPower = field.getAnnotation(ZeroPower.class);
- if (zeroPower == null) throw new RuntimeException("ZeroPower annotation is null?!");
- motor.setZeroPowerBehavior(zeroPower.value());
- } else {
- throw new RuntimeException("@ZeroPower annotation can only be used on DcMotor (or subclasses)");
- }
- }
- if (field.isAnnotationPresent(AutoClearEncoder.class)) {
- if (targetType.isAssignableFrom(DcMotor.class)) {
- DcMotor motor = (DcMotor) result;
- DcMotor.RunMode current = motor.getMode();
- motor.setMode(DcMotor.RunMode.STOP_AND_RESET_ENCODER);
- motor.setMode(current);
- } else {
- throw new RuntimeException("@AutoClearEncoder annotation can only be used on DcMotor (or subclasses)");
- }
- }
+ reversed.use(field, result);
+ zeroPower.use(field, result);
+ autoClearEncoder.use(field, result);
} catch (IllegalArgumentException e) {
throw new RuntimeException("Field " + field.getName() + " typecast failed");
} finally {