Java中基于含复杂if/then/else的JSON Schema构建JSON对象
问题背景
需要在Java环境中基于带多层嵌套if/then/else结构的JSON Schema构建合规JSON对象,所有属性的取值已经提前存在可访问的Map中,可直接读取填充。
顶层properties下的固定属性处理逻辑简单,直接遍历属性名从Map取值填充即可,核心难点是多层嵌套条件分支的匹配处理,之前检索过常见的JSON Schema生成类库,没有找到能很好适配这类复杂嵌套条件的方案,需要可落地的实现思路或类库推荐。
涉及的JSON Schema示例如下:
{ "$schema": "http://example.org", "$id": "http://example.org", "title": "schema title", "description": "description", "properties": { "name": { "description": "description", "type": "string", "enum": [ "name1", "name2" ] }, "storage": { "description": "description", "type": "integer", "minimum": "200", "maximum": "500", "default": "200", }, "domain": { "description": "description", "type": "string" }, }, "if": { "properties": { "name": { "const": "name1" } } }, "then": { "if": { "properties": { "version": { "const": "version1" } } }, "then": { "properties": { "cpus": { "description": "description", "type": "integer", "minimum": 1, "maximum": 8 }, "memory": { "description": "description", "type": "integer", "minimum": 1, "maximum": 32 }, }, "required": [ "cpus", "memory" ] }, "else": { "if": { "properties": { "version": { "const": "version2" } } }, "then": { "properties": { "cpus": { "description": "description", "type": "integer", "minimum": 1, "maximum": 8 }, "diskSize": { "description": "description", "type": "integer", "minimum": 250, "maximum": 1000 }, }, "required": [ "cpus", "diskSize" ] } } }, "else": { "if": { "properties": { "name": { "const": "name2" } } }, "then": { "if": { "properties": { "version": { "const": "version3" } } }, "then": { "properties": { "diskSize": { "description": "description", "type": "integer", "minimum": 100, "maximum": 500 } "memory": { "description": "description", "type": "integer", "minimum": 1, "maximum": 28 } }, "required": [ "diskSize", "memory" ] }, "else": { "if": { "properties": { "version": { "const": "version4" } } }, "then": { "properties": { "cpus": { "description": "description", "type": "integer", "minimum": 1, "maximum": 28 }, "memory": { "description": "description", "type": "integer", "minimum": 1, "maximum": 64 } }, "required": [ "cpus", "memory" ] } } } } }
落地方案
不用自己写高复杂度的全分支遍历逻辑,两类方案都可以快速实现:
- 复用成熟JSON Schema校验库的条件求值能力
不需要专门找JSON生成类库,主流的JSON Schema校验组件(比如Jackson生态的json-schema-validator、Everit JSON Schema)已经完整实现了JSON Schema标准里的if/then/else嵌套条件求值逻辑,不需要自己维护分支判断规则。
实现步骤非常清晰:- 先遍历Schema顶层properties的字段列表,从Map中读取对应值,构建初始的ObjectNode对象
- 给Schema校验器注册自定义的节点收集监听器,将初始构建的ObjectNode传入校验上下文,触发校验流程,校验器会自动走完所有条件分支匹配,你可以通过监听器拿到所有匹配成功分支下的properties定义、required字段列表
- 遍历收集到的分支字段,从Map中读取对应值填充到初始ObjectNode即可
这种方案兼容性最好,后续哪怕Schema新增更多层嵌套条件、增加其他条件关键字(比如allOf、anyOf),也不需要修改核心逻辑。
- 轻量递归实现方案
如果不想引入额外的校验依赖,递归逻辑的复杂度远低于你的预期,不需要遍历所有分支:- 封装一个通用的条件匹配方法:入参为当前层级的if节点、存储属性值的Map,逐一比对if节点中所有const约束的字段值和Map中存储的实际值是否完全一致
- 匹配成功则处理当前then节点:先收集then节点下的properties、required字段,从Map取值填充到结果对象,再判断then节点内部是否存在嵌套的if/then/else结构,存在则递归调用本方法处理
- 匹配失败则处理当前else节点:同样先收集else节点下的字段完成填充,再判断else节点内部是否有嵌套条件结构,递归处理即可
整个流程是单路径向下匹配,时间复杂度和条件嵌套深度正相关,不会出现性能问题,代码量也很小。
注意你提供的示例Schema存在两处语法错误:一是storage字段default值末尾多了冗余逗号,二是name=name2、version=version3分支下diskSize属性定义末尾缺失逗号,实际使用前先修正语法问题,避免Schema解析失败。
内容的提问来源于stack exchange,提问作者JackFF
相关产品推荐
相关产品推荐

