"additionalProperties" : false
が私が持っているすべてのクラスに適用されるJSONスキーマを生成したいと思います。
次のクラスがあるとします。
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
がすべてのクラスに適用されるスキーマを生成するにはどうすればよいですか?
schema
の例
{ "type" : "object", "id" : "urn:jsonschema:com.xxx.xxx:A", "additionalProperties" : false, "properties" : { "s" : { "type" : "string" }, "b" : { "type" : "object", "id" : "urn:jsonschema:com.xxx.xxx:B", "properties" : { "bd" : { "type" : "number" } } } } }
注:スキームを部分的に生成したくありません。
情報:興味のある人がこの問題の修正をサポートできる場合は、このシナリオの問題を開いています。 すべての追加コンテンツを拒否する必要があるjsonスキーマを生成します
次のように、各プロパティのスキーマを指定する必要があります。
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;
}
以下は私のために働いた:
_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>
_
次のクラスを使用します。
Test.Java:
_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;
}
}
_
...および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
の出力):
_{
"$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"
]
}
}
}
_
これにより、TestとTestChildの両方で_"additionalProperties": false
_になります。
注:スキーマ生成コードでJsonSchemaConfig.nullableJsonSchemaDraft4()
をJsonSchemaConfig.vanillaJsonSchemaDraft4()
に置き換えて、「type:null」または「type:ActualType」の「oneof」参照を削除して、 「type:ActualType」(プロパティに@JsonProperty(required = true)
で注釈を付けない限り、これでも「required」配列に追加されないことに注意してください)。
反射を使用したくない場合は、もっと簡単なルートに行きます。 JSONPathを使用します。したがって、以下をpom.xml
に追加する必要があります。
<dependency>
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path</artifactId>
<version>2.3.0</version>
</dependency>
次に、以下のコードは、生成されたJSONファイルを変更する方法を示しています
package taruntest;
import com.jayway.jsonpath.*;
public class Test {
public static void main(String[] args) throws Exception {
String data = "{\n" +
" \"type\" : \"object\",\n" +
" \"id\" : \"urn:jsonschema:com.xxx.xxx:A\",\n" +
" \"additionalProperties\" : false,\n" +
" \"properties\" : {\n" +
" \"s\" : {\n" +
" \"type\" : \"string\"\n" +
" },\n" +
" \"b\" : {\n" +
" \"type\" : \"object\",\n" +
" \"id\" : \"urn:jsonschema:com.xxx.xxx:B\",\n" +
" \"properties\" : {\n" +
" \"bd\" : {\n" +
" \"type\" : \"number\"\n" +
" }\n" +
" }\n" +
" }\n" +
" }\n" +
"}";
DocumentContext doc = JsonPath.parse(data);
doc.put("$..[?(@.id =~ /urn:jsonschema:.*/)]", "additionalProperties", false);
String modified = doc.jsonString();
System.out.println(modified);
}
}
実行の出力は(手動でフォーマットされます)
{
"type": "object",
"id": "urn:jsonschema:com.xxx.xxx:A",
"additionalProperties": false,
"properties": {
"s": {
"type": "string"
},
"b": {
"type": "object",
"id": "urn:jsonschema:com.xxx.xxx:B",
"properties": {
"bd": {
"type": "number"
}
},
"additionalProperties": false
}
}
}
これは私の解決策であり、反映やハッキングの方法はなく、私にとっては非常にうまく機能します。
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);
}
}
}
}