LoginSignup
15
17

More than 3 years have passed since last update.

Java ライブラリである Jackson の @JsonProperty アノテーションを使って JSON をパースしてオブジェクト化する

Last updated at Posted at 2019-06-06

概要

  • Java の JSON ライブラリである Jackson を使う
  • いくつかの書き方で JSON 文字列をパースしてオブジェクト化してみる
  • @ JsonProperty アノテーションを使ってオブジェクト化する
  • 比較用にアノテーションを使わない書き方もやってみる

今回のパース対象の JSON

{
  "user": {
    "name": "Pompom Pudding",
    "score": {
      "kokugo": "good",
      "sansuu": 100
    },
    "favorites": ["soccer", "puzzle"]
  }
}

いくつかの書き方で JSON をパースしてオブジェクト化する

クラスを用意せずに Map オブジェクトを直接生成する場合 (アノテーション不使用)

ObjectMapper#readValue の第二引数に Map.class を渡せば Map オブジェクトを取得できる。
オブジェクトを生成するのはシンプルだが、生成されたオブジェクトから目的のデータを取り出すのが複雑になる。

ObjectMapper mapper = new ObjectMapper();
Map obj = mapper.readValue(json, Map.class);
System.out.println(obj);
String name = (String)(((Map)obj.get("user")).get("name"));
System.out.println("name=" + name);

出力例。

{user={name=Pompom Pudding, score={kokugo=good, sansuu=100}, favorites=[soccer, puzzle]}}
name=Pompom Pudding

クラスに public なインスタンス変数を用意する場合 (アノテーション不使用)

public なインスタンス変数、または getter setter を用意することでオブジェクト化することが可能になる。
その場合 @ JsonProperty アノテーションを記述する必要は無い。

import java.util.Map;
public class PublicUserObject {
  public Map user;
}
ObjectMapper mapper = new ObjectMapper();
PublicUserObject obj = mapper.readValue(json, PublicUserObject.class);
System.out.println(obj);
String name = (String)obj.user.get("name");
System.out.println("name=" + name);

出力例。

PublicUserObject@e6abefac
name=Pompom Pudding

クラスに private なインスタンス変数を用意する場合 (アノテーション使用)

private なインスタンス変数を使う場合は @ JsonProperty にてマッピングしたい JSON のキー(名前)を指定する必要がある。

import java.util.Map;
import com.fasterxml.jackson.annotation.JsonProperty;

public class SimpleUserObject {

  @JsonProperty("user")
  private Map user;

  public Map getUser() {
    return user;
  }

  @Override
  public String toString() {
    return getClass().getName() + ": user:" + user;
  }
}
ObjectMapper mapper = new ObjectMapper();
SimpleUserObject obj = mapper.readValue(json, SimpleUserObject.class);
System.out.println(obj);
String name = (String) obj.getUser().get("name");
System.out.println("name=" + name);

出力例。

SimpleUserObject: user:{name=Pompom Pudding, score={kokugo=good, sansuu=100}, favorites=[soccer, puzzle]}
name=Pompom Pudding

クラスに private なインスタンス変数とアクセス用のメソッドを用意した場合 (アノテーション使用)

もう少ししっかりアクセサメソッドを作っておくと外部のクラスから使いやすくなる。

import java.util.List;
import java.util.Map;
import com.fasterxml.jackson.annotation.JsonProperty;

public class AccessorUserObject {

  @JsonProperty("user")
  private Map user;

  public String getName() {
    return (String) user.get("name");
  }

  private Map getScore() {
    return (Map) user.get("score");
  }

  public String getKokugoScore() {
    return (String) getScore().get("kokugo");
  }

  public int getSansuuScore() {
    return (int) getScore().get("sansuu");
  }

  public List getFavorites() {
    return (List) user.get("favorites");
  }

  @Override
  public String toString() {
    return getClass().getName() +
        ", getName: " + getName() +
        ", getKokugoScore: " + getKokugoScore() +
        ", getSansuuScore: " + getSansuuScore() +
        ", getFavorites: " + getFavorites();
  }
}
ObjectMapper mapper = new ObjectMapper();
AccessorUserObject obj = mapper.readValue(json, AccessorUserObject.class);
System.out.println(obj);
String name = obj.getName();
System.out.println("name=" + name);

出力例。

AccessorUserObject, getName: Pompom Pudding, getKokugoScore: good, getSansuuScore: 100, getFavorites: [soccer, puzzle]
name=Pompom Pudding

マッピング用のクラスを用意した場合 (アノテーション使用)

JSON データをマッピングするためのクラスと内部クラスを用意する。

import java.util.List;
import com.fasterxml.jackson.annotation.JsonProperty;

public class StructedUserObject {

  @JsonProperty("user")
  public User user;

  public static class User {

    public String name;
    public Score score;
    public List favorites;

    @Override
    public String toString() {
      return getClass().getSimpleName()
          + ": name: " + name
          + ", score: " + score
          + ", favorites: " + favorites;
    }
  }

  public static class Score {

    public String kokugo;
    public int sansuu;

    @Override
    public String toString() {
      return getClass().getSimpleName()
          + ": kokugo: " + kokugo
          + ", sansuu: " + sansuu;
    }
  }

  @Override
  public String toString() {
    return getClass().getName() + ": user:" + user;
  }
}
ObjectMapper mapper = new ObjectMapper();
StructedUserObject obj = mapper.readValue(json, StructedUserObject.class);
System.out.println(obj);
String name = obj.user.name;
System.out.println("name=" + name);

出力例。

StructedUserObject: user:User: name: Pompom Pudding, score: Score: kokugo: good, sansuu: 100, favorites: [soccer, puzzle]
name=Pompom Pudding

今回の動作確認に使ったファイルと実行環境

Java と Maven

$ mvn --version
Apache Maven 3.6.1 (d66c9c0b3152b2e69ee9bac180bb8fcc8e6af555; 2019-04-05T04:00:29+09:00)
Maven home: /usr/local/Cellar/maven/3.6.1/libexec
Java version: 11.0.2, vendor: Oracle Corporation, runtime: /Library/Java/JavaVirtualMachines/openjdk-11.0.2.jdk/Contents/Home
Default locale: ja_JP, platform encoding: UTF-8
OS name: "mac os x", version: "10.14.5", arch: "x86_64", family: "mac"

ファイル一覧

├── pom.xml
├── src
│   └── main
│       └── java
│           └── info
│               └── maigo
│                   └── lab
│                       └── myjacksonsamples
│                           ├── AccessorUserObject.java
│                           ├── Main.java
│                           ├── PublicUserObject.java
│                           ├── SimpleUserObject.java
│                           └── StructedUserObject.java
└── user.json

pom.xml

Maven でビルド&実行できるように pom.xml ファイルを用意する。
dependencies に Jackson ライブラリ jackson-core, jackson-databind, jackson-annotations を追加する。
Maven から Java プログラムを実行できるように plugins に exec-maven-plugin を追加する。

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>info.maigo.lab</groupId>
  <artifactId>my-jackson-samples</artifactId>
  <version>1.0-SNAPSHOT</version>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>11</maven.compiler.source>
    <maven.compiler.target>11</maven.compiler.target>
  </properties>

  <!-- $ mvn exec:java -->
  <!-- https://www.mojohaus.org/exec-maven-plugin/ -->
  <build>
    <plugins>
      <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>exec-maven-plugin</artifactId>
        <version>1.6.0</version>
        <configuration>
          <mainClass>info.maigo.lab.myjacksonsamples.Main</mainClass>
        </configuration>
      </plugin>
    </plugins>
  </build>

  <dependencies>

    <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core -->
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-core</artifactId>
      <version>2.9.9</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
      <version>2.9.9</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations -->
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-annotations</artifactId>
      <version>2.9.9</version>
    </dependency>

  </dependencies>

</project>

JAR ファイルを生成するコマンド。

$ mvn package

サンプルプログラムを実行するコマンド。

$ mvn exec:java

Java ソースコード

Main.java

package info.maigo.lab.myjacksonsamples;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Map;

import com.fasterxml.jackson.databind.ObjectMapper;

public class Main {

    public static void main(String[] args) throws IOException {
        String json = Files.readString(Path.of("user.json"), StandardCharsets.UTF_8);
        createMappedUserObject(json);
        createPublicUserObject(json);
        createSimpleUserObject(json);
        createAccessorUserObject(json);
        createStructedUserObject(json);
    }

    private static void createMappedUserObject(String json) throws IOException {
        ObjectMapper mapper = new ObjectMapper();
        Map obj = mapper.readValue(json, Map.class);
        System.out.println(obj);
        String name = (String) (((Map) obj.get("user")).get("name"));
        System.out.println("name=" + name);
    }

    private static void createPublicUserObject(String json) throws IOException {
        ObjectMapper mapper = new ObjectMapper();
        PublicUserObject obj = mapper.readValue(json, PublicUserObject.class);
        System.out.println(obj);
        String name = (String) obj.user.get("name");
        System.out.println("name=" + name);
    }

    private static void createSimpleUserObject(String json) throws IOException {
        ObjectMapper mapper = new ObjectMapper();
        SimpleUserObject obj = mapper.readValue(json, SimpleUserObject.class);
        System.out.println(obj);
        String name = (String) obj.getUser().get("name");
        System.out.println("name=" + name);
    }

    private static void createAccessorUserObject(String json) throws IOException {
        ObjectMapper mapper = new ObjectMapper();
        AccessorUserObject obj = mapper.readValue(json, AccessorUserObject.class);
        System.out.println(obj);
        String name = obj.getName();
        System.out.println("name=" + name);
    }

    private static void createStructedUserObject(String json) throws IOException {
        ObjectMapper mapper = new ObjectMapper();
        StructedUserObject obj = mapper.readValue(json, StructedUserObject.class);
        System.out.println(obj);
        String name = obj.user.name;
        System.out.println("name=" + name);
    }
}

PublicUserObject.java

package info.maigo.lab.myjacksonsamples;

import java.util.Map;

public class PublicUserObject {

    public Map user;

}

SimpleUserObject.java

package info.maigo.lab.myjacksonsamples;

import com.fasterxml.jackson.annotation.JsonProperty;

import java.util.Map;

public class SimpleUserObject {

    @JsonProperty("user")
    private Map user;


    public Map getUser() {
        return user;
    }

    @Override
    public String toString() {
        return getClass().getName() + ": user:" + user;
    }
}

AccessorUserObject.java

package info.maigo.lab.myjacksonsamples;

import java.util.List;
import java.util.Map;

import com.fasterxml.jackson.annotation.JsonProperty;

public class AccessorUserObject {

    @JsonProperty("user")
    private Map user;

    public String getName() {
        return (String) user.get("name");
    }

    private Map getScore() {
        return (Map) user.get("score");
    }

    public String getKokugoScore() {
        return (String) getScore().get("kokugo");
    }

    public int getSansuuScore() {
        return (int) getScore().get("sansuu");
    }

    public List getFavorites() {
        return (List) user.get("favorites");
    }

    @Override
    public String toString() {
        return getClass().getName() +
                ", getName: " + getName() +
                ", getKokugoScore: " + getKokugoScore() +
                ", getSansuuScore: " + getSansuuScore() +
                ", getFavorites: " + getFavorites();
    }
}

StructedUserObject.java

package info.maigo.lab.myjacksonsamples;

import java.util.List;

import com.fasterxml.jackson.annotation.JsonProperty;

public class StructedUserObject {

    @JsonProperty("user")
    public User user;

    public static class User {

        public String name;
        public Score score;
        public List favorites;

        @Override
        public String toString() {
            return getClass().getSimpleName()
                    + ": name: " + name
                    + ", score: " + score
                    + ", favorites: " + favorites;
        }
    }

    public static class Score {

        public String kokugo;
        public int sansuu;

        @Override
        public String toString() {
            return getClass().getSimpleName()
                    + ": kokugo: " + kokugo
                    + ", sansuu: " + sansuu;
        }
    }

    @Override
    public String toString() {
        return getClass().getName() + ": user:" + user;
    }
}

user.json

{
  "user": {
    "name": "Pompom Pudding",
    "score": {
      "kokugo": "good",
      "sansuu": 100
    },
    "favorites": ["soccer", "puzzle"]
  }
}

参考資料

15
17
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
15
17