Jacksonでコンストラクタを利用してデシリアライズ
   2 min read

Jackson は引数なしコンストラクタが必要、というblogを目にしましたが、正しくありません。

  • @JsonCreator を付与することでそのコンストラクタを使ってデシリアライズするように指示できます。

    • コンストラクタが1つしか無い場合は省略できます。

  • JSON プロパティと Java フィールドのマッピングは @JsonProperty で行えます。

    • jackson-module-parameter-names を利用すると、メソッドシグネチャのパラメータを利用してマッピングできるので、この設定を省略できます。

      • ちなみに、この機能は Jackson 3.x では本体(jackson-databind)に統合されるようです。(2.x は Java7 以前もサポート対象にしているので Java8 以降の機能は切り出しているみたいです)

というわけで、今 Jackson を使うなら、次のようにすれば良いです:

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.module.paramnames.ParameterNamesModule;
import lombok.RequiredArgsConstructor;
import lombok.Value;

public class JavaMain {
    public static final String JSON_TEXT = "{\"name\": \"Bob\", \"age\": 30 }";

    public static void main(String[] args) throws JsonProcessingException {
        ObjectMapper om = new ObjectMapper();
        om.registerModule(new ParameterNamesModule());

        Person person = om.readValue(JSON_TEXT, Person.class);
        System.out.println(person);
    }
}

@Value
// ちなみに Lombok を使っていて自動生成されるコンストラクタにアノテーションを付与したい場合は:
// @RequiredArgsConstructor(onConstructor = @__(@JsonCreator))

class Person {
    String name;
    int age;
}

Java17 なら record class に置き換えられるので、 Person はもはや Lombok を利用しなくとも簡単に書けるようになりました:

record Person(String name, int age) {
}

コンパイルオプションに、メソッドシグネチャに仮引数名を残す設定 -parameters を追加する必要もあります。

これは、 maven-compiler-pluginparameterstrue にすることで実現できます。

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>3.10.1</version>
    <configuration>
        <parameters>true</parameters>
    </configuration>

プラグインのバージョンが古い(3.6.2 未満)場合はこのオプションが無いので、代わりに compilerArgs で設定します。

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>3.5.1</version>
    <configuration>
        <compilerArgs>
            <arg>-parameters</arg>
        </compilerArgs>
    </configuration>
    ...

関連: