Java
 Computer >> コンピューター >  >> プログラミング >> Java

【Java】Gsonの「Expected BEGIN_OBJECT but was BEGIN_ARRAY」エラーの原因と解決方法

Gsonを使ってJSONをデシリアライズする際、Gson側はJSONオブジェクトを期待しているのに、実際にはJSON配列が見つかるケースがあります。オブジェクトと配列は互いに変換できないため、この場合、実行時にJsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was BEGIN_ARRAYというエラーがスローされます。

エラーの原因

このエラーは、JSON文字列の中でフィールドの値が配列([ ])として定義されているのに、対応するJavaのPOJOクラスでは単一のオブジェクト型として宣言している場合に発生します。GsonはJSONの構造とJavaクラスの構造を一致させてマッピングするため、この不一致があるとパースに失敗します。

エラーが発生するコード例

import com.google.gson.Gson;
public class GsonErrorTest {
    public static void main(String args[]) throws Exception {
        String json = "{\"employee\":[{\"name\":\"Raja Ramesh\", \"technology\":\"java\"}]}";
        Gson gson = new Gson();
        Software software = gson.fromJson(json, Software.class);
        System.out.println(software);
    }
}
class Software {
    Employee employee;
}
class Employee {
    String name;
    String technology;
}

出力結果

Exception in thread "main" com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 14
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:176)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java:93)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:172)
at com.google.gson.Gson.fromJson(Gson.java:795)
at com.google.gson.Gson.fromJson(Gson.java:761)
at com.google.gson.Gson.fromJson(Gson.java:710)
at com.google.gson.Gson.fromJson(Gson.java:682)
at BeginObjectError.main(BeginObjectError.java:7)
Caused by: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 14
at com.google.gson.stream.JsonReader.expect(JsonReader.java:339)
at com.google.gson.stream.JsonReader.beginObject(JsonReader.java:322)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:165)

上記の例では、JSON内の employee フィールドは配列になっていますが、POJOクラスでは単一の Employee オブジェクトとして宣言しているため、エラーが発生しています。

解決方法:POJOのフィールド型をコレクション型または配列型に変更する

このエラーを解決するには、POJOクラスのフィールド型をCollection型または配列型に変更します。以下の例では、POJOクラス内でListコレクションを使用しています。

修正後のコード例

import java.util.List;
import com.google.gson.Gson;
public class GsonListTest {
    public static void main(String args[]) throws Exception {
        String jsonString = "{\"employees\":[{\"name\":\"Raja Ramesh\", \"technology\":\"Java\"}]}";
        Gson gson = new Gson();
        Software software = gson.fromJson(jsonString, Software.class);
        System.out.println(software);
    }
}
class Software {
    List<Employee> employees;
    @Override
    public String toString() {
        return "Software [employees=" + employees + "]";
    }
}
class Employee {
    String name;
    String technology;
    @Override
    public String toString() {
        return "Employee [name=" + name + ", technology=" + technology + "]";
    }
}

出力結果

Software [employees=[Employee [name=Raja Ramesh, technology=Java]]]

このように、JSONの構造(オブジェクトか配列か)とPOJOのフィールド型を一致させることで、「Expected BEGIN_OBJECT but was BEGIN_ARRAY」エラーを回避できます。特に外部APIのレスポンスを扱う場合は、受け取るJSONの構造を事前に確認し、それに合わせて適切なデータ型(単一オブジェクト、List、配列など)を定義することが重要です。

  1. 【Java入門】Gsonライブラリを使ってJSON文字列をファイルに書き込む方法

    GsonライブラリとはGsonは、JavaオブジェクトをJSON形式に変換(シリアライズ)するためのGoogle製オープンソースライブラリです。逆に、JSON文字列からJavaオブジェクトへの変換(デシリアライズ)も簡単に行えるため、JavaでJSONを扱う際の定番ライブラリとして広く利用されています。Gsonを使用する際の中心的なクラスはGsonクラスです。インスタンスはnew Gson()のように直接生成できますが、設定をカスタマイズしたい場合はGsonBuilderクラスを使ってGsonインスタンスを作成することも可能です。この記事では、Gsonクラスが提供するtoJson()メソッドを

  2. JavaのNullPointerException(NPE)の原因と解決方法を徹底解説

    NullPointerExceptionは、アプリケーションコードや参照先のAPI、ミドルウェアが以下のような状況に遭遇した際に、JVM(Java仮想マシン)によってスローされる実行時例外です。 nullオブジェクトのインスタンスメソッドを呼び出そうとした場合 nullオブジェクトの特定のフィールドへアクセスまたは変更しようとした場合 nullオブジェクトを配列として扱い、長さ(length)を取得しようとした場合 NullPointerExceptionを解決するための手順 java.lang.NullPointerExceptionのスタックトレースを確認し、例外がどこで発生したのか