Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

arthas 构建 vmtool & ognl & spring context.getBean 等命令入参支持复杂类型 JSON 转换 #127

Open
anjia0532 opened this issue May 15, 2024 · 17 comments
Assignees
Labels
enhancement New feature or request

Comments

@anjia0532
Copy link
Contributor

anjia0532 commented May 15, 2024

Vmtool Get Instance Invoke Method Field 为例,对于简单的基础类型可以直接写,但是对于自定义类型则相对麻烦些。

插件默认给 vmtool -x 3 --action getInstances --className 类 --express 'instances[0].方法(new 类())' -c classload hash

OGNL 的方式

vmtool -x 3 --action getInstances --className 类  --express '#p=new 类(),#p.setFieldA("参数A"),instances[0].方法(#p)'  -c classload hash
# 解释一下
# 定义参数 #p=new 类()
# 调用方法进行赋值 #p.setFieldA("参数A")
# 方法入参 instances[0].方法(#p)
# 多个语句之间用英文逗号隔开

Json 的方式

我个人更喜欢用这种方式

# hutool
vmtool -x 3 --action getInstances --className 类  --express 'instances[0].方法(@cn.hutool.json.JSONUtil@toBean("{\"fieldA\":\"参数A\"}",类.class))'  -c classload hash

# fastjson
vmtool -x 3 --action getInstances --className 类  --express 'instances[0].方法(@com.alibaba.fastjson.JSONObject@parseObject("{\"fieldA\":\"参数A\"}",类.class))'  -c classload hash

是否考虑再简化下操作?比如自动生成全了。人工只填写参数就行了。

@WangJi92
Copy link
Owner

@anjia0532 idea 很不错,之前也考虑过这个参数问题,现在的实现相对比较简单

  • 根据class 生成 一个 json 的默认信息的字符串,这个json的字符串也是需要编辑的。
  • 项目里面的json 工具类这个信息,fastjson or other json tools 这个也得考虑,arthas issue 我记得我评论过一次 fastjson 转换的例子,相对来说比较复杂对于用户来说。

@anjia0532
Copy link
Contributor Author

因为json反序列化框架太多了,都兼容不太现实,要么类似 spring bean 那样,让用户自己配置反序列化类和方法。工具这块只是实现将用户贴入的json压缩(json min 化,去掉换行符,string字符串内的换行符替换成 \n ,将""替换成"")。好处简单替换下,可以格式化。开发人员阅读起来更方便。

要么是默认实现第一种,#p=new 类(),#p.方法(参数),......, 调用(#p) 这种实现起来更简单些,但是对于一些大类,没法格式化,肉眼看比较费事。

@WangJi92 WangJi92 added the enhancement New feature or request label May 21, 2024
@WangJi92 WangJi92 self-assigned this May 21, 2024
@WangJi92
Copy link
Owner

工程实现

解析流程

  • 1、右键唤起菜单,获取当前clazz 方法
  • 2、for 便利解析每一个参数
  • 3、如果方法为基本类型,生成默认ognl参数
  • 4、特殊处理 (Ognl 不支持泛型)
    • 通过psiElement build json
    • 查询 工程中是否有FastJson、JackJSon、Gson ?
    • List listClazz ({JSON} com.alibaba.fastjson.JSON.parseObject("json",User.class) )
    • User[] users,User...users arrayClazz (new User[] {JSON} JSON.parseObject("json",User.class))
    • Map<String,User> person (#{ "key" : JSON})
    • User (JSON.parseObject("json",User.class)))
  • 5、构建好命令,打开对话框

序列化框

  • FastJson
    com.alibaba.fastjson.JSON.parseObject(java.lang.String, java.lang.Class)
  • Gson
    Gson gson = new Gson()
    com.google.gson.Gson.fromJson(java.lang.String, java.lang.Class)
  • JackJson
    ObjectMapper objectMapper = new ObjectMapper();
    com.fasterxml.jackson.databind.ObjectMapper.readValue(java.lang.String, java.lang.Class)

序列化框架查找当前工程中存在的 FastJson>JackJson>Gson

样例

样例支持情况还挺多的,只要不是泛型(ognl 不支持泛型),基本是都没有问题,为了支持这个命令,arthas 插件反向支持了一个可以反向生产Clazz的JSON 字符串的命令。

单User

  • code
@PostMapping("/userFastJson")
@ResponseBody
public Object userFastJson(@RequestBody User user) {

    return user;
}
  • arthas command
vmtool -x 3 --action getInstances --className com.wangji92.arthas.plugin.demo.controller.CommonController  --express 'instances[0].userFastJson(@com.alibaba.fastjson.JSON@parseObject("{\"name\":\" \",\"age\":0}",@com.wangji92.arthas.plugin.demo.controller.User@class))'  -c  2c95c2c2

List

  • code
@PostMapping("/userFastJson2")
@ResponseBody
public Object userFastJsonList(@RequestBody List<User> user) {

    return user;
}
  • arthas command
vmtool -x 3 --action getInstances --className com.wangji92.arthas.plugin.demo.controller.CommonController  --express 'instances[0].userFastJsonList({@com.alibaba.fastjson.JSON@parseObject("{\"name\":\" \",\"age\":0}",@com.wangji92.arthas.plugin.demo.controller.User@class)})'  -c  2c95c2c2

User[]

  • code
@PostMapping("/userFastJson3")
@ResponseBody
public Object userFastJsonArray(@RequestBody User[] user) {

    return user;
}
  • arthas command
vmtool -x 3 --action getInstances --className com.wangji92.arthas.plugin.demo.controller.CommonController  --express 'instances[0].userFastJsonArray(new com.wangji92.arthas.plugin.demo.controller.User[]{@com.alibaba.fastjson.JSON@parseObject("{\"name\":\" \",\"age\":0}",@com.wangji92.arthas.plugin.demo.controller.User@class)})'  -c 75d40b07

Map<String,User>

  • code
@PostMapping("/userFastJson4")
@ResponseBody
public Object userFastJsonArray(@RequestBody Map<String,User> user) {

    return user;
}
  • arthas command
vmtool -x 3 --action getInstances --className com.wangji92.arthas.plugin.demo.controller.CommonController  --express 'instances[0].userFastJsonArray(#{"_AR_": @com.alibaba.fastjson.JSON@parseObject("{\"name\":\" \",\"age\":0}",@com.wangji92.arthas.plugin.demo.controller.User@class)})'  -c 75d40b07

总结

基本上这个命令功能,基本上实现完毕,还有写小缺陷需要自测一下,就可以发布了

  • 支持一个 反向生成JSON 的命令。

@WangJi92
Copy link
Owner

@anjia0532 你看看呢?

@WangJi92
Copy link
Owner

WangJi92 commented May 24, 2024

Set 不支持 ,其实还可以这么写?

 @PostMapping("/userFastJson233")
  @ResponseBody
  public Object userFastJsonSet(@RequestBody Set<User> user) {

      return user;
  }

userFastJsonSet((#set=new java.util.HashSet(),#set.add(JSON解析的结果),#set)

  • 最外层这个跨号当做一个整体,然后增加数据,最后一个#set 是返回的结果,相等于 userFastJsonSet 调用时候传递的参数
vmtool -x 3 --action getInstances --className com.wangji92.arthas.plugin.demo.controller.CommonController  --express 'instances[0].userFastJsonSet((#set=new java.util.HashSet(),#set.add(@com.alibaba.fastjson.JSON@parseObject("{\"name\":\"wnagji\",\"age\":0}",@com.wangji92.arthas.plugin.demo.controller.User@class)),#set))'  -c 197a18de 

@anjia0532
Copy link
Contributor Author

奈斯

@anjia0532 你看看呢?

@WangJi92 WangJi92 changed the title [document]快速构建方法入参的两种办法 arthas 构建 vmtool & ognl & spring context.getBean 等命令入参支持复杂类型 JSON 转换 May 24, 2024
@WangJi92
Copy link
Owner

ognl 不支持泛型,如何骚操作处理复杂参数?

ognl 不支持泛型?

  • ognl 脚本里面不能出现 <> 符号

  • com.alibaba.fastjson.JSON#parseObject(java.lang.String, com.alibaba.fastjson.TypeReference<T>, com.alibaba.fastjson.parser.Feature...) 这种转换的方式不支持 ,只能为Clazz

如何处理?

  • 尝试通过set 方法设置泛型的对象信息

  • 由于最外层没有指定泛型,可能生成的Object 对象和实践对象对应的类型不匹配的,可能需要手动修改一下

 /**
     *  处理这种泛型复杂参数 TestGeneratesClazz<String,Map<String,User>> test
     *  1、ognl 本身不支持泛型参数
     *  2、通过Json 构建外层对象 TestGeneratesClazz
     *  3、获取TestGeneratesClazz所有泛型参数
     *  4、遍历TestGeneratesClazz 所有字段 包含了泛型参数 且非基本类型,通过判断是否有set方法进行赋值 同理赋值使用json 构造
     *  5、构建脚本 差异化解决无法处理泛型的问题..
     * @param param
     * @return
     */
    public Object testParam(TestGeneratesClazz<String,Map<String,User>> param) {
        return param;
    }
  • arthas 脚本
vmtool -x 3 --action getInstances --className com.wangji92.arthas.plugin.demo.controller.CommonController  --express 'instances[0].testParam((#[email protected]@parseObject("{\"user2\":{\"name\":\" \",\"age\":0},\"integer\":0,\"st\":\" \",\"user\":\" \",\"test\":{\"_key_\":{\"name\":\" \",\"age\":0}}}",@com.wangji92.arthas.plugin.demo.controller.TestGeneratesClazz@class),(#p.setUser(@com.alibaba.fastjson.JSON@parseObject("{\"user2\":{\"name\":\" \",\"age\":0},\"integer\":0,\"st\":\" \",\"user\":\" \",\"test\":{\"_key_\":{\"name\":\" \",\"age\":0}}}",@com.wangji92.arthas.plugin.demo.controller.TestGeneratesClazz@class))),(#p.setTest(@com.alibaba.fastjson.JSON@parseObject("{\"user2\":{\"name\":\" \",\"age\":0},\"integer\":0,\"st\":\" \",\"user\":\" \",\"test\":{\"_key_\":{\"name\":\" \",\"age\":0}}}",@com.wangji92.arthas.plugin.demo.controller.TestGeneratesClazz@class))),#p))'  -c 6f54e410

@WangJi92
Copy link
Owner

浏览器 JSON 插件

JSON-handle

@WangJi92
Copy link
Owner

json 压缩 转义

https://www.json.cn/jsonzip/ 这个工具比较方便点

@anjia0532
Copy link
Contributor Author

anjia0532 commented May 27, 2024

非广哈,如果不介意安装三方工具(而不是打开网页的话),我个人更推荐 https://u.tools/download/ 支持 win/mac/linux 。类似时间戳转换,json格式化,压缩,翻译,加解密等等有很丰富的插件。不用费劲收藏各类工具网站
image
image

@WangJi92
Copy link
Owner

@anjia0532 这个工具 我也有安装哈哈 OCR识别很爽

@anjia0532
Copy link
Contributor Author

有个蛋疼的小tips,如果要用JSON序列化反序列化,注意检查下参数里有没有字段上加了 @JsonIgnore@JSONField(serialze=false) 等注解。否则会出现反序列化不传值的问题。

@WangJi92
Copy link
Owner

有个蛋疼的小tips,如果要用JSON序列化反序列化,注意检查下参数里有没有字段上加了 @JsonIgnore@JSONField(serialze=false) 等注解。否则会出现反序列化不传值的问题。
这里干掉了..
image

@anjia0532
Copy link
Contributor Author

嗯,我不是说插件会把本该忽略的字段带上,而是针对用户说的,在用的过程中,遇到死活传不进的值,看看有没有加这个注解。

@WangJi92
Copy link
Owner

嗯,我不是说插件会把本该忽略的字段带上,而是针对用户说的,在用的过程中,遇到死活传不进的值,看看有没有加这个注解。

这个是JSON 工具限制的 ~ 忽略了

@anjia0532
Copy link
Contributor Author

anjia0532 commented Jun 18, 2024

@WangJi92 非广哈,新版的 arthas 的 json 序列化我体验了,但是感觉 Cool Request 的调用体验更好一些。

普通入参
image

对象入参
image

@WangJi92
Copy link
Owner

@anjia0532 这个侧重点不一样,这个http请求,我喜欢用官方 Idea HTTP Client ,arthas 这个是反向构造一个json 字符串,用来写文档之类的

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants