Karate 1.3.0起JavaScript函数处理JSON对象异常问题咨询
Karate 1.3.0+ 中JavaScript函数处理JSON对象的异常及解决办法
问题背景
在Karate 1.2.0及更早版本中,Feature文件中可通过如下JavaScript函数处理JSON对象(注:原代码存在笔误,函数内部错误引用全局变量myObj,以下示例已修正为使用参数obj):
* def checkObj = """ function(obj) { const keys = Object.keys(obj); print("### object:", JSON.stringify(obj)); print("### keys:", keys); keys.forEach(key => { print("### key:", key); print("### value:", obj[key]); }); } """ * def myObj = { foo: "bar" } * checkObj(myObj)
预期输出(Karate 1.2.0及更早)
### object: {"foo":"bar"} ### keys: foo ### key: foo ### value: bar
实际输出(Karate 1.3.0+)
从Karate 1.3.0开始,执行相同代码会输出Java Map的内置方法而非对象的业务键值:
### object: {} ### keys: get,values,clear,replaceAll,entrySet,forEach,containsValue,keySet,getOrDefault,remove,put,clone,isEmpty,replace,size,merge,putAll,putIfAbsent,compute,containsKey,computeIfAbsent,computeIfPresent,equals,toString,hashCode ### key: get ### value: undefined ### key: values ### value: undefined ... // 剩余方法输出省略
但内联JavaScript代码仍可正常工作:
* def myObj = { foo: "bar" } * print("### object:", JSON.stringify(myObj)) * print("### key(s):", Object.keys(myObj)) * print("### value:", myObj.foo)
输出符合预期:
### object: {"foo":"bar"} ### key(s): foo ### value: bar
原因分析
Karate 1.3.0对JavaScript引擎的对象传递逻辑做了未文档化的变更:传递给独立JS函数的JSON对象不再自动转换为原生JavaScript对象,而是保留为Java HashMap的包装实例。因此Object.keys()会遍历Java Map的内置方法,而非业务键值;而内联JS代码因执行上下文不同,仍会自动完成对象转换。
解决办法
方法1:将Java Map转换为原生JS对象
在函数内部通过JSON.parse(JSON.stringify(obj))把传入的对象转成原生JS对象后再处理:
* def checkObj = """ function(obj) { const nativeObj = JSON.parse(JSON.stringify(obj)); const keys = Object.keys(nativeObj); print("### object:", JSON.stringify(nativeObj)); print("### keys:", keys); keys.forEach(key => { print("### key:", key); print("### value:", nativeObj[key]); }); } """ * def myObj = { foo: "bar" } * checkObj(myObj)
方法2:使用Karate内置API获取键值
Karate提供原生karate.keys()方法直接获取对象的键列表,无需依赖JS的Object.keys():
* def checkObj = """ function(obj) { const keys = karate.keys(obj); print("### object:", JSON.stringify(obj)); print("### keys:", keys); keys.forEach(key => { print("### key:", key); print("### value:", obj[key]); }); } """ * def myObj = { foo: "bar" } * checkObj(myObj)
方法3:直接调用Java Map的方法
如果不需要转换为原生JS对象,可直接调用Java Map的keySet()方法获取键,在JS中转换为数组后处理:
* def checkObj = """ function(obj) { const keys = Array.from(obj.keySet()); print("### object:", JSON.stringify(obj)); print("### keys:", keys); keys.forEach(key => { print("### key:", key); print("### value:", obj.get(key)); }); } """ * def myObj = { foo: "bar" } * checkObj(myObj)
内容的提问来源于stack exchange,提问作者Drunda Nibel
相关产品推荐
相关产品推荐

