2

I am trying to generate a JSON schema using POJOs with deep inheritance structure.

Using jackson-module-jsonSchema library I am able to generate a schema.

Given a simplified Java example:

public interface I {...}
public class A implements I {
    public int varA;
}
public class B implements I {
    public int varB;
}
public class C {
    public I varC;
}

Below is my code to generate the schema:

import com.fasterxml.jackson.databind.*
import com.fasterxml.jackson.module.jsonSchema.*

// ...

ObjectMapper mapper = new ObjectMapper();

SchemaFactoryWrapper visitor = new SchemaFactoryWrapper();

mapper.acceptJsonFormatVisitor(mapper.constructType(C.class), visitor);

JsonSchema schema = visitor.finalSchema();

String outputSchemaJson = mapper.writerWithDefaultPrettyPrinter()
                                .writeValueAsString(schema);

Actual Json Schema:

{
  "type" : "object",
  "id" : "urn:jsonschema:com:mycompany:GenerateSchemas:C",
  "properties" : {
    "varC" : {
      "type" : "any"
    }
  }
}

Desired Json Schema:

{
  "definitions": {
    "A": {
        "type" : "object",
        "id" : "urn:jsonschema:com:mycompany:GenerateSchemas:A",
        "properties" : {
          "varA" : {
            "type" : "integer"
          }
        }
      },
    "B": {
        "type" : "object",
        "id" : "urn:jsonschema:com:mycompany:GenerateSchemas:B",
        "properties" : {
          "varB" : {
            "type" : "integer"
          }
        }
      }
  },
  "type" : "object",
  "id" : "urn:jsonschema:com:mycompany:GenerateSchemas:C",
  "properties" : {
    "varC" : {
      "type" : "object",
      "oneOf": [
        { "$ref": "urn:jsonschema:com:mycompany:GenerateSchemas:A" },
        { "$ref": "urn:jsonschema:com:mycompany:GenerateSchemas:B" }
      ]
    }
  }
}

I have tried overriding core classes from Json Schema library. This answer from stack overflow was helpful to generate a schema with references.

Now I am trying to understand what I need to override such that I can use reflection to get all inheriting-classes of an interface and add oneOf references to it.

Rohit Mistry
  • 113
  • 3
  • 11

1 Answers1

1

I was finally able to figure out which classes I needed to override.

Notes:

  • Java does not support dynamically finding sub-classes via reflection through a simple out-of-box api. A workaround was to annotate classes with @JsonSubType which I was able to extract at run-time.

  • In version 2.9.8 of the json-module-schema library (where revision 1 of solution is written), there is no support yet for object definitions. Just to get the work done, I had to override a few extra classes to make this possible.

  • definitions need to be defined in the json schema only once at root level because there can be cases of recursive references.


With updated POJO code:

@JsonSubTypes({
    @JsonSubTypes.Type(name = "A", value = A.class),
    @JsonSubTypes.Type(name = "B", value = B.class)
})
public interface I {}

public class A implements I {
    public int varA;
}
public class B implements I {
    public int varB;
}
public class C {
    public I varC;
}

The desired json schema output is produced successfully.

Given the following code: https://gist.github.com/rrmistry/2246c959d1c9cc45894ecf55305c61fd, I imported GenerateSchema class to make schema generation code more simplified:

public void generate() throws Exception {
    generateSchemasFromJavaSubTypes(C.class);
}

private void generateSchemasFromJavaSubTypes(Class<?> classToGenerate) throws Exception {

    JsonSchema schema = GenerateSchemas.generateSchemaFromJavaClass(classToGenerate);

    ObjectMapper mapper = new ObjectMapper();

    String jsonSchemaStr = mapper.writerWithDefaultPrettyPrinter()
                                 .writeValueAsString(schema);
}

GitHub issue has been created to request native support: https://github.com/FasterXML/jackson-module-jsonSchema/issues/135

Rohit Mistry
  • 113
  • 3
  • 11