You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JMeter跨JSR223 Sampler传递自定义对象遇类型转换异常

JMeter跨JSR223采样器传递自定义对象时类型转换异常问题

问题现象

在JMeter 5.6.3中使用Groovy 3.0.20的JSR223采样器,将自定义TestDataModel对象列表通过vars.putObject()存入JMeter变量,同一采样器内读取操作正常,但跨采样器用vars.getObject()读取后遍历,抛出类型转换异常:

message: javax.script.ScriptException: org.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object 'TestDataModel@5b28818c' with class 'TestDataModel' to class 'TestDataModel'
javax.script.ScriptException: org.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object 'TestDataModel@5b28818c' with class 'TestDataModel' to class 'TestDataModel'
    at org.codehaus.groovy.jsr223.GroovyScriptEngineImpl.eval(GroovyScriptEngineImpl.java:320) ~[groovy-jsr223-3.0.20.jar:3.0.20]
    at org.codehaus.groovy.jsr223.GroovyCompiledScript.eval(GroovyCompiledScript.java:71) ~[groovy-jsr223-3.0.20.jar:3.0.20]
    at java.scripting/javax.script.CompiledScript.eval(CompiledScript.java:89) ~[java.scripting:?]
    at org.apache.jmeter.util.JSR223TestElement.processFileOrScript(JSR223TestElement.java:230) ~[ApacheJMeter_core.jar:5.6.3]
    at org.apache.jmeter.protocol.java.sampler.JSR223Sampler.sample(JSR223Sampler.java:72) [ApacheJMeter_java.jar:5.6.3]
    at org.apache.jmeter.threads.JMeterThread.doSampling(JMeterThread.java:651) [ApacheJMeter_core.jar:5.6.3]
    at org.apache.jmeter.threads.JMeterThread.executeSamplePackage(JMeterThread.java:570) [ApacheJMeter_core.jar:5.6.3]
    at org.apache.jmeter.threads.JMeterThread.processSampler(JMeterThread.java:501) [ApacheJMeter_core.jar:5.6.3]
    at org.apache.jmeter.threads.JMeterThread.run(JMeterThread.java:268) [ApacheJMeter_core.jar:5.6.3]
    at java.base/java.lang.Thread.run(Thread.java:834) [?:?]
Caused by: org.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object 'TestDataModel@5b28818c' with class 'TestDataModel' to class 'TestDataModel'
    at org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation.continueCastOnSAM(DefaultTypeTransformation.java:404) ~[groovy-3.0.20.jar:3.0.20]
    at org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation.continueCastOnNumber(DefaultTypeTransformation.java:315) ~[groovy-3.0.20.jar:3.0.20]
    at org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation.castToType(DefaultTypeTransformation.java:243) ~[groovy-3.0.20.jar:3.0.20]
    at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.castToType(ScriptBytecodeAdapter.java:615) ~[groovy-3.0.20.jar:3.0.20]
    at Script16.run(Script16.groovy:9) ~[?:?]
    at org.codehaus.groovy.jsr223.GroovyScriptEngineImpl.eval(GroovyScriptEngineImpl.java:317) ~[groovy-jsr223-3.0.20.jar:3.0.20]

相关代码

自定义类TestDataModel

class TestDataModel {
    private String jmsMessageID;
    private long jmsTimestamp;
    private String targetValue;

    // Constructor
    public TestDataModel(String jmsMessageID, long jmsTimestamp, String targetValue) {
        this.jmsMessageID = jmsMessageID;
        this.jmsTimestamp = jmsTimestamp;
        this.targetValue = targetValue;
    }

    // Getters for accessing private fields
    public String getJmsMessageID() {
        return jmsMessageID;
    }

    public long getJmsTimestamp() {
        return jmsTimestamp;
    }

    public String getTargetValue() {
        return targetValue;
    }
}

该类已通过user.classpath配置项添加到JMeter类路径。

JSR223 Sampler1(存对象)

import TestDataModel

List<TestDataModel> dataList = new ArrayList<>()

// Example: Adding message data to the list
dataList.add(new TestDataModel("ID1", System.currentTimeMillis(), "Value1"));
dataList.add(new TestDataModel("ID2", System.currentTimeMillis(), "Value2"));
dataList.add(new TestDataModel("ID3", System.currentTimeMillis(), "Value3"));


    // Example: Searching for a specific targetValue
    String targetValue1 = "Value2";
    for (TestDataModel testDataModel : dataList) {
      if (testDataModel.getTargetValue().equals(targetValue1)) {
          log.info("Found message with targetValue: " + targetValue1)
          log.info("JMSMessageID: " + testDataModel.getJmsMessageID())
          log.info("JMSTimestamp: " + testDataModel.getJmsTimestamp())
          break
      } else {
        log.info("Target message with targetValue: " + targetValue1 + " was not found")
        }
    }
    
    vars.putObject("customObject", dataList)
    
    def retrievedCustomObject = vars.getObject("customObject")
    
    
    // Example2: Searching for a specific targetValue
    String targetValue2 = "Value3";
    for (TestDataModel testDataModel : retrievedCustomObject) {
      if (testDataModel.getTargetValue().equals(targetValue2)) {
          log.info("Found message with targetValue: " + targetValue2)
          log.info("JMSMessageID: " + testDataModel.getJmsMessageID())
          log.info("JMSTimestamp: " + testDataModel.getJmsTimestamp())
          break
      } else {
        log.info("Target message with targetValue: " + targetValue2 + " was not found")
        }
    }

JSR223 Sampler2(读对象)

import TestDataModel

// Retrieve the customObject object from JMeter variables
def customObject = vars.getObject("customObject");

// Check if the object is not null
if (customObject != null) {
    // Iterate over the customObject
    for (TestDataModel data : customObject) {
        // Access data properties and perform actions as needed
        log.info("JMSMessageID: " + data.getJmsMessageID() + ", JMSTimestamp: " + data.getJmsTimestamp() + ", Value: " + data.getTargetValue());
        // Perform further processing here
    }
} else {
    log.info("customObject is null or not found in JMeter variables.");
}

问题原因

核心原因是类加载器冲突:

  • JMeter的每个JSR223采样器默认使用独立的Groovy脚本引擎类加载器,尽管类名都是TestDataModel,但不同采样器中该类由不同类加载器加载,JVM会判定为两个完全不同的类,因此无法完成类型转换。
  • 同一采样器内类加载器一致,所以存取对象操作正常;跨采样器时类加载器不同,触发类型转换异常。

解决方案

方案1:统一使用JMeter共享类加载器

修改每个JSR223采样器的脚本编译设置:

  • 在采样器配置界面,找到Compile script locally选项,取消勾选(默认可能处于勾选状态)。
  • 此设置会让所有JSR223采样器使用JMeter主类加载器加载自定义类,确保类实例的类加载器一致。

方案2:利用Groovy动态特性避免强类型转换

修改Sampler2的遍历逻辑,不使用强类型循环,改用Groovy动态遍历:

def customObject = vars.getObject("customObject");

if (customObject != null) {
    customObject.each { data ->
        log.info("JMSMessageID: " + data.getJmsMessageID() + ", JMSTimestamp: " + data.getJmsTimestamp() + ", Value: " + data.getTargetValue());
    }
} else {
    log.info("customObject is null or not found in JMeter variables.");
}

Groovy的动态特性会通过反射调用方法,绕过类加载器导致的类型检查问题。

方案3:将自定义类打包为Jar放入JMeter lib目录

  • 将TestDataModel类编译成Jar文件,放到JMeter安装目录的lib或lib/ext文件夹下。
  • 重启JMeter后,该类会由JMeter系统类加载器加载,所有采样器共享同一个类定义,彻底避免类加载器冲突。

内容的提问来源于stack exchange,提问作者JustNatural

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 05:57:02