将 XSD 导入 OpenAPI

Import XSD to OpenAPI

我在 XSD 文件中有一些模型定义,我需要从 OpenApi 定义中引用这些模型。由于文件太大,无法手动重塑,我需要将其放入构建系统中,以便如果 XSD 更改,我可以为 OpenApi 重新生成 models/schemas。

我尝试过并且几乎奏效的方法是使用 xsd2json and then converting it with the node module json-schema-to-openapi。但是 xsd2json 正在删除一些 complexElement 模型。例如 "$ref": "#/definitions/tns:ContentNode" 在一个模型内部用作子类型,但在模式中没有 ContentNode 的定义,当我查看 XSD 时,有一个 complexElement ContentNode.

的定义

我还没有尝试过但对我来说似乎有点过分的另一种方法是使用 xjb 从 XSD 生成 Java 模型,然后使用 JacksonSchema 生成 json 架构。

是否有任何已建立的库或方法,可以在 OpenApi 中使用 XSD?

您遇到的问题是您正在对 multi-step 转换应用推理工具。正如您所发现的,推理工具本质上很挑剔,并不是在所有情况下都有效。这有点像玩 Chinese whispers - 链条的每一步都可能有损,所以你从另一端得到的可能是乱码。

根据您建议的替代方法,我建议采用类似的解决方案:

OpenAPI 显然是一个 API 定义标准。您应该可以采用代码优先的方法,在代码中组合 API 操作并公开从 XJB 生成的类型。然后你可以使用 Apiee and its annotations to generate the OpenAPI definition. This assumes you are using JAX-RS 作为你的 API。

这仍然是一个 two-step 过程,但成功几率更高。这里的好处是您的第一步,将您的 XSD 类型推断为 java 类型,有望对定义您的 API 操作的代码产生很小的影响(如果有的话)。尽管仍然会有一个手动步骤(更新模型),OpenAPI 定义将在代码重建后自动更新。

我最终实现了第二种方法,使用 jaxb 将 XSD 模型转换为 java 模型,然后使用 Jackson 将模式写入文件。

Gradle:

plugins {
    id 'java'
    id 'application'
}

group 'foo'
version '1.0-SNAPSHOT'

sourceCompatibility = 1.8

repositories {
    mavenCentral()
}

dependencies {
    testCompile group: 'junit', name: 'junit', version: '4.12'
    compile group: 'com.fasterxml.jackson.module', name: 'jackson-module-jsonSchema', version: '2.9.8'
}

configurations {
    jaxb
}

dependencies {
    jaxb (
            'com.sun.xml.bind:jaxb-xjc:2.2.7',
            'com.sun.xml.bind:jaxb-impl:2.2.7'
    )
}

application {
    mainClassName = 'foo.bar.Main'
}

task runConverter(type: JavaExec, group: 'application') {
    classpath = sourceSets.main.runtimeClasspath

    main = 'foo.bar.Main'
}

task jaxb {
    System.setProperty('javax.xml.accessExternalSchema', 'all')
    def jaxbTargetDir = file("src/main/java")

    doLast {
        jaxbTargetDir.mkdirs()

        ant.taskdef(
                name: 'xjc',
                classname: 'com.sun.tools.xjc.XJCTask',
                classpath: configurations.jaxb.asPath
        )
        ant.jaxbTargetDir = jaxbTargetDir

        ant.xjc(
                destdir: '${jaxbTargetDir}',
                package: 'foo.bar.model',
                schema: 'src/main/resources/crs.xsd'
        )
    }
}

compileJava.dependsOn jaxb

使用主转换器 class,它的作用类似于:

package foo.bar;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.module.jsonSchema.JsonSchema;
import com.fasterxml.jackson.module.jsonSchema.JsonSchemaGenerator;
import foo.bar.model.Documents;

public class Main {

    public static void main(String[] args) {
        ObjectMapper mapper = new ObjectMapper();
        JsonSchemaGenerator schemaGen = new JsonSchemaGenerator(mapper);
        try {
            JsonSchema schema = schemaGen.generateSchema(Documents.class);
            System.out.print(mapper.writerWithDefaultPrettyPrinter().writeValueAsString(schema));
        } catch (JsonMappingException e) {
            e.printStackTrace();
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
    }

}

虽然它仍然不完美,...这将需要遍历所有模型 classes 并生成一个包含架构的文件。此外,它不使用引用,如果 class 有另一个 class 的成员,则模式将内联打印而不是引用。这需要使用 SchemaFactoryWrapper 进行更多自定义,但可以完成。