能否通过编程方式展开JSON Schema中的引用以实现载荷校验与字段过滤?
方案1:基于现有json-schema-validator库实现Schema引用展开
你当前使用的json-schema-validator库本身已经完成了所有$ref的解析逻辑,只需要自己补一层递归展开的代码即可:
- 首先通过
SchemaLoader加载原始Schema得到JsonSchema实例,它内部已经通过RefResolver完成了所有引用的寻址,不需要自己处理引用路径解析 - 递归遍历Schema节点,遇到
$ref字段时直接调用getRefSchema()方法获取引用对应的实际Schema节点,替换当前的$ref节点即可 - 新增已处理引用路径的Set做校验,避免循环引用导致的死循环问题
参考代码示例:
// 加载原始Schema JsonNode rawSchema = objectMapper.readTree(originSchemaStr); SchemaLoader loader = SchemaLoader.builder().schemaJson(rawSchema).build(); JsonSchema jsonSchema = loader.load().build(); // 递归展开引用的方法 private JsonNode resolveSchemaRefs(JsonNode node, JsonSchema schema, Set<String> processedRefs) throws URISyntaxException { if (node.isObject()) { ObjectNode objNode = (ObjectNode) node; // 遇到$ref则替换为实际Schema节点 if (objNode.has("$ref")) { String refVal = objNode.get("$ref").asText(); if (processedRefs.contains(refVal)) { return objNode; // 循环引用直接返回,避免死循环 } processedRefs.add(refVal); JsonNode refSchemaNode = schema.getRefSchema(new JsonRef(new URI(refVal))).getSchemaNode(); return resolveSchemaRefs(refSchemaNode, schema, processedRefs); } // 遍历所有子字段递归处理 Iterator<Map.Entry<String, JsonNode>> fieldIter = objNode.fields(); while (fieldIter.hasNext()) { Map.Entry<String, JsonNode> entry = fieldIter.next(); objNode.set(entry.getKey(), resolveSchemaRefs(entry.getValue(), schema, processedRefs)); } } else if (node.isArray()) { ArrayNode arrayNode = (ArrayNode) node; for (int i = 0; i < arrayNode.size(); i++) { arrayNode.set(i, resolveSchemaRefs(arrayNode.get(i), schema, processedRefs)); } } return node; }
处理后得到的无引用Schema就可以直接传给你当前使用的过滤库。
方案2:换用一站式校验+过滤库
如果不想自己维护引用展开逻辑,可以直接换用同时支持校验、引用解析、自动过滤未定义字段的库,比两个库拼接的方案更稳定:
可以使用networknt的json-schema-validator库,它内置了完整的$ref解析能力,只需要开启removeAdditionalProperties配置,校验的同时会自动删除所有Schema未定义的字段,完全满足你的业务需求。
参考代码示例:
SchemaValidatorsConfig config = new SchemaValidatorsConfig(); config.setRemoveAdditionalProperties(true); // 开启自动过滤未定义字段 // 指定Schema版本,按你的实际使用场景选择 JsonSchemaFactory factory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V7); JsonSchema schema = factory.getSchema(originSchemaStr, config); // 校验的同时完成字段过滤 Set<ValidationMessage> validateErrors = schema.validate(payloadNode); // 校验完成后payloadNode已经移除了所有Schema未定义的字段
额外建议
如果是PII字段过滤场景,建议额外维护一份敏感字段黑名单做二次校验,避免Schema编写遗漏导致敏感数据落库。
内容的提问来源于stack exchange,提问作者DanHam
相关产品推荐
相关产品推荐

