From d0eef22c9f0dd536bef6233c47057b96ff8b8cf7 Mon Sep 17 00:00:00 2001 From: Rich Turner <7072278+richturner@users.noreply.github.com> Date: Thu, 11 Nov 2021 22:49:25 +0000 Subject: [PATCH] Bug fix for JsonSchemaTitle in definition schemas also added disableRefTitle config item to exclude titles from $ref schemas --- .../jsonSchema/JsonSchemaGenerator.scala | 36 ++++++++++------ .../jackson/jsonSchema/UseItFromJavaTest.java | 4 +- .../jsonSchema/JsonSchemaGeneratorTest.scala | 24 ++++++++++- .../testData/PojoWithSuperTypeProperties.java | 43 +++++++++++++++++++ .../testDataScala/PolymorphismAndTitle.scala | 5 ++- 5 files changed, 97 insertions(+), 15 deletions(-) create mode 100644 src/test/scala/com/kjetland/jackson/jsonSchema/testData/PojoWithSuperTypeProperties.java diff --git a/src/main/scala/com/kjetland/jackson/jsonSchema/JsonSchemaGenerator.scala b/src/main/scala/com/kjetland/jackson/jsonSchema/JsonSchemaGenerator.scala index 17e2258..7f57d76 100755 --- a/src/main/scala/com/kjetland/jackson/jsonSchema/JsonSchemaGenerator.scala +++ b/src/main/scala/com/kjetland/jackson/jsonSchema/JsonSchemaGenerator.scala @@ -39,7 +39,8 @@ object JsonSchemaConfig { useMultipleEditorSelectViaProperty = false, uniqueItemClasses = Set(), classTypeReMapping = Map(), - jsonSuppliers = Map() + jsonSuppliers = Map(), + disableRefTitle = false ) /** @@ -74,7 +75,8 @@ object JsonSchemaConfig { classOf[java.util.Set[_]] ), classTypeReMapping = Map(), - jsonSuppliers = Map() + jsonSuppliers = Map(), + disableRefTitle = false ) /** @@ -100,7 +102,8 @@ object JsonSchemaConfig { useMultipleEditorSelectViaProperty = false, uniqueItemClasses = Set(), classTypeReMapping = Map(), - jsonSuppliers = Map() + jsonSuppliers = Map(), + disableRefTitle = false ) // Java-API @@ -121,7 +124,9 @@ object JsonSchemaConfig { jsonSuppliers:java.util.Map[String, Supplier[JsonNode]], subclassesResolver:SubclassesResolver, failOnUnknownProperties:Boolean, - javaxValidationGroups:java.util.List[Class[_]] + javaxValidationGroups:java.util.List[Class[_]], + jsonSchemaDraft: JsonSchemaDraft, + disableRefTitle:Boolean ):JsonSchemaConfig = { import scala.collection.JavaConverters._ @@ -145,7 +150,9 @@ object JsonSchemaConfig { failOnUnknownProperties, if (javaxValidationGroups == null) Array[Class[_]]() else { javaxValidationGroups.toArray.asInstanceOf[Array[Class[_]]] - } + }, + jsonSchemaDraft, + disableRefTitle ) } @@ -245,7 +252,8 @@ case class JsonSchemaConfig subclassesResolver:SubclassesResolver = new SubclassesResolverImpl(), // Using default impl that scans entire classpath failOnUnknownProperties:Boolean = true, javaxValidationGroups:Array[Class[_]] = Array(), // Used to match against different validation-groups (javax.validation.constraints) - jsonSchemaDraft:JsonSchemaDraft = JsonSchemaDraft.DRAFT_04 + jsonSchemaDraft:JsonSchemaDraft = JsonSchemaDraft.DRAFT_04, + disableRefTitle:Boolean ) { def withFailOnUnknownProperties(failOnUnknownProperties:Boolean):JsonSchemaConfig = { @@ -485,7 +493,7 @@ class JsonSchemaGenerator level:Int = 0, val node: ObjectNode = JsonNodeFactory.instance.objectNode(), val definitionsHandler:DefinitionsHandler, - currentProperty:Option[BeanProperty] // This property may represent the BeanProperty when we're directly processing beneath the property + currentProperty:Option[BeanProperty] = None // This property may represent the BeanProperty when we're directly processing beneath the property ) extends JsonFormatVisitorWrapper with MySerializerProvider { def l(s: => String): Unit = { @@ -1002,9 +1010,11 @@ class JsonSchemaGenerator thisOneOfNode.put("$ref", definitionInfo.ref.get) // If class is annotated with JsonSchemaTitle, we should add it - Option(subType.getDeclaredAnnotation(classOf[JsonSchemaTitle])).map(_.value()).foreach { - title => - thisOneOfNode.put("title", title) + if (!config.disableRefTitle) { + Option(subType.getDeclaredAnnotation(classOf[JsonSchemaTitle])).map(_.value()).foreach { + title => + thisOneOfNode.put("title", title) + } } anyOfArrayNode.add(thisOneOfNode) @@ -1067,8 +1077,10 @@ class JsonSchemaGenerator extractPolymorphismInfo(_type).map { case pi: PolymorphismInfo => // This class is a child in a polymorphism config.. - // Set the title = subTypeName - thisObjectNode.put("title", pi.subTypeName) + // Set the title = subTypeName if title not already set + if (!thisObjectNode.has("title")) { + thisObjectNode.put("title", pi.subTypeName) + } // must inject the 'type'-param and value as enum with only one possible value // This is done to make sure the json generated from the schema using this oneOf diff --git a/src/test/java/com/kjetland/jackson/jsonSchema/UseItFromJavaTest.java b/src/test/java/com/kjetland/jackson/jsonSchema/UseItFromJavaTest.java index cbc250e..2481b0a 100755 --- a/src/test/java/com/kjetland/jackson/jsonSchema/UseItFromJavaTest.java +++ b/src/test/java/com/kjetland/jackson/jsonSchema/UseItFromJavaTest.java @@ -42,7 +42,9 @@ public UseItFromJavaTest() { new HashMap<>(), null, true, - null); + null, + null, + false); JsonSchemaGenerator g2 = new JsonSchemaGenerator(objectMapper, config); diff --git a/src/test/scala/com/kjetland/jackson/jsonSchema/JsonSchemaGeneratorTest.scala b/src/test/scala/com/kjetland/jackson/jsonSchema/JsonSchemaGeneratorTest.scala index 751f941..0696372 100755 --- a/src/test/scala/com/kjetland/jackson/jsonSchema/JsonSchemaGeneratorTest.scala +++ b/src/test/scala/com/kjetland/jackson/jsonSchema/JsonSchemaGeneratorTest.scala @@ -176,7 +176,6 @@ class JsonSchemaGeneratorTest extends FunSuite with Matchers { assert(node.at(s"/properties/$typeParamName/type").asText() == "string") assert(node.at(s"/properties/$typeParamName/enum/0").asText() == typeName) assert(node.at(s"/properties/$typeParamName/default").asText() == typeName) - assert(node.at(s"/title").asText() == typeName) assertPropertyRequired(node, typeParamName, required = true) if (html5Checks) { @@ -1711,6 +1710,29 @@ class JsonSchemaGeneratorTest extends FunSuite with Matchers { // Currently there are no differences in the generated jsonSchema other than the $schema-url } + test("PojoWithSuperTypeProperties") { + val config = JsonSchemaConfig.vanillaJsonSchemaDraft4.copy(disableRefTitle = true) + val _jsonSchemaGenerator = new JsonSchemaGenerator(_objectMapper, debug = true, config) + val schema = _jsonSchemaGenerator.generateJsonSchema(classOf[PojoWithSuperTypeProperties]) + + println("--------------------------------------------") + println(asPrettyJson(schema, jsonSchemaGeneratorScala.rootObjectMapper)) + + assert( schema.at("/properties/prop1/oneOf/0/$ref").asText() == "#/definitions/PolymorphismAndTitle1") + assert( schema.at("/properties/prop1/oneOf/0/title").asText() == "") + assert( schema.at("/properties/prop1/oneOf/1/$ref").asText() == "#/definitions/PolymorphismAndTitle2") + assert( schema.at("/properties/prop1/oneOf/1/title").asText() == "") + assert( schema.at("/properties/prop2/oneOf/0/$ref").asText() == "#/definitions/PolymorphismAndTitle1") + assert( schema.at("/properties/prop2/oneOf/0/title").asText() == "") + assert( schema.at("/properties/prop2/oneOf/1/$ref").asText() == "#/definitions/PolymorphismAndTitle2") + assert( schema.at("/properties/prop2/oneOf/1/title").asText() == "") + assert( schema.at("/properties/prop2/title").asText() == "CustomPropTitle2") + assert( schema.at("/properties/prop2/description").asText() == "Custom prop title 2 description") + assert(schema.at("/definitions/PolymorphismAndTitle1/title").asText() == "CustomTitle1") + assert(schema.at("/definitions/PolymorphismAndTitle1/description").asText() == "Custom title 1 description") + assert(schema.at("/definitions/PolymorphismAndTitle2/title").asText() == "CustomTitle2") + assert(schema.at("/definitions/PolymorphismAndTitle2/description").asText() == "Custom title 2 description") + } } trait TestData { diff --git a/src/test/scala/com/kjetland/jackson/jsonSchema/testData/PojoWithSuperTypeProperties.java b/src/test/scala/com/kjetland/jackson/jsonSchema/testData/PojoWithSuperTypeProperties.java new file mode 100644 index 0000000..87f3e8c --- /dev/null +++ b/src/test/scala/com/kjetland/jackson/jsonSchema/testData/PojoWithSuperTypeProperties.java @@ -0,0 +1,43 @@ +package com.kjetland.jackson.jsonSchema.testData; + +import com.fasterxml.jackson.annotation.JsonPropertyDescription; +import com.kjetland.jackson.jsonSchema.annotations.JsonSchemaTitle; +import com.kjetland.jackson.jsonSchema.testDataScala.PolymorphismAndTitleBase; + +import java.util.Objects; + +public class PojoWithSuperTypeProperties { + + public PolymorphismAndTitleBase prop1; + + @JsonSchemaTitle("CustomPropTitle2") + @JsonPropertyDescription("Custom prop title 2 description") + public PolymorphismAndTitleBase prop2; + + private PojoWithSuperTypeProperties() { + } + + public PojoWithSuperTypeProperties(PolymorphismAndTitleBase prop1) { + this.prop1 = prop1; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + PojoWithSuperTypeProperties that = (PojoWithSuperTypeProperties) o; + return prop1.equals(that.prop1); + } + + @Override + public int hashCode() { + return Objects.hash(prop1); + } + + @Override + public String toString() { + return "PojoWithSuperTypeProperties{" + + "prop1=" + prop1 + + '}'; + } +} diff --git a/src/test/scala/com/kjetland/jackson/jsonSchema/testDataScala/PolymorphismAndTitle.scala b/src/test/scala/com/kjetland/jackson/jsonSchema/testDataScala/PolymorphismAndTitle.scala index bff348f..c87d76e 100644 --- a/src/test/scala/com/kjetland/jackson/jsonSchema/testDataScala/PolymorphismAndTitle.scala +++ b/src/test/scala/com/kjetland/jackson/jsonSchema/testDataScala/PolymorphismAndTitle.scala @@ -1,6 +1,6 @@ package com.kjetland.jackson.jsonSchema.testDataScala -import com.fasterxml.jackson.annotation.{JsonSubTypes, JsonTypeInfo} +import com.fasterxml.jackson.annotation.{JsonPropertyDescription, JsonSubTypes, JsonTypeInfo} import com.kjetland.jackson.jsonSchema.annotations.JsonSchemaTitle @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type") @@ -10,6 +10,9 @@ import com.kjetland.jackson.jsonSchema.annotations.JsonSchemaTitle trait PolymorphismAndTitleBase @JsonSchemaTitle("CustomTitle1") +@JsonPropertyDescription("Custom title 1 description") case class PolymorphismAndTitle1(a:String) extends PolymorphismAndTitleBase +@JsonSchemaTitle("CustomTitle2") +@JsonPropertyDescription("Custom title 2 description") case class PolymorphismAndTitle2(a:String) extends PolymorphismAndTitleBase