有没有办法根据 groovy 地图验证架构?
Is there a way to validate a schema against a groovy map?
我的用例是 Jenkins 特定的,但这是一个一般性的 Groovy 问题
我有一张地图,我想对其应用架构。如果此地图缺少字段或某些字段类型错误 (string/int/list/map/etc),我想抛出一条明确的错误消息,解释地图与架构不匹配的位置。
我像这样将 Jenkinsfile 中的映射传递给共享库中的函数,因此 mypipeline 需要包含架构验证部分:
#Jenkinsfile
@Library('my-shared-lib') _
mypipeline ([
'validate-this-map': [
// manditory-param-one must exist and be a list
'manditory-param-one': ["aaa","bbb","ccc"]
// manditory-param-two must exist and be a map
'manditory-param-two': [
"manditory-one": "111", // must include this field and be a string
"manditory-two": "222", // must include this field and be a string
"optional": "33",
]
// manditory-param-three must exist and be a list of maps that have specific fields
'manditory-param-three': [
"manditory-one": [
// all maps in this list must have these two fields
"aaa": true // validate bool
"bbb": "sdfsfdsd" //validate string
]
]
'optional-param': "sdfsdfs" // ignore this. dont fail if this is here
]
])
我过去所做的是将特定于语言的构造(在本例中为 groovy 映射)翻译为 json 并应用支持高级的 json 模式递归等功能。虽然这可能很不稳定,但我想知道这是否可以用惯用的 groovy 方式实现。
我不想将 validate-this-map
设为 class,因为这会使我 认为 的 Jenkinsfile 配置复杂化。有没有办法让 groovy 将地图转换为 class 并让 groovy 验证 class 属性或其他东西?
您可以在构造函数中使用 Groovy 的命名参数并自动创建对象层次结构。
然后你可以在上面添加简单的验证,为了简单起见,我在下面使用了Groovy Truth
。
代码(在对 JSON 键进行一些清理后)可能如下所示:
import groovy.transform.*
// your classes
@ToString
class A {
List<String> manditoryParamOne
ManditoryParamTwo manditoryParamTwo
ManditoryParamThree manditoryParamThree
String optionalParam
boolean asBoolean() {
manditoryParamOne && manditoryParamTwo && manditoryParamThree
}
}
@ToString
class ManditoryParamTwo {
String manditoryOne, manditoryTwo, optional
boolean asBoolean() {
manditoryOne && manditoryTwo
}
}
@ToString
class ManditoryParamThree {
ManditoryOne manditoryOne
boolean asBoolean() {
manditoryOne
}
}
@ToString
class ManditoryOne{
Boolean aaa
String bbb
boolean asBoolean() {
null != aaa && bbb
}
}
// some test code, pay attention to map keys
def mapValid = [
// manditory-param-one must exist and be a list
'manditoryParamOne': ["aaa","bbb","ccc"],
// manditory-param-two must exist and be a map
'manditoryParamTwo': [
"manditoryOne": "111", // must include this field and be a string
"manditoryTwo": "222", // must include this field and be a string
"optional": "33",
],
// manditory-param-three must exist and be a list of maps that have specific fields
'manditoryParamThree': [
"manditoryOne": [
// all maps in this list must have these two fields
"aaa": true, // validate bool
"bbb": "sdfsfdsd" //validate string
]
],
'optionalParam': "sdfsdfs" // ignore this. dont fail if this is here
]
A a = new A( mapValid )
assert a.toString() == 'A([aaa, bbb, ccc], ManditoryParamTwo(111, 222, 33), ManditoryParamThree(ManditoryOne(true, sdfsfdsd)), sdfsdfs)'
assert true == !!a
assert true == !!a.manditoryParamOne
assert true == !!a.manditoryParamTwo
def mapInvalid = [
'manditoryParamTwo': [
"manditoryOne": "111", // must include this field and be a string
"manditoryTwo": "222", // must include this field and be a string
"optional": "33",
],
// manditory-param-three must exist and be a list of maps that have specific fields
'manditoryParamThree': [
"manditoryOne": [
"bbb": "sdfsfdsd" //validate string
]
]
]
A aa = new A( mapInvalid )
assert false == !!aa
assert true == !!aa.manditoryParamTwo
assert false == !!aa.manditoryParamThree
我的用例是 Jenkins 特定的,但这是一个一般性的 Groovy 问题
我有一张地图,我想对其应用架构。如果此地图缺少字段或某些字段类型错误 (string/int/list/map/etc),我想抛出一条明确的错误消息,解释地图与架构不匹配的位置。
我像这样将 Jenkinsfile 中的映射传递给共享库中的函数,因此 mypipeline 需要包含架构验证部分:
#Jenkinsfile
@Library('my-shared-lib') _
mypipeline ([
'validate-this-map': [
// manditory-param-one must exist and be a list
'manditory-param-one': ["aaa","bbb","ccc"]
// manditory-param-two must exist and be a map
'manditory-param-two': [
"manditory-one": "111", // must include this field and be a string
"manditory-two": "222", // must include this field and be a string
"optional": "33",
]
// manditory-param-three must exist and be a list of maps that have specific fields
'manditory-param-three': [
"manditory-one": [
// all maps in this list must have these two fields
"aaa": true // validate bool
"bbb": "sdfsfdsd" //validate string
]
]
'optional-param': "sdfsdfs" // ignore this. dont fail if this is here
]
])
我过去所做的是将特定于语言的构造(在本例中为 groovy 映射)翻译为 json 并应用支持高级的 json 模式递归等功能。虽然这可能很不稳定,但我想知道这是否可以用惯用的 groovy 方式实现。
我不想将 validate-this-map
设为 class,因为这会使我 认为 的 Jenkinsfile 配置复杂化。有没有办法让 groovy 将地图转换为 class 并让 groovy 验证 class 属性或其他东西?
您可以在构造函数中使用 Groovy 的命名参数并自动创建对象层次结构。
然后你可以在上面添加简单的验证,为了简单起见,我在下面使用了Groovy Truth
。
代码(在对 JSON 键进行一些清理后)可能如下所示:
import groovy.transform.*
// your classes
@ToString
class A {
List<String> manditoryParamOne
ManditoryParamTwo manditoryParamTwo
ManditoryParamThree manditoryParamThree
String optionalParam
boolean asBoolean() {
manditoryParamOne && manditoryParamTwo && manditoryParamThree
}
}
@ToString
class ManditoryParamTwo {
String manditoryOne, manditoryTwo, optional
boolean asBoolean() {
manditoryOne && manditoryTwo
}
}
@ToString
class ManditoryParamThree {
ManditoryOne manditoryOne
boolean asBoolean() {
manditoryOne
}
}
@ToString
class ManditoryOne{
Boolean aaa
String bbb
boolean asBoolean() {
null != aaa && bbb
}
}
// some test code, pay attention to map keys
def mapValid = [
// manditory-param-one must exist and be a list
'manditoryParamOne': ["aaa","bbb","ccc"],
// manditory-param-two must exist and be a map
'manditoryParamTwo': [
"manditoryOne": "111", // must include this field and be a string
"manditoryTwo": "222", // must include this field and be a string
"optional": "33",
],
// manditory-param-three must exist and be a list of maps that have specific fields
'manditoryParamThree': [
"manditoryOne": [
// all maps in this list must have these two fields
"aaa": true, // validate bool
"bbb": "sdfsfdsd" //validate string
]
],
'optionalParam': "sdfsdfs" // ignore this. dont fail if this is here
]
A a = new A( mapValid )
assert a.toString() == 'A([aaa, bbb, ccc], ManditoryParamTwo(111, 222, 33), ManditoryParamThree(ManditoryOne(true, sdfsfdsd)), sdfsdfs)'
assert true == !!a
assert true == !!a.manditoryParamOne
assert true == !!a.manditoryParamTwo
def mapInvalid = [
'manditoryParamTwo': [
"manditoryOne": "111", // must include this field and be a string
"manditoryTwo": "222", // must include this field and be a string
"optional": "33",
],
// manditory-param-three must exist and be a list of maps that have specific fields
'manditoryParamThree': [
"manditoryOne": [
"bbb": "sdfsfdsd" //validate string
]
]
]
A aa = new A( mapInvalid )
assert false == !!aa
assert true == !!aa.manditoryParamTwo
assert false == !!aa.manditoryParamThree