Commit 51e65a42 authored by Morten Kjetland's avatar Morten Kjetland
Browse files

Polymorphism anyOf-support now works at both first level and sub-levels

parent d75ef347
Loading
Loading
Loading
Loading
+55 −44
Original line number Diff line number Diff line
@@ -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())
@@ -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)
@@ -126,7 +128,6 @@ class JsonSchemaGenerator(rootObjectMapper:ObjectMapper) {
              val childNode = JsonNodeFactory.instance.objectNode()

              objectMapper.acceptJsonFormatVisitor(propertyType, createChild(thisPropertyNode))
          }

          }

@@ -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 {
@@ -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
  }

}