mirror of
https://github.com/PhotonVision/photonvision
synced 2026-07-04 03:11:40 +00:00
fix: reflection bug in onDataChangeEvent (#1416)
This commit is contained in:
committed by
GitHub
parent
06f0f7d66f
commit
596c87519c
@@ -202,33 +202,7 @@ public class VisionModuleChangeSubscriber extends DataChangeSubscriber {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var propField = currentSettings.getClass().getField(propName);
|
setProperty(currentSettings, propName, newPropValue);
|
||||||
var propType = propField.getType();
|
|
||||||
|
|
||||||
if (propType.isEnum()) {
|
|
||||||
var actual = propType.getEnumConstants()[(int) newPropValue];
|
|
||||||
propField.set(currentSettings, actual);
|
|
||||||
} else if (propType.isAssignableFrom(DoubleCouple.class)) {
|
|
||||||
var orig = (ArrayList<Number>) newPropValue;
|
|
||||||
var actual = new DoubleCouple(orig.get(0), orig.get(1));
|
|
||||||
propField.set(currentSettings, actual);
|
|
||||||
} else if (propType.isAssignableFrom(IntegerCouple.class)) {
|
|
||||||
var orig = (ArrayList<Number>) newPropValue;
|
|
||||||
var actual = new IntegerCouple(orig.get(0).intValue(), orig.get(1).intValue());
|
|
||||||
propField.set(currentSettings, actual);
|
|
||||||
} else if (propType.equals(Double.TYPE)) {
|
|
||||||
propField.setDouble(currentSettings, ((Number) newPropValue).doubleValue());
|
|
||||||
} else if (propType.equals(Integer.TYPE)) {
|
|
||||||
propField.setInt(currentSettings, (Integer) newPropValue);
|
|
||||||
} else if (propType.equals(Boolean.TYPE)) {
|
|
||||||
if (newPropValue instanceof Integer) {
|
|
||||||
propField.setBoolean(currentSettings, (Integer) newPropValue != 0);
|
|
||||||
} else {
|
|
||||||
propField.setBoolean(currentSettings, (Boolean) newPropValue);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
propField.set(newPropValue, newPropValue);
|
|
||||||
}
|
|
||||||
logger.trace("Set prop " + propName + " to value " + newPropValue);
|
logger.trace("Set prop " + propName + " to value " + newPropValue);
|
||||||
} catch (NoSuchFieldException | IllegalAccessException e) {
|
} catch (NoSuchFieldException | IllegalAccessException e) {
|
||||||
logger.error(
|
logger.error(
|
||||||
@@ -237,8 +211,9 @@ public class VisionModuleChangeSubscriber extends DataChangeSubscriber {
|
|||||||
+ " with value "
|
+ " with value "
|
||||||
+ newPropValue
|
+ newPropValue
|
||||||
+ " on "
|
+ " on "
|
||||||
+ currentSettings,
|
+ currentSettings
|
||||||
e);
|
+ " | "
|
||||||
|
+ e.getClass().getSimpleName());
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
logger.error("Unknown exception when setting PSC prop!", e);
|
logger.error("Unknown exception when setting PSC prop!", e);
|
||||||
}
|
}
|
||||||
@@ -247,4 +222,46 @@ public class VisionModuleChangeSubscriber extends DataChangeSubscriber {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the value of a property in the given object using reflection. This method should not be
|
||||||
|
* used generally and is only known to be correct in the context of `onDataChangeEvent`.
|
||||||
|
*
|
||||||
|
* @param currentSettings The object whose property needs to be set.
|
||||||
|
* @param propName The name of the property to be set.
|
||||||
|
* @param newPropValue The new value to be assigned to the property.
|
||||||
|
* @throws IllegalAccessException If the field cannot be accessed.
|
||||||
|
* @throws NoSuchFieldException If the field does not exist.
|
||||||
|
* @throws Exception If an some other unknown exception occurs while setting the property.
|
||||||
|
*/
|
||||||
|
protected static void setProperty(Object currentSettings, String propName, Object newPropValue)
|
||||||
|
throws IllegalAccessException, NoSuchFieldException, Exception {
|
||||||
|
var propField = currentSettings.getClass().getField(propName);
|
||||||
|
var propType = propField.getType();
|
||||||
|
|
||||||
|
if (propType.isEnum()) {
|
||||||
|
var actual = propType.getEnumConstants()[(int) newPropValue];
|
||||||
|
propField.set(currentSettings, actual);
|
||||||
|
} else if (propType.isAssignableFrom(DoubleCouple.class)) {
|
||||||
|
var orig = (ArrayList<Number>) newPropValue;
|
||||||
|
var actual = new DoubleCouple(orig.get(0), orig.get(1));
|
||||||
|
propField.set(currentSettings, actual);
|
||||||
|
} else if (propType.isAssignableFrom(IntegerCouple.class)) {
|
||||||
|
var orig = (ArrayList<Number>) newPropValue;
|
||||||
|
var actual = new IntegerCouple(orig.get(0).intValue(), orig.get(1).intValue());
|
||||||
|
propField.set(currentSettings, actual);
|
||||||
|
} else if (propType.equals(Double.TYPE)) {
|
||||||
|
propField.setDouble(currentSettings, ((Number) newPropValue).doubleValue());
|
||||||
|
} else if (propType.equals(Integer.TYPE)) {
|
||||||
|
propField.setInt(currentSettings, (Integer) newPropValue);
|
||||||
|
} else if (propType.equals(Boolean.TYPE)) {
|
||||||
|
if (newPropValue instanceof Integer) {
|
||||||
|
propField.setBoolean(currentSettings, (Integer) newPropValue != 0);
|
||||||
|
} else {
|
||||||
|
propField.setBoolean(currentSettings, (Boolean) newPropValue);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
propField.set(currentSettings, newPropValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,150 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) Photon Vision.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.photonvision.vision.processes;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
import static org.photonvision.vision.processes.VisionModuleChangeSubscriber.setProperty;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.function.Executable;
|
||||||
|
import org.photonvision.common.util.numbers.DoubleCouple;
|
||||||
|
import org.photonvision.common.util.numbers.IntegerCouple;
|
||||||
|
|
||||||
|
public class VisionModuleChangeSubscriberTest {
|
||||||
|
enum TestEnum {
|
||||||
|
VALUE1,
|
||||||
|
VALUE2
|
||||||
|
}
|
||||||
|
|
||||||
|
static class TestClass {
|
||||||
|
public TestEnum enumField;
|
||||||
|
public DoubleCouple doubleCoupleField;
|
||||||
|
public IntegerCouple integerCoupleField;
|
||||||
|
public double doubleField;
|
||||||
|
public int intField;
|
||||||
|
public boolean booleanField;
|
||||||
|
public String stringField;
|
||||||
|
|
||||||
|
public TestClass() {
|
||||||
|
enumField = TestEnum.VALUE1;
|
||||||
|
doubleCoupleField = new DoubleCouple(0, 0);
|
||||||
|
integerCoupleField = new IntegerCouple(0, 0);
|
||||||
|
doubleField = 0;
|
||||||
|
intField = 0;
|
||||||
|
booleanField = false;
|
||||||
|
stringField = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
// Either set with the enum Variant or the ordinal value
|
||||||
|
void testSetEnumField() throws Exception {
|
||||||
|
TestClass obj = new TestClass();
|
||||||
|
assertEquals(obj.enumField, TestEnum.VALUE1);
|
||||||
|
|
||||||
|
setProperty(obj, "enumField", TestEnum.VALUE2.ordinal());
|
||||||
|
assertEquals(TestEnum.VALUE2, obj.enumField);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testSetDoubleCoupleField() throws Exception {
|
||||||
|
TestClass obj = new TestClass();
|
||||||
|
assertEquals(new DoubleCouple(0, 0), obj.doubleCoupleField);
|
||||||
|
|
||||||
|
ArrayList<Number> values = new ArrayList<>();
|
||||||
|
values.add(1.1);
|
||||||
|
values.add(2.2);
|
||||||
|
|
||||||
|
setProperty(obj, "doubleCoupleField", values);
|
||||||
|
|
||||||
|
assertEquals(1.1, obj.doubleCoupleField.getFirst());
|
||||||
|
assertEquals(2.2, obj.doubleCoupleField.getSecond());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testSetIntegerCoupleField() throws Exception {
|
||||||
|
TestClass obj = new TestClass();
|
||||||
|
assertEquals(new IntegerCouple(0, 0), obj.integerCoupleField);
|
||||||
|
|
||||||
|
ArrayList<Number> values = new ArrayList<>();
|
||||||
|
values.add(1);
|
||||||
|
values.add(2);
|
||||||
|
|
||||||
|
setProperty(obj, "integerCoupleField", values);
|
||||||
|
|
||||||
|
assertEquals(1, obj.integerCoupleField.getFirst());
|
||||||
|
assertEquals(2, obj.integerCoupleField.getSecond());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testSetDoubleField() throws Exception {
|
||||||
|
TestClass obj = new TestClass();
|
||||||
|
assertEquals(0, obj.doubleField);
|
||||||
|
|
||||||
|
setProperty(obj, "doubleField", 3.14);
|
||||||
|
assertEquals(3.14, obj.doubleField);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testSetIntField() throws Exception {
|
||||||
|
TestClass obj = new TestClass();
|
||||||
|
assertEquals(0, obj.intField);
|
||||||
|
|
||||||
|
setProperty(obj, "intField", 42);
|
||||||
|
assertEquals(42, obj.intField);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testSetBooleanField() throws Exception {
|
||||||
|
TestClass obj = new TestClass();
|
||||||
|
assertEquals(false, obj.booleanField);
|
||||||
|
|
||||||
|
setProperty(obj, "booleanField", 1);
|
||||||
|
assertTrue(obj.booleanField);
|
||||||
|
|
||||||
|
setProperty(obj, "booleanField", 0);
|
||||||
|
assertFalse(obj.booleanField);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testSetStringField() throws Exception {
|
||||||
|
TestClass obj = new TestClass();
|
||||||
|
assertEquals("", obj.stringField);
|
||||||
|
|
||||||
|
setProperty(obj, "stringField", "test");
|
||||||
|
assertEquals("test", obj.stringField);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testSetNonExistentField() {
|
||||||
|
TestClass obj = new TestClass();
|
||||||
|
Executable executable = () -> setProperty(obj, "nonExistentField", 1);
|
||||||
|
assertThrows(NoSuchFieldException.class, executable);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testSetFieldWithIncompatibleType() {
|
||||||
|
TestClass obj = new TestClass();
|
||||||
|
Executable executable = () -> setProperty(obj, "doubleField", "string");
|
||||||
|
assertThrows(Exception.class, executable);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user