Loading src/main/scala/com/kjetland/jackson/jsonSchema/JsonSchemaGenerator.scala +55 −44 Original line number Diff line number Diff line Loading @@ -70,23 +70,8 @@ class JsonSchemaGenerator(rootObjectMapper:ObjectMapper) { } override def expectObjectFormat(_type: JavaType) = { node.put("type", "object") val propertiesNode = JsonNodeFactory.instance.objectNode() node.set("properties", propertiesNode) new JsonObjectFormatVisitor with MySerializerProvider { override def optionalProperty(writer: BeanProperty): Unit = { val propertyName = writer.getName val propertyType = writer.getType l(s"${propertyName}: ${propertyType}") // check for polymorphism //val polymorphism:Boolean = !propertyType.isConcrete && !propertyType.isArrayType && !propertyType.isCollectionLikeType && !propertyType.isContainerType && propertyType.isAbstract val subTypes: List[SubTypeAndTypeName[_]] = Option(propertyType.getRawClass.getDeclaredAnnotation(classOf[JsonSubTypes])).map { val subTypes: List[SubTypeAndTypeName[_]] = Option(_type.getRawClass.getDeclaredAnnotation(classOf[JsonSubTypes])).map { ann: JsonSubTypes => ann.value().map { t: JsonSubTypes.Type => SubTypeAndTypeName(t.value(), t.name()) Loading @@ -96,29 +81,46 @@ class JsonSchemaGenerator(rootObjectMapper:ObjectMapper) { if (subTypes.nonEmpty) { //l(s"polymorphism - subTypes: $subTypes") val anyOfNode = JsonNodeFactory.instance.objectNode() propertiesNode.set(propertyName, anyOfNode) val anyOfArrayNode = JsonNodeFactory.instance.arrayNode() anyOfNode.set("anyOf", anyOfArrayNode) node.set("anyOf", anyOfArrayNode) val subTypeSpecifierPropertyName: String = propertyType.getRawClass.getDeclaredAnnotation(classOf[JsonTypeInfo]).property() val subTypeSpecifierPropertyName: String = _type.getRawClass.getDeclaredAnnotation(classOf[JsonTypeInfo]).property() subTypes.foreach { subType: SubTypeAndTypeName[_] => l(s"polymorphism - subType: $subType") val thisPropertyNode = JsonNodeFactory.instance.objectNode() anyOfArrayNode.add(thisPropertyNode) val thisAnyOfNode = JsonNodeFactory.instance.objectNode() anyOfArrayNode.add(thisAnyOfNode) val childVisitor = createChild( thisPropertyNode ) val childVisitor = createChild( thisAnyOfNode ) objectMapper.acceptJsonFormatVisitor(subType.clazz, childVisitor) // must inject the 'type'-param and value as enum with only one possible value thisPropertyNode.get("properties").asInstanceOf[ObjectNode].put(subTypeSpecifierPropertyName, subType.subTypeName) val propertiesNode = thisAnyOfNode.get("properties").asInstanceOf[ObjectNode] val enumValuesNode = JsonNodeFactory.instance.arrayNode() enumValuesNode.add(subType.subTypeName) val enumObjectNode = JsonNodeFactory.instance.objectNode() enumObjectNode.set("enum", enumValuesNode) propertiesNode.set(subTypeSpecifierPropertyName, enumObjectNode) } null // Returning null to stop jackson from visiting this object since we have done it manually } else { node.put("type", "object") val propertiesNode = JsonNodeFactory.instance.objectNode() node.set("properties", propertiesNode) new JsonObjectFormatVisitor with MySerializerProvider { override def optionalProperty(writer: BeanProperty): Unit = { val propertyName = writer.getName val propertyType = writer.getType l(s"${propertyName}: ${propertyType}") val thisPropertyNode = JsonNodeFactory.instance.objectNode() propertiesNode.set(propertyName, thisPropertyNode) Loading @@ -126,7 +128,6 @@ class JsonSchemaGenerator(rootObjectMapper:ObjectMapper) { val childNode = JsonNodeFactory.instance.objectNode() objectMapper.acceptJsonFormatVisitor(propertyType, createChild(thisPropertyNode)) } } Loading @@ -136,6 +137,9 @@ class JsonSchemaGenerator(rootObjectMapper:ObjectMapper) { override def property(name: String, handler: JsonFormatVisitable, propertyTypeHint: JavaType): Unit = ??? } } } override def expectBooleanFormat(_type: JavaType) = new JsonBooleanFormatVisitor { Loading @@ -154,9 +158,16 @@ class JsonSchemaGenerator(rootObjectMapper:ObjectMapper) { def generateJsonSchema[T <: Any](clazz:Class[T]):JsonNode = { val rootVisitor = new MyJsonFormatVisitorWrapper(rootObjectMapper) val rootNode = JsonNodeFactory.instance.objectNode() // Specify that this is a v4 json schema rootNode.put("$schema", "http://json-schema.org/draft-04/schema#") val rootVisitor = new MyJsonFormatVisitorWrapper(rootObjectMapper, node = rootNode) rootObjectMapper.acceptJsonFormatVisitor(clazz, rootVisitor) rootVisitor.node rootNode } } Loading
src/main/scala/com/kjetland/jackson/jsonSchema/JsonSchemaGenerator.scala +55 −44 Original line number Diff line number Diff line Loading @@ -70,23 +70,8 @@ class JsonSchemaGenerator(rootObjectMapper:ObjectMapper) { } override def expectObjectFormat(_type: JavaType) = { node.put("type", "object") val propertiesNode = JsonNodeFactory.instance.objectNode() node.set("properties", propertiesNode) new JsonObjectFormatVisitor with MySerializerProvider { override def optionalProperty(writer: BeanProperty): Unit = { val propertyName = writer.getName val propertyType = writer.getType l(s"${propertyName}: ${propertyType}") // check for polymorphism //val polymorphism:Boolean = !propertyType.isConcrete && !propertyType.isArrayType && !propertyType.isCollectionLikeType && !propertyType.isContainerType && propertyType.isAbstract val subTypes: List[SubTypeAndTypeName[_]] = Option(propertyType.getRawClass.getDeclaredAnnotation(classOf[JsonSubTypes])).map { val subTypes: List[SubTypeAndTypeName[_]] = Option(_type.getRawClass.getDeclaredAnnotation(classOf[JsonSubTypes])).map { ann: JsonSubTypes => ann.value().map { t: JsonSubTypes.Type => SubTypeAndTypeName(t.value(), t.name()) Loading @@ -96,29 +81,46 @@ class JsonSchemaGenerator(rootObjectMapper:ObjectMapper) { if (subTypes.nonEmpty) { //l(s"polymorphism - subTypes: $subTypes") val anyOfNode = JsonNodeFactory.instance.objectNode() propertiesNode.set(propertyName, anyOfNode) val anyOfArrayNode = JsonNodeFactory.instance.arrayNode() anyOfNode.set("anyOf", anyOfArrayNode) node.set("anyOf", anyOfArrayNode) val subTypeSpecifierPropertyName: String = propertyType.getRawClass.getDeclaredAnnotation(classOf[JsonTypeInfo]).property() val subTypeSpecifierPropertyName: String = _type.getRawClass.getDeclaredAnnotation(classOf[JsonTypeInfo]).property() subTypes.foreach { subType: SubTypeAndTypeName[_] => l(s"polymorphism - subType: $subType") val thisPropertyNode = JsonNodeFactory.instance.objectNode() anyOfArrayNode.add(thisPropertyNode) val thisAnyOfNode = JsonNodeFactory.instance.objectNode() anyOfArrayNode.add(thisAnyOfNode) val childVisitor = createChild( thisPropertyNode ) val childVisitor = createChild( thisAnyOfNode ) objectMapper.acceptJsonFormatVisitor(subType.clazz, childVisitor) // must inject the 'type'-param and value as enum with only one possible value thisPropertyNode.get("properties").asInstanceOf[ObjectNode].put(subTypeSpecifierPropertyName, subType.subTypeName) val propertiesNode = thisAnyOfNode.get("properties").asInstanceOf[ObjectNode] val enumValuesNode = JsonNodeFactory.instance.arrayNode() enumValuesNode.add(subType.subTypeName) val enumObjectNode = JsonNodeFactory.instance.objectNode() enumObjectNode.set("enum", enumValuesNode) propertiesNode.set(subTypeSpecifierPropertyName, enumObjectNode) } null // Returning null to stop jackson from visiting this object since we have done it manually } else { node.put("type", "object") val propertiesNode = JsonNodeFactory.instance.objectNode() node.set("properties", propertiesNode) new JsonObjectFormatVisitor with MySerializerProvider { override def optionalProperty(writer: BeanProperty): Unit = { val propertyName = writer.getName val propertyType = writer.getType l(s"${propertyName}: ${propertyType}") val thisPropertyNode = JsonNodeFactory.instance.objectNode() propertiesNode.set(propertyName, thisPropertyNode) Loading @@ -126,7 +128,6 @@ class JsonSchemaGenerator(rootObjectMapper:ObjectMapper) { val childNode = JsonNodeFactory.instance.objectNode() objectMapper.acceptJsonFormatVisitor(propertyType, createChild(thisPropertyNode)) } } Loading @@ -136,6 +137,9 @@ class JsonSchemaGenerator(rootObjectMapper:ObjectMapper) { override def property(name: String, handler: JsonFormatVisitable, propertyTypeHint: JavaType): Unit = ??? } } } override def expectBooleanFormat(_type: JavaType) = new JsonBooleanFormatVisitor { Loading @@ -154,9 +158,16 @@ class JsonSchemaGenerator(rootObjectMapper:ObjectMapper) { def generateJsonSchema[T <: Any](clazz:Class[T]):JsonNode = { val rootVisitor = new MyJsonFormatVisitorWrapper(rootObjectMapper) val rootNode = JsonNodeFactory.instance.objectNode() // Specify that this is a v4 json schema rootNode.put("$schema", "http://json-schema.org/draft-04/schema#") val rootVisitor = new MyJsonFormatVisitorWrapper(rootObjectMapper, node = rootNode) rootObjectMapper.acceptJsonFormatVisitor(clazz, rootVisitor) rootVisitor.node rootNode } }