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 368401df7948044be6d31c18ad620dba4df9518c Author: Vladimir Sitnikov <[email protected]> AuthorDate: Fri Nov 7 13:15:30 2025 +0300 chore: remove uses of commons-codec. Java 17 has both Base64 and HexFormat --- bin/testfiles/TCP_TESTS.jmx | 20 ++++++++-------- src/components/build.gradle.kts | 1 - src/core/build.gradle.kts | 3 --- .../org/apache/jmeter/util/JSR223TestElement.java | 14 ++++++++--- .../org/apache/jmeter/util/ScriptCacheKey.java | 22 ++++++++++-------- .../jmeter/util/keystore/JmeterKeyStore.java | 4 ++-- src/dist/build.gradle.kts | 4 ++++ src/functions/build.gradle.kts | 1 - .../jmeter/functions/DigestEncodeFunction.java | 27 ++++++++-------------- .../java/org/apache/jorphan/util/JOrphanUtils.java | 26 +++++---------------- .../jmeter/protocol/http/proxy/ProxyControl.java | 10 ++++---- 11 files changed, 60 insertions(+), 72 deletions(-) diff --git a/bin/testfiles/TCP_TESTS.jmx b/bin/testfiles/TCP_TESTS.jmx index 1bfd6e85cd..d646bef3a0 100644 --- a/bin/testfiles/TCP_TESTS.jmx +++ b/bin/testfiles/TCP_TESTS.jmx @@ -74,7 +74,7 @@ import org.apache.mina.transport.socket.nio.NioSocketAcceptor; class TimeServerHandler extends IoHandlerAdapter { private static final String EOL = "\n"; - Logger log = LoggerFactory.getLogger(TimeServerHandler.class); + Logger log = LoggerFactory.getLogger(TimeServerHandler.class); public void exceptionCaught( IoSession session, Throwable cause ) throws Exception { log.error("Exception occured", cause); @@ -85,7 +85,7 @@ class TimeServerHandler extends IoHandlerAdapter { String str = message.trim().toString(); log.info("Received {}", str); - + String[] words = str.split(" "); if(words[0].equalsIgnoreCase("quit") ) { session.close(); @@ -269,10 +269,10 @@ vars.put("CR",URLDecoder.decode("%0A", "ASCII")); <stringProp name="cacheKey">e7ac0019-16aa-40b4-b30f-e254c0a75f27</stringProp> <stringProp name="filename"></stringProp> <stringProp name="parameters"></stringProp> - <stringProp name="script">import org.apache.commons.codec.binary.Hex; -Hex hex = new Hex(); -OUT.println(new String(hex.decode(prev.getResponseData()))); -vars.put("result_decoded", new String(hex.decode(prev.getResponseData())));</stringProp> + <stringProp name="script">import java.util.HexFormat; +String decoded = new String(HexFormat.of().parseHex(prev.getResponseDataAsString())); +OUT.println(decoded); +vars.put("result_decoded", decoded);</stringProp> <stringProp name="scriptLanguage">groovy</stringProp> </JSR223PostProcessor> <hashTree/> @@ -500,10 +500,10 @@ if (oldResponseMessage != null && oldResponseMessage.contains("java <stringProp name="cacheKey">e7ac0019-16aa-40b4-b30f-e254c0a75f27</stringProp> <stringProp name="filename"></stringProp> <stringProp name="parameters"></stringProp> - <stringProp name="script">import org.apache.commons.codec.binary.Hex; -Hex hex = new Hex(); -OUT.println(new String(hex.decode(prev.getResponseData()))); -vars.put("result_decoded", new String(hex.decode(prev.getResponseData())));</stringProp> + <stringProp name="script">import java.util.HexFormat; +String decoded = new String(HexFormat.of().parseHex(prev.getResponseDataAsString())); +OUT.println(decoded); +vars.put("result_decoded", decoded);</stringProp> <stringProp name="scriptLanguage">groovy</stringProp> </JSR223PostProcessor> <hashTree/> diff --git a/src/components/build.gradle.kts b/src/components/build.gradle.kts index 111475b090..f485e2bc69 100644 --- a/src/components/build.gradle.kts +++ b/src/components/build.gradle.kts @@ -51,7 +51,6 @@ dependencies { implementation("net.minidev:json-smart") implementation("net.minidev:accessors-smart") implementation("org.apache.commons:commons-pool2") - implementation("commons-codec:commons-codec") implementation("org.ow2.asm:asm") implementation("org.jodd:jodd-log") { exclude("ch.qos.logback") diff --git a/src/core/build.gradle.kts b/src/core/build.gradle.kts index de661927bd..ab84960a6a 100644 --- a/src/core/build.gradle.kts +++ b/src/core/build.gradle.kts @@ -91,9 +91,6 @@ dependencies { implementation("com.github.weisj:darklaf-property-loader") implementation("com.github.weisj:darklaf-extensions-rsyntaxarea") implementation("com.miglayout:miglayout-swing") - implementation("commons-codec:commons-codec") { - because("DigestUtils") - } implementation("org.apache-extras.beanshell:bsh:2.0b6") { because("Direct dependency required from BeanShellInterpreter") } diff --git a/src/core/src/main/java/org/apache/jmeter/util/JSR223TestElement.java b/src/core/src/main/java/org/apache/jmeter/util/JSR223TestElement.java index 5b042f33b6..f6fe6716ab 100644 --- a/src/core/src/main/java/org/apache/jmeter/util/JSR223TestElement.java +++ b/src/core/src/main/java/org/apache/jmeter/util/JSR223TestElement.java @@ -21,7 +21,10 @@ import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.Serializable; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; import java.util.Properties; import java.util.function.Function; @@ -32,7 +35,6 @@ import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import javax.script.ScriptException; -import org.apache.commons.codec.digest.DigestUtils; import org.apache.jmeter.samplers.SampleResult; import org.apache.jmeter.samplers.Sampler; import org.apache.jmeter.testelement.TestStateListener; @@ -306,8 +308,14 @@ public abstract class JSR223TestElement extends ScriptingTestElement */ private void computeScriptMD5(String script) { // compute the md5 of the script if needed - if(scriptMd5 == null) { - scriptMd5 = ScriptCacheKey.ofString(DigestUtils.md5Hex(script)); + if (scriptMd5 == null) { + try { + MessageDigest md = MessageDigest.getInstance("MD5"); + md.update(script.getBytes(StandardCharsets.UTF_8)); + scriptMd5 = ScriptCacheKey.ofDigest(md.digest()); + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException("MessageDigest.getInstance(MD5) was not found", e); + } } } diff --git a/src/core/src/main/java/org/apache/jmeter/util/ScriptCacheKey.java b/src/core/src/main/java/org/apache/jmeter/util/ScriptCacheKey.java index 6b7ea21c97..c006adf5bc 100644 --- a/src/core/src/main/java/org/apache/jmeter/util/ScriptCacheKey.java +++ b/src/core/src/main/java/org/apache/jmeter/util/ScriptCacheKey.java @@ -17,6 +17,8 @@ package org.apache.jmeter.util; +import java.util.Arrays; +import java.util.HexFormat; import java.util.Objects; interface ScriptCacheKey { @@ -25,8 +27,8 @@ interface ScriptCacheKey { * @param key cache key * @return cache key */ - static ScriptCacheKey ofString(String key) { - return new StringScriptCacheKey(key); + static ScriptCacheKey ofDigest(byte[] key) { + return new DigestScriptCacheKey(key); } /** @@ -40,11 +42,11 @@ interface ScriptCacheKey { return new FileScriptCacheKey(language, absolutePath, lastModified); } - final class StringScriptCacheKey implements ScriptCacheKey { - final String contents; + final class DigestScriptCacheKey implements ScriptCacheKey { + final byte[] digest; - StringScriptCacheKey(String contents) { - this.contents = contents; + DigestScriptCacheKey(byte[] digest) { + this.digest = digest; } @Override @@ -55,19 +57,19 @@ interface ScriptCacheKey { if (o == null || getClass() != o.getClass()) { return false; } - StringScriptCacheKey that = (StringScriptCacheKey) o; - return Objects.equals(contents, that.contents); + DigestScriptCacheKey that = (DigestScriptCacheKey) o; + return Arrays.equals(digest, that.digest); } @Override public int hashCode() { - return contents.hashCode(); + return Arrays.hashCode(digest); } @Override public String toString() { return "StringScriptCacheKey{" + - "contents='" + contents + '\'' + + "contents='" + HexFormat.of().formatHex(digest) + '\'' + '}'; } } diff --git a/src/core/src/main/java/org/apache/jmeter/util/keystore/JmeterKeyStore.java b/src/core/src/main/java/org/apache/jmeter/util/keystore/JmeterKeyStore.java index 40eaf0d17a..2f0b69c01c 100644 --- a/src/core/src/main/java/org/apache/jmeter/util/keystore/JmeterKeyStore.java +++ b/src/core/src/main/java/org/apache/jmeter/util/keystore/JmeterKeyStore.java @@ -34,12 +34,12 @@ import java.util.Arrays; import java.util.Collection; import java.util.Enumeration; import java.util.HashMap; +import java.util.HexFormat; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.stream.Collectors; -import org.apache.commons.codec.binary.Hex; import org.apache.jmeter.threads.JMeterContextService; import org.apache.jorphan.util.StringUtilities; import org.slf4j.Logger; @@ -242,7 +242,7 @@ public final class JmeterKeyStore { if (data instanceof String s) { return s; } - return Hex.encodeHexString((byte[]) data); + return HexFormat.of().formatHex((byte[]) data); } private static String sanGeneralNameIndexToName(Integer index) { diff --git a/src/dist/build.gradle.kts b/src/dist/build.gradle.kts index 44bfe693e4..26661caa01 100644 --- a/src/dist/build.gradle.kts +++ b/src/dist/build.gradle.kts @@ -89,6 +89,10 @@ dependencies { api(project(p)) } + runtimeOnly("commons-codec:commons-codec") { + because("commons-codec was a dependency in previous JMeter versions, so we keep it for compatibility") + } + binLicense(project(":src:licenses", "binLicense")) srcLicense(project(":src:licenses", "srcLicense")) generatorJar(project(":src:generator", "archives")) diff --git a/src/functions/build.gradle.kts b/src/functions/build.gradle.kts index b948246962..773eb6b7df 100644 --- a/src/functions/build.gradle.kts +++ b/src/functions/build.gradle.kts @@ -24,7 +24,6 @@ dependencies { testImplementation(testFixtures(projects.src.core)) implementation("org.mozilla:rhino") - implementation("commons-codec:commons-codec") implementation("org.apache.commons:commons-jexl") implementation("org.apache.commons:commons-jexl3") implementation("commons-io:commons-io") { diff --git a/src/functions/src/main/java/org/apache/jmeter/functions/DigestEncodeFunction.java b/src/functions/src/main/java/org/apache/jmeter/functions/DigestEncodeFunction.java index b7325ad23a..0d215dc2bd 100644 --- a/src/functions/src/main/java/org/apache/jmeter/functions/DigestEncodeFunction.java +++ b/src/functions/src/main/java/org/apache/jmeter/functions/DigestEncodeFunction.java @@ -22,10 +22,9 @@ import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.Collection; +import java.util.HexFormat; import java.util.List; -import java.util.Locale; -import org.apache.commons.codec.binary.Hex; import org.apache.jmeter.engine.util.CompoundVariable; import org.apache.jmeter.samplers.SampleResult; import org.apache.jmeter.samplers.Sampler; @@ -85,7 +84,14 @@ public class DigestEncodeFunction extends AbstractFunction { md.update(salt.getBytes(StandardCharsets.UTF_8)); } byte[] bytes = md.digest(); - encodedString = uppercase(Hex.encodeHexString(bytes), values, 3); + HexFormat hexFormat = HexFormat.of(); + if (values.length > 3) { + String shouldUpperCase = values[3].execute(); + if (Boolean.parseBoolean(shouldUpperCase)) { + hexFormat = hexFormat.withUpperCase(); + } + } + encodedString = hexFormat.formatHex(bytes); addVariableValue(encodedString, values, 4); } catch (NoSuchAlgorithmException e) { log.error("Error calling {} function with value {}, digest algorithm {}, salt {}, ", KEY, stringToEncode, @@ -94,21 +100,6 @@ public class DigestEncodeFunction extends AbstractFunction { return encodedString; } - /** - * Upper case value if optional parameter value is true - * - * @param encodedString - * @param index - * @return - */ - private static String uppercase(String encodedString, CompoundVariable[] values, int index) { - String shouldUpperCase = values.length > index ? values[index].execute() : null; - if (Boolean.parseBoolean(shouldUpperCase)) { - return encodedString.toUpperCase(Locale.ROOT); - } - return encodedString; - } - @Override public void setParameters(Collection<CompoundVariable> parameters) throws InvalidVariableException { checkParameterCount(parameters, MIN_PARAMETER_COUNT, MAX_PARAMETER_COUNT); diff --git a/src/jorphan/src/main/java/org/apache/jorphan/util/JOrphanUtils.java b/src/jorphan/src/main/java/org/apache/jorphan/util/JOrphanUtils.java index 1ca523bc6e..794f8406a7 100644 --- a/src/jorphan/src/main/java/org/apache/jorphan/util/JOrphanUtils.java +++ b/src/jorphan/src/main/java/org/apache/jorphan/util/JOrphanUtils.java @@ -27,6 +27,7 @@ import java.net.ServerSocket; import java.net.Socket; import java.security.SecureRandom; import java.util.ArrayList; +import java.util.HexFormat; import java.util.List; import java.util.Map; import java.util.StringTokenizer; @@ -403,15 +404,7 @@ public final class JOrphanUtils { * @return hex representation of binary input */ public static String baToHexString(byte[] ba) { - StringBuilder sb = new StringBuilder(ba.length * 2); - for (byte b : ba) { - int j = b & 0xff; - if (j < 16) { - sb.append('0'); // $NON-NLS-1$ add zero padding - } - sb.append(Integer.toHexString(j)); - } - return sb.toString(); + return baToHexString(ba, '\0'); } /** @@ -422,18 +415,11 @@ public final class JOrphanUtils { * @return hex representation of binary input */ public static String baToHexString(byte[] ba, char separator) { - StringBuilder sb = new StringBuilder(ba.length * 2); - for (int i = 0; i < ba.length; i++) { - if (i > 0 && separator != 0) { - sb.append(separator); - } - int j = ba[i] & 0xff; - if (j < 16) { - sb.append('0'); // $NON-NLS-1$ add zero padding - } - sb.append(Integer.toHexString(j)); + HexFormat format = HexFormat.of(); + if (separator != 0) { + format = format.withDelimiter(Character.toString(separator)); } - return sb.toString(); + return format.formatHex(ba); } /** diff --git a/src/protocol/http/src/main/java/org/apache/jmeter/protocol/http/proxy/ProxyControl.java b/src/protocol/http/src/main/java/org/apache/jmeter/protocol/http/proxy/ProxyControl.java index b7b29c1708..826549a979 100644 --- a/src/protocol/http/src/main/java/org/apache/jmeter/protocol/http/proxy/ProxyControl.java +++ b/src/protocol/http/src/main/java/org/apache/jmeter/protocol/http/proxy/ProxyControl.java @@ -27,6 +27,7 @@ import java.io.Serializable; import java.nio.charset.StandardCharsets; import java.security.GeneralSecurityException; import java.security.KeyStore; +import java.security.MessageDigest; import java.security.UnrecoverableKeyException; import java.security.cert.CertificateExpiredException; import java.security.cert.CertificateNotYetValidException; @@ -34,6 +35,7 @@ import java.security.cert.X509Certificate; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Arrays; +import java.util.Base64; import java.util.Collection; import java.util.Date; import java.util.Deque; @@ -49,8 +51,6 @@ import java.util.prefs.Preferences; import java.util.regex.PatternSyntaxException; import java.util.stream.Collectors; -import org.apache.commons.codec.binary.Base64; -import org.apache.commons.codec.digest.DigestUtils; import org.apache.jmeter.assertions.Assertion; import org.apache.jmeter.assertions.ResponseAssertion; import org.apache.jmeter.assertions.gui.AssertionGui; @@ -720,7 +720,7 @@ public class ProxyControl extends GenericController implements NonTestElement { authorization.setURL(computeAuthUrl(result.getUrlAsString())); authorization.setMechanism(mechanism); if(BASIC_AUTH.equals(authType)) { - String authCred = new String(Base64.decodeBase64(authCredentialsBase64), StandardCharsets.UTF_8); + String authCred = new String(Base64.getDecoder().decode(authCredentialsBase64), StandardCharsets.UTF_8); String[] loginPassword = authCred.split(":"); //$NON-NLS-1$ if(loginPassword.length == 2) { authorization.setUser(loginPassword[0]); @@ -785,10 +785,12 @@ public class ProxyControl extends GenericController implements NonTestElement { if (caCert == null) { return new String[]{"Could not find certificate"}; } + MessageDigest md = MessageDigest.getInstance("SHA-1"); + md.update(caCert.getEncoded()); return new String[] { caCert.getSubjectX500Principal().toString(), - "Fingerprint(SHA1): " + JOrphanUtils.baToHexString(DigestUtils.sha1(caCert.getEncoded()), ' '), + "Fingerprint(SHA1): " + JOrphanUtils.baToHexString(md.digest(), ' '), "Created: "+ caCert.getNotBefore().toString() }; } catch (GeneralSecurityException e) {
