This is an automated email from the ASF dual-hosted git repository.

vladimirsitnikov pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/jmeter.git

commit d154f27827635481c807eeb5ccebf87b6df5b3e1
Author: Alioth Null <[email protected]>
AuthorDate: Sun Mar 23 22:05:42 2025 +0800

    remove reflection
---
 src/core/build.gradle.kts                          |   3 +
 .../src/main/java/org/apache/jmeter/JMeter.java    |   2 +-
 .../apache/jmeter/util/BeanShellInterpreter.java   | 182 ++++++++++-----------
 .../apache/jmeter/util/BeanShellTestElement.java   |  16 +-
 src/dist/src/dist/expected_release_jars.csv        |   4 +-
 .../org/apache/jmeter/functions/BeanShell.java     |   6 +-
 6 files changed, 101 insertions(+), 112 deletions(-)

diff --git a/src/core/build.gradle.kts b/src/core/build.gradle.kts
index 98141cdcab..98160b953a 100644
--- a/src/core/build.gradle.kts
+++ b/src/core/build.gradle.kts
@@ -95,6 +95,9 @@ dependencies {
     implementation("commons-codec:commons-codec") {
         because("DigestUtils")
     }
+    implementation("org.apache-extras.beanshell:bsh:2.0b6") {
+        because("Direct dependency required from BeanShellInterpreter")
+    }
     runtimeOnly("commons-collections:commons-collections") {
         because("Compatibility for old plugins")
     }
diff --git a/src/core/src/main/java/org/apache/jmeter/JMeter.java 
b/src/core/src/main/java/org/apache/jmeter/JMeter.java
index d929254962..5fa41bec70 100644
--- a/src/core/src/main/java/org/apache/jmeter/JMeter.java
+++ b/src/core/src/main/java/org/apache/jmeter/JMeter.java
@@ -632,7 +632,7 @@ public class JMeter implements JMeterPlugin {
             try {
                 BeanShellInterpreter bsi = new BeanShellInterpreter();
                 bsi.source(bshinit);
-            } catch (ClassNotFoundException|JMeterException e) {
+            } catch (JMeterException e) {
                 if (log.isWarnEnabled()) {
                     log.warn("Could not process Beanshell file: {}", 
e.getMessage());
                 }
diff --git 
a/src/core/src/main/java/org/apache/jmeter/util/BeanShellInterpreter.java 
b/src/core/src/main/java/org/apache/jmeter/util/BeanShellInterpreter.java
index c07926ff12..f1d3da5b97 100644
--- a/src/core/src/main/java/org/apache/jmeter/util/BeanShellInterpreter.java
+++ b/src/core/src/main/java/org/apache/jmeter/util/BeanShellInterpreter.java
@@ -18,77 +18,38 @@
 package org.apache.jmeter.util;
 
 import java.io.File;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
+import java.io.IOException;
 
 import org.apache.commons.lang3.StringUtils;
-import org.apache.jorphan.util.JMeterError;
 import org.apache.jorphan.util.JMeterException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import bsh.EvalError;
+import bsh.Interpreter;
+
 /**
  * BeanShell setup function - encapsulates all the access to the BeanShell
  * Interpreter in a single class.
  *
- * The class uses dynamic class loading to access BeanShell, which means that
- * all the source files can be built without needing access to the bsh jar.
- *
- * If the beanshell jar is not present at run-time, an error will be logged
+ * This class wraps a BeanShell instance.
  *
+ * Note that reflection-based dynamic class loading has been removed, so the
+ * bsh jar must be available at compile-time and runtime.
  */
-
 public class BeanShellInterpreter {
     private static final Logger log = 
LoggerFactory.getLogger(BeanShellInterpreter.class);
 
-    private static final Method bshGet;
-
-    private static final Method bshSet;
-
-    private static final Method bshEval;
-
-    private static final Method bshSource;
-
-    private static final Class<?> bshClass;
-
-    private static final String BSH_INTERPRETER = "bsh.Interpreter"; 
//$NON-NLS-1$
-
-    static {
-        // Temporary copies, so can set the final ones
-        Method get = null;
-        Method eval = null;
-        Method set = null;
-        Method source = null;
-        Class<?> clazz = null;
-        ClassLoader loader = Thread.currentThread().getContextClassLoader();
-        try {
-            clazz = loader.loadClass(BSH_INTERPRETER);
-            Class<String> string = String.class;
-            Class<Object> object = Object.class;
-
-            get = clazz.getMethod("get", string); //$NON-NLS-1$
-            eval = clazz.getMethod("eval", string); //$NON-NLS-1$
-            set = clazz.getMethod("set", string, object); //$NON-NLS-1$
-            source = clazz.getMethod("source", string); //$NON-NLS-1$
-        } catch (ClassNotFoundException|SecurityException | 
NoSuchMethodException e) {
-            log.error("Beanshell Interpreter not found", e);
-        } finally {
-            bshEval = eval;
-            bshGet = get;
-            bshSet = set;
-            bshSource = source;
-            bshClass = clazz;
-        }
-    }
-
     // This class is not serialised
-    private Object bshInstance = null; // The interpreter instance for this 
class
+    private Interpreter bshInstance = null; // The interpreter instance for 
this class
 
     private final String initFile; // Script file to initialize the 
Interpreter with
 
     private final Logger logger; // Logger to use during initialization and 
script run
 
-    public BeanShellInterpreter() throws ClassNotFoundException {
+    private static final String BSH_ERROR_TEMPLATE = "Error invoking bsh 
method: %s";
+
+    public BeanShellInterpreter() {
         this(null, null);
     }
 
@@ -96,25 +57,16 @@ public class BeanShellInterpreter {
      *
      * @param init initialisation file
      * @param log logger to pass to interpreter
-     * @throws ClassNotFoundException when beanshell can not be instantiated
      */
-    public BeanShellInterpreter(String init, Logger log)  throws 
ClassNotFoundException {
+    public BeanShellInterpreter(String init, Logger log) {
         initFile = init;
         logger = log;
         init();
     }
 
     // Called from ctor, so must be private (or final, but it does not seem 
useful elsewhere)
-    private void init() throws ClassNotFoundException {
-        if (bshClass == null) {
-            throw new ClassNotFoundException(BSH_INTERPRETER);
-        }
-        try {
-            bshInstance = bshClass.getDeclaredConstructor().newInstance();
-        } catch (IllegalArgumentException | ReflectiveOperationException | 
SecurityException e) {
-            log.error("Can't instantiate BeanShell", e);
-            throw new ClassNotFoundException("Can't instantiate BeanShell", e);
-        }
+    private void init() {
+        bshInstance = new Interpreter();
          if (logger != null) {// Do this before starting the script
             try {
                 set("log", logger);//$NON-NLS-1$
@@ -148,65 +100,111 @@ public class BeanShellInterpreter {
 
     /**
      * Resets the BeanShell interpreter.
-     *
-     * @throws ClassNotFoundException if interpreter cannot be instantiated
      */
-    public void reset() throws ClassNotFoundException {
+    public void reset() {
        init();
     }
 
-    private Object bshInvoke(Method m, Object[] o, boolean shouldLog) throws 
JMeterException {
+    public Object eval(String s) throws JMeterException {
         Object r = null;
-        final String errorString = "Error invoking bsh method: ";
         try {
-            r = m.invoke(bshInstance, o);
-        } catch (IllegalArgumentException | IllegalAccessException e) { // 
Programming error
-            final String message = errorString + m.getName();
-            log.error(message);
-            throw new JMeterError(message, e);
-        } catch (InvocationTargetException e) { // Can occur at run-time
-            // could be caused by the bsh Exceptions:
-            // EvalError, ParseException or TargetError
-            String message = errorString + m.getName();
+            r = bshInstance.eval(s);
+        } catch (EvalError e) {
+            String message = String.format(BSH_ERROR_TEMPLATE, "eval");
             Throwable cause = e.getCause();
             if (cause != null) {
                 message += "\t" + cause.getLocalizedMessage();
             }
-
-            if (shouldLog) {
-                log.error(message);
-            }
+            log.error(message);
             throw new JMeterException(message, e);
         }
         return r;
     }
 
-    public Object eval(String s) throws JMeterException {
-        return bshInvoke(bshEval, new Object[] { s }, true);
-    }
-
     public Object evalNoLog(String s) throws JMeterException {
-        return bshInvoke(bshEval, new Object[] { s }, false);
+        Object r = null;
+        try {
+            r = bshInstance.eval(s);
+        } catch (EvalError e) {
+            String message = String.format(BSH_ERROR_TEMPLATE, "eval");
+            Throwable cause = e.getCause();
+            if (cause != null) {
+                message += "\t" + cause.getLocalizedMessage();
+            }
+            throw new JMeterException(message, e);
+        }
+        return r;
     }
 
-    public Object set(String s, Object o) throws JMeterException {
-        return bshInvoke(bshSet, new Object[] { s, o }, true);
+    public void set(String s, Object o) throws JMeterException {
+        try {
+            bshInstance.set(s, o);
+        } catch (EvalError e) {
+            String message = String.format(BSH_ERROR_TEMPLATE, "set");
+            Throwable cause = e.getCause();
+            if (cause != null) {
+                message += "\t" + cause.getLocalizedMessage();
+            }
+            log.error(message);
+            throw new JMeterException(message, e);
+        }
     }
 
-    public Object set(String s, boolean b) throws JMeterException {
-        return bshInvoke(bshSet, new Object[] { s, b}, true);
+    public void set(String s, boolean b) throws JMeterException {
+        try {
+            bshInstance.set(s, b);
+        } catch (EvalError e) {
+            String message = String.format(BSH_ERROR_TEMPLATE, "set");
+            Throwable cause = e.getCause();
+            if (cause != null) {
+                message += "\t" + cause.getLocalizedMessage();
+            }
+            log.error(message);
+            throw new JMeterException(message, e);
+        }
     }
 
     public Object source(String s) throws JMeterException {
-        return bshInvoke(bshSource, new Object[] { s }, true);
+        Object r = null;
+        try {
+            r = bshInstance.source(s);
+        } catch (EvalError | IOException e) {
+            String message = String.format(BSH_ERROR_TEMPLATE, "source");
+            Throwable cause = e.getCause();
+            if (cause != null) {
+                message += "\t" + cause.getLocalizedMessage();
+            }
+            log.error(message);
+            throw new JMeterException(message, e);
+        }
+        return r;
     }
 
     public Object get(String s) throws JMeterException {
-        return bshInvoke(bshGet, new Object[] { s }, true);
+        Object r = null;
+        try {
+            r = bshInstance.get(s);
+        } catch (EvalError e) {
+            String message = String.format(BSH_ERROR_TEMPLATE, "get");
+            Throwable cause = e.getCause();
+            if (cause != null) {
+                message += "\t" + cause.getLocalizedMessage();
+            }
+            log.error(message);
+            throw new JMeterException(message, e);
+        }
+        return r;
     }
 
     // For use by Unit Tests
-    public static boolean isInterpreterPresent(){
+    public static boolean isInterpreterPresent() {
+        Class<?> bshClass = null;
+        ClassLoader loader = Thread.currentThread().getContextClassLoader();
+        try {
+            bshClass = loader.loadClass("bsh.Interpreter");
+        } catch (ClassNotFoundException e) {
+            log.error("Beanshell Interpreter not found", e);
+        }
         return bshClass != null;
     }
 }
diff --git 
a/src/core/src/main/java/org/apache/jmeter/util/BeanShellTestElement.java 
b/src/core/src/main/java/org/apache/jmeter/util/BeanShellTestElement.java
index 816b3299e1..88b9bdd1bc 100644
--- a/src/core/src/main/java/org/apache/jmeter/util/BeanShellTestElement.java
+++ b/src/core/src/main/java/org/apache/jmeter/util/BeanShellTestElement.java
@@ -75,11 +75,7 @@ public abstract class BeanShellTestElement extends 
AbstractTestElement
      */
     protected BeanShellInterpreter getBeanShellInterpreter() {
         if (isResetInterpreter()) {
-            try {
-                bshInterpreter.reset();
-            } catch (ClassNotFoundException e) {
-                log.error("Cannot reset BeanShell: {}", e.toString()); // 
NOSONAR last arg would be exception
-            }
+            bshInterpreter.reset();
         }
 
         JMeterContext jmctx = JMeterContextService.getContext();
@@ -101,13 +97,9 @@ public abstract class BeanShellTestElement extends 
AbstractTestElement
         parameters=""; // ensure variables are not null
         filename="";
         script="";
-        try {
-            String initFileName = 
JMeterUtils.getProperty(getInitFileProperty());
-            hasInitFile = initFileName != null;
-            bshInterpreter = new BeanShellInterpreter(initFileName, log);
-        } catch (ClassNotFoundException e) {
-            log.error("Cannot find BeanShell: {}", e.toString()); // NOSONAR 
last arg would be exception
-        }
+        String initFileName = JMeterUtils.getProperty(getInitFileProperty());
+        hasInitFile = initFileName != null;
+        bshInterpreter = new BeanShellInterpreter(initFileName, log);
     }
 
     protected Object readResolve() {
diff --git a/src/dist/src/dist/expected_release_jars.csv 
b/src/dist/src/dist/expected_release_jars.csv
index a6b456bff1..3acb323486 100644
--- a/src/dist/src/dist/expected_release_jars.csv
+++ b/src/dist/src/dist/expected_release_jars.csv
@@ -33,7 +33,7 @@
 462124,commons-jexl3-3.2.1.jar
 760623,commons-jvm-4.1.0.jar
 657952,commons-lang3-3.14.0.jar
-70816,commons-logging-1.3.0.jar
+73737,commons-logging-1.3.5.jar
 2213560,commons-math3-3.6.1.jar
 322780,commons-net-3.10.0.jar
 150048,commons-pool2-2.12.0.jar
@@ -137,4 +137,4 @@
 7188,xmlpull-1.1.3.1.jar
 1027769,xmlresolver-5.2.1-data.jar
 165689,xmlresolver-5.2.1.jar
-644649,xstream-1.4.20.jar
+646504,xstream-1.4.21.jar
diff --git 
a/src/functions/src/main/java/org/apache/jmeter/functions/BeanShell.java 
b/src/functions/src/main/java/org/apache/jmeter/functions/BeanShell.java
index f72284c877..8a924904ec 100644
--- a/src/functions/src/main/java/org/apache/jmeter/functions/BeanShell.java
+++ b/src/functions/src/main/java/org/apache/jmeter/functions/BeanShell.java
@@ -131,11 +131,7 @@ public class BeanShell extends AbstractFunction {
 
         values = parameters.toArray();
 
-        try {
-            bshInterpreter = new 
BeanShellInterpreter(JMeterUtils.getProperty(INIT_FILE), log);
-        } catch (ClassNotFoundException e) {
-            throw new InvalidVariableException("BeanShell not found", e);
-        }
+        bshInterpreter = new 
BeanShellInterpreter(JMeterUtils.getProperty(INIT_FILE), log);
     }
 
     /** {@inheritDoc} */

Reply via email to