Search code examples
javajsonjacksonjsonschemajackson-modules

Jackson JSON Schema generator for Joda date time


I am using Jackson JSON schema module version 2.7.4 to generate JSON schema for some of my classes. In my classes, I have used Joda DateTime object. The schema for this object is generated with all it's properties exploded (as shown below). Is it possible to convert this to something like DATE_TIME?

"createdDate":{  
     "type":"object",
     "id":"urn:jsonschema:org:joda:time:DateTime",
     "properties":{  
        "weekOfWeekyear":{  
           "type":"integer"
        },
        "weekyear":{  
           "type":"integer"
        },
        "yearOfEra":{  
           "type":"integer"
        },
        "secondOfDay":{  
           "type":"integer"
        },
        "minuteOfDay":{  
           "type":"integer"
        },
        "yearOfCentury":{  
           "type":"integer"
        },
        "centuryOfEra":{  
           "type":"integer"
        },
        "millisOfDay":{  
           "type":"integer"
        },
        "monthOfYear":{  
           "type":"integer"
        },
        "hourOfDay":{  
           "type":"integer"
        },
        "minuteOfHour":{  
           "type":"integer"
        },
        "secondOfMinute":{  
           "type":"integer"
        },
        "millisOfSecond":{  
           "type":"integer"
        },
        "year":{  
           "type":"integer"
        },
        "dayOfMonth":{  
           "type":"integer"
        },
        "dayOfWeek":{  
           "type":"integer"
        },
        "era":{  
           "type":"integer"
        },
        "dayOfYear":{  
           "type":"integer"
        },
        "chronology":{  
           "type":"object",
           "id":"urn:jsonschema:org:joda:time:Chronology",
           "properties":{  
              "zone":{  
                 "type":"object",
                 "id":"urn:jsonschema:org:joda:time:DateTimeZone",
                 "properties":{  
                    "id":{  
                       "type":"string"
                    },
                    "fixed":{  
                       "type":"boolean"
                    }
                 }
              }
           }
        },
        "zone":{  
           "type":"object",
           "$ref":"urn:jsonschema:org:joda:time:DateTimeZone"
        },
        "millis":{  
           "type":"integer"
        },
        "afterNow":{  
           "type":"boolean"
        },
        "beforeNow":{  
           "type":"boolean"
        },
        "equalNow":{  
           "type":"boolean"
        }
     }
  },

Solution

  • I don't know if this is the right solution, but this is what was suggested in another web site and this worked for me; hence, I am posting this as an answer.

    In Jackson schema module, there is a notion of VisitorContext which can be registered with ObjectMapper class for schema generation. As per the suggestion, I provided an implementation of this as:

    public static class VisitorContextWithoutSchemaInlining extends VisitorContext {
      @Override
      public String addSeenSchemaUri(final JavaType aSeenSchema) {
        return getSeenSchemaUri(aSeenSchema);
      }
    
      @Override
      public String getSeenSchemaUri(final JavaType aSeenSchema) {
        return isEligibleForInlineSchema(aSeenSchema) ? javaTypeToUrn(aSeenSchema) : null;
      }
    
      private boolean isEligibleForInlineSchema(final JavaType type) {
        return type.getRawClass() != String.class
                    && !isBoxedPrimitive(type)
                    && !type.isPrimitive()
                    && !type.isMapLikeType()
                    && !type.isCollectionLikeType()
                    && type.getRawClass() == DateTime.class
                    ;
        }
    
        private boolean isBoxedPrimitive(final JavaType type) {
          return type.getRawClass() == Boolean.class
                 || type.getRawClass() == Byte.class
                 || type.getRawClass() == Long.class
                 || type.getRawClass() == Integer.class
                 || type.getRawClass() == Short.class
                 || type.getRawClass() == Float.class
                 || type.getRawClass() == Double.class
                 ;
        }
    }
    

    To use this with ObjectMapper, I did this:

    final ObjectMapper mapper = new ObjectMapper();
    final ObjectWriter objectWriter = mapper.writer();
    
    final SchemaFactoryWrapper visitor = new SchemaFactoryWrapper();
    visitor.setVisitorContext(new VisitorContextWithoutSchemaInlining());
    
    objectWriter.acceptJsonFormatVisitor(candidateClass, visitor);
    final JsonSchema jsonSchema = visitor.finalSchema();
    final String schemaJsonString = objectWriter.forType(JsonSchema.class).writeValueAsString(jsonSchema);
    

    With this I could see my schema has this for createdDate

    "createdDate":{"type":"object","$ref":"urn:jsonschema:org:joda:time:DateTime"}