From 025732093fb341d19957d07fc232c402cdef6002 Mon Sep 17 00:00:00 2001 From: Thad House Date: Thu, 11 Jun 2026 15:33:51 -0700 Subject: [PATCH] [wpilib] Remove UserControls (#8973) It was too complex, and we can solve it by figuring out how to make singleton GenericHID objects, implemented in #8970. --- .../java/wpilib/robot/DefaultTeleMode.java | 7 +- .../src/main/java/wpilib/robot/OpRobot.java | 3 - .../driverstation/DefaultUserControls.java | 33 ---- .../wpilib/driverstation/UserControls.java | 15 -- .../driverstation/UserControlsInstance.java | 26 ---- .../org/wpilib/framework/OpModeRobot.java | 49 +----- .../java/org/wpilib/framework/RobotBase.java | 24 +-- .../expansionhubsample/DefaultTeleMode.java | 21 +-- .../examples/expansionhubsample/Robot.java | 3 - .../org/wpilib/util/ConstructorMatchTest.java | 141 +++++------------- 10 files changed, 55 insertions(+), 267 deletions(-) delete mode 100644 wpilibj/src/main/java/org/wpilib/driverstation/DefaultUserControls.java delete mode 100644 wpilibj/src/main/java/org/wpilib/driverstation/UserControls.java delete mode 100644 wpilibj/src/main/java/org/wpilib/driverstation/UserControlsInstance.java diff --git a/developerRobot/src/main/java/wpilib/robot/DefaultTeleMode.java b/developerRobot/src/main/java/wpilib/robot/DefaultTeleMode.java index f859207b7b..1240b61afd 100644 --- a/developerRobot/src/main/java/wpilib/robot/DefaultTeleMode.java +++ b/developerRobot/src/main/java/wpilib/robot/DefaultTeleMode.java @@ -4,7 +4,6 @@ package wpilib.robot; -import org.wpilib.driverstation.DefaultUserControls; import org.wpilib.opmode.PeriodicOpMode; import org.wpilib.opmode.Teleop; @@ -13,12 +12,8 @@ public class DefaultTeleMode extends PeriodicOpMode { @SuppressWarnings("unused") private final OpRobot robot; - @SuppressWarnings("unused") - private final DefaultUserControls userControls; - - public DefaultTeleMode(OpRobot robot, DefaultUserControls userControls) { + public DefaultTeleMode(OpRobot robot) { this.robot = robot; - this.userControls = userControls; } @Override diff --git a/developerRobot/src/main/java/wpilib/robot/OpRobot.java b/developerRobot/src/main/java/wpilib/robot/OpRobot.java index 096b905f35..085a8b7760 100644 --- a/developerRobot/src/main/java/wpilib/robot/OpRobot.java +++ b/developerRobot/src/main/java/wpilib/robot/OpRobot.java @@ -4,12 +4,9 @@ package wpilib.robot; -import org.wpilib.driverstation.DefaultUserControls; -import org.wpilib.driverstation.UserControlsInstance; import org.wpilib.framework.OpModeRobot; /** This is a dev program for testing OpModeRobot. */ -@UserControlsInstance(DefaultUserControls.class) public class OpRobot extends OpModeRobot { /** Called once at the beginning of the robot program. */ public OpRobot() {} diff --git a/wpilibj/src/main/java/org/wpilib/driverstation/DefaultUserControls.java b/wpilibj/src/main/java/org/wpilib/driverstation/DefaultUserControls.java deleted file mode 100644 index e788fed86a..0000000000 --- a/wpilibj/src/main/java/org/wpilib/driverstation/DefaultUserControls.java +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) FIRST and other WPILib contributors. -// Open Source Software; you can modify and/or share it under the terms of -// the WPILib BSD license file in the root directory of this project. - -package org.wpilib.driverstation; - -import org.wpilib.driverstation.internal.DriverStationBackend; - -/** - * A default implementation of UserControls that provides Gamepad instances for each of the 6 - * joystick ports provided by the DS. - */ -public class DefaultUserControls implements UserControls { - private final Gamepad[] m_gamepads; - - /** Constructs a DefaultUserControls instance with Gamepads for each port. */ - public DefaultUserControls() { - m_gamepads = new Gamepad[DriverStationBackend.JOYSTICK_PORTS]; - for (int i = 0; i < m_gamepads.length; i++) { - m_gamepads[i] = new Gamepad(i); - } - } - - /** - * Returns the Gamepad instance for the specified port. - * - * @param port The joystick port number. - * @return The Gamepad instance for the given port. - */ - public Gamepad getGamepad(int port) { - return m_gamepads[port]; - } -} diff --git a/wpilibj/src/main/java/org/wpilib/driverstation/UserControls.java b/wpilibj/src/main/java/org/wpilib/driverstation/UserControls.java deleted file mode 100644 index ad6c03d5b3..0000000000 --- a/wpilibj/src/main/java/org/wpilib/driverstation/UserControls.java +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (c) FIRST and other WPILib contributors. -// Open Source Software; you can modify and/or share it under the terms of -// the WPILib BSD license file in the root directory of this project. - -package org.wpilib.driverstation; - -/** - * An interface representing user controls such as gamepads or joysticks. If your main robot class - * has a UserControlsInstance attribute with a class implementing this interface, the constructor is - * able to receive an instance of that class. Additionally, any OpModes can also receive that same - * instance. - * - *

The implementation of this class must have a default constructor - */ -public interface UserControls {} diff --git a/wpilibj/src/main/java/org/wpilib/driverstation/UserControlsInstance.java b/wpilibj/src/main/java/org/wpilib/driverstation/UserControlsInstance.java deleted file mode 100644 index f10b074320..0000000000 --- a/wpilibj/src/main/java/org/wpilib/driverstation/UserControlsInstance.java +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) FIRST and other WPILib contributors. -// Open Source Software; you can modify and/or share it under the terms of -// the WPILib BSD license file in the root directory of this project. - -package org.wpilib.driverstation; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * An annotation to specify the UserControls implementation class to be used for a robot. Apply this - * annotation to your main robot class, providing a class that implements the UserControls - * interface. - */ -@Target(ElementType.TYPE) -@Retention(RetentionPolicy.RUNTIME) -public @interface UserControlsInstance { - /** - * The UserControls implementation class to be used. - * - * @return The class that implements UserControls. - */ - Class value(); -} diff --git a/wpilibj/src/main/java/org/wpilib/framework/OpModeRobot.java b/wpilibj/src/main/java/org/wpilib/framework/OpModeRobot.java index dd84f80e27..b691469a70 100644 --- a/wpilibj/src/main/java/org/wpilib/framework/OpModeRobot.java +++ b/wpilibj/src/main/java/org/wpilib/framework/OpModeRobot.java @@ -24,8 +24,6 @@ import java.util.jar.JarFile; import org.wpilib.driverstation.Alert; import org.wpilib.driverstation.DriverStationErrors; import org.wpilib.driverstation.RobotState; -import org.wpilib.driverstation.UserControls; -import org.wpilib.driverstation.UserControlsInstance; import org.wpilib.driverstation.internal.DriverStationBackend; import org.wpilib.hardware.hal.ControlWord; import org.wpilib.hardware.hal.DriverStationJNI; @@ -90,23 +88,6 @@ public abstract class OpModeRobot extends RobotBase { "Error adding OpMode " + cls.getSimpleName() + ": " + message, false); } - private final Optional> m_userControlsBaseClass; - private UserControls m_userControlsInstance; - - void setUserControlsInstance(UserControls userControlsInstance) { - if (m_userControlsBaseClass.isEmpty()) { - throw new IllegalStateException("No UserControls class specified"); - } - - if (!m_userControlsBaseClass.get().isAssignableFrom(userControlsInstance.getClass())) { - throw new IllegalArgumentException( - userControlsInstance.getClass().getSimpleName() - + " is not assignable to " - + m_userControlsBaseClass.get().getSimpleName()); - } - m_userControlsInstance = userControlsInstance; - } - /** * Find a public constructor to instantiate the opmode. This constructor can have up to 2 * parameters. The first parameter (if present) must be assignable from this.getClass(). The @@ -116,28 +97,12 @@ public abstract class OpModeRobot extends RobotBase { private Optional> findOpModeConstructor(Class cls) { Optional> ctor; - // try 2-parameter constructor - if (m_userControlsBaseClass.isPresent()) { - ctor = ConstructorMatch.findBestConstructor(cls, getClass(), m_userControlsBaseClass.get()); - if (ctor.isPresent()) { - return ctor; - } - } - // try 1-parameter constructor with RobotBase parameter ctor = ConstructorMatch.findBestConstructor(cls, getClass()); if (ctor.isPresent()) { return ctor; } - // try 1-parameter constructor with UserControls parameter - if (m_userControlsBaseClass.isPresent()) { - ctor = ConstructorMatch.findBestConstructor(cls, m_userControlsBaseClass.get()); - if (ctor.isPresent()) { - return ctor; - } - } - // try no-parameter constructor ctor = ConstructorMatch.findBestConstructor(cls); return ctor; @@ -151,11 +116,7 @@ public abstract class OpModeRobot extends RobotBase { return null; } try { - if (m_userControlsInstance != null) { - return constructor.get().newInstance(this, m_userControlsInstance); - } else { - return constructor.get().newInstance(this); - } + return constructor.get().newInstance(this); } catch (ReflectiveOperationException e) { DriverStationErrors.reportError( "Could not instantiate OpMode " + cls.getSimpleName(), e.getStackTrace()); @@ -564,14 +525,6 @@ public abstract class OpModeRobot extends RobotBase { // Add LoopFunc as periodic callback (match C++) addPeriodic(this::loopFunc, period); - // Check to see if we have a DS annotation - UserControlsInstance userControlsAnnotation = - getClass().getAnnotation(UserControlsInstance.class); - if (userControlsAnnotation != null) { - m_userControlsBaseClass = Optional.of(userControlsAnnotation.value()); - } else { - m_userControlsBaseClass = Optional.empty(); - } // Scan for annotated opmode classes within the derived class's package and subpackages addAnnotatedOpModeClasses(getClass().getPackage()); RobotState.publishOpModes(); diff --git a/wpilibj/src/main/java/org/wpilib/framework/RobotBase.java b/wpilibj/src/main/java/org/wpilib/framework/RobotBase.java index 8426477f6d..acdabf3164 100644 --- a/wpilibj/src/main/java/org/wpilib/framework/RobotBase.java +++ b/wpilibj/src/main/java/org/wpilib/framework/RobotBase.java @@ -8,8 +8,6 @@ import java.util.Optional; import java.util.concurrent.locks.ReentrantLock; import org.wpilib.driverstation.DriverStationErrors; import org.wpilib.driverstation.RobotState; -import org.wpilib.driverstation.UserControls; -import org.wpilib.driverstation.UserControlsInstance; import org.wpilib.driverstation.internal.DriverStationBackend; import org.wpilib.hardware.hal.HAL; import org.wpilib.hardware.hal.HALUtil; @@ -291,32 +289,16 @@ public abstract class RobotBase implements AutoCloseable { private static boolean m_suppressExitWarning; private static T constructRobot(Class robotClass) throws Throwable { - UserControlsInstance userControlsAttribute = - robotClass.getDeclaredAnnotation(UserControlsInstance.class); - UserControls userControlsInstance = null; - Optional> constructorMatch = Optional.empty(); - if (userControlsAttribute != null) { - var userControlsClass = userControlsAttribute.value(); - userControlsInstance = userControlsClass.getDeclaredConstructor().newInstance(); - constructorMatch = ConstructorMatch.findBestConstructor(robotClass, userControlsClass); - } - - if (constructorMatch.isEmpty()) { - // Try to find a constructor with no parameters if there is no UserControls constructor - constructorMatch = ConstructorMatch.findBestConstructor(robotClass); - } + Optional> constructorMatch = + ConstructorMatch.findBestConstructor(robotClass); if (constructorMatch.isEmpty()) { throw new IllegalArgumentException( "No valid constructor found in robot class " + robotClass.getName()); } - T robot = constructorMatch.get().newInstance(userControlsInstance); + T robot = constructorMatch.get().newInstance(); - if (userControlsInstance != null && robot instanceof OpModeRobot opModeRobot) { - // Insert the UserControls instance into the opModeRobot for use when constructing opmodes - opModeRobot.setUserControlsInstance(userControlsInstance); - } return robot; } diff --git a/wpilibjExamples/src/main/java/org/wpilib/examples/expansionhubsample/DefaultTeleMode.java b/wpilibjExamples/src/main/java/org/wpilib/examples/expansionhubsample/DefaultTeleMode.java index a3225ef7a3..29c8ea3594 100644 --- a/wpilibjExamples/src/main/java/org/wpilib/examples/expansionhubsample/DefaultTeleMode.java +++ b/wpilibjExamples/src/main/java/org/wpilib/examples/expansionhubsample/DefaultTeleMode.java @@ -4,27 +4,28 @@ package org.wpilib.examples.expansionhubsample; -import org.wpilib.driverstation.DefaultUserControls; +import org.wpilib.driverstation.DriverStation; +import org.wpilib.driverstation.Gamepad; import org.wpilib.opmode.PeriodicOpMode; import org.wpilib.opmode.Teleop; @Teleop public class DefaultTeleMode extends PeriodicOpMode { private final Robot robot; - private final DefaultUserControls userControls; + private final Gamepad gamepad; - public DefaultTeleMode(Robot robot, DefaultUserControls userControls) { + public DefaultTeleMode(Robot robot) { this.robot = robot; - this.userControls = userControls; + this.gamepad = DriverStation.getGamepad(0); } @Override public void periodic() { - robot.motor0.setThrottle(-userControls.getGamepad(0).getLeftY()); - robot.motor1.setThrottle(-userControls.getGamepad(0).getRightY()); - robot.motor2.setThrottle(-userControls.getGamepad(0).getLeftX()); - robot.motor3.setThrottle(-userControls.getGamepad(0).getRightX()); - robot.servo0.setPosition(userControls.getGamepad(0).getLeftTriggerAxis()); - robot.servo1.setPosition(userControls.getGamepad(0).getRightTriggerAxis()); + robot.motor0.setThrottle(-gamepad.getLeftY()); + robot.motor1.setThrottle(-gamepad.getRightY()); + robot.motor2.setThrottle(-gamepad.getLeftX()); + robot.motor3.setThrottle(-gamepad.getRightX()); + robot.servo0.setPosition(gamepad.getLeftTriggerAxis()); + robot.servo1.setPosition(gamepad.getRightTriggerAxis()); } } diff --git a/wpilibjExamples/src/main/java/org/wpilib/examples/expansionhubsample/Robot.java b/wpilibjExamples/src/main/java/org/wpilib/examples/expansionhubsample/Robot.java index 90760bd81b..c66ed6ce50 100644 --- a/wpilibjExamples/src/main/java/org/wpilib/examples/expansionhubsample/Robot.java +++ b/wpilibjExamples/src/main/java/org/wpilib/examples/expansionhubsample/Robot.java @@ -4,8 +4,6 @@ package org.wpilib.examples.expansionhubsample; -import org.wpilib.driverstation.DefaultUserControls; -import org.wpilib.driverstation.UserControlsInstance; import org.wpilib.framework.OpModeRobot; import org.wpilib.hardware.expansionhub.ExpansionHubMotor; import org.wpilib.hardware.expansionhub.ExpansionHubServo; @@ -14,7 +12,6 @@ import org.wpilib.hardware.expansionhub.ExpansionHubServo; * This is a demo program showing the use of the Expansion Hub motors and servos. The motors and * servos are driven using the controllers in the telop opmode, and timed in the auto op mode. */ -@UserControlsInstance(DefaultUserControls.class) public class Robot extends OpModeRobot { public final ExpansionHubMotor motor0 = new ExpansionHubMotor(0, 0); public final ExpansionHubMotor motor1 = new ExpansionHubMotor(0, 1); diff --git a/wpiutil/src/test/java/org/wpilib/util/ConstructorMatchTest.java b/wpiutil/src/test/java/org/wpilib/util/ConstructorMatchTest.java index 389f795158..bd64d7caa6 100644 --- a/wpiutil/src/test/java/org/wpilib/util/ConstructorMatchTest.java +++ b/wpiutil/src/test/java/org/wpilib/util/ConstructorMatchTest.java @@ -106,57 +106,17 @@ class ConstructorMatchTest { // Since this is built for opmodes, we're going to write tests that assume that // scenario. - public interface UserControls {} - - public static class DefaultUserControls implements UserControls {} - - public static class CustomUserControls implements UserControls {} - public static class RobotBase {} - public static class RobotWithNoUserControls extends RobotBase {} + public static class BasicRobot extends RobotBase {} - public static class RobotWithDefaultUserControls extends RobotBase { - public RobotWithDefaultUserControls(DefaultUserControls controls) {} - } + public static class CustomRobot extends RobotBase {} @Test - void testRobotWithDefaultUserControls() throws ReflectiveOperationException { - var ctor = - ConstructorMatch.findBestConstructor( - RobotWithDefaultUserControls.class, DefaultUserControls.class); + void testRobotNoArgs() throws ReflectiveOperationException { + var ctor = ConstructorMatch.findBestConstructor(BasicRobot.class); assertTrue(ctor.isPresent()); - ctor.get().newInstance(new DefaultUserControls()); - assertThrows( - IllegalArgumentException.class, () -> ctor.get().newInstance(new CustomUserControls())); - } - - public static class RobotWithCustomUserControls extends RobotBase { - public RobotWithCustomUserControls(CustomUserControls controls) {} - } - - @Test - void testRobotWithCustomUserControls() throws ReflectiveOperationException { - var ctor = - ConstructorMatch.findBestConstructor( - RobotWithCustomUserControls.class, CustomUserControls.class); - assertTrue(ctor.isPresent()); - ctor.get().newInstance(new CustomUserControls()); - assertThrows( - IllegalArgumentException.class, () -> ctor.get().newInstance(new DefaultUserControls())); - } - - public static class RobotWithUserControls extends RobotBase { - public RobotWithUserControls(UserControls controls) {} - } - - @Test - void testRobotWithUserControls() throws ReflectiveOperationException { - var ctor = - ConstructorMatch.findBestConstructor(RobotWithUserControls.class, UserControls.class); - assertTrue(ctor.isPresent()); - ctor.get().newInstance(new DefaultUserControls()); - ctor.get().newInstance(new CustomUserControls()); + ctor.get().newInstance(); } public static class OpModeWithRobotBase { @@ -167,108 +127,85 @@ class ConstructorMatchTest { void testOpModeWithRobotBase() throws ReflectiveOperationException { var ctor = ConstructorMatch.findBestConstructor(OpModeWithRobotBase.class, RobotBase.class); assertTrue(ctor.isPresent()); - var defaultUserControls = new DefaultUserControls(); - var customUserControls = new CustomUserControls(); - ctor.get().newInstance(new RobotWithNoUserControls(), defaultUserControls); - ctor.get() - .newInstance(new RobotWithDefaultUserControls(defaultUserControls), defaultUserControls); - ctor.get().newInstance(new RobotWithCustomUserControls(customUserControls), customUserControls); - ctor.get().newInstance(new RobotWithUserControls(defaultUserControls), defaultUserControls); + ctor.get().newInstance(new RobotBase()); + ctor.get().newInstance(new BasicRobot()); + ctor.get().newInstance(new CustomRobot()); } - public static class OpModeWithRobotWithNoUserControls { - public OpModeWithRobotWithNoUserControls(RobotWithNoUserControls robot) {} + public static class OpModeWithBasicRobot { + public OpModeWithBasicRobot(BasicRobot robot) {} } @Test - void testOpModeWithRobotWithNoUserControls() throws ReflectiveOperationException { - var ctor = - ConstructorMatch.findBestConstructor( - OpModeWithRobotWithNoUserControls.class, RobotWithNoUserControls.class); + void testOpModeWithBasicRobot() throws ReflectiveOperationException { + var ctor = ConstructorMatch.findBestConstructor(OpModeWithBasicRobot.class, BasicRobot.class); assertTrue(ctor.isPresent()); - var defaultUserControls = new DefaultUserControls(); - ctor.get().newInstance(new RobotWithNoUserControls(), defaultUserControls); + ctor.get().newInstance(new BasicRobot()); + assertThrows(IllegalArgumentException.class, () -> ctor.get().newInstance(new RobotBase())); + assertThrows(IllegalArgumentException.class, () -> ctor.get().newInstance(new CustomRobot())); } - public static class OpModeWithRobotWithDefaultUserControls { - public OpModeWithRobotWithDefaultUserControls(RobotWithDefaultUserControls robot) {} + public static class OpModeWithMultipleRobotConstructors { + public OpModeWithMultipleRobotConstructors(RobotBase robot) {} - public OpModeWithRobotWithDefaultUserControls( - RobotWithDefaultUserControls robot, DefaultUserControls controls) {} + public OpModeWithMultipleRobotConstructors(BasicRobot robot) {} - public OpModeWithRobotWithDefaultUserControls(DefaultUserControls controls) {} + public OpModeWithMultipleRobotConstructors() {} } @Test - void testOpModeWithRobotWithDefaultUserControlsRobotArg() throws ReflectiveOperationException { + void testOpModeWithMultipleRobotConstructorsRobotArg() throws ReflectiveOperationException { var ctor = ConstructorMatch.findBestConstructor( - OpModeWithRobotWithDefaultUserControls.class, RobotWithDefaultUserControls.class); + OpModeWithMultipleRobotConstructors.class, BasicRobot.class); assertTrue(ctor.isPresent()); - var defaultUserControls = new DefaultUserControls(); - ctor.get() - .newInstance(new RobotWithDefaultUserControls(defaultUserControls), defaultUserControls); + var parameterTypes = ctor.get().getParameterTypes(); + assertEquals(BasicRobot.class, parameterTypes.get(0)); + ctor.get().newInstance(new BasicRobot()); } @Test - void testOpModeWithRobotWithDefaultUserControlsControlsArg() throws ReflectiveOperationException { - var ctor = - ConstructorMatch.findBestConstructor( - OpModeWithRobotWithDefaultUserControls.class, DefaultUserControls.class); + void testOpModeWithMultipleRobotConstructorsNoArgs() throws ReflectiveOperationException { + var ctor = ConstructorMatch.findBestConstructor(OpModeWithMultipleRobotConstructors.class); assertTrue(ctor.isPresent()); - var defaultUserControls = new DefaultUserControls(); - ctor.get() - .newInstance(new RobotWithDefaultUserControls(defaultUserControls), defaultUserControls); + ctor.get().newInstance(); } - @Test - void testOpModeWithRobotWithDefaultUserControlsNoArgs() throws ReflectiveOperationException { - var ctor = - ConstructorMatch.findBestConstructor( - OpModeWithRobotWithDefaultUserControls.class, - RobotWithDefaultUserControls.class, - DefaultUserControls.class); - assertTrue(ctor.isPresent()); - var defaultUserControls = new DefaultUserControls(); - ctor.get() - .newInstance(new RobotWithDefaultUserControls(defaultUserControls), defaultUserControls); - } + public static class ModeBase {} + + public static class DefaultMode extends ModeBase {} public static class MostSpecificFirstArg { - public MostSpecificFirstArg(RobotBase robot, DefaultUserControls controls) {} + public MostSpecificFirstArg(RobotBase robot, DefaultMode mode) {} - public MostSpecificFirstArg(RobotWithDefaultUserControls robot, UserControls controls) {} + public MostSpecificFirstArg(BasicRobot robot, ModeBase mode) {} } @Test void testMostSpecificFirstArg() throws ReflectiveOperationException { var ctor = ConstructorMatch.findBestConstructor( - MostSpecificFirstArg.class, - RobotWithDefaultUserControls.class, - DefaultUserControls.class); + MostSpecificFirstArg.class, BasicRobot.class, DefaultMode.class); assertTrue(ctor.isPresent()); var parameterTypes = ctor.get().getParameterTypes(); - assertEquals(RobotWithDefaultUserControls.class, parameterTypes.get(0)); - assertEquals(UserControls.class, parameterTypes.get(1)); + assertEquals(BasicRobot.class, parameterTypes.get(0)); + assertEquals(ModeBase.class, parameterTypes.get(1)); } public static class MostSpecificSecondArg { - public MostSpecificSecondArg(RobotBase robot, DefaultUserControls controls) {} + public MostSpecificSecondArg(RobotBase robot, DefaultMode mode) {} - public MostSpecificSecondArg(RobotBase robot, UserControls controls) {} + public MostSpecificSecondArg(RobotBase robot, ModeBase mode) {} } @Test void testMostSpecificSecondArg() throws ReflectiveOperationException { var ctor = ConstructorMatch.findBestConstructor( - MostSpecificSecondArg.class, - RobotWithDefaultUserControls.class, - DefaultUserControls.class); + MostSpecificSecondArg.class, BasicRobot.class, DefaultMode.class); assertTrue(ctor.isPresent()); var parameterTypes = ctor.get().getParameterTypes(); assertEquals(RobotBase.class, parameterTypes.get(0)); - assertEquals(DefaultUserControls.class, parameterTypes.get(1)); + assertEquals(DefaultMode.class, parameterTypes.get(1)); } }