IT/Android

[Android] jsonSyntaxException Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 2 에러 해결, Json 파싱 처리

토마토조아 2019. 5. 28. 08:45
728x90

현재의 글은 Java8 + RxJava2 + Retrofit2 + OkHttp3 으로 되어 있다.

Kotlin + RxJava2 + Retrofit2 + OkHttp3의 내용을 원하면 아래의 글도 참고해볼 수 있다. 

[IT/Android] - [Android] Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 2 path $ 에러

 

JSON 형식의 데이터를 다루다보면 위의 에러를 간혹 접할 수 있다.
위의 에러의 원인은 GSON으로 JSON데이터를 파싱할 때 형식이 맞지 않아서 발생하는 에러이다.

문제의 원인을 살펴보자.

일반적인 JSON의 데이터는 아래와 같이 되어있다.

{
    "name": "Apple",
    "family": "Fruit",
    "age": 12,
    "weight": 4.2,
	"brother": [
		{"name": "Banana", "family": "Fruit", "age": 12, "weight": 3.5},
		{"name": "Melon", "family": "Fruit", "age": 31, "weight": 6.1},
		{"name": "Fish", "family": "Fish", "age": 2, "weight": 1.1}
	]
}



그러나 위의 에러가 발생할 때의 JSON의 데이터 형식을 보면 아래와 같이 되어있는 경우가 종종있다.
반드시 아래와 같은 상황은 아니지만 참고할 수 있는 상황이다. 밑의 예제는 JSON데이터가 처음부터 Array로 시작되는 경우이다.

[
	{
		"name": "Apple",
		"family": "Fruit",
		"age": 12,
		"weight": 4.2
	},
	{
		"brother": [
			{"name": "Banana", "family": "Fruit", "age": 12, "weight": 3.5},
			{"name": "Melon", "family": "Fruit", "age": 31, "weight": 6.1},
			{"name": "Fish", "family": "Fish", "age": 2, "weight": 1.1}
		]
	}
]




Retrofit2 와 RxJava2를 이용해서 네트워킹 프로그래밍을 주로 사용하게 되고, 결과값은 JSON데이터를 다루게 되는 경우가 많을 것이다.
HTTP인터페이스를 만들고 POJO 클래스를 만들어서 Retrofit에 GSON컨버터를 붙이고 RxJava로 비동기 프로그래밍을 이용하여 결과값을 컨트롤하게 될 것이다.
수정을 해야할 부분은, HTTP인터페이스 부분과 RxJava로 결과값 호출하는 부분을 수정해야 할 확률이 높다.

    // Retrofit2 interface 에러 해결 전
    @GET("Address.jsp") 
    Single<JsonData> GetJsonData( 
            @Query(value="apiKey", encoded=true) String apiKey, 
            @Query("page") String page, 
            @Query("count") String count 
    ); 

    // Retrofit2 interface 에러 해결 후
    // JsonData를 Array 형태로 변경한 것을 볼 수 있다.
    @GET("Address.jsp") 
    Single<JsonData[]> GetJsonData( 
            @Query(value="apiKey", encoded=true) String apiKey, 
            @Query("page") String page, 
            @Query("count") String count 
    ); 

 

// MainActivity 에서 Retrofit2 + RxJava2로 호출하는 부분 수정 전
RestfulAdapter.getInstance(this) 
        .GetJsonData( 
                getString(R.string.http_apikey), 
                "30", 
                "1") 
        .observeOn(AndroidSchedulers.mainThread()) 
        .subscribeOn(Schedulers.io()) 
        .doOnError(new Consumer() { 
            @Override 
            public void accept(Throwable throwable) throws Exception { 
                Toast.makeText(MainActivity.this, "Error", Toast.LENGTH_SHORT).show(); 
            } 
        }) 
        .unsubscribeOn(Schedulers.io()) 
        .subscribe(new Consumer<JsonData>() { 
            @Override 
            public void accept(JsonData JsonData) throws Exception { 
                Toast.makeText(MainActivity.this, JsonData.getList().size(), Toast.LENGTH_SHORT).show(); 
            } 
        }); 


// MainActivity 에서 Retrofit2 + RxJava2로 호출하는 부분 수정 후
RestfulAdapter.getInstance(this) 
        .GetJsonData( 
                getString(R.string.http_apikey), 
                "30", 
                "1") 
        .observeOn(AndroidSchedulers.mainThread()) 
        .subscribeOn(Schedulers.io()) 
        .doOnError(new Consumer() { 
            @Override 
            public void accept(Throwable throwable) throws Exception { 
                Toast.makeText(MainActivity.this, "Error", Toast.LENGTH_SHORT).show(); 
            } 
        }) 
        .unsubscribeOn(Schedulers.io()) 
        .subscribe(new Consumer<JsonData[]>() { 
            @Override 
            public void accept(JsonData[] JsonData) throws Exception { 
                Toast.makeText(MainActivity.this, JsonData[1].getList().size(), Toast.LENGTH_SHORT).show(); 
            } 
        }); 

 

위와 같이 JsonData부분은 JsonData[]와 같이 수정해서 사용하면 에러가 해결된다.

Json데이터를 설계할 때 서버에서 받아오는 결과값과 앱에서 처리하는 데이터 형식을 잘 맞춰야한다.

728x90