mbknor / mbknor-jackson-jsonSchema

Generate JSON Schema with Polymorphism using Jackson annotations
MIT License
235 stars 79 forks source link

Inlining abstract classes #28

Closed ratulm closed 6 years ago

ratulm commented 7 years ago

Hi, I have an inter-linked class structure, the essence of which can be captured as the following:

    public class SchemaTest {
       public List<Parent> parents;   
    }

    @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "class")
    @JsonSubTypes({
       @JsonSubTypes.Type(value = Child1.class),
       @JsonSubTypes.Type(value = Child2.class)})
     public abstract class Parent {
      }

     public class Child1 extends Parent {
        public List<Parent> parents1;      
     }

     public class Child2 extends Parent {      
        public List<Parent> parents2;
     }

The module generates schema by essentially inlining the abstract class, as follows:

  {
    "$schema" : "http://json-schema.org/draft-04/schema#",
    "title" : "Schema Test",
    "type" : "object",
    "additionalProperties" : false,
    "properties" : {
      "parents" : {
        "type" : "array",
        "items" : {
          "oneOf" : [
            {
              "$ref" : "#/definitions/Child2"
            },
            {
              "$ref" : "#/definitions/Child1"
            }
          ]
        }
      }
    },
    "definitions" : {
      "Child2" : {
        "type" : "object",
        "additionalProperties" : false,
        "properties" : {
          "class" : {
            "type" : "string",
            "enum" : [
              null
            ],
            "default" : null
          },
          "parents2" : {
            "type" : "array",
            "items" : {
              "oneOf" : [
                {
                  "$ref" : "#/definitions/Child2"
                },
                {
                  "$ref" : "#/definitions/Child1"
                }
              ]
            }
          }
        },
        "title" : null,
        "required" : [
          "class"
        ]
      },
      "Child1" : {
        "type" : "object",
        "additionalProperties" : false,
        "properties" : {
          "class" : {
            "type" : "string",
            "enum" : [
              null
            ],
            "default" : null
          },
          "parents1" : {
            "type" : "array",
            "items" : {
              "oneOf" : [
                {
                  "$ref" : "#/definitions/Child2"
                },
                {
                  "$ref" : "#/definitions/Child1"
                }
              ]
            }
          }
        },
        "title" : null,
        "required" : [
          "class"
        ]
      }
    }
  }

The issue is that this representation is losing information that all of the oneOf's are of the same type (Parent). Would it be possible to generate something like the following?

   {
    "$schema" : "http://json-schema.org/draft-04/schema#",
    "title" : "Schema Test",
    "type" : "object",
    "additionalProperties" : false,
    "properties" : {
      "parents" : {
        "type" : "array",
        "items" : {
          "$ref" : "#/definitions/Parent"
        }
      }
    },
    "definitions" : {
      "Parent" : {
        "oneOf" : [
          {
            "$ref" : "#/definitions/Child2"
          },
          {
            "$ref" : "#/definitions/Child1"
          }
        ]
      },
      "Child2" : {
        "type" : "object",
        "additionalProperties" : false,
        "properties" : {
          "class" : {
            "type" : "string",
            "enum" : [
              null
            ],
            "default" : null
          },
          "parents2" : {
            "type" : "array",
            "items" : {
              "$ref" : "#/definitions/Parent"
            }
          }
        },
        "title" : null,
        "required" : [
          "class"
        ]
      },
      "Child1" : {
        "type" : "object",
        "additionalProperties" : false,
        "properties" : {
          "class" : {
            "type" : "string",
            "enum" : [
              null
            ],
            "default" : null
          },
          "parents1" : {
            "type" : "array",
            "items" : {
              "$ref" : "#/definitions/Parent"
            }
          }
        },
        "title" : null,
        "required" : [
          "class"
        ]
      }
    }
  }
ratulm commented 7 years ago

For a real-world example, see http://intentionet.github.io/batfish/docson/#../datamodel.json. The relevant part is routingPolicies --> expand "Statement" --> expand "If" which nicely shows that If contains Statement.

I got this by modifying expectObjectFormat. The changes are committed to branch noAbstractInline of my fork. I didn't issue a pull requests because it breaks some tests, and I don't have the expertise to fix them easily.

Happy to help if you wanted to incorporate this change.

Thanks.

mbknor commented 7 years ago

I'm not sure but I might think that what you suggests is an improvement :) I'll look into it.

mbknor commented 6 years ago

Closing issue due to lack of interest