You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 13:54:55