将 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
进行更多自定义,但可以完成。
我在 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
进行更多自定义,但可以完成。