Gson

シリアライゼーションJavaJSONGoogleオブジェクトマッピングリフレクションアノテーション

ライブラリ

Gson

概要

GsonはGoogleが開発したJava用の高性能JSONライブラリです。JavaオブジェクトとJSON間の相互変換を簡潔なAPIで実現し、Spring Bootを含む多くのJavaフレームワークで標準的に使用されています。柔軟なアノテーション、カスタムアダプター、多様な設定オプションにより企業レベルでの複雑なシナリオに対応します。現在メンテナンスモードですが、バグ修正とマイナーアップデートは継続しており、Javaエコシステムで広く信頼されています。

詳細

Gson 2.13.1は、10年以上の開発実績を持つ成熟したライブラリです。2025年現在はメンテナンスモードに入っていますが、既存のバグ修正は継続され、安定したJSONシリアライゼーション機能を提供しています。シンプルなtoJson/fromJSONメソッド、豊富なアノテーション(@SerializedName、@JsonIgnore等)、TypeTokenによるジェネリクス対応、カスタムシリアライザー・デシリアライザーなど、Java開発者にとって親しみやすい設計となっています。ただし、Androidでの使用については注意が必要です。

主な特徴

  • シンプルAPI: toJson()とfromJson()の直感的なメソッド
  • 豊富なアノテーション: @SerializedName、@Expose、@Since等で細かい制御
  • ジェネリクス対応: TypeTokenによる型安全なコレクション処理
  • カスタマイズ性: カスタムシリアライザー・デシリアライザーによる柔軟な変換
  • フィールド除外: 複数の除外戦略(修飾子、アノテーション、バージョン管理)
  • 広範な採用: Spring Bootをはじめとする多くのフレームワークでの標準使用

メリット・デメリット

メリット

  • 学習コストが低く、直感的なAPIでJavaオブジェクトとJSONの変換が簡単
  • 豊富なアノテーションとGsonBuilderによる細かい設定制御が可能
  • TypeTokenによるジェネリクス型の安全な処理
  • カスタムシリアライザー・デシリアライザーによる複雑な変換ロジック対応
  • 10年以上の実績によるエンタープライズレベルの信頼性
  • オープンソースで無料、活発なコミュニティサポート

デメリット

  • メンテナンスモードのため新機能追加は期待できない
  • Androidでの使用が推奨されず、Kotlin SerializationやMoshiが代替推奨
  • リフレクションベースのため難読化・最適化との相性が悪い
  • 他のJVM言語(Kotlin、Scala)の固有機能サポートが限定的
  • パフォーマンス面でJacksonやothermodernライブラリに劣る場合がある
  • 複雑なJSONスキーマでは設定が煩雑になる可能性

参考ページ

書き方の例

基本的なセットアップ

<!-- Maven Dependencies -->
<dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
    <version>2.13.1</version>
</dependency>
// Gradle Dependencies
dependencies {
    implementation 'com.google.code.gson:gson:2.13.1'
}

基本的なシリアライゼーション・デシリアライゼーション

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import java.util.List;
import java.util.Arrays;

// 基本的なPOJO
class User {
    private int id;
    private String name;
    private String email;
    private boolean active;
    
    // コンストラクタ
    public User(int id, String name, String email, boolean active) {
        this.id = id;
        this.name = name;
        this.email = email;
        this.active = active;
    }
    
    // デフォルトコンストラクタ(デシリアライゼーション用)
    public User() {}
    
    // 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 String getEmail() { return email; }
    public void setEmail(String email) { this.email = email; }
    public boolean isActive() { return active; }
    public void setActive(boolean active) { this.active = active; }
}

public class GsonBasicExample {
    public static void main(String[] args) {
        Gson gson = new Gson();
        
        // オブジェクトの作成
        User user = new User(1, "田中太郎", "[email protected]", true);
        
        // 1. オブジェクト → JSON文字列
        String jsonString = gson.toJson(user);
        System.out.println("JSON文字列: " + jsonString);
        // 出力: {"id":1,"name":"田中太郎","email":"[email protected]","active":true}
        
        // 2. JSON文字列 → オブジェクト
        String inputJson = "{\"id\":2,\"name\":\"佐藤花子\",\"email\":\"[email protected]\",\"active\":false}";
        User deserializedUser = gson.fromJson(inputJson, User.class);
        System.out.println("デシリアライズ結果: " + deserializedUser.getName());
        
        // 3. 配列の処理
        int[] numbers = {1, 2, 3, 4, 5};
        String numbersJson = gson.toJson(numbers);
        System.out.println("配列JSON: " + numbersJson);
        
        int[] deserializedNumbers = gson.fromJson("[10,20,30]", int[].class);
        System.out.println("配列デシリアライズ: " + Arrays.toString(deserializedNumbers));
        
        // 4. コレクションの処理(TypeToken使用)
        List<User> users = Arrays.asList(
            new User(1, "ユーザー1", "[email protected]", true),
            new User(2, "ユーザー2", "[email protected]", false)
        );
        
        String usersJson = gson.toJson(users);
        System.out.println("ユーザーリストJSON: " + usersJson);
        
        // TypeTokenを使用してList<User>をデシリアライズ
        TypeToken<List<User>> userListType = new TypeToken<List<User>>(){};
        List<User> deserializedUsers = gson.fromJson(usersJson, userListType.getType());
        System.out.println("デシリアライズされたユーザー数: " + deserializedUsers.size());
        
        // 5. プリミティブ型の処理
        String stringJson = gson.toJson("Hello Gson");
        int intJson = gson.fromJson("42", int.class);
        boolean boolJson = gson.fromJson("true", boolean.class);
        
        System.out.println("文字列JSON: " + stringJson);
        System.out.println("整数デシリアライズ: " + intJson);
        System.out.println("真偽値デシリアライズ: " + boolJson);
    }
}

アノテーションとカスタマイゼーション

import com.google.gson.annotations.*;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;

// 高度なアノテーション使用例
public class AdvancedUser {
    
    @SerializedName("user_id") // JSONでの名前指定
    private int id;
    
    @SerializedName("full_name")
    private String name;
    
    @Expose(serialize = true, deserialize = true) // 明示的な露出制御
    private String email;
    
    @Expose(serialize = false, deserialize = true) // 書き込み専用
    private String password;
    
    @Expose(serialize = true, deserialize = false) // 読み取り専用
    private String internalToken;
    
    @Since(1.1) // バージョン1.1以降で有効
    private String newField;
    
    @Until(2.0) // バージョン2.0未満で有効
    private String deprecatedField;
    
    private transient String temporaryData; // シリアライゼーションから除外
    
    @JsonAdapter(LocalDateTimeAdapter.class) // カスタムアダプター指定
    private LocalDateTime createdAt;
    
    // コンストラクタ
    public AdvancedUser(int id, String name, String email) {
        this.id = id;
        this.name = name;
        this.email = email;
        this.createdAt = LocalDateTime.now();
        this.internalToken = "internal_" + id;
    }
    
    // getter/setter
    public int getId() { return id; }
    public String getName() { return name; }
    public String getEmail() { return email; }
    public void setPassword(String password) { this.password = password; }
    public LocalDateTime getCreatedAt() { return createdAt; }
}

// カスタムアダプター例
class LocalDateTimeAdapter implements JsonSerializer<LocalDateTime>, JsonDeserializer<LocalDateTime> {
    private final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    
    @Override
    public JsonElement serialize(LocalDateTime src, Type typeOfSrc, JsonSerializationContext context) {
        return new JsonPrimitive(src.format(formatter));
    }
    
    @Override
    public LocalDateTime deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) 
            throws JsonParseException {
        return LocalDateTime.parse(json.getAsString(), formatter);
    }
}

public class AnnotationExample {
    public static void main(String[] args) {
        // 基本的なGson(全てのフィールドを処理)
        Gson basicGson = new Gson();
        
        // カスタム設定のGson
        Gson customGson = new GsonBuilder()
            .excludeFieldsWithoutExposeAnnotation() // @Exposeアノテーションのみ処理
            .setVersion(1.5) // バージョン1.5として設定
            .setPrettyPrinting() // 整形出力
            .serializeNulls() // null値も出力
            .create();
        
        AdvancedUser user = new AdvancedUser(1, "高度ユーザー", "[email protected]");
        user.setPassword("secret123");
        
        // 基本的なシリアライゼーション
        String basicJson = basicGson.toJson(user);
        System.out.println("基本JSON:\n" + basicJson);
        
        // カスタム設定でのシリアライゼーション
        String customJson = customGson.toJson(user);
        System.out.println("カスタムJSON:\n" + customJson);
        
        // アノテーションによる制御の確認
        System.out.println("@Exposeアノテーションにより、emailとpasswordのみが出力される");
        System.out.println("@Since/@Untilアノテーションによりバージョン制御が適用される");
    }
}

GsonBuilderによる詳細設定

import com.google.gson.*;
import com.google.gson.reflect.TypeToken;
import java.lang.reflect.Modifier;
import java.util.Date;
import java.text.DateFormat;

// 除外戦略の実装
class CustomExclusionStrategy implements ExclusionStrategy {
    
    @Override
    public boolean shouldSkipField(FieldAttributes field) {
        // "internal"で始まるフィールドを除外
        return field.getName().startsWith("internal");
    }
    
    @Override
    public boolean shouldSkipClass(Class<?> clazz) {
        // 特定のクラスを除外(例:InternalConfig)
        return clazz.getSimpleName().equals("InternalConfig");
    }
}

public class GsonConfigurationExample {
    
    public static Gson createConfiguredGson() {
        return new GsonBuilder()
            // 基本設定
            .setPrettyPrinting() // 整形出力
            .serializeNulls() // null値を出力
            .disableHtmlEscaping() // HTMLエスケープを無効化
            
            // 日付処理
            .setDateFormat("yyyy-MM-dd HH:mm:ss") // 日付フォーマット
            .setDateFormat(DateFormat.FULL, DateFormat.FULL) // ロケール対応日付
            
            // フィールド除外設定
            .excludeFieldsWithModifiers(Modifier.STATIC, Modifier.TRANSIENT) // 修飾子による除外
            .setExclusionStrategies(new CustomExclusionStrategy()) // カスタム除外戦略
            
            // 命名規則
            .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES) // snake_case
            
            // バージョン管理
            .setVersion(2.0) // バージョン2.0として設定
            
            // 複雑なMapキーのサポート
            .enableComplexMapKeySerialization()
            
            // エラー対応
            .setLenient() // 厳密でないJSONパースを許可
            
            .create();
    }
    
    public static void demonstrateConfiguration() {
        Gson gson = createConfiguredGson();
        
        // テストデータ
        TestData data = new TestData();
        data.name = "設定テスト";
        data.createdAt = new Date();
        data.internalId = "internal_123"; // 除外されるフィールド
        data.publicId = "public_456";
        
        // シリアライゼーション
        String json = gson.toJson(data);
        System.out.println("設定適用JSON:\n" + json);
        
        // 複雑なMapキーの例
        Map<ComplexKey, String> complexMap = new HashMap<>();
        complexMap.put(new ComplexKey("key1", 100), "value1");
        complexMap.put(new ComplexKey("key2", 200), "value2");
        
        String complexJson = gson.toJson(complexMap);
        System.out.println("複雑なMapキーJSON:\n" + complexJson);
        
        // デシリアライゼーション
        TestData deserializedData = gson.fromJson(json, TestData.class);
        System.out.println("デシリアライズ結果: " + deserializedData.name);
    }
    
    static class TestData {
        String name;
        Date createdAt;
        String internalId; // CustomExclusionStrategyで除外される
        String publicId;
        private static String staticField = "static"; // 修飾子で除外される
        private transient String transientField = "transient"; // 修飾子で除外される
    }
    
    static class ComplexKey {
        String name;
        int value;
        
        ComplexKey(String name, int value) {
            this.name = name;
            this.value = value;
        }
        
        // equals/hashCodeの実装が必要
        @Override
        public boolean equals(Object obj) {
            if (this == obj) return true;
            if (obj == null || getClass() != obj.getClass()) return false;
            ComplexKey that = (ComplexKey) obj;
            return value == that.value && Objects.equals(name, that.name);
        }
        
        @Override
        public int hashCode() {
            return Objects.hash(name, value);
        }
    }
}

JSONパース・操作(JsonElement使用)

import com.google.gson.*;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;
import java.io.StringReader;
import java.io.StringWriter;

public class JsonElementExample {
    
    public static void jsonElementOperations() {
        Gson gson = new Gson();
        
        // JSON文字列
        String jsonString = """
            {
                "user": {
                    "id": 123,
                    "name": "JSON操作ユーザー",
                    "contact": {
                        "email": "[email protected]",
                        "phone": "090-1234-5678"
                    },
                    "hobbies": ["読書", "映画", "プログラミング"]
                },
                "metadata": {
                    "version": "1.0",
                    "timestamp": "2025-01-01T12:00:00Z"
                }
            }
            """;
        
        // JsonElementとしてパース
        JsonElement rootElement = JsonParser.parseString(jsonString);
        
        // 値の読み取り
        JsonObject root = rootElement.getAsJsonObject();
        JsonObject user = root.getAsJsonObject("user");
        
        int userId = user.get("id").getAsInt();
        String userName = user.get("name").getAsString();
        String email = user.getAsJsonObject("contact").get("email").getAsString();
        
        System.out.println("ユーザー情報:");
        System.out.println("ID: " + userId);
        System.out.println("名前: " + userName);
        System.out.println("メール: " + email);
        
        // 配列の処理
        JsonArray hobbies = user.getAsJsonArray("hobbies");
        System.out.println("趣味:");
        for (JsonElement hobby : hobbies) {
            System.out.println("  - " + hobby.getAsString());
        }
        
        // 条件付きアクセス
        if (root.has("metadata")) {
            JsonObject metadata = root.getAsJsonObject("metadata");
            String version = metadata.get("version").getAsString();
            System.out.println("バージョン: " + version);
        }
        
        // null値チェック
        JsonElement description = user.get("description");
        if (description == null || description.isJsonNull()) {
            System.out.println("説明フィールドは存在しないかnullです");
        }
    }
    
    public static void jsonElementModification() {
        // 新しいJSONオブジェクトの作成
        JsonObject root = new JsonObject();
        
        // プリミティブ値の追加
        root.addProperty("name", "新規ユーザー");
        root.addProperty("age", 25);
        root.addProperty("active", true);
        root.addProperty("score", 95.5);
        
        // ネストしたオブジェクトの作成
        JsonObject contact = new JsonObject();
        contact.addProperty("email", "[email protected]");
        contact.addProperty("phone", "090-9876-5432");
        root.add("contact", contact);
        
        // 配列の作成
        JsonArray skills = new JsonArray();
        skills.add("Java");
        skills.add("JSON");
        skills.add("Gson");
        root.add("skills", skills);
        
        // 既存オブジェクトの追加
        User existingUser = new User(999, "既存ユーザー", "[email protected]", true);
        root.add("existing_user", JsonParser.parseString(new Gson().toJson(existingUser)));
        
        // 結果出力
        Gson gson = new GsonBuilder().setPrettyPrinting().create();
        String result = gson.toJson(root);
        System.out.println("作成されたJSON:\n" + result);
        
        // 部分的な修正
        root.addProperty("age", 26); // 年齢更新
        root.getAsJsonObject("contact").addProperty("address", "東京都"); // アドレス追加
        skills.add("Spring Boot"); // スキル追加
        
        System.out.println("更新後JSON:\n" + gson.toJson(root));
    }
    
    public static void streamingJsonProcessing() {
        try {
            // ストリーミング書き込み
            StringWriter stringWriter = new StringWriter();
            JsonWriter writer = new JsonWriter(stringWriter);
            writer.setIndent("  "); // インデント設定
            
            writer.beginObject();
            writer.name("users").beginArray();
            
            // 大量データのストリーミング処理
            for (int i = 1; i <= 1000; i++) {
                writer.beginObject();
                writer.name("id").value(i);
                writer.name("name").value("ユーザー" + i);
                writer.name("active").value(i % 2 == 0);
                writer.name("score").value(i * 0.95);
                writer.endObject();
                
                if (i % 100 == 0) {
                    System.out.println("処理済み: " + i + " ユーザー");
                }
            }
            
            writer.endArray();
            writer.endObject();
            writer.close();
            
            String jsonResult = stringWriter.toString();
            System.out.println("ストリーミング処理完了: " + jsonResult.length() + " 文字");
            
            // ストリーミング読み込み
            JsonReader reader = new JsonReader(new StringReader(jsonResult));
            reader.beginObject();
            
            while (reader.hasNext()) {
                String name = reader.nextName();
                if ("users".equals(name)) {
                    reader.beginArray();
                    int count = 0;
                    
                    while (reader.hasNext()) {
                        reader.beginObject();
                        
                        int id = 0;
                        String userName = "";
                        boolean active = false;
                        
                        while (reader.hasNext()) {
                            String fieldName = reader.nextName();
                            switch (fieldName) {
                                case "id":
                                    id = reader.nextInt();
                                    break;
                                case "name":
                                    userName = reader.nextString();
                                    break;
                                case "active":
                                    active = reader.nextBoolean();
                                    break;
                                case "score":
                                    reader.nextDouble(); // スキップ
                                    break;
                            }
                        }
                        
                        reader.endObject();
                        count++;
                        
                        if (active && id <= 10) {
                            System.out.println("アクティブユーザー: " + userName);
                        }
                    }
                    
                    reader.endArray();
                    System.out.println("ストリーミング読み込み完了: " + count + " ユーザー");
                }
            }
            
            reader.endObject();
            reader.close();
            
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    public static void main(String[] args) {
        System.out.println("=== JsonElement操作例 ===");
        jsonElementOperations();
        
        System.out.println("\n=== JsonElement修正例 ===");
        jsonElementModification();
        
        System.out.println("\n=== ストリーミング処理例 ===");
        streamingJsonProcessing();
    }
}

エラーハンドリングとベストプラクティス

import com.google.gson.*;
import java.lang.reflect.Type;

public class GsonErrorHandlingExample {
    
    public static void comprehensiveErrorHandling() {
        Gson gson = new Gson();
        
        // 1. 基本的なエラーハンドリング
        try {
            String invalidJson = "{\"name\": 田中太郎, \"age\": }"; // 不正なJSON
            User user = gson.fromJson(invalidJson, User.class);
        } catch (JsonSyntaxException e) {
            System.out.println("JSON構文エラー: " + e.getMessage());
        }
        
        // 2. 型の不一致エラー
        try {
            String wrongTypeJson = "{\"id\": \"文字列\", \"name\": \"テストユーザー\"}";
            User user = gson.fromJson(wrongTypeJson, User.class);
        } catch (JsonSyntaxException e) {
            System.out.println("型変換エラー: " + e.getMessage());
        }
        
        // 3. 安全なデシリアライゼーション
        User safeUser = safeDeserialize("{\"id\": 123, \"name\": \"安全ユーザー\"}", User.class);
        if (safeUser != null) {
            System.out.println("安全にデシリアライズ: " + safeUser.getName());
        }
        
        // 4. 部分的なJSONパース
        String partialJson = "{\"validField\": \"値\", \"invalidField\": }";
        JsonObject partial = parsePartialJson(partialJson);
        if (partial != null) {
            System.out.println("部分パース結果: " + partial.toString());
        }
        
        // 5. 堅牢な設定でのGson作成
        Gson robustGson = createRobustGson();
        String flexibleJson = """
            {
                "id": "123",
                "name": "堅牢ユーザー",
                "email": "[email protected]",
                "unknownField": "これは無視される"
            }
            """;
        
        User robustUser = safeDeserialize(flexibleJson, User.class, robustGson);
        if (robustUser != null) {
            System.out.println("堅牢デシリアライズ: " + robustUser.getName());
        }
    }
    
    // 安全なデシリアライゼーションメソッド
    public static <T> T safeDeserialize(String json, Class<T> clazz) {
        return safeDeserialize(json, clazz, new Gson());
    }
    
    public static <T> T safeDeserialize(String json, Class<T> clazz, Gson gson) {
        try {
            return gson.fromJson(json, clazz);
        } catch (JsonSyntaxException e) {
            System.err.println("JSON構文エラー: " + e.getMessage());
            return null;
        } catch (JsonIOException e) {
            System.err.println("JSON IO エラー: " + e.getMessage());
            return null;
        } catch (JsonParseException e) {
            System.err.println("JSONパースエラー: " + e.getMessage());
            return null;
        } catch (Exception e) {
            System.err.println("予期しないエラー: " + e.getMessage());
            return null;
        }
    }
    
    // 部分的なJSONパース
    public static JsonObject parsePartialJson(String json) {
        try {
            return JsonParser.parseString(json).getAsJsonObject();
        } catch (JsonSyntaxException e) {
            System.err.println("部分パース中にエラー: " + e.getMessage());
            
            // 可能な限り有効な部分を抽出する試み
            try {
                int lastValidIndex = findLastValidJsonIndex(json);
                if (lastValidIndex > 0) {
                    String truncatedJson = json.substring(0, lastValidIndex);
                    return JsonParser.parseString(truncatedJson).getAsJsonObject();
                }
            } catch (Exception innerE) {
                System.err.println("復旧試行も失敗: " + innerE.getMessage());
            }
            
            return null;
        }
    }
    
    // 堅牢なGson設定
    public static Gson createRobustGson() {
        return new GsonBuilder()
            .setLenient() // 厳密でないJSONを許可
            .serializeNulls() // null値のシリアライゼーション
            .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES) // 命名規則
            .registerTypeAdapter(String.class, new StringDeserializer()) // カスタムデシリアライザー
            .registerTypeAdapter(Integer.class, new SafeIntegerDeserializer()) // 安全な整数デシリアライザー
            .create();
    }
    
    // 簡単な有効JSONインデックス検索(実際の実装ではより堅牢な方法が必要)
    private static int findLastValidJsonIndex(String json) {
        int braceCount = 0;
        for (int i = 0; i < json.length(); i++) {
            char c = json.charAt(i);
            if (c == '{') braceCount++;
            else if (c == '}') braceCount--;
            
            if (braceCount == 0 && i > 0) {
                return i + 1;
            }
        }
        return -1;
    }
    
    // カスタム文字列デシリアライザー
    static class StringDeserializer implements JsonDeserializer<String> {
        @Override
        public String deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) 
                throws JsonParseException {
            if (json.isJsonNull()) {
                return null;
            }
            if (json.isJsonPrimitive()) {
                return json.getAsString();
            }
            // 非文字列の場合は文字列化
            return json.toString();
        }
    }
    
    // 安全な整数デシリアライザー
    static class SafeIntegerDeserializer implements JsonDeserializer<Integer> {
        @Override
        public Integer deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) 
                throws JsonParseException {
            if (json.isJsonNull()) {
                return null;
            }
            
            try {
                if (json.isJsonPrimitive()) {
                    JsonPrimitive primitive = json.getAsJsonPrimitive();
                    if (primitive.isNumber()) {
                        return primitive.getAsInt();
                    }
                    if (primitive.isString()) {
                        return Integer.parseInt(primitive.getAsString());
                    }
                }
                return 0; // デフォルト値
            } catch (NumberFormatException e) {
                System.err.println("整数変換エラー、デフォルト値0を使用: " + json);
                return 0;
            }
        }
    }
    
    // パフォーマンス測定付きデシリアライゼーション
    public static <T> T deserializeWithMetrics(String json, Class<T> clazz) {
        long startTime = System.nanoTime();
        long memoryBefore = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
        
        try {
            Gson gson = new Gson();
            T result = gson.fromJson(json, clazz);
            
            long endTime = System.nanoTime();
            long memoryAfter = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
            
            double durationMs = (endTime - startTime) / 1_000_000.0;
            long memoryUsed = memoryAfter - memoryBefore;
            
            System.out.println("デシリアライゼーション時間: " + String.format("%.2f", durationMs) + "ms");
            System.out.println("メモリ使用量: " + memoryUsed + " bytes");
            
            return result;
        } catch (Exception e) {
            long endTime = System.nanoTime();
            double durationMs = (endTime - startTime) / 1_000_000.0;
            System.err.println("エラー発生 (経過時間: " + String.format("%.2f", durationMs) + "ms): " + e.getMessage());
            return null;
        }
    }
    
    public static void main(String[] args) {
        System.out.println("=== Gson エラーハンドリング例 ===");
        comprehensiveErrorHandling();
        
        // メトリクス付きデシリアライゼーションのテスト
        System.out.println("\n=== パフォーマンス測定例 ===");
        String testJson = new Gson().toJson(new User(1, "メトリクステスト", "[email protected]", true));
        User metricsUser = deserializeWithMetrics(testJson, User.class);
        if (metricsUser != null) {
            System.out.println("測定結果: " + metricsUser.getName());
        }
    }
}

インスタンス作成とカスタムアダプター

import com.google.gson.*;
import java.lang.reflect.Type;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

// カスタムInstanceCreator
class UserInstanceCreator implements InstanceCreator<User> {
    @Override
    public User createInstance(Type type) {
        // デフォルト値でUserインスタンスを作成
        return new User(0, "デフォルトユーザー", "[email protected]", false);
    }
}

// 複雑なオブジェクトのアダプター
class ConfigurationAdapter implements JsonSerializer<Configuration>, JsonDeserializer<Configuration> {
    
    @Override
    public JsonElement serialize(Configuration src, Type typeOfSrc, JsonSerializationContext context) {
        JsonObject jsonObject = new JsonObject();
        jsonObject.addProperty("version", src.getVersion());
        jsonObject.addProperty("environment", src.getEnvironment());
        jsonObject.add("features", context.serialize(src.getFeatures()));
        jsonObject.addProperty("timestamp", src.getCreatedAt().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
        
        // センシティブ情報は除外
        if (!src.getEnvironment().equals("production")) {
            jsonObject.addProperty("debug", src.isDebugMode());
        }
        
        return jsonObject;
    }
    
    @Override
    public Configuration deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) 
            throws JsonParseException {
        JsonObject jsonObject = json.getAsJsonObject();
        
        Configuration config = new Configuration();
        config.setVersion(jsonObject.get("version").getAsString());
        config.setEnvironment(jsonObject.get("environment").getAsString());
        
        // featuresをデシリアライズ
        Type listType = new TypeToken<List<String>>(){}.getType();
        List<String> features = context.deserialize(jsonObject.get("features"), listType);
        config.setFeatures(features);
        
        // timestampをLocalDateTimeに変換
        String timestamp = jsonObject.get("timestamp").getAsString();
        config.setCreatedAt(LocalDateTime.parse(timestamp, DateTimeFormatter.ISO_LOCAL_DATE_TIME));
        
        // debugフィールドが存在する場合のみ設定
        if (jsonObject.has("debug")) {
            config.setDebugMode(jsonObject.get("debug").getAsBoolean());
        }
        
        return config;
    }
}

// 設定クラス
class Configuration {
    private String version;
    private String environment;
    private List<String> features;
    private boolean debugMode;
    private LocalDateTime createdAt;
    
    public Configuration() {
        this.createdAt = LocalDateTime.now();
        this.features = new ArrayList<>();
    }
    
    // getter/setter
    public String getVersion() { return version; }
    public void setVersion(String version) { this.version = version; }
    public String getEnvironment() { return environment; }
    public void setEnvironment(String environment) { this.environment = environment; }
    public List<String> getFeatures() { return features; }
    public void setFeatures(List<String> features) { this.features = features; }
    public boolean isDebugMode() { return debugMode; }
    public void setDebugMode(boolean debugMode) { this.debugMode = debugMode; }
    public LocalDateTime getCreatedAt() { return createdAt; }
    public void setCreatedAt(LocalDateTime createdAt) { this.createdAt = createdAt; }
}

public class AdvancedAdapterExample {
    
    public static void demonstrateCustomAdapters() {
        // カスタムアダプターを登録したGsonの作成
        Gson gson = new GsonBuilder()
            .registerTypeAdapter(User.class, new UserInstanceCreator())
            .registerTypeAdapter(Configuration.class, new ConfigurationAdapter())
            .setPrettyPrinting()
            .create();
        
        // Configurationオブジェクトの作成
        Configuration config = new Configuration();
        config.setVersion("2.1.0");
        config.setEnvironment("development");
        config.setFeatures(Arrays.asList("auth", "logging", "metrics", "cache"));
        config.setDebugMode(true);
        
        // シリアライゼーション
        String configJson = gson.toJson(config);
        System.out.println("設定JSON:\n" + configJson);
        
        // デシリアライゼーション
        Configuration deserializedConfig = gson.fromJson(configJson, Configuration.class);
        System.out.println("デシリアライズ結果:");
        System.out.println("バージョン: " + deserializedConfig.getVersion());
        System.out.println("環境: " + deserializedConfig.getEnvironment());
        System.out.println("機能数: " + deserializedConfig.getFeatures().size());
        System.out.println("デバッグモード: " + deserializedConfig.isDebugMode());
        
        // 本番環境での動作確認(debugフィールドが除外される)
        config.setEnvironment("production");
        String prodJson = gson.toJson(config);
        System.out.println("\n本番環境JSON:\n" + prodJson);
        
        // InstanceCreatorの動作確認
        String emptyUserJson = "{}"; // 空のJSONでもUserInstanceCreatorが動作
        User defaultUser = gson.fromJson(emptyUserJson, User.class);
        System.out.println("\nInstanceCreator結果: " + defaultUser.getName());
    }
    
    public static void main(String[] args) {
        System.out.println("=== カスタムアダプター例 ===");
        demonstrateCustomAdapters();
    }
}