Java中如何利用JSON Schema移除JSON的可选元素
问题
我们需要通过队列传递JSON字符串,但队列存在大小限制。能否借助JSON Schema移除JSON字符串/对象中的可选元素,让它适配队列大小?
示例JSON Schema
{"components": {"schemas": {"Data": {"properties": {"admittedOn": {"example": "2023-02-20","title": "The admittedOn Schema","type": "string"},"claimAmount": {"example": 500,"title": "The claimAmount Schema","type": "integer"},"clinicName": {"enum": ["Mayo Clinic","Appollo","Care","Govt"],"example": "Mayo Clinic","title": "The clinicName Schema","type": "string"},"dischargedOn": {"example": "2023-02-25","title": "The dischargedOn Schema","type": "string"},"firstName": {"example": "Jon","title": "The firstName Schema","type": "string"},"lastName": {"example": "Doe","title": "The lastName Schema","type": "string"},"stateCode": {"example": "MN","title": "The state code","type": "string"}},"required": ["firstName","lastName","admittedOn","clinicName"],"type": "object"},"Event": {"additionalProperties": false,"properties": {"data": {"$ref": "#/components/schemas/Data"},"datacontenttype": {"type": "string"},"dataref": {"type": "string"},"dataschema": {"type": "string"},"environment": {"pattern": "^[^pP]|^.[^rR]|^..[^oO]|^...[^dD]$","type": "string"},"id": {"type": "string"},"partitionkey": {"type": "string"},"sampledrate": {"type": "integer"},"sequence": {"type": "string"},"severitynumber": {"type": "integer"},"severitytext": {"type": "string"},"source": {"pattern": "^[a-zA-Z0-9\\.\\_\\-\\:\\@\\/]*$","type": "string"},"specversion": {"enum": ["1.0"],"type": "string"},"subject": {"type": "string"},"time": {"pattern": "^((?:(\\d{4}-\\d{2}-\\d{2})T(\\d{2}:\\d{2}:\\d{2}(?:\\.\\d+)?))(Z|[\\+-]\\d{2}:\\d{2})?)$","type": "string"},"traceparent": {"pattern": "^[\\da-f]{2}-[\\da-f]{32}-[\\da-f]{16}-[\\da-f]{2}$","type": "string"},"tracestate": {"pattern": "^([^,]+=[^,]+)(,([^,]+=[^,]+))*?$","type": "string"},"type": {"default": "patient.covid.claims.v3.0.0","enum": ["patient.covid.claims.v3.0.0"],"pattern": "^[a-zA-Z0-9\\.\\_\\-]*$","type": "string"}},"required": ["data","environment","id","source","specversion","type"],"type": "object"}}}}
示例原JSON字符串
{"id": "5a54e6ae-b92e-4393-a360-e28376fa7af5","type": "patient.covid.claims.v1.0.0","source": "myapp","specversion": "1.0","subject": "Claim request","time": "2023-11-06T17:40:18.003Z","datacontenttype": "application/json","environment": "dev","data": {"firstName": "Myrtie Bowman","lastName": "Ethel Harper","admittedOn": "2023-02-20","dischargedOn": "2023-02-25","clinicName": "Mayo Clinic","claimAmount": 500,"stateCode": "MN"}}
移除可选元素后的期望JSON
{"id": "5a54e6ae-b92e-4393-a360-e28376fa7af5","type": "patient.covid.claims.v1.0.0","source": "myapp","specversion": "1.0","environment": "dev","data": {"firstName": "Myrtie Bowman","lastName": "Ethel Harper","admittedOn": "2023-02-20","clinicName": "Mayo Clinic"}}
请问如何在Java中利用JSON Schema移除JSON中的可选元素?
解决方案
可以通过解析JSON Schema提取必填字段,再递归遍历JSON对象只保留这些字段来实现。以下是结合org.everit.json.schema和Jackson库的具体实现:
1. 引入依赖
在Maven的pom.xml中添加以下依赖:
<dependency> <groupId>org.everit.json</groupId> <artifactId>org.everit.json.schema</artifactId> <version>1.14.0</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.15.2</version> </dependency> <dependency> <groupId>org.json</groupId> <artifactId>json</artifactId> <version>20230227</version> </dependency>
2. 核心过滤代码
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import org.everit.json.schema.ObjectSchema; import org.everit.json.schema.ReferenceSchema; import org.everit.json.schema.Schema; import org.everit.json.schema.SchemaLoader; import org.json.JSONObject; import org.json.JSONTokener; import java.io.StringReader; import java.util.Set; public class JsonSchemaFilter { private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); public static JsonNode filterBySchema(String rawJson, String schemaStr) throws Exception { // 解析完整Schema,定位到根对象Event的Schema JSONObject fullSchemaJson = new JSONObject(new JSONTokener(new StringReader(schemaStr))); JSONObject rootSchemaJson = fullSchemaJson.getJSONObject("components") .getJSONObject("schemas") .getJSONObject("Event"); Schema rootSchema = SchemaLoader.load(rootSchemaJson); // 解析原始JSON JsonNode originalNode = OBJECT_MAPPER.readTree(rawJson); // 递归过滤只保留必填字段 return filterNode(originalNode, (ObjectSchema) rootSchema, fullSchemaJson); } private static JsonNode filterNode(JsonNode node, ObjectSchema schema, JSONObject fullSchema) { if (!node.isObject()) { return node; // 非对象类型直接返回 } Set<String> requiredFields = schema.getRequiredProperties(); JSONObject filtered = new JSONObject(); for (String field : requiredFields) { if (!node.has(field)) continue; JsonNode fieldNode = node.get(field); Schema fieldSchema = schema.getPropertySchemas().get(field); // 处理嵌套对象 if (fieldSchema instanceof ObjectSchema) { filtered.put(field, OBJECT_MAPPER.convertValue( filterNode(fieldNode, (ObjectSchema) fieldSchema, fullSchema), JSONObject.class)); } // 处理$ref引用的子Schema else if (fieldSchema instanceof ReferenceSchema) { ReferenceSchema refSchema = (ReferenceSchema) fieldSchema; JSONObject refSchemaJson = resolveRefSchema(fullSchema, refSchema.getRef()); Schema resolvedSchema = SchemaLoader.load(refSchemaJson); filtered.put(field, OBJECT_MAPPER.convertValue( filterNode(fieldNode, (ObjectSchema) resolvedSchema, fullSchema), JSONObject.class)); } // 普通字段直接保留 else { filtered.put(field, OBJECT_MAPPER.convertValue(fieldNode, Object.class)); } } return OBJECT_MAPPER.readTree(filtered.toString()); } // 解析$ref路径对应的Schema private static JSONObject resolveRefSchema(JSONObject fullSchema, String refPath) { String[] pathParts = refPath.replaceFirst("^#/", "").split("/"); JSONObject current = fullSchema; for (String part : pathParts) { current = current.getJSONObject(part); } return current; } // 测试用例 public static void main(String[] args) throws Exception { // 替换为你的Schema和JSON字符串 String schema = "你的Schema字符串"; String rawJson = "你的原始JSON字符串"; JsonNode result = filterBySchema(rawJson, schema); System.out.println(result.toPrettyString()); } }
3. 代码说明
- 首先解析JSON Schema,针对示例结构定位到
Event根对象的Schema定义 - 递归遍历JSON对象:只保留Schema中标记为
required的字段,遇到嵌套对象或$ref引用的子Schema时,继续递归过滤 - 专门处理
$ref引用:解析引用路径并加载对应的子Schema,确保嵌套对象也能正确过滤
该实现会严格按照Schema的必填字段规则裁剪JSON,有效缩小体积以适配队列大小限制。
内容的提问来源于stack exchange,提问作者Paramesh Korrakuti
相关产品推荐
相关产品推荐

