2015-01-09 10 views
9

Co mam:Generowanie schematu Json z POJO z niespodzianką

Generuję schemat JSON z pojo. Mój kod do generowania schematu wygląda następująco:

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

Generuję kilka schematów za pomocą powyższego kodu. Jednym z POJOs posiada wewnętrzną enum osadzoną w celu ograniczenia możliwych wartości, tak jak poniżej:

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<String, Object> additionalProperties = new HashMap<String, Object>(); 

    /** 
    * 
    * @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<String, MyClass.StartDayOfWeek> constants = new HashMap<String, MyClass.StartDayOfWeek>(); 

     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; 
      } 
     } 

    } 

} 

Powyższy kod powinien ograniczać możliwe wartości String w danych JSON, który jest przekazywana dookoła do „Poniedziałek”, „Tuesday”, „Wednesday”, itp

Kiedy uruchomić generator schematu na kodzie w pytaniu, spodziewam się, żeby coś podobnego do poniższego schematu:

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

ale zamiast dostaję to:

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

Zrobiłem kilka wykopalisk w kodzie źródłowym modułu Jackson Schema i zorientowałem się, że Jackson używa ".toString()" jako domyślnej metody serializacji dla typów enum, ale to, czego potrzebuję zamiast tego to stworzyć linię, która wygląda tak: w oparciu o StartDayOfWeek.values()

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

Czy ktoś wie jak to zrobić?

+0

Może chcesz spróbować JJSchema zamiast. – fge

+0

Biorąc pod uwagę, że otrzymuję NPE, gdy podążam za ich przykładem użycia, fakt, że nie było aktualizacji projektu w ciągu 6 miesięcy i fakt, że wciąż jest widocznie w stanie beta, nie sądzę, że to jest bardzo dobra opcja – StormeHawke

+0

Czy używasz niestandardowego deserializatora, aby poprawnie deserializować (tj. wyliczać, a nie jak łańcuch) wartości dni tygodnia? – user3159253

Odpowiedz

2

odpowiedź Storme za odwołuje org.codehaus, która jest starsza wersja Jackson. Poniższe jest podobne, ale używa metody quickxml (nowsza wersja).

Pom:

<dependency> 
    <groupId>com.fasterxml.jackson.core</groupId> 
    <artifactId>jackson-core</artifactId> 
    <version>2.7.1</version> 
</dependency> 
<dependency> 
    <groupId>com.fasterxml.jackson.core</groupId> 
    <artifactId>jackson-databind</artifactId> 
    <version>2.7.1</version> 
</dependency> 
<dependency> 
    <groupId>com.fasterxml.jackson.core</groupId> 
    <artifactId>jackson-annotations</artifactId> 
    <version>2.7.1</version> 
</dependency> 
<dependency> 
    <groupId>com.fasterxml.jackson.module</groupId> 
    <artifactId>jackson-module-jsonSchema</artifactId> 
    <version>2.1.0</version> 
</dependency> 

Kod:

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); 
    } 

} 
+1

Zauważ, że oba org.codehaus.jackson i com.fasterxml.jackson będą generować wersję vson schematu json, a nie v4. Więcej szczegółów na - https://github.com/FasterXML/jackson-module-jsonSchema/issues/9 –

11

Wydaje się, że nie jest to możliwe przy użyciu instrukcji, które znalazłem przy użyciu databind. Jednak znalazłem kolejny moduł jacksona, który wydaje się ładnie poradzić. Dziwnie kilka obiektów nosi taką samą nazwę.

TLDR: należy używać obiektów z pakietu org.codehaus.jackson.map, a nie z pakietu com.fasterxml.jackson.databind. Jeśli postępujesz zgodnie z instrukcjami na stronie this, robisz to źle. Po prostu użyj modułu jackson-mapper.

Oto kod dla przyszłych pracowników Google:

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); 
} 
+1

codehaus reprezentuje starszą wersję Jacksona, prawda? –

+0

Myślę, że tak. Wiem tylko, że to działało dla mnie tam, gdzie inne próby nie były potrzebne. – StormeHawke

Powiązane problemy