Jsonパーサーライブラリ『Jackson』が最高すぎる件

この記事は、ラクスパートナーズ AdventCalendar 2024の5日目の記事となります。

## はじめに

ラクスパートナーズ 開発エンジニア 齋藤です。 今年も残すところ一か月を切ったらしく、町はイルミネーションでキラキラしてますね。 イルミネーションは割と好きで毎年見に行ってるんですが、今年はなんと丸の内でマリオのイルミネーションがやってますので是非見に行ってみてください。
[MARUNOUCHI BRIGHT HOLIDAY 2024 ～LET’S PLAY in MARUNOUCHI with SUPER MARIO～](https://www.marunouchi.com/lp/brightholiday/)

さて、話を本題に戻して今回紹介するのはJavaのJsonパーサーライブラリである`Jackson`です。 最近、業務で存在を知って感動したのでおすそ分けです。 よかったら読んでいってください。

## 対象読者
- Java, Kotlinユーザー
- この記事にたどり着いたすべての人

## 目次
1. 使い方
1. 機能
1. まとめ

## 1. 使い方

### 必要な依存関係の追加
Jacksonを使用するには、以下のようにGradleに依存関係を追加します。
```
implementation 'com.fasterxml.jackson.core:jackson-databind:2.15.2'
```
バージョンは適宜読み替えてください。

### シリアライズとデシリアライズ

#### デシリアライズ（Json→Javaオブジェクト）
Jacksonでは、JSON文字列をオブジェクトに変換（デシリアライズ）するのが非常に簡単です。
例えば、以下のようなJSONデータがあるとします。

```json
{
  "id": 1,
  "name": "ラクスパートナーズ",
  "isExist": true
}
```

対応するクラスを用意します
```java
public class Company {
    private int id;
    private String name;
    private boolean isExist;

    // getter, setter
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public boolean isExist() {
        return isExist;
    }
    public void setPartner(boolean isExist) {
        this.isExist = isExist;
    }
}

```

JSONをデシリアライズするコード
```java
import com.fasterxml.jackson.databind.ObjectMapper;

public class Main {
    public static void main(String[] args) throws Exception {
        String json = """
            {
                "id": 1,
                "name": "ラクスパートナーズ",
                "isExist": true
            }
        """;

        ObjectMapper objectMapper = new ObjectMapper();
        Company company = objectMapper.readValue(json, Company.class);

        System.out.println("ID: " + company.getId());
        System.out.println("Name: " + company.getName());
        System.out.println("Is Exist: " + company.isExist());
    }
}

```

実行結果
```java
ID: 1
Name: ラクスパートナーズ
Is Exist: true
```

#### シリアライズ（Javaオブジェクト→Json）
先程とは反対にシリアライズも簡単に行ことができます。

```java
import com.fasterxml.jackson.databind.ObjectMapper;

public class Main {
    public static void main(String[] args) throws Exception {
        Company company = new Company();
        company.setId(1);
        company.setName("ラクスパートナーズ");
        company.setIsExist(true);

        ObjectMapper objectMapper = new ObjectMapper();
        String json = objectMapper.writeValueAsString(company);

        System.out.println(json);
    }
}

```

実行結果
```json
{"id":1,"name":"ラクスパートナーズ","isExist":true}
```

ここまででJacksonの導入とシリアライズ/デシリアライズについて説明しました。
次の項ではよりいろいろな機能について紹介します。

## 2. 機能

#### `@JsonProperty`
以下のようなスネークケースのJSONをJavaクラスにマッピングする例を示します。
```json
{
  "company_id": 1,
  "company_name": "ラクスパートナーズ"
}
```

対応するJavaクラス
```java
import com.fasterxml.jackson.annotation.JsonProperty;

public class Company {
    @JsonProperty("company_id")
    private int id;

    @JsonProperty("company_name")
    private String name;

    // getter, setter略
}
```
これでjsonファイルとJavaクラスの変数名が異なる場合でも正しく対応付けすることが可能です。

#### `@JsonIgnore`
JSONデータに含まれないフィールドを無視することができます

**無視フィールド**
```java
import com.fasterxml.jackson.annotation.JsonIgnore;

public class User {
    private String name;

    @JsonIgnore
    private String password;

    // getter, setter略
}
```
`@JsonIgnore`を指定したフィールドは、シリアライズ・デシリアライズの対象外になります。したがって、今回の場合は`password`が無視されます。

#### `@JsonInclude(JsonInclude.Include.NON_NULL)`
**デフォルト値の設定**
```java
import com.fasterxml.jackson.annotation.JsonInclude;

@JsonInclude(JsonInclude.Include.NON_NULL)
public class User {
    private String name;
    private String role = "user";

    // getter, setter略
}
```

#### `@JsonNaming`
クラス全体に命名規則を適用することも可能です。

今回はスネークケースでみてみます

```java
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
import com.fasterxml.jackson.databind.annotation.JsonNaming;

@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
public class Company {
    private int companyId;
    private String companyName;

    // getter, setter
    public int getCompanyId() {
        return companyId;
    }

    public void setCompanyId(int companyId) {
        this.companyId = companyId;
    }

    public String getCompanyName() {
        return companyName;
    }

    public void setCompanyName(String companyName) {
        this.companyName = companyName;
    }
}

```

上記のクラスを使用すると以下のJsonをデシリアライズすることが可能です。
```json
{
  "company_id": 1,
  "company_name": "ラクスパートナーズ"
}
```
逆にJavaオブジェクトをシリアライズすると上記のjsonが生成されます。

Jacksonで使用可能な命名規則は下記のとおりです
- PropertyNamingStrategies.LowerCamelCaseStrategy キャメルケース (例: companyName)　
- PropertyNamingStrategies.SnakeCaseStrategy: スネークケース（例: company_name）
- PropertyNamingStrategies.KebabCaseStrategy: ケバブケース（例: company-name）
- PropertyNamingStrategies.UpperCamelCaseStrategy: パスカルケース（例: CompanyName）
- PropertyNamingStrategies.LowerCaseStrategy: すべて小文字（例: companyname）

※キャメルケースはデフォルトなので明示的に書かなくても使用可能です。

今回はこの辺でとどめておきますがポリモーフィズムに対応していたり、カスタムシリアライザーやカスタムデシリアライザーをさくせいすることで複雑なデータ構造もあつかうことができます。

## 3. まとめ
本記事ではJavaのJsonパーサーライブラリである`Jackson`について紹介をしました。 とても簡単かつ柔軟にJsonをあつかうことができるとおもいます。

`Jackson`のポイントおさらい
- シンプルな使い方
    - 導入はgradleに依存関係を追加するだけ
    - Jsonのシリアライズ・デシリアライズが簡単に書ける
- 様々な機能
    - 命名規則
    - フィールドの設定
    - カスタムシリアライザー・カスタムデシリアライザー
    - ポリモーフィズム対応
- 業務での使用例
    - REST APIのリクエストやレスポンスのデータ操作
    - 設定ファイルの読み込み

## 最後に
自分も詳しくしらべたのは最近だったのですが、簡単にこの記事が書けるくらい学習コストもひくく使いやすいので本当におすすめですJava, KotlinでJsonを扱うすべての人に届け。 ちなみに一番感動したのはクラス全体に適用できる命名規則ですね。可読性もあがるし、バグも減る一石二鳥です。