Java 踩坑小记——ProcessBuilder 与 Json 字符串参数
2025年1月22日大约 2 分钟
今天在调试一个用到 ProcessBuilder 执行外部指令的 Spring Boot 项目时,踩到了一个和字符串转义有关的坑,记录一下。
问题背景
项目中有需求调用一个外部的 Shell 脚本,脚本有个参数是 Json 字符串,而这个 Json 字符串在脚本内又会被传入另一个程序中调 Gson 解析。不从项目调用而是直接 Shell 运行的时候一切正常,但是在项目中调用时,目标解析 Json 字符串会报错。
问题分析
java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 1 column 2 path $
日志已经很清楚了,显然是应该传入的 Json 参数是作为非 Json 字符串出现的。于是怀疑 ProcessBuilder 在传入参数时有问题。
解决
在直接调用时,Json 属性的引号需要转义,因为需要让 Shell 知道如何正确分割参数,因此参数是这样的:
-confProp "{\"key\":\"value\"}"
注意,外侧的两个引号是 Shell 的引号,标识 Json 字符串整体是一个参数,内侧的引号是 Json 的引号。
但在 Java 中,传入 ProcessBuilder 进行命令构建的时候无需转义,它是直接分配参数数组的,因此参数应该是这样的:
// 正确
// 应该得到的 command 是 [sh, script.sh, -confProp, {"key":"value"}]
new ProcessBuilder("sh", "script.sh", "-confProp", "{\"key\":\"value\"}");
// 错误, 虽然看似传入的参数和 Shell 一样,但是由于 ProcessBuilder 直接构建
// 参数数组,因此这里的命令实际上是 [sh, script.sh, -confProp, "{\"key\":\"value\"}"]
new ProcessBuilder("sh", "script.sh", "-confProp", "\"{\\\"key\\\":\\\"value\\\"}\");
More
实际上我是把这个配置项写在了 application.properties
中,然后在项目中读取配置项,因此写配置项的时候还需要注意一点,Spring 读取的配置项是不需要转义的,因此配置项应该是这样的:
# 正确
example.conf={"key":"value"}
# 错误
example.conf="{\"key\":\"value\"}"