概要
- 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"]
}
}