web-dev-qa-db-ja.com

ひねりを加えたPOJOからのJsonスキーマの生成

私が持っているもの:

PojoからJSONスキーマを生成しています。スキーマを生成する私のコードは次のようになります。

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

上記のコードでいくつかのスキーマを生成しています。 pojoの1つには、次のように、可能な値を制限するための内部列挙型があります。

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

    }

}
_

上記のコードは、渡されるJSONデータの可能なString値を「Monday」、「Tuesday」、「Wednesday」などに制限する必要があります。

問題のコードでスキーマジェネレーターを実行すると、次のスキーマのようなものが得られます。

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

しかし、代わりに私はこれを取得しています:

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

Jacksonスキーマモジュールのソースコードを掘り下げて、ジャクソンが列挙型のデフォルトのシリアル化メソッドとして「.toString()」を使用していることがわかったが、代わりに次の行を作成する必要があるStartDayOfWeek.values()に基づいてこのように見えます:

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

誰かがそれを行う方法を知っていますか?

13
StormeHawke

Stormeの回答は、古いバージョンのジャクソンであるorg.codehausを参照しています。以下は似ていますが、fasterxml(新しいバージョン)を使用しています。

ポン:

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

コード:

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

}
6
James Oravec

Databindを使用して見つけた手順を使用してそれを行うことはできないようです。しかし、私はトリックをうまくやっているように見える別のジャクソンモジュールを見つけました。奇妙なことに、いくつかのオブジェクトは同じ名前が付けられています。

TLDR:org.codehaus.jackson.mapパッケージではなく、com.fasterxml.jackson.databindパッケージのオブジェクトを使用します。 this ページの指示に従っている場合、それは間違っています。代わりにjackson-mapperモジュールを使用してください。

将来の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);
}
18
StormeHawke

誰かがここに来て、彼のコードで最新のドラフトバージョンをサポートしたい場合。

お好みの言語についてはこちらをご覧ください: https://json-schema.org/implementations.html

1
rufreakde