diff --git a/lib/src/main/java/com/team2813/lib2813/preferences/PersistedConfiguration.java b/lib/src/main/java/com/team2813/lib2813/preferences/PersistedConfiguration.java
index 68491c3a..4551b78d 100644
--- a/lib/src/main/java/com/team2813/lib2813/preferences/PersistedConfiguration.java
+++ b/lib/src/main/java/com/team2813/lib2813/preferences/PersistedConfiguration.java
@@ -16,8 +16,8 @@
/**
* Initializes the fields of a Record Class from values stored in {@link Preferences}.
*
- *
The Preference values can be updated in the SmartDashboard and/or Shuffleboard UI; updated
- * values will be stored in the flash storage for the robot.
+ *
The Preference values can be updated in the Elastic. Updated values will be stored in the
+ * flash storage for the robot.
*
*
Example use:
*
@@ -124,6 +124,7 @@ public final class PersistedConfiguration {
* @param preferenceName Preference subtable to use to get the values.
* @param configWithDefaults Record instance with all values set to their preferred default
* values.
+ * @return An instance of the record class, populated with data from the Preferences table.
* @throws IllegalArgumentException If {@code preferenceName} is empty or contains a {@code '/'}.
* @throws IllegalStateException If {@code preferenceName} was used for a different record class.
*/
@@ -152,6 +153,7 @@ public static T fromPreferences(String preferenceName, T conf
*
* @param preferenceName Preference subtable to use to get the values.
* @param recordClass Type of the record instance to populate from preferences.
+ * @return An instance of the record class, populated with data from the Preferences table.
* @throws IllegalArgumentException If {@code preferenceName} is empty or contains a {@code '/'}.
* @throws IllegalStateException If {@code preferenceName} was used for a different record class.
*/
@@ -159,11 +161,22 @@ public static T fromPreferences(String preferenceName, Class<
return fromPreferences(preferenceName, recordClass, null);
}
+ /**
+ * Creates a record class instance of the provided type, with fields populated from Preferences.
+ *
+ * @param preferenceName Preference subtable to use to get the values.
+ * @param recordClass Type of the record instance to populate from preferences.
+ * @param configWithDefaults Record instance with all values set to their preferred default values
+ * (can be {@code null}).
+ * @return An instance of the record class, populated with data from the Preferences table.
+ */
private static T fromPreferences(
String preferenceName, Class recordClass, T configWithDefaults) {
deleteLegacyKeys();
- NetworkTableInstance ntInstance = NetworkTableInstance.getDefault();
validatePreferenceName(preferenceName);
+
+ // TODO: Use Preferences.getNetworkTable() once there is a release of WPILib that includes it.
+ NetworkTableInstance ntInstance = NetworkTableInstance.getDefault();
verifyNotRegisteredToAnotherClass(ntInstance, preferenceName, recordClass);
try {
@@ -188,6 +201,15 @@ private static void validatePreferenceName(String name) {
}
}
+ /**
+ * Throws an exception if the given record class has been registered under a different name.
+ *
+ * @param ntInstance The network table instance that the preference is published to.
+ * @param name Preference subtable that will be used to get the values.
+ * @param recordClass Type of the record instance to populate from preferences.
+ * @throws IllegalStateException If the subtable of the given name was registered to a different
+ * class.
+ */
private static void verifyNotRegisteredToAnotherClass(
NetworkTableInstance ntInstance, String name, Class extends Record> recordClass) {
String recordName = recordClass.getCanonicalName();
@@ -210,6 +232,15 @@ private static void verifyNotRegisteredToAnotherClass(
}
}
+ /**
+ * Creates an instance of the given type using the provided default values.
+ *
+ * @param prefix String to prepend to record field names to get the Preference key.
+ * @param clazz Record class type.
+ * @param configWithDefaults Default values to use if there are no values stored in NetworkTables.
+ * @return An instance of the record class, populated with data from the Preferences table.
+ * @throws ReflectiveOperationException If the fields of the class cannot be read via reflection.
+ */
private static T createFromPreferences(
String prefix, Class extends T> clazz, T configWithDefaults)
throws ReflectiveOperationException {
@@ -265,19 +296,51 @@ private static T createFromPreferences(
return constructor.newInstance(params);
}
+ /**
+ * Type-safe functional interface for creating an instance of a type using data in Preferences.
+ */
@FunctionalInterface
- private interface PreferenceFactory {
- Object create(
- RecordComponent component, String key, Object defaultValue, boolean initializePreference);
+ private interface GenericPreferenceFactory {
+ /**
+ * Gets a value from Preferences for the given component.
+ *
+ * @param component Provides dynamic access to the component of the record class.
+ * @param key The Preference key that should be used when initializing the Preference.
+ * @param defaultValue The default value that should be used when initializing the Preference.
+ * @param initializePreference Whether the preference should be initialized.
+ * @return The value; will match the type in "component";
+ */
+ T create(RecordComponent component, String key, T defaultValue, boolean initializePreference);
}
+ /**
+ * Functional interface for creating an instance of a type using data in Preferences.
+ *
+ * Note: this interface exists to avoid ugly casts in the code that uses the reflection APIs.
+ */
@FunctionalInterface
- private interface GenericPreferenceFactory {
- T create(RecordComponent component, String key, T defaultValue, boolean initializePreference);
+ private interface PreferenceFactory {
+ /**
+ * Gets a value from Preferences for the given component.
+ *
+ * @param component Provides dynamic access to the component of the record class.
+ * @param key The Preference key that should be used when initializing the Preference.
+ * @param defaultValue The default value that should be used when initializing the Preference.
+ * @param initializePreference Whether the preference should be initialized.
+ * @return The value; will match the type in "component";
+ */
+ Object create(
+ RecordComponent component, String key, Object defaultValue, boolean initializePreference);
}
private static final Map TYPE_TO_FACTORY = new HashMap<>();
+ /**
+ * Registers a preference factory with a type.
+ *
+ * @param type The type to register.
+ * @param simpleFactory The factory that should be used to create values of the given type.
+ */
@SuppressWarnings("unchecked")
private static void register(Class type, GenericPreferenceFactory simpleFactory) {
PreferenceFactory factory =
@@ -458,6 +521,7 @@ private static Supplier> supplierFactory(
return () -> factory.create(component, key, null, false);
}
+ /** Deletes Preferences that were created by older versions of this class. */
private static void deleteLegacyKeys() {
if (!deletedLegacyKeys) {
// Preferences installs a listener that makes all new topics persistent. The ".registeredTo"
@@ -472,6 +536,12 @@ private static void deleteLegacyKeys() {
}
}
+ /**
+ * Emits a warning, usually via {@link DataLogManager}.
+ *
+ * @param format A format string as described in {@link java.util.Formatter Formatter}.
+ * @param args Arguments referenced by the format specifiers in the format string.
+ */
private static void warn(String format, Object... args) {
String message = String.format("WARNING: " + format, args);
errorReporter.accept(message);