Computer >> 컴퓨터 >  >> 프로그래밍 >> Java

Java Gson 'Expected BEGIN_OBJECT but was BEGIN_ARRAY' 오류 해결 방법

Gson으로 JSON을 역직렬화(deserialize)할 때, Gson은 JSON 객체를 기대하지만 실제로는 JSON 배열을 만나는 경우가 있습니다. 객체와 배열은 서로 자동 변환되지 않기 때문에 이런 상황에서는 런타임에 다음과 같은 오류가 발생합니다.

JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was BEGIN_ARRAY

즉, "객체(BEGIN_OBJECT)가 시작되어야 하는데 배열(BEGIN_ARRAY)이 발견되었다"는 의미로, JSON 구조와 자바 POJO 클래스의 필드 타입이 일치하지 않을 때 나타나는 대표적인 오류입니다.

오류가 발생하는 예제

아래 코드에서 JSON 문자열의 "employee" 키에는 배열([ ])이 담겨 있지만, POJO 클래스에서는 단일 객체(Employee)로 선언되어 있어 오류가 발생합니다.

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)

해결 방법

이 문제를 해결하려면 POJO 클래스의 필드 타입을 컬렉션(Collection) 또는 배열(Array) 타입으로 변경해야 합니다. JSON 데이터가 배열 형태라면, 자바 쪽에서도 해당 데이터를 리스트나 배열로 받아야 하기 때문입니다.

아래 예제에서는 Software 클래스의 필드를 List<Employee> 타입으로 변경하여 오류를 해결했습니다.

수정된 예제

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]]]

정리

'Expected BEGIN_OBJECT but was BEGIN_ARRAY' 오류는 JSON 구조와 매핑되는 자바 클래스 타입이 불일치할 때 발생합니다. JSON에서 배열로 표현된 데이터는 반드시 List, 배열 등의 컬렉션 타입으로 선언해야 하며, 반대로 JSON이 단일 객체라면 POJO도 객체 타입으로 선언해야 합니다. 역직렬화 전에 JSON 구조를 먼저 확인하고 그에 맞게 클래스를 설계하면 이러한 오류를 손쉽게 예방할 수 있습니다.