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

基于Java实现JSON Schema合并及引用重构方案咨询

Java实现相互引用的JSON Schema合并方案

需求说明

需要实现一个JSON Schema合并工具,基于Java开发,核心目标:

  • 从项目resources目录读取多个存在相互引用关系的JSON Schema文件
  • 将所有Schema合并为一个单一Schema文件
  • 把原Schema中的外部文件引用(如$ref: "./xxx.json")替换为合并后Schema内部definitions的引用路径(如$ref: "#/definitions/xxx")

输入示例文件

ClientInTestAlliance.json

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "title": "ClientInTestAlliance",
  "description": "测试联盟状态的表示。联盟允许玩家联合起来共同赢得测试,在测试UI中也称为联盟。",
  "type": "object",
  "properties": {
    "@c": {
      "type": "string",
      "const": "ultshared.UltInTestAlliance",
      "description": "描述JSON对象的类",
      "required": true,
      "javaName": "jsonTypeId"
    },
    "allianceID": {
      "type": "integer",
      "description": "测试联盟的ID",
      "required": true
    },
    "leaderID": {
      "type": "integer",
      "description": "测试联盟领导者的玩家ID",
      "required": true
    },
    "chatCode": {
      "type": "string",
      "description": "测试联盟的聊天代码,用于标识测试联盟的聊天室。",
      "required": true
    },
    "members":{
      "type": "object",
      "description": "测试联盟的成员,键为成员的玩家ID。",
      "additionalProperties": {
        "$ref": "./ClientInTestAllianceMember.json"
      },
      "required": true,
      "existingJavaType": "java.util.Map<Integer, ClientInTestAllianceMember>"
    },
    "logMessages":{
      "type": "array",
      "description": "测试联盟中重要事件的消息,例如领导者变更、成员离开等。最新的消息在列表末尾。",
      "items": {
        "$ref": "./ClientInTestAllianceLogMessage.json"
      }
    },
    "applicants":{
      "type": "array",
      "description": "测试联盟的申请者。",
      "items": {
        "$ref": "./ClientInTestAllianceApplicant.json"
      }
    },
    "invitations":{
      "type": "array",
      "description": "测试联盟的邀请。",
      "items": {
        "$ref": "./ClientInTestAllianceInvitation.json"
      }
    }
  },
  "additionalProperties": false
}

ClientInTestAllianceApplicant.json

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "title": "ClientInTestAllianceApplicant",
  "description": "测试联盟申请者的表示",
  "type": "object",
  "properties": {
    "@c": {
      "type": "string",
      "const": "ultshared.UltInTestAllianceApplicant",
      "description": "描述JSON对象的类",
      "required": true,
      "javaName": "jsonTypeId"
    },
    "playerID": {
      "type": "integer",
      "description": "申请者的玩家ID",
      "required": true
    },
    "timeStamp": {
      "type": "integer",
      "description": "申请提交的时间戳(自纪元以来的毫秒数)",
      "required": true
    }
  },
  "additionalProperties": false
}

ClientInTestAllianceInvitation.json

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "title": "ClientInTestAllianceInvitation",
  "description": "联盟邀请的表示",
  "type": "object",
  "properties": {
    "@c": {
      "type": "string",
      "const": "ultshared.FrontendInTestAllianceInvitation",
      "description": "描述JSON对象的类",
      "required": true,
      "javaName": "jsonTypeId"
    },
    "invitingPlayerID": {
      "type": "integer",
      "description": "发送邀请的玩家ID",
      "required": true
    },
    "invitedPlayerID": {
      "type": "integer",
      "description": "接收邀请的玩家ID",
      "required": true
    },
    "timeStamp": {
      "type": "integer",
      "description": "邀请发送的时间(自纪元以来的毫秒数)",
      "required": true
    }
  },
  "additionalProperties": false
}

ClientInTestAllianceLogMessage.json

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "title": "ClientInTestAllianceLogMessage",
  "description": "联盟操作日志消息的表示",
  "type": "object",
  "properties": {
    "@c": {
      "type": "string",
      "const": "ultshared.UltInTestAllianceLogMessage",
      "description": "描述JSON对象的类",
      "required": true,
      "javaName": "jsonTypeId"
    },
    "logDate": {
      "type": "integer",
      "description": "操作创建的服务器时间(自纪元以来的毫秒数)",
      "required": true
    },
    "playerID": {
      "type": "integer",
      "description": "执行操作的玩家ID",
      "required": true
    },
    "targetPlayerID": {
      "type": "integer",
      "description": "操作的目标玩家ID,如果玩家自行离开联盟则可能为0",
      "required": true
    },
    "inTestAllianceAction": {
      "type": "integer",
      "description": "操作类型,查看服务器类UltInTestAllianceAction了解可能的值",
      "required": true
    }
  },
  "additionalProperties": false
}

ClientInTestAllianceMember.json

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "title": "ClientInTestAllianceMember",
  "description": "联盟成员的表示",
  "type": "object",
  "properties": {
    "@c": {
      "type": "string",
      "const": "ultshared.UltInTestAllianceMember",
      "description": "描述JSON对象的类",
      "required": true,
      "javaName": "jsonTypeId"
    },
    "playerID": {
      "type": "integer",
      "description": "成员的玩家ID",
      "required": true
    },
    "joinDate": {
      "type": "integer",
      "description": "成员加入联盟的日期",
      "required": true
    }
  },
  "additionalProperties": false
}

期望输出示例

unified_client_json_schema.json

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "definitions": {
    "UltInGameAlliance": {
      "type": "object",
      "properties": {
        "@c": {
          "type": "string",
          "const": "ultshared.UltInGameAlliance",
          "description": "描述JSON对象的类",
          "required": true,
          "javaName": "jsonTypeId"
        },
        "allianceID": {
          "type": "integer",
          "description": "游戏内联盟的ID",
          "required": true
        },
        "leaderID": {
          "type": "integer",
          "description": "游戏内联盟领导者的玩家ID",
          "required": true
        },
        "chatCode": {
          "type": "string",
          "description": "游戏内联盟的聊天代码,用于标识游戏内联盟的聊天室。",
          "required": true
        },
        "members": {
          "type": "object",
          "description": "游戏内联盟的成员,键为成员的玩家ID。",
          "additionalProperties": {
            "$ref": "#/definitions/ClientInGameAllianceMember"
          },
          "required": true,
          "existingJavaType": "java.util.Map<Integer, ClientInGameAllianceMember>"
        },
        "logMessages": {
          "type": "array",
          "description": "游戏内联盟中重要事件的消息,例如领导者变更、成员离开等。最新的消息在列表末尾。",
          "items": {
            "$ref": "#/definitions/ClientInGameAllianceLogMessage"
          }
        },
        "applicants": {
          "type": "array",
          "description": "游戏内联盟的申请者。",
          "items": {
            "$ref": "#/definitions/ClientInGameAllianceApplicant"
          }
        },
        "invitations": {
          "type": "array",
          "description": "游戏内联盟的邀请。",
          "items": {
            "$ref": "#/definitions/ClientInGameAllianceInvitation"
          }
        }
      },
      "additionalProperties": false
    },
    "ClientInGameAllianceApplicant": {
      "type": "object",
      "properties": {
        "@c": {
          "type": "string",
          "const": "ultshared.UltInGameAllianceApplicant",
          "description": "描述JSON对象的类",
          "required": true,
          "javaName": "jsonTypeId"
        },
        "playerID": {
          "type": "integer",
          "description": "申请者的玩家ID",
          "required": true
        },
        "timeStamp": {
          "type": "integer",
          "description": "申请提交的时间戳(自纪元以来的毫秒数)",
          "required": true
        }
      },
      "additionalProperties": false
    },
    "ClientInGameAllianceInvitation": {
      "type": "object",
      "properties": {
        "@c": {
          "type": "string",
          "const": "ultshared.FrontendInGameAllianceInvitation",
          "description": "描述JSON对象的类",
          "required": true,
          "javaName": "jsonTypeId"
        },
        "invitingPlayerID": {
          "type": "integer",
          "description": "发送邀请的玩家ID",
          "required": true
        },
        "invitedPlayerID": {
          "type": "integer",
          "description": "接收邀请的玩家ID",
          "required": true
        },
        "timeStamp": {
          "type": "integer",
          "description": "邀请发送的时间(自纪元以来的毫秒数)",
          "required": true
        }
      },
      "additionalProperties": false
    },
    "ClientInGameAllianceLogMessage": {
      "type": "object",
      "properties": {
        "@c": {
          "type": "string",
          "const": "ultshared.UltInGameAllianceLogMessage",
          "description": "描述JSON对象的类",
          "required": true,
          "javaName": "jsonTypeId"
        },
        "logDate": {
          "type": "integer",
          "description": "操作创建的服务器时间(自纪元以来的毫秒数)",
          "required": true
        },
        "playerID": {
          "type": "integer",
          "description": "执行操作的玩家ID",
          "required": true
        },
        "targetPlayerID": {
          "type": "integer",
          "description": "操作的目标玩家ID,如果玩家自行离开联盟则可能为0",
          "required": true
        },
        "inGameAllianceAction": {
          "type": "integer",
          "description": "操作类型,查看服务器类UltInGameAllianceAction了解可能的值",
          "required": true
        }
      },
      "additionalProperties": false
    },
    "ClientInGameAllianceMember": {
      "type": "object",
      "properties": {
        "@c": {
          "type": "string",
          "const": "ultshared.UltInGameAllianceMember",
          "description": "描述JSON对象的类",
          "required": true,
          "javaName": "jsonTypeId"
        },
        "playerID": {
          "type": "integer",
          "description": "成员的玩家ID",
          "required": true
        },
        "joinDate": {
          "type": "integer",
          "description": "成员加入联盟的日期",
          "required": true
        }
      },
      "additionalProperties": false
    }
  }
}

解决方案实现

实现思路

  1. 遍历resources目录下所有JSON Schema文件,读取并缓存为JSON对象
  2. 为每个Schema生成definitions中的唯一键(优先使用@c字段的const值,次选title字段)
  3. 递归遍历Schema结构,将所有外部文件引用替换为内部定义的引用路径
  4. 将所有处理后的Schema统一放入合并后Schema的definitions节点,输出为单一文件

Java代码实现

依赖配置(Maven)

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.15.2</version>
</dependency>

核心代码

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;

public class JsonSchemaMerger {
    private static final ObjectMapper objectMapper = new ObjectMapper();
    private static final Map<String, String> fileNameToDefKey = new HashMap<>();
    private static final Map<String, JsonNode> schemaCache = new HashMap<>();

    public static void main(String[] args) throws IOException {
        // 读取resources目录下所有JSON Schema文件
        Path resourcesPath = Paths.get("src", "main", "resources");
        Files.walk(resourcesPath)
                .filter(Files::isRegularFile)
                .filter(path -> path.toString().endsWith(".json"))
                .forEach(path -> {
                    try {
                        loadSchema(path);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                });

        // 构建合并后的Schema
        ObjectNode mergedSchema = objectMapper.createObjectNode();
        mergedSchema.put("$schema", "https://json-schema.org/draft/2020-12/schema");
        ObjectNode definitions = objectMapper.createObjectNode();

        // 处理每个Schema的引用并添加到definitions
        for (Map.Entry<String, JsonNode> entry : schemaCache.entrySet()) {
            String defKey = fileNameToDefKey.get(entry.getKey());
            JsonNode processedSchema = resolveReferences(entry.getValue());
            definitions.set(defKey, processedSchema);
        }

        mergedSchema.set("definitions", definitions);

        // 输出到目标文件
        objectMapper.writerWithDefaultPrettyPrinter()
                .writeValue(Paths.get("unified_client_json_schema.json").toFile(), mergedSchema);
    }

    /**
     * 加载单个Schema文件并缓存,生成definitions键
     */
    private static void loadSchema(Path path) throws IOException {
        String fileName = path.getFileName().toString();
        JsonNode schema = objectMapper.readTree(Files.newInputStream(path));
        schemaCache.put(fileName, schema);

        // 生成definitions中的键:优先用@c的const值,否则用title
        String defKey;
        if (schema.has("properties") && schema.get("properties").has("@c") && schema.get("properties").get("@c").has("const")) {
            defKey = schema.get("properties").get("@c").get("const").asText().split("\\.")[1];
        } else {
            defKey = schema.get("title").asText();
        }
        fileNameToDefKey.put(fileName, defKey);
    }

    /**
     * 递归替换Schema中的外部引用为内部定义引用
     */
    private static JsonNode resolveReferences(JsonNode node) {
        if (node.isObject()) {
            ObjectNode objectNode = (ObjectNode) node.deepCopy();
            // 替换外部$ref引用
            if (objectNode.has("$ref")) {
                String refValue = objectNode.get("$ref").asText();
                String fileName = refValue.substring(refValue.lastIndexOf("/") + 1);
                String defKey = fileNameToDefKey.get(fileName);
                if (defKey != null) {
相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 13:07:25