Путь JSON: как преобразовать ссылки URN в локальные ссылки

При преобразовании файла схемы JSON в классы Java с использованием Maven org.jsonschema2pojo:jsonschema2pojo-maven-plugin:1.0.0-alpha2 я получаю ошибки, связанные со ссылками на urn, которые не могут быть разрешены.

Вот пример сообщения об ошибке:

[ERROR] Failed to execute goal org.jsonschema2pojo:jsonschema2pojo-maven-plugin:1.0.0-alpha2:generate (default) on project model-reservation: Execution default of goal org.jsonschema2pojo:jsonschema
2pojo-maven-plugin:1.0.0-alpha2:generate failed: Unrecognised URI, can't resolve this: urn:jsonschema:com:lumina:pnr:model:Reference: unknown protocol: urn -> [Help 1]

Вот JSON, на который он ссылается с элементом $ref, вызывающим исключение:

    "remarkFields": {
      "type": "object",
      "additionalProperties": {
        "type": "array",
        "items": {
          "type": "object",
          "id": "urn:jsonschema:com:lumina:pnr:model:FileFinishingField",
          "properties": {
            "lineNumber": {
              "type": "integer"
            },
            "name": {
              "type": "string"
            },
            "value": {
              "type": "string"
            },
            "references": {
              "type": "array",
              "items": {
                "type": "object",
                "$ref": "urn:jsonschema:com:lumina:pnr:model:Reference"
              }
            }
          }
        }
      }
    }

Как я могу преобразовать их в локальные ссылки в Java и использовать результат преобразования для успешного преобразования моего кода в классы Java с помощью подключаемого модуля org.jsonschema2pojo:jsonschema2pojo-maven-plugin:1.0.0-alpha2 Maven?

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
0
1 081
1

Ответы 1

Возможно, существуют более эффективные способы решения этой проблемы, но одно из возможных решений таково:

Используйте рекурсивный метод для преобразования ссылок стиля urn в локальные ссылки:

Вот рекурсивный метод с использованием библиотеки Джексона:

private static final String ITEMS = "items";
private static final String ID = "id";
private static final String PROPERTIES = "properties";
private static final String ADDITIONAL_PROPERTIES = "additionalProperties";
private static final String REF = "$ref";

private static void parseReferences(JsonNode jsonNode, String path) {
    if (jsonNode.has(ID)) {
        typeMap.put(jsonNode.get(ID).asText(), path);
        final JsonNode properties = jsonNode.get(PROPERTIES);
        final Iterator<Map.Entry<String, JsonNode>> fields = properties.fields();
        path += "/" + PROPERTIES;

        while (fields.hasNext()) {
            Map.Entry<String, JsonNode> entry = fields.next();
            parseReferences(entry.getValue(), path + "/" + entry.getKey());
        }
    } else if (jsonNode.has(ITEMS)) {
        final JsonNode item = jsonNode.get(ITEMS);
        parseReferences(item, path + "/" + ITEMS);
    } else if (jsonNode.has(REF)) {
        ObjectNode objectNode = (ObjectNode) jsonNode;
        objectNode.set(REF, new TextNode(typeMap.get(jsonNode.get(REF).asText())));
    } else if (jsonNode.has(ADDITIONAL_PROPERTIES)) {
        JsonNode additionalProperties = jsonNode.get(ADDITIONAL_PROPERTIES);
        parseReferences(additionalProperties, path + "/" + ADDITIONAL_PROPERTIES);
    }
}

Вот как я вызываю этот метод после создания экземпляра парсера JAXB:

private static void writeSchemaToFile(ObjectMapper jaxbObjectMapper, String origPath, String path) throws Exception {
    InputStream resourceAsStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(origPath);
    try (Reader r = new InputStreamReader(resourceAsStream, "UTF-8")) {
        JsonNode root = jaxbObjectMapper.readTree(r);
        parseReferences(root, "#");
        String changedJson = jaxbObjectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(root);
        final Path targetPath = Paths.get(path);
        if (!Files.exists(targetPath)) {
            Path parent = targetPath.getParent();
            if (parent != null) {
                Files.createDirectories(parent);
            }
        }
        try (Writer writer = Files.newBufferedWriter(targetPath, Charset.forName("UTF-8"), StandardOpenOption.CREATE)) {
            writer.write(changedJson);
        }
    }
}

Если вы вызовете этот метод, он преобразует JSON, указанный в вопросе, в:

"remarkFields" : {
  "type" : "object",
  "additionalProperties" : {
    "type" : "array",
    "items" : {
      "type" : "object",
      "id" : "urn:jsonschema:com:lumina:pnr:model:FileFinishingField",
      "properties" : {
        "lineNumber" : {
          "type" : "integer"
        },
        "name" : {
          "type" : "string"
        },
        "value" : {
          "type" : "string"
        },
        "references" : {
          "type" : "array",
          "items" : {
            "type" : "object",
            "$ref" : "#/properties/passengers/items/properties/reference"
          }
        }
      }
    }
  }
}

В вашем примере кода отсутствует переменная typeMap, но в остальном она работает нормально. Добавить верхний уровень: static HashMap<String, String> typeMap = new HashMap<>();

Michael Johansen 09.09.2021 07:30

Другие вопросы по теме