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} */
