この記事から得られる知識
この記事を読むことで、あなたは以下の知識を体系的に習得できます。
- Gsonライブラリの基本的な概念とプロジェクトへの導入方法
- JavaオブジェクトとJSON文字列間の基本的な変換(シリアライズ・デシリアライズ)
- ネストしたオブジェクト、リスト、マップなどの複雑なデータ構造の取り扱い
GsonBuilder
を使用したGsonインスタンスの高度なカスタマイズ方法(Pretty Printing、nullの処理など)@SerializedName
アノテーションによるJavaフィールド名とJSONキー名のマッピングExclusionStrategy
や@Expose
を用いた、特定のフィールドを変換対象から除外するテクニック- ジェネリクス型を安全に扱うための
TypeToken
の利用方法 - Java 8以降の日時APIなど、標準で対応していない型を扱うためのカスタムシリアライザ・デシリアライザの実装方法
はじめに:Gsonとは何か?
Gson(ジーソン)は、Googleによって開発されたオープンソースのJavaライブラリです。その主な目的は、JavaオブジェクトをJSON(JavaScript Object Notation)形式の文字列に変換(シリアライズ)したり、その逆のJSON文字列を等価なJavaオブジェクトに変換(デシリアライズ)したりすることです。
現代の多くのWebアプリケーションやサービスでは、サーバーとクライアント間、あるいはサービス間のデータ交換形式としてJSONが広く採用されています。Javaで開発を行う上で、このJSONデータを効率的かつ安全に扱うことは非常に重要です。Gsonは、そのシンプルで直感的なAPIと高い信頼性から、多くのJava開発者に選ばれ続けているライブラリです。
Gsonの大きな特徴の一つは、変換対象となるJavaクラスに特別なアノテーションを付与する必要が基本的にはない点です。既存の改変できないクラスであっても、容易にJSONとの相互変換が可能です。また、Javaのジェネリクスを広範囲にサポートしているため、複雑なデータ構造も柔軟に扱うことができます。
第1章: Gsonのセットアップと基本的な使い方
プロジェクトへの導入
Gsonを利用するためには、まずプロジェクトの依存関係にGsonライブラリを追加する必要があります。ビルドツールとしてMavenまたはGradleを使用するのが一般的です。
Mavenの場合 (`pom.xml`)
<dependencies>
タグ内に以下の<dependency>
を追加します。バージョンは執筆時点で比較的新しいものを記載していますが、Maven Centralで最新のバージョンを確認することをお勧めします。
<!-- https://mvnrepository.com/artifact/com.google.code.gson/gson -->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.13.1</version>
</dependency>
Gradleの場合 (`build.gradle`)
dependencies
ブロックに以下の行を追加します。
// https://mvnrepository.com/artifact/com.google.code.gson/gson
implementation 'com.google.code.gson:gson:2.13.1'
Gsonインスタンスの生成
Gsonの機能を利用するには、まずcom.google.gson.Gson
クラスのインスタンスを生成します。最も簡単な方法は、デフォルトコンストラクタを呼び出すことです。
import com.google.gson.Gson;
public class Main {
public static void main(String[] args) {
// 最も基本的なGsonインスタンスの生成
Gson gson = new Gson();
System.out.println("Gsonインスタンスが生成されました。");
}
}
Gsonインスタンスの再利用
Gson
オブジェクトは、JSON操作中に内部状態を保持しません。つまり、スレッドセーフであり、複数のシリアライズ・デシリアライズ操作で同じインスタンスを安全に再利用できます。パフォーマンス向上の観点からも、操作のたびに新しいインスタンスを生成するのではなく、一度生成したインスタンスをアプリケーション全体で共有・再利用することが推奨されます。
第2章: JavaオブジェクトからJSONへ (シリアライズ)
JavaオブジェクトをJSON文字列に変換するプロセスをシリアライズと呼びます。Gsonでは、toJson()
メソッドを使用します。
基本的なデータ型のシリアライズ
プリミティブ型やそのラッパークラス、文字列、配列などを簡単にJSONに変換できます。
import com.google.gson.Gson;
public class SerializationBasic {
public static void main(String[] args) {
Gson gson = new Gson();
// プリミティブ型
System.out.println("int: " + gson.toJson(100)); // 出力: 100
System.out.println("String: " + gson.toJson("Hello, Gson!")); // 出力: "Hello, Gson!"
System.out.println("boolean: " + gson.toJson(true)); // 出力: true
System.out.println("double: " + gson.toJson(99.99)); // 出力: 99.99
// 配列
int[] numbers = {1, 2, 3, 4, 5};
System.out.println("Array: " + gson.toJson(numbers)); // 出力:
String[] fruits = {"Apple", "Banana", "Cherry"};
System.out.println("String Array: " + gson.toJson(fruits)); // 出力: ["Apple","Banana","Cherry"]
}
}
POJO (Plain Old Java Object) のシリアライズ
実際のアプリケーション開発では、独自のクラス(POJO)をJSONに変換する場面がほとんどです。以下のようなUser
クラスを例に見てみましょう。
// 変換対象のUserクラス
public class User {
private String name;
private int age;
private String email;
private boolean isDeveloper;
private Address address; // ネストしたオブジェクト
private String[] skills; // 配列
public User(String name, int age, String email, boolean isDeveloper, Address address, String[] skills) {
this.name = name;
this.age = age;
this.email = email;
this.isDeveloper = isDeveloper;
this.address = address;
this.skills = skills;
}
// getter/setterは省略
}
// Userクラスが持つAddressクラス
public class Address {
private String country;
private String city;
public Address(String country, String city) {
this.country = country;
this.city = city;
}
// getter/setterは省略
}
このUser
オブジェクトをシリアライズするコードは以下のようになります。
import com.google.gson.Gson;
public class SerializeObject {
public static void main(String[] args) {
Gson gson = new Gson();
Address address = new Address("Japan", "Tokyo");
String[] skills = {"Java", "SQL", "Cloud"};
User user = new User("Taro Yamada", 30, "taro.yamada@example.com", true, address, skills);
String jsonOutput = gson.toJson(user);
System.out.println(jsonOutput);
}
}
実行結果 (JSON):
{"name":"Taro Yamada","age":30,"email":"taro.yamada@example.com","isDeveloper":true,"address":{"country":"Japan","city":"Tokyo"},"skills":["Java","SQL","Cloud"]}
ご覧の通り、ネストされたオブジェクトや配列を含む複雑なオブジェクトも、toJson()
メソッドを一度呼び出すだけで、期待通りのJSON文字列に変換されていることがわかります。
第3章: JSONからJavaオブジェクトへ (デシリアライズ)
JSON文字列をJavaオブジェクトに変換するプロセスをデシリアライズと呼びます。Gsonでは、fromJson()
メソッドを使用します。
このメソッドは2つの引数を取ります。第一引数にJSON文字列、第二引数に変換先のJavaクラスのClass
オブジェクトを指定します。
単純なJSONのデシリアライズ
前章で作成したUser
クラスと対応するJSON文字列を使って、デシリアライズを試してみましょう。
import com.google.gson.Gson;
public class DeserializeObject {
public static void main(String[] args) {
Gson gson = new Gson();
String jsonInput = "{\"name\":\"Hanako Tanaka\",\"age\":25,\"email\":\"hanako.tanaka@example.com\",\"isDeveloper\":false,\"address\":{\"country\":\"USA\",\"city\":\"New York\"},\"skills\":[\"Python\",\"Marketing\"]}";
// JSONからUserオブジェクトに変換
User user = gson.fromJson(jsonInput, User.class);
// 結果の確認
System.out.println("Name: " + user.getName());
System.out.println("Age: " + user.getAge());
System.out.println("City: " + user.getAddress().getCity());
System.out.println("First Skill: " + user.getSkills());
}
}
JSONのキー名とJavaクラスのフィールド名が一致していれば、Gsonが自動的にマッピングを行い、オブジェクトを正しく復元してくれます。
JSON配列からJavaのListへ
JSONがオブジェクトの配列である場合、JavaのList
にデシリアライズしたいケースが頻繁にあります。しかし、ここにはJavaの型消去(Type Erasure)という特性による注意点があります。
単純にgson.fromJson(jsonArray, List.class)
と記述しても、Gsonはリストの要素がどの型(User
なのかAddress
なのか)であるかを実行時に知ることができません。この問題を解決するために、GsonはTypeToken
というクラスを提供しています。
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import java.lang.reflect.Type;
import java.util.List;
public class DeserializeList {
public static void main(String[] args) {
Gson gson = new Gson();
String jsonArrayInput = "[{\"name\":\"Taro Yamada\",\"age\":30},{\"name\":\"Hanako Tanaka\",\"age\":25}]";
// ★ TypeTokenを使ってList<User>の型情報を取得
Type userListType = new TypeToken<List<User>>(){}.getType();
// JSON配列をList<User>に変換
List<User> userList = gson.fromJson(jsonArrayInput, userListType);
// 結果の確認
for (User user : userList) {
System.out.println("User: " + user.getName() + ", Age: " + user.getAge());
}
}
}
ポイント: new TypeToken<List<User>>(){}.getType()
という少し奇妙な構文は、匿名内部クラスを作成することで、ジェネリクスの型情報(この場合はList<User>
)を実行時まで保持するためのテクニックです。これにより、Gsonは正しくList<User>
を生成できます。
第4章: Gsonを使いこなすための応用テクニック
Gsonの真価は、その高いカスタマイズ性にあります。GsonBuilder
クラスを使うことで、様々な挙動を細かく制御できます。
GsonBuilderによるインスタンスのカスタマイズ
new Gson()
の代わりにnew GsonBuilder().create()
を使うことで、カスタマイズされたGson
インスタンスを生成できます。
メソッド | 説明 |
---|---|
setPrettyPrinting() |
JSONの出力をインデントや改行を含む、人間が読みやすい形式(Pretty Print)にします。デバッグ時に非常に役立ちます。 |
serializeNulls() |
デフォルトでは、Gsonは値がnull のフィールドをシリアライズ時に無視(出力しない)します。このメソッドを呼び出すと、null のフィールドも"fieldName": null という形式でJSONに出力されるようになります。 |
setDateFormat(String pattern) |
java.util.Date 型のフィールドを、指定したパターン(例: "yyyy-MM-dd HH:mm:ss" )でシリアライズ・デシリアライズします。 |
addSerializationExclusionStrategy(ExclusionStrategy) |
シリアライズ時に特定のフィールドを除外するためのカスタム戦略(ExclusionStrategy)を追加します。 |
registerTypeAdapter(Type, Object) |
特定の型に対して、カスタムのシリアライザやデシリアライザを登録します。 |
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
public class GsonBuilderExample {
public static void main(String[] args) {
// GsonBuilderを使ってカスタマイズ
Gson gson = new GsonBuilder()
.setPrettyPrinting() // Pretty Printを有効化
.serializeNulls() // null値もシリアライズ
.setDateFormat("yyyy/MM/dd") // Date型のフォーマットを指定
.create();
User user = new User("Jiro Suzuki", 35, null, true, null, null); // emailなどがnull
String jsonOutput = gson.toJson(user);
System.out.println(jsonOutput);
}
}
実行結果 (Pretty Printed JSON):
{
"name": "Jiro Suzuki",
"age": 35,
"email": null,
"isDeveloper": true,
"address": null,
"skills": null
}
setPrettyPrinting()
によって整形され、serializeNulls()
によってnull
のフィールドも出力されていることが確認できます。
@SerializedName: JSONキー名とフィールド名のマッピング
JSONのキー名がJavaの命名規則(例: snake_case
)と異なり、Javaクラスのフィールド名(例: camelCase
)と直接マッピングできない場合があります。このような場合、@SerializedName
アノテーションが役立ちます。
import com.google.gson.annotations.SerializedName;
public class Product {
// JSONの "product_id" キーをこのフィールドにマッピング
@SerializedName("product_id")
private int productId;
// "productName" はキー名が同じなのでアノテーション不要
private String productName;
// JSONの "price_in_yen" キーをこのフィールドにマッピング
@SerializedName("price_in_yen")
private double priceInYen;
// 複数のキー名をマッピングすることも可能(デシリアライズ時)
@SerializedName(value = "in_stock", alternate = {"is_available"})
private boolean inStock;
// コンストラクタ、getter/setterは省略
}
このアノテーションにより、Gsonはシリアライズ・デシリアライズ時に指定された名前を使ってマッピングを行います。alternate
属性を使えば、デシリアライズ時に複数の異なるキー名に対応させることも可能です。
フィールドの除外: @Expose と ExclusionStrategy
特定のフィールドをJSON変換の対象から外したい場合があります。Gsonにはいくつかの方法が用意されています。
transient
キーワード: Javaのtransient
修飾子が付いたフィールドは、デフォルトでシリアライズの対象外となります。最も手軽な方法ですが、Gson以外のシリアライズ機構にも影響を与える可能性があります。-
@Expose
アノテーション: より細かく制御したい場合に用います。このアノテーションを使うには、GsonBuilder
でexcludeFieldsWithoutExposeAnnotation()
を呼び出す必要があります。これにより、@Expose
が付与されたフィールドのみが変換対象となります。public class Employee { @Expose private String name; @Expose(serialize = true, deserialize = false) // シリアライズのみ対象 private int employeeId; private String password; // @Exposeがないので対象外 // ... } // Gsonインスタンスの生成 Gson gson = new GsonBuilder() .excludeFieldsWithoutExposeAnnotation() .create();
-
ExclusionStrategy
: 最も柔軟な方法です。特定のクラス型、アノテーション、フィールド修飾子など、独自の条件に基づいてフィールドを除外するロジックを実装できます。import com.google.gson.*; // 特定のアノテーションが付いたフィールドを除外する戦略 public @interface SkipSerialization {} ExclusionStrategy strategy = new ExclusionStrategy() { @Override public boolean shouldSkipField(FieldAttributes f) { // @SkipSerializationアノテーションが付いていれば除外 return f.getAnnotation(SkipSerialization.class) != null; } @Override public boolean shouldSkipClass(Class<?> clazz) { return false; } }; Gson gson = new GsonBuilder() .setExclusionStrategies(strategy) .create();
カスタム(デ)シリアライザ: 日時など特殊な型の扱い
Gsonはjava.util.Date
には対応していますが、Java 8で導入された新しい日時API(java.time.LocalDate
, java.time.LocalDateTime
など)にはデフォルトで対応していません。これらの型を扱うには、カスタムのシリアライザとデシリアライザを登録する必要があります。
ここではLocalDate
を例に、ISO 8601形式(例: “2025-07-14″)の文字列に変換するアダプタを作成します。
import com.google.gson.*;
import java.lang.reflect.Type;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
// LocalDate用のTypeAdapterを実装
class LocalDateAdapter implements JsonSerializer<LocalDate>, JsonDeserializer<LocalDate> {
private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ISO_LOCAL_DATE;
@Override
public JsonElement serialize(LocalDate src, Type typeOfSrc, JsonSerializationContext context) {
return new JsonPrimitive(FORMATTER.format(src));
}
@Override
public LocalDate deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
return FORMATTER.parse(json.getAsString(), LocalDate::from);
}
}
public class CustomSerializerExample {
public static void main(String[] args) {
Gson gson = new GsonBuilder()
.registerTypeAdapter(LocalDate.class, new LocalDateAdapter())
.setPrettyPrinting()
.create();
Event event = new Event("Tech Conference", LocalDate.of(2025, 10, 24));
String json = gson.toJson(event);
System.out.println("Serialized JSON:\n" + json);
Event deserializedEvent = gson.fromJson(json, Event.class);
System.out.println("\nDeserialized Event Date: " + deserializedEvent.getDate());
}
}
class Event {
private String name;
private LocalDate date;
// コンストラクタ、getter/setter
}
このようにJsonSerializer
とJsonDeserializer
インターフェースを実装したクラスを作成し、GsonBuilder
にregisterTypeAdapter
で登録することで、あらゆるカスタム型に対応できるようになります。
第5章: 実践的なユースケースと注意点
Web APIとの連携
Gsonの最も一般的な用途は、REST APIとの通信です。クライアントとしてAPIにリクエストを送信する際は、リクエストボディとなるJavaオブジェクトをtoJson()
でJSON文字列に変換します。逆にAPIからレスポンスを受け取った際は、そのJSON文字列をfromJson()
でJavaオブジェクトに変換し、アプリケーションで利用します。
設定ファイルの読み書き
アプリケーションの設定をJSONファイルで管理する際にもGsonは便利です。設定項目を保持するクラスを定義し、起動時にJSONファイルを読み込んでfromJson()
で設定オブジェクトを生成したり、設定変更時にtoJson()
でファイルに書き出したりすることができます。
パフォーマンスに関する注意
前述の通り、Gson
インスタンスはスレッドセーフであり、生成にはコストがかかります。特にGsonBuilder
で複雑な設定を行っている場合、そのコストは無視できません。アプリケーション内でインスタンスをシングルトンとして管理するか、DI(Dependency Injection)フレームワークを利用して注入するなど、インスタンスの再利用を心がけてください。
よくある例外: JsonSyntaxException
デシリアライズ時によく遭遇するのがJsonSyntaxException
です。これは、渡された文字列が有効なJSON形式ではないことを示しています。原因としては、JSONの構文エラー(カンマの付け忘れ、括弧の不一致など)、予期しないデータ型(数値であるべき箇所に文字列が入っているなど)が考えられます。この例外が発生した場合は、入力されたJSON文字列の内容をまず確認することが重要です。
Androidでの利用について
GsonはAndroid開発でも広く使われてきましたが、公式リポジトリでは注意が喚起されています。Gsonはリフレクションを多用するため、R8 (ProGuard) などによるコードの圧縮・難読化・最適化と相性が悪く、実行時エラーを引き起こす可能性があります。Androidのネイティブ開発では、リフレクションではなくコード生成を利用するMoshiやKotlinx Serializationなどのライブラリの使用が推奨されています。
まとめ
本記事では、JavaライブラリGsonの基本的な使い方から、GsonBuilder
や各種アノテーション、カスタムアダプタを用いた応用的なテクニックまで、幅広く解説しました。Gsonは、そのシンプルさと強力なカスタマイズ性により、JavaにおけるJSON処理のデファクトスタンダードの一つとしての地位を確立しています。
基本的なシリアライズ・デシリアライズは数行のコードで実現でき、複雑な要件にもExclusionStrategy
やカスタムTypeAdapter
で柔軟に対応できます。この記事で紹介した知識を活用すれば、あなたのJavaアプリケーションにおけるデータ交換処理を、より効率的で堅牢なものにできるはずです。
Gsonをマスターすることで、Web API連携や設定管理など、モダンなアプリケーション開発に不可欠なJSON操作を自信を持って行えるようになります。ぜひ、実際のプロジェクトで活用してみてください。