Sun*_*vic 58 groovy json jenkins jenkins-pipeline
解决:感谢S.Richmond的回答.我需要取消设置所有存储的groovy.json.internal.LazyMap
类型的映射,这意味着使变量envServers
和object
使用后无效.
附加:搜索此错误的人可能有兴趣使用Jenkins管道步骤readJSON
- 在此处查找更多信息.
我正在尝试使用Jenkins Pipeline从用户那里获取输入,该输入作为json字符串传递给作业.然后Pipeline使用slurper解析它,我挑选出重要的信息.然后,它将使用该信息与不同的作业参数并行多次运行1个作业.
直到我添加下面的代码"## Error when below here is added"
脚本运行正常.即使是该点下面的代码也会自行运行.但合并后,我得到以下错误.
我应该注意到被触发的作业被调用并且确实成功运行但是发生了以下错误并且失败了主要作业.因此,主要工作不会等待触发作业的返回.我可以尝试/捕捉周围build job:
但我希望主要工作等待触发的工作完成.
谁能在这里协助?如果您需要更多信息,请告诉我们.
干杯
def slurpJSON() {
return new groovy.json.JsonSlurper().parseText(BUILD_CHOICES);
}
node {
stage 'Prepare';
echo 'Loading choices as build properties';
def object = slurpJSON();
def serverChoices = [];
def serverChoicesStr = '';
for (env in object) {
envName = env.name;
envServers = env.servers;
for (server in envServers) {
if (server.Select) {
serverChoicesStr += server.Server;
serverChoicesStr += ',';
}
}
}
serverChoicesStr = serverChoicesStr[0..-2];
println("Server choices: " + serverChoicesStr);
## Error when below here is added
stage 'Jobs'
build job: 'Dummy Start App', parameters: [[$class: 'StringParameterValue', name: 'SERVER_NAME', value: 'TestServer'], [$class: 'StringParameterValue', name: 'SERVER_DOMAIN', value: 'domain.uk'], [$class: 'StringParameterValue', name: 'APP', value: 'application1']]
}
Run Code Online (Sandbox Code Playgroud)
错误:
java.io.NotSerializableException: groovy.json.internal.LazyMap
at org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:860)
at org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:569)
at org.jboss.marshalling.river.BlockMarshaller.doWriteObject(BlockMarshaller.java:65)
at org.jboss.marshalling.river.BlockMarshaller.writeObject(BlockMarshaller.java:56)
at org.jboss.marshalling.MarshallerObjectOutputStream.writeObjectOverride(MarshallerObjectOutputStream.java:50)
at org.jboss.marshalling.river.RiverObjectOutputStream.writeObjectOverride(RiverObjectOutputStream.java:179)
at java.io.ObjectOutputStream.writeObject(Unknown Source)
at java.util.LinkedHashMap.internalWriteEntries(Unknown Source)
at java.util.HashMap.writeObject(Unknown Source)
...
...
Caused by: an exception which occurred:
in field delegate
in field closures
in object org.jenkinsci.plugins.workflow.cps.CpsThreadGroup@5288c
Run Code Online (Sandbox Code Playgroud)
luk*_*a5z 102
请JsonSlurperClassic
改用.
从Groovy 2.3(注:Jenkins 2.7.1使用Groovy 2.4.7)JsonSlurper
返回LazyMap
而不是HashMap
.这使得新的实现JsonSlurper
不是线程安全的而不是可序列化的.这使得它在管道DSL脚本中的@NonDSL函数之外无法使用.
但是,您可以回退到groovy.json.JsonSlurperClassic
支持旧行为,并且可以在管道脚本中安全地使用.
import groovy.json.JsonSlurperClassic
@NonCPS
def jsonParse(def json) {
new groovy.json.JsonSlurperClassic().parseText(json)
}
node('master') {
def config = jsonParse(readFile("config.json"))
def db = config["database"]["address"]
...
}
Run Code Online (Sandbox Code Playgroud)
PS.JsonSlurperClassic
在调用它之前,您仍需要批准.
S.R*_*ond 49
我今天遇到了这个问题,通过一些暴力,我已经想出了如何解决它以及可能的原因.
可能最好从这个原因开始:
Jenkins有一个范例,可以通过重新启动服务器来中断,暂停和恢复所有作业.为了实现这一点,管道及其数据必须是完全可序列化的 - IE需要能够保存所有内容的状态.类似地,它需要能够序列化构建中节点和子作业之间的全局变量状态,这就是我认为你和我发生的事情,以及为什么只有在你添加额外的构建步骤时它才会发生.
无论出于何种原因,JSONObject默认情况下不可序列化.我不是Java开发人员,所以我不能不遗余力地谈论这个话题.虽然我不知道他们对Groovy和Jenkins有多适用,但有很多答案可以解决这个问题.有关更多信息,请参阅此帖子.
你如何解决它:
如果你知道如何,你可以以某种方式使JSONObject可序列化.否则,您可以通过确保没有该类型的全局变量来解决它.
尝试取消设置object
var或将其包装在方法中,使其范围不是全局节点.
mko*_*bit 12
编辑:正如@Sunvic在评论中所指出的,下面的解决方案不适用于JSON Arrays.
我通过使用JsonSlurper
然后HashMap
从惰性结果创建一个新的处理这个.HashMap
是Serializable
.
我认为,这需要双方的白名单new HashMap(Map)
和JsonSlurper
.
@NonCPS
def parseJsonText(String jsonText) {
final slurper = new JsonSlurper()
return new HashMap<>(slurper.parseText(jsonText))
}
Run Code Online (Sandbox Code Playgroud)
总的来说,我建议只使用Pipeline Utility Steps插件,因为它有一个readJSON
步骤可以支持工作区或文本中的文件.
Reg*_*ult 11
我想支持其中一个答案:我建议只使用 Pipeline Utility Steps 插件,因为它有一个 readJSON 步骤,可以支持工作区中的文件或文本:https ://jenkins.io/doc/pipeline/steps /pipeline-utility-steps/#readjson-read-json-from-files-in-the-workspace
script{
def foo_json = sh(returnStdout:true, script: "aws --output json XXX").trim()
def foo = readJSON text: foo_json
}
Run Code Online (Sandbox Code Playgroud)
这不需要任何白名单或额外的东西。
这是要求的详细答案。
未设置对我有用:
String res = sh(script: "curl --header 'X-Vault-Token: ${token}' --request POST --data '${payload}' ${url}", returnStdout: true)
def response = new JsonSlurper().parseText(res)
String value1 = response.data.value1
String value2 = response.data.value2
// unset response because it's not serializable and Jenkins throws NotSerializableException.
response = null
Run Code Online (Sandbox Code Playgroud)
我从解析的响应中读取值,当我不再需要该对象时,我会取消设置它。
来自@mkobit 的答案的稍微更通用的形式将允许对数组和映射进行解码:
import groovy.json.JsonSlurper
@NonCPS
def parseJsonText(String json) {
def object = new JsonSlurper().parseText(json)
if(object instanceof groovy.json.internal.LazyMap) {
return new HashMap<>(object)
}
return object
}
Run Code Online (Sandbox Code Playgroud)
注意:请注意,这只会将顶级 LazyMap 对象转换为 HashMap。任何嵌套的 LazyMap 对象仍将存在并继续导致 Jenkins 出现问题。
小智 5
您可以使用以下函数将 LazyMap 转换为常规 LinkedHashMap(它将保留原始数据的顺序):
LinkedHashMap nonLazyMap (Map lazyMap) {
LinkedHashMap res = new LinkedHashMap()
lazyMap.each { key, value ->
if (value instanceof Map) {
res.put (key, nonLazyMap(value))
} else if (value instanceof List) {
res.put (key, value.stream().map { it instanceof Map ? nonLazyMap(it) : it }.collect(Collectors.toList()))
} else {
res.put (key, value)
}
}
return res
}
...
LazyMap lazyMap = new JsonSlurper().parseText (jsonText)
Map serializableMap = nonLazyMap(lazyMap);
Run Code Online (Sandbox Code Playgroud)
或者更好地使用前面评论中注意到的 readJSON 步骤:
Map serializableMap = readJSON text: jsonText
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
50221 次 |
最近记录: |