Java 使用注释的多模式生成器
Java multi-schema generator using annotations
我有一系列相互关联的 Java classes,它们构成了可能模式的超集。我正在寻找一些方法来 annotate/tag 各个字段,以便我可以为每个 'namespace'.
创建单独的 JSON 模式
一个简单的例子:
class SupersetClass {
@BelongsToSchema(schema={"alice"}, description="foo")
Integer a;
@BelongsToSchema(schema={"alice", "bob"}, description="bar")
String b;
@BelongsToSchema(schema={"bob"}, description="")
Long c;
}
输出会有单独的 Alice 和 Bob 模式,其中 Alice 有 a 和 b,Bob 有 b 和 c。
我目前的想法是遍历我想要生成的模式,然后使用反射创建一个自定义派生 class 并将其传递给 jackson-mapper,但是如果已经有一个这样做的好方法。
Disclaimer: I'm the maintainer of the victools/jsonschema-generator
library mentioned below.
如果您不打算使用(稍微过时的)FasterXML/jackson-module-jsonSchema, you could use the victools/jsonschema-generator 库。后者支持更新的 JSON Schema Draft 版本,并在最终生成的模式中为您提供了很大的灵活性。但是,它(至少到今天为止)不支持开箱即用的相同范围的杰克逊特定注释。
也就是说,有多种方法可以解决您的问题。
1。简单地忽略属于不同上下文的属性
SchemaGeneratorConfigBuilder configBuilder = new SchemaGeneratorConfigBuilder(
SchemaVersion.DRAFT_2019_09, OptionPreset.PLAIN_JSON);
configBuilder.forFields()
.withIgnoreCheck(field -> {
BelongsToSchema annotation = field.getAnnotation(BelongsToSchema.class);
return annotation != null
&& !Arrays.asList(annotation.schema()).contains("alice");
});
2。在提及它们时排除来自不同上下文的属性模式
configBuilder.forFields()
.withTargetTypeOverridesResolver(field -> {
BelongsToSchema annotation = field.getAnnotation(BelongsToSchema.class);
if (annotation == null || Arrays.asList(annotation.value()).contains("alice")) {
return null;
}
return Collections.singletonList(field.getContext().resolve(Object.class));
});
3。包括外部 $ref
而不是实际的子模式
configBuilder.forFields()
.withCustomDefinitionProvider((field, context) -> {
BelongsToSchema annotation = field.getAnnotation(BelongsToSchema.class);
if (annotation == null || Arrays.asList(annotation.value()).contains("alice")) {
return null;
}
ObjectNode customSubschema = context.getGeneratorConfig().createObjectNode()
.put(SchemaKeyword.TAG_REF.forVersion(SchemaVersion.DRAFT_2019_09),
"https://your-external.ref/" + field.getSimpleTypeDescription());
return new CustomPropertyDefinition(customSubschema);
});
根据您的具体需求,可能还有更多可能性。
我鼓励您尝试一下,看看 documentation. If you have project-specific questions, feel free to raise those as Issues on GitHub。
我有一系列相互关联的 Java classes,它们构成了可能模式的超集。我正在寻找一些方法来 annotate/tag 各个字段,以便我可以为每个 'namespace'.
创建单独的 JSON 模式一个简单的例子:
class SupersetClass {
@BelongsToSchema(schema={"alice"}, description="foo")
Integer a;
@BelongsToSchema(schema={"alice", "bob"}, description="bar")
String b;
@BelongsToSchema(schema={"bob"}, description="")
Long c;
}
输出会有单独的 Alice 和 Bob 模式,其中 Alice 有 a 和 b,Bob 有 b 和 c。
我目前的想法是遍历我想要生成的模式,然后使用反射创建一个自定义派生 class 并将其传递给 jackson-mapper,但是如果已经有一个这样做的好方法。
Disclaimer: I'm the maintainer of the
victools/jsonschema-generator
library mentioned below.
如果您不打算使用(稍微过时的)FasterXML/jackson-module-jsonSchema, you could use the victools/jsonschema-generator 库。后者支持更新的 JSON Schema Draft 版本,并在最终生成的模式中为您提供了很大的灵活性。但是,它(至少到今天为止)不支持开箱即用的相同范围的杰克逊特定注释。
也就是说,有多种方法可以解决您的问题。
1。简单地忽略属于不同上下文的属性
SchemaGeneratorConfigBuilder configBuilder = new SchemaGeneratorConfigBuilder(
SchemaVersion.DRAFT_2019_09, OptionPreset.PLAIN_JSON);
configBuilder.forFields()
.withIgnoreCheck(field -> {
BelongsToSchema annotation = field.getAnnotation(BelongsToSchema.class);
return annotation != null
&& !Arrays.asList(annotation.schema()).contains("alice");
});
2。在提及它们时排除来自不同上下文的属性模式
configBuilder.forFields()
.withTargetTypeOverridesResolver(field -> {
BelongsToSchema annotation = field.getAnnotation(BelongsToSchema.class);
if (annotation == null || Arrays.asList(annotation.value()).contains("alice")) {
return null;
}
return Collections.singletonList(field.getContext().resolve(Object.class));
});
3。包括外部 $ref
而不是实际的子模式
configBuilder.forFields()
.withCustomDefinitionProvider((field, context) -> {
BelongsToSchema annotation = field.getAnnotation(BelongsToSchema.class);
if (annotation == null || Arrays.asList(annotation.value()).contains("alice")) {
return null;
}
ObjectNode customSubschema = context.getGeneratorConfig().createObjectNode()
.put(SchemaKeyword.TAG_REF.forVersion(SchemaVersion.DRAFT_2019_09),
"https://your-external.ref/" + field.getSimpleTypeDescription());
return new CustomPropertyDefinition(customSubschema);
});
根据您的具体需求,可能还有更多可能性。
我鼓励您尝试一下,看看 documentation. If you have project-specific questions, feel free to raise those as Issues on GitHub。