티스토리 뷰

반응형

발생 오류와 코드 그리고 발생했던 이유 : com.google.gson.stream.MalformedJsonException

com.google.gson.stream.MalformedJsonException: Use JsonReader.setLenient(true) to accept malformed JSON at line 1 column 7 path $

// 오류 발생 코드
httpMessage.setPayload(gson.fromJson(jsonString, JsonElement.class).getAsJsonObject());

API request, response를 로깅을 하는 과정에서 오류 발생하였는데, 

String jsonString에 들어있던 스트링의 내용이 Json 포맷이 아닌데 getAsJsonObject()을 하려 했기 때문이다.

 

안 좋은 JsonString 예 )

String jsonString = "http://zi-c.tistory.com/asbcdfdasf?%Fsfsdf%sdfafsfsdk" 

 이런 식으로 스트링 형식에 특수 문자도 들어있었다.

 

좋은 JsonString 예 )

String jsonString = "{ \"name\" : \"뜝\"}"

이런 식으로 JsonObject가 스트링화 된 형태였어야 jsonElement로 변환 후 getAsJsonObject해도 정상적으로 Object화 됨.

 

 

해결법 :  TRY - CATCH를 활용하자! 

항상 비-Json 형식의 스트링이 들어올 수 밖에 없는 상황이였으므로,

JsonElement의 parseReader 함수를 사용하여 MalformedJsonException을 발생할 때를 예외 처리를 해주었다.

parseReader 함수는 MalformedJsonException이 발생하면 JsonSyntaxException을 throw 해주기 때문에 Try-Catch를 활용하여 예외처리를 할 수 있었다.

 

해결 코드 

JsonParser에서 JsonSyntaxException이 발생한 경우, String을 json-포맷화 하여 다시 설정해주고 다시 동일한 코드를 실행시켜주었다.

import com.google.gson.JsonParser;

try {
	httpMessage.setPayload(JsonParser.parseString(jsonString).getAsJsonObject());
} catch (JsonSyntaxException e) {
	jsonString = "{ \"log\" : \"" + jsonString + "\"}";
	httpMessage.setPayload(JsonParser.parseString(jsonString).getAsJsonObject());
}

* 이 코드를 사용하는 함수 단에서 IOException을 throw 하고 있었기 때문에 catch (MalformedJsonException e) 로는 예외 처리가 불가능 하였다. 다행히 JsonParser를 활용하여 해결하였다.

package com.google.gson;

public static JsonElement parseReader(Reader reader) throws JsonIOException, JsonSyntaxException {
    try {
        JsonReader jsonReader = new JsonReader(reader);
        JsonElement element = parseReader(jsonReader);
        if (!element.isJsonNull() && jsonReader.peek() != JsonToken.END_DOCUMENT) {
            throw new JsonSyntaxException("Did not consume the entire document.");
        } else {
            return element;
        }
    } catch (MalformedJsonException var3) {
        throw new JsonSyntaxException(var3);
    } catch (IOException var4) {
        throw new JsonIOException(var4);
    } catch (NumberFormatException var5) {
        throw new JsonSyntaxException(var5);
    }
}

 

 


내가 해본 시도들 

 

시도 1 : setLenient(true) 하라길래 해봄... 안됨

결과 : 새로운 Exception 발생 - com.google.gson.JsonPrimitive cannot be cast to com.google.gson.JsonObject

JsonReader reader = new JsonReader(new StringReader(jsonString));
reader.setLenient(true);
httpMessage.setPayload(gson.fromJson(reader, JsonElement.class));

시도 2 : getAsJsonObject 안 하게 바로 JsonObject.class로 받아봄... 안됨

결과 : 새로운 Exception 발생 - Expected a com.google.gson.JsonObject but was com.google.gson.JsonPrimitive

httpMessage.setPayload(gson.fromJson(jsonString, JsonObject.class));

시도 3 : 구글링 해서 코드를 바꿔봄... 안됨

결과 : 새로운 Exception 발생 - com.google.gson.JsonSyntaxException: Expected a com.google.gson.JsonObject but was com.google.gson.JsonPrimitive

JsonReader reader = new JsonReader(new StringReader(jsonString));
reader.setLenient(true);
httpMessage.setPayload(gson.fromJson(reader, JsonObject.class));

시도 4 : 안됨

string 이라 primitive type에서 분류될 것이라 생각하였는데, else로 타고 들어가지더라. 

JsonElement jsonElement = gson.fromJson(jsonString, JsonElement.class);
if (jsonElement.isJsonPrimitive()) {
    JsonObject jsonObject = new JsonObject();
    jsonObject.add("logContent", jsonElement);
    httpMessage.setPayload(jsonObject);
}
else 
    httpMessage.setPayload(jsonElement.getAsJsonObject());

 

반응형
반응형