Generate Json Schema from POJO with a twist

匿名 (未验证) 提交于 2019-12-03 02:05:01

问题:

What I have:

I'm generating a JSON schema from a pojo. My code to generate the schema looks like so:

ObjectMapper mapper = new ObjectMapper(); TitleSchemaFactoryWrapper visitor = new TitleSchemaFactoryWrapper(); mapper.acceptJsonFormatVisitor(clazz, visitor); JsonSchema schema = visitor.finalSchema(); schemas.put(clazz, mapper.writerWithDefaultPrettyPrinter().writeValueAsString(schema));

I'm generating several schemas via the above code. One of the pojos has an internal embedded enum to limit the possible values, like so:

public class MyClass {      @JsonProperty("name")     private String name;     @JsonProperty("startDayOfWeek")     private MyClass.StartDayOfWeek startDayOfWeek;     /**      * The ID of a timezone returned by the timezones route.      *       */     @JsonProperty("timezone")     private String timezone;     @JsonIgnore     private Map additionalProperties = new HashMap();      /**      *       * @return      *     The startDayOfWeek      */     @JsonProperty("startDayOfWeek")     public MyClass.StartDayOfWeek getStartDayOfWeek() {         return startDayOfWeek;     }      /**      *       * @param startDayOfWeek      *     The startDayOfWeek      */     @JsonProperty("startDayOfWeek")     public void setStartDayOfWeek(MyClass.StartDayOfWeek startDayOfWeek) {         this.startDayOfWeek = startDayOfWeek;     }      public static enum StartDayOfWeek {          MONDAY("Monday"),         TUESDAY("Tuesday"),         WEDNESDAY("Wednesday"),         THURSDAY("Thursday"),         FRIDAY("Friday"),         SATURDAY("Saturday"),         SUNDAY("Sunday");         private final String value;         private static Map constants = new HashMap();          static {             for (MyClass.StartDayOfWeek c: values()) {                 constants.put(c.value, c);             }         }          private StartDayOfWeek(String value) {             this.value = value;         }          @JsonValue         @Override         public String toString() {             return this.value;         }          @JsonCreator         public static MyClass.StartDayOfWeek fromValue(String value) {             MyClass.StartDayOfWeek constant = constants.get(value);             if (constant == null) {                 throw new IllegalArgumentException(value);             } else {                 return constant;             }         }      }  }

The above code should limit the possible String values in the JSON data that's passed around to "Monday", "Tuesday", "Wednesday", etc.

When I run the schema generator on the code in question, I expect to get something like the following schema:

{   "type" : "object",   "javaType" : "my.package.MyClass",   "properties": {     "startDayOfWeek" : {       "type" : "string",       "enum" : [ "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday" ]     }   } }

but instead I'm getting this:

{   "type" : "object",   "id" : "urn:jsonschema:my:package:MyClass",   "title" : "Lmy/package/MyClass;",   "properties" : {     "startDayOfWeek" : {       "type" : "string"     }   } }

I've done some digging in the Jackson Schema Module source code and figured out that what's happening is Jackson's using ".toString()" as the default serialization method for enum types, but what I need it to do instead is create the line that looks like this based on StartDayOfWeek.values():

"enum" : [ "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday" ]

Does anyone know how to do that?

回答1:

Storme's answer references org.codehaus, which is an older version of jackson. The following is similar but uses fasterxml (newer version).

Pom:

com.fasterxml.jackson.corejackson-core2.7.1com.fasterxml.jackson.corejackson-databind2.7.1com.fasterxml.jackson.corejackson-annotations2.7.1com.fasterxml.jackson.modulejackson-module-jsonSchema2.1.0

Code:

import ...TargetClass; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.databind.jsonschema.JsonSchema;  import java.io.IOException;  public final class JsonSchemaGenerator {      private JsonSchemaGenerator() { };      public static void main(String[] args) throws IOException {         System.out.println(JsonSchemaGenerator.getJsonSchema(TargetClass.class));     }      public static String getJsonSchema(Class clazz) throws IOException {         ObjectMapper mapper = new ObjectMapper();         mapper.configure(SerializationFeature.WRITE_ENUMS_USING_TO_STRING, true);         JsonSchema schema = mapper.generateJsonSchema(clazz);         return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(schema);     }  }


回答2:

It seems to not be possible using the instructions I found using databind. However I found another jackson module that seems to do the trick nicely. Oddly several of the objects are named the same.

TLDR: use objects from the org.codehaus.jackson.map package rather than the com.fasterxml.jackson.databind package. If you're following the instructions on this page then you're doing it wrong. Just use the jackson-mapper module instead.

Here's the code for future googlers:

private static String getJsonSchema(Class clazz) throws IOException {     org.codehaus.jackson.map.ObjectMapper mapper = new ObjectMapper();     //There are other configuration options you can set.  This is the one I needed.     mapper.configure(SerializationConfig.Feature.WRITE_ENUMS_USING_TO_STRING, true);      JsonSchema schema = mapper.generateJsonSchema(clazz);      return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(schema); }


标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!