GSON
GSON은 Java <–> JSON 변환을 아주 쉽게 가능하도록 도와주는 자바 라이브러리다.
GSON을 사용해서 코드를 작성하면 이기종 호환성, 유지보수에 꽤나 도움이 된다.
주요 스펙
- 기본형 변환 지원
- 클래스 변환 지원
- 제네릭 지원. List, Map 등 콜렉션을 변환할 때 아주 유용하다
- 멀티스레드 지원. Gson을 내부 상태를 갖지 않아 Thread-safe이다.
- 빠르고 가볍다. Serialize보다 우월하다.
생성
private static final Gson gson = new Gson();
매번 new를 할 필요 없다, 하나의 Gson객체면 충분하다. gson객체는 공유 가능하다.
형 변환
Java -> JSON
gson.toJson(short,int,long,float,double,String,Object);
JSON -> Java
gson.fromJson(JSON문자, JavaClass.class); // 예를 들어, gson.fromJson(jsonStr, int.class);
제네릭 변환
Java -> JSON
gson.toJSON(Generic); // 예를 들어, List<MyClass> list;
JSON -> Java
gson.fromJson(JSON문자열, new TypeToken<제네릭타입>() {}.getType());
예를 들어, gson.fromJson(JSON문자열, new TypeToken<List<MyClass>>() {}.getType());
—– 추가
안드로이드 어플리케이션을 개발하다 보면 주소록을 다루는 일이 종종 있습니다. 어플리케이션에서 주소록에 관련된 정보를 접근할 일이 있는 어플이라면 ContentResolver를 통해 단말의 주소록에 접근해서 필요한 정보를 가져오게 됩니다.
그런데, 최근 개발하고 있는 스포카 어플을 통해 아주 많은 사람의 연락처가 저장된 주소록을 가지고 이런 저런 로직을 실행하는 상황을 테스트 하다보니, OutOfMemory(OOM)에러가 발생하는 현상을 볼 수 있었습니다. 모바일 디바이스들은 PC와 다르게 자원이 제한적이기 때문에 어떻게 하면 OOM을 일으키지 않을 수 있을까 라는 고민을 해야 하는 상황이었습니다.
대강 문제가 되었던 클라이언트 사이드의 로직을 살펴보면 이렇습니다.
- 단말의 주소록에 접근하여 필요한 정보를 추출 후 서버에 전송
- 서버에서 정보를 가공하여 필요한 json 문자열을 생성 후 반환, 이 문자열은 주소록에서 보낸 정보의 양에 비례해서 늘어나게 됩니다.
- 클라이언트 측에서 서버 측에서 보낸 json 문자열을 이용하여 JSONObject객체를 만든 후 이 JSONObject를 이용 리스트 완성
eclipse의 MAT(Memory Analyzer)을 이용하여 어느 시점에서 OOM이 일어나는지를 추측해보았습니다. 서버에서 보내준 json형식의 문자열을 HttpURLConnection을 통해 전달받고 이를 StringBuilder를 이용하여 완전한 문자열으로 만들던 도중에 OOM이 일어나는 것으로 의심되었는데 이 때문에 JSONObject의 생성자에 json 문자열을 전달하기도 전에 메모리가 가득 차 버리니 매우 난감한 상황이었습니다.
대게 주소록에 사람이 그렇게 많지 않으므로 (200~500명 정도) 아무런 문제가 없었지만 10000명 정도의 더미데이터를 주소록에 저장하고 테스트하다 보니 append 메서드를 호출하다 OOM에러를 뱉으면서 어플이 종료되었습니다. 문제는 append 메서드를 호출 시 StringBuilder의 capacity를 넘을 경우 내부적으로는 메모리 재할당과 copy과정이 일어난다는 것이었습니다. 그렇다고 초기 StringBuilder생성시 capacity를 무작정 높게 잡기도 애매한 상황이었습니다.
gson
gson은 Java객체를 json형식으로 변환하고 그 역으로도 변환할 수 있도록 도와주는 라이브러리입니다. gson의 사용법이 궁금하다면 gson user guide를 읽어보면 되고 api가 궁금하다면 gson api document를 참조하면 됩니다.
gson 적용
대략 이런 방식으로 프로젝트에 gson라이브러리를 적용하였고, HttpURLConnection을 통해 받아온 InputStream을 이용 바로 객체를 생성할 수 있었습니다. 이전에 StringBuilder를 이용할때 생기는 오버헤드가 사라진 셈이죠. 위와 같은 방식으로 OOM이 생기는 문제 상황을 해결 할 수 있었습니다.
위의 예는 상황을 최대한 단순화하여 설명하려고 작성한 예제이고 이 사이트를 통해 더 상세하게 설명된 사용예를 보실 수 있습니다.