Java Jackson:如何生成拒绝所有附加内容的json模式
我想生成JSON模式,其中Java Jackson:如何生成拒绝所有附加内容的json模式,java,json,jackson,jsonschema,json-schema-validator,Java,Json,Jackson,Jsonschema,Json Schema Validator,我想生成JSON模式,其中“additionalProperties”:false将应用于我拥有的所有类 假设我有以下课程: class A{ private String s; private B b; public String getS() { return s; } public B getB() { return b; } } class B{ private BigDecimal bd;
“additionalProperties”:false将应用于我拥有的所有类
假设我有以下课程:
class A{
private String s;
private B b;
public String getS() {
return s;
}
public B getB() {
return b;
}
}
class B{
private BigDecimal bd;
public BigDecimal getBd() {
return bd;
}
}
当我按照下面的代码生成模式时,模式属性“additionalProperties”:false
仅适用于类A
ObjectMapper mapper = new ObjectMapper();
JsonSchemaGenerator schemaGen = new JsonSchemaGenerator(mapper);
ObjectSchema schema = schemaGen.generateSchema(A.class).asObjectSchema();
schema.rejectAdditionalProperties();
mapper.writerWithDefaultPrettyPrinter().writeValueAsString(schema);
如何生成将在所有类上应用“additionalProperties”:false
的模式
模式的示例
{
“类型”:“对象”,
“id”:“urn:jsonschema:com.xxx.xxx:A”,
“附加属性”:false,
“财产”:{
“s”:{
“类型”:“字符串”
},
“b”:{
“类型”:“对象”,
“id”:“urn:jsonschema:com.xxx.xxx:B”,
“财产”:{
“bd”:{
“类型”:“编号”
}
}
}
}
}
注意:我不想一部分一部分地生成方案
有关信息:
我已经为这个场景打开了一个问题,如果您感兴趣的人可以支持这个问题的修复 您需要为每个属性指定模式,如:
ObjectMapper mapper = new ObjectMapper();
JsonSchemaGenerator schemaGen = new JsonSchemaGenerator(mapper);
ObjectSchema schemaB = schemaGen.generateSchema(B.class).asObjectSchema();
schemaB.rejectAdditionalProperties();
ObjectSchema schema = schemaGen.generateSchema(A.class).asObjectSchema();
schema.rejectAdditionalProperties();
schema.putProperty("b", schemaB);
您可以利用反射api为您自动完成这项工作。下面是一个简单的例子:
public static void main(String[] args) throws JsonProcessingException {
final ObjectMapper mapper = new ObjectMapper();
final JsonSchemaGenerator schemaGen = new JsonSchemaGenerator(mapper);
ObjectSchema schema = generateSchema(schemaGen, A.class);
schema.rejectAdditionalProperties();
System.out.print(mapper.writerWithDefaultPrettyPrinter().writeValueAsString(schema));
}
public static <T> ObjectSchema generateSchema(JsonSchemaGenerator generator, Class<T> type) throws JsonMappingException {
ObjectSchema schema = generator.generateSchema(type).asObjectSchema();
for (final Field field : type.getDeclaredFields()) {
if (!field.getType().getName().startsWith("java") && !field.getType().isPrimitive()) {
final ObjectSchema fieldSchema = generateSchema(generator, field.getType());
fieldSchema.rejectAdditionalProperties();
schema.putProperty(field.getName(), fieldSchema);
}
}
return schema;
}
publicstaticvoidmain(字符串[]args)抛出JsonProcessingException{
最终ObjectMapper映射器=新ObjectMapper();
最终JsonSchemaGenerator schemaGen=新JsonSchemaGenerator(映射器);
ObjectSchema=generateSchema(schemaGen,A.class);
schema.rejectAdditionalProperties();
System.out.print(mapper.writerWithDefaultPrettyPrinter().writeValueAsString(schema));
}
公共静态ObjectSchema generateSchema(JsonSchemaGenerator生成器,类类型)引发JsonMappingException{
ObjectSchema=generator.generateSchema(类型).asObjectSchema();
for(最后一个字段:type.getDeclaredFields()){
如果(!field.getType().getName().startsWith(“java”)和&!field.getType().isPrimitive()){
final ObjectSchema fieldSchema=generateSchema(生成器,field.getType());
fieldSchema.rejectAdditionalProperties();
schema.putProperty(field.getName(),fieldSchema);
}
}
返回模式;
}
如果您不想使用反射,我会选择更简单的路线。我会使用JSONPath。因此,您需要将以下内容添加到pom.xml
<dependency>
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path</artifactId>
<version>2.3.0</version>
</dependency>
运行的输出为(手动格式化)
以下几点对我很有用:
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.kjetland.jackson.jsonSchema.JsonSchemaConfig;
import com.kjetland.jackson.jsonSchema.JsonSchemaGenerator;
...
ObjectMapper objectMapper = new ObjectMapper();
JsonSchemaConfig config = JsonSchemaConfig.nullableJsonSchemaDraft4();
JsonSchemaGenerator schemaGenerator = new JsonSchemaGenerator(objectMapper, config);
JsonNode jsonNode = schemaGenerator.generateJsonSchema(Test.class);
String jsonSchemaText = jsonNode.toString();
使用maven依赖项:
<dependency>
<groupId>com.kjetland</groupId>
<artifactId>mbknor-jackson-jsonschema_2.12</artifactId>
<version>1.0.28</version>
</dependency>
…和TestChild.java:
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
public class TestChild {
@JsonProperty(required = true)
private final String childName;
@JsonCreator
public TestChild (@JsonProperty("childName") String childName) {
this.childName = childName;
}
public String getChildName () {
return childName;
}
}
结果(通过jq-C.
管道传输的jsonSchemaText
的输出,用于精确格式化):
这会导致Test和TestChild上出现“additionalProperties”:false
注意:您可以在模式生成代码中将JsonSchemaConfig.nullableJsonSchemaDraft4()
替换为JsonSchemaConfig.vanillaJsonSchemaDraft4()
,以摆脱带有“type:null”或“type:ActualType”的“其中一个”引用,而只使用“type:ActualType”(注意,这仍然不会将它们添加到“required”中)数组,除非您使用@JsonProperty(required=true)
)注释属性。这是我的解决方案,没有任何反射和破解方式,对我来说效果非常好
public static void rejectAdditionalProperties(JsonSchema jsonSchema) {
if (jsonSchema.isObjectSchema()) {
ObjectSchema objectSchema = jsonSchema.asObjectSchema();
ObjectSchema.AdditionalProperties additionalProperties = objectSchema.getAdditionalProperties();
if (additionalProperties instanceof ObjectSchema.SchemaAdditionalProperties) {
rejectAdditionalProperties(((ObjectSchema.SchemaAdditionalProperties) additionalProperties).getJsonSchema());
} else {
for (JsonSchema property : objectSchema.getProperties().values()) {
rejectAdditionalProperties(property);
}
objectSchema.rejectAdditionalProperties();
}
} else if (jsonSchema.isArraySchema()) {
ArraySchema.Items items = jsonSchema.asArraySchema().getItems();
if (items.isSingleItems()) {
rejectAdditionalProperties(items.asSingleItems().getSchema());
} else if (items.isArrayItems()) {
for (JsonSchema schema : items.asArrayItems().getJsonSchemas()) {
rejectAdditionalProperties(schema);
}
}
}
}
谢谢你的回答,但我不想手动放置属性。Jackson有任何api来提供吗?在我的回答中,我建议使用java反射api来自动完成。我不知道还有什么其他方法可以做到这一点。请注意,这也会导致基于“引用”的模式,而不是问题中提供的示例中所示的扁平模式(不允许自引用结构,例如分支可能包含分支和/或叶子的树)。谢谢。我将尝试您的解决方案并让您知道。它是scala库。有提供相同功能的java
库吗?我使用的是这个,而不是scala。我使用的是纯java。这个库可能是用scala编写的,但它肯定是用java编写的。就我个人而言,我不认为这是在某个地方的服务中使用的东西。我认为这是在maven插件中运行的东西。在我的工作中,我们编写了这样一个插件,作为maven构建过程的一部分,从我们的模型类生成模式,并将其上传到S3存储桶,因此我们甚至不将这些LIB拉入生成的JAR。
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
public class Test {
@JsonProperty(required = true)
private final String name;
private final TestChild child;
@JsonCreator
public Test (
@JsonProperty("name") String name,
@JsonProperty("child") TestChild child) {
this.name = name;
this.child = child;
}
public String getName () {
return name;
}
public TestChild getChild () {
return child;
}
}
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
public class TestChild {
@JsonProperty(required = true)
private final String childName;
@JsonCreator
public TestChild (@JsonProperty("childName") String childName) {
this.childName = childName;
}
public String getChildName () {
return childName;
}
}
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "Test",
"type": "object",
"additionalProperties": false,
"properties": {
"name": {
"type": "string"
},
"child": {
"oneOf": [
{
"type": "null",
"title": "Not included"
},
{
"$ref": "#/definitions/TestChild"
}
]
}
},
"required": [
"name"
],
"definitions": {
"TestChild": {
"type": "object",
"additionalProperties": false,
"properties": {
"childName": {
"type": "string"
}
},
"required": [
"childName"
]
}
}
}
public static void rejectAdditionalProperties(JsonSchema jsonSchema) {
if (jsonSchema.isObjectSchema()) {
ObjectSchema objectSchema = jsonSchema.asObjectSchema();
ObjectSchema.AdditionalProperties additionalProperties = objectSchema.getAdditionalProperties();
if (additionalProperties instanceof ObjectSchema.SchemaAdditionalProperties) {
rejectAdditionalProperties(((ObjectSchema.SchemaAdditionalProperties) additionalProperties).getJsonSchema());
} else {
for (JsonSchema property : objectSchema.getProperties().values()) {
rejectAdditionalProperties(property);
}
objectSchema.rejectAdditionalProperties();
}
} else if (jsonSchema.isArraySchema()) {
ArraySchema.Items items = jsonSchema.asArraySchema().getItems();
if (items.isSingleItems()) {
rejectAdditionalProperties(items.asSingleItems().getSchema());
} else if (items.isArrayItems()) {
for (JsonSchema schema : items.asArrayItems().getJsonSchemas()) {
rejectAdditionalProperties(schema);
}
}
}
}