From 8387aac0cc624b84267643321dce99acfc612d59 Mon Sep 17 00:00:00 2001 From: Jared Davis Date: Wed, 10 Jun 2026 22:38:48 -0400 Subject: [PATCH] Eliminate runtime reflection in Operators. Perform reflection in OperatorsTest instead. --- .../org/scijava/parsington/Operators.java | 84 ++++++++++++++----- .../org/scijava/parsington/OperatorsTest.java | 47 +++++++++++ 2 files changed, 110 insertions(+), 21 deletions(-) create mode 100644 src/test/java/org/scijava/parsington/OperatorsTest.java diff --git a/src/main/java/org/scijava/parsington/Operators.java b/src/main/java/org/scijava/parsington/Operators.java index c6fdf66..656d3fd 100644 --- a/src/main/java/org/scijava/parsington/Operators.java +++ b/src/main/java/org/scijava/parsington/Operators.java @@ -33,9 +33,8 @@ import static org.scijava.parsington.Operator.Associativity.LEFT; import static org.scijava.parsington.Operator.Associativity.RIGHT; -import java.lang.reflect.Field; -import java.lang.reflect.Modifier; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import org.scijava.parsington.Operator.Associativity; @@ -172,6 +171,67 @@ public final class Operators { public static final Operator UNSIGNED_RIGHT_SHIFT_ASSIGN = op(">>>=", 2, RIGHT, 0); + private static final List operatorList = new ArrayList<>( + Arrays.asList( + DOT, + PARENS, + BRACKETS, + BRACES, + TRANSPOSE, + DOT_TRANSPOSE, + POW, + DOT_POW, + POST_INC, + POST_DEC, + PRE_INC, + PRE_DEC, + POS, + NEG, + COMPLEMENT, + NOT, + MUL, + DIV, + MOD, + RIGHT_DIV, + DOT_MUL, + DOT_DIV, + DOT_RIGHT_DIV, + ADD, + SUB, + LEFT_SHIFT, + RIGHT_SHIFT, + UNSIGNED_RIGHT_SHIFT, + LESS_THAN, + GREATER_THAN, + LESS_THAN_OR_EQUAL, + GREATER_THAN_OR_EQUAL, + INSTANCEOF, + EQUAL, + NOT_EQUAL, + BITWISE_AND, + BITWISE_OR, + LOGICAL_AND, + LOGICAL_OR, + QUESTION, + COLON, + ASSIGN, + POW_ASSIGN, + DOT_POW_ASSIGN, + MUL_ASSIGN, + DIV_ASSIGN, + MOD_ASSIGN, + RIGHT_DIV_ASSIGN, + DOT_DIV_ASSIGN, + DOT_RIGHT_DIV_ASSIGN, + ADD_ASSIGN, + SUB_ASSIGN, + AND_ASSIGN, + OR_ASSIGN, + LEFT_SHIFT_ASSIGN, + RIGHT_SHIFT_ASSIGN, + UNSIGNED_RIGHT_SHIFT_ASSIGN)); + + private Operators() { // NB: Prevent instantiation of utility class. } @@ -183,19 +243,7 @@ private Operators() { * {@link Operators} class, in declaration order. */ public static List standardList() { - // Build the standard list from all available Operator constants. - final ArrayList ops = new ArrayList<>(); - for (final Field f : Operators.class.getFields()) { - if (!isOperator(f)) continue; - try { - ops.add((Operator) f.get(null)); - } - catch (final IllegalAccessException exc) { - // This should never happen. - throw new IllegalStateException(exc); - } - } - return ops; + return new ArrayList<>(operatorList); } // -- Helper methods -- @@ -212,10 +260,4 @@ private static Group group(final String leftSymbol, return new Group(leftSymbol, rightSymbol, precedence); } - private static boolean isOperator(final Field f) { - final int mods = f.getModifiers(); - return Modifier.isStatic(mods) && Modifier.isFinal(mods) && - Operator.class.isAssignableFrom(f.getType()); - } - } diff --git a/src/test/java/org/scijava/parsington/OperatorsTest.java b/src/test/java/org/scijava/parsington/OperatorsTest.java new file mode 100644 index 0000000..250bccd --- /dev/null +++ b/src/test/java/org/scijava/parsington/OperatorsTest.java @@ -0,0 +1,47 @@ +package org.scijava.parsington; + +import org.junit.jupiter.api.Test; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class OperatorsTest extends AbstractTest { + + @Test + public void testStandardList() { + // ensure the Operators static list matches a list generated by reflection on the Operators class + List fromStatic = Operators.standardList(); + List fromReflection = standardList(); + Collections.sort(fromStatic); + Collections.sort(fromReflection); + + assertEquals(fromStatic, fromReflection); + } + + public List standardList() { + // Build the standard list from all available Operator constants. + final ArrayList ops = new ArrayList<>(); + for (final Field f : Operators.class.getFields()) { + if (!isOperator(f)) continue; + try { + ops.add((Operator) f.get(null)); + } catch (final IllegalAccessException exc) { + // This should never happen. + throw new IllegalStateException(exc); + } + } + return ops; + } + + private boolean isOperator(final Field f) { + final int mods = f.getModifiers(); + return Modifier.isStatic(mods) && Modifier.isFinal(mods) && + Operator.class.isAssignableFrom(f.getType()); + } + +} \ No newline at end of file