IT_Programming/Java

[JSON-LIB 사용] JSON 형태의 Data 사용하기

JJun ™ 2011. 7. 4. 15:37

------------------------------------------------------------------------------------------------

 출처: http://elliecn.tistory.com/38

          http://elliecn.tistory.com/39

------------------------------------------------------------------------------------------------

 

JSON은 {"a":1, "b":"b1", "c":"c1"} 처럼 {}, ":", ",", "[]"를 써서 key : value 형식으로 직관적으로 간단하게 
데이터를 표현할 수 있는 데이터 표현 형식이다.

 

XML처럼 엄격한 스키마 정의를 통해 스키마 validation 같은 효과를 누릴 수는 없지만 그만큼 가볍고 쉽게 원하는 데이터를 표현할 수 있는 장점 때문에 REST 형식의 웹 서비스에서 데이터 바인딩에 많이 활용하고 있다. (JSON 포맷에 대한 자세한 내용은 http://www.json.org/를 참조할 것)

XML이 명확하고 잘 정의된 포맷이긴 하지만 XML 크기가 크고 구조가 복잡한 경우에는 그걸 parsing 하고 객체로 marshalling / unmarshalling 하는 과정에서 무시무시할 정도로 리소스를 많이 쓰기 때문에 대체로 내부 시스템간 메시지를 주고받을 때 전체를 XML화하기는 부담스럽기 마련이다.

어느 프로젝트 수행 도중 역시 이런 이슈가 발생해서 서비스가 주고받는 메시지의 데이터 포맷을 자체 
정의할까 하다가 제안한 것이 JSON 인데
(JavaScript Object Notation이라는 명칭 때문에 자바스크립트 용 포맷으로 오해하는 경우도 많지만 사실 본질적으로 텍스트이므로 어느 언어에서건  사용 가능한 데이터
포맷일 뿐이다.)

실제로 테스트해보니 객체로 표현가능한 모든 데이터가 JSON으로도 표현 가능했다. 

이제 남은 것은 JSON으로 기술된 데이터를 파싱하고 객체로 만들거나, 반대로 객체를 JSON 형태로
바꿀 때 쓸 파서를 정하는 일이었는데, 직접 구현하기보다는 많이 나와 있는 오픈소스  JSON 라이브러리를
선택하기로 했다.

C, C++, C#, ASP, Action Script, Java, Java Script, Perl, PHP, LISP 등 거의 모든 개발 언어에 대해
JSON 라이브러리가 나와 있으므로 사용상 어려움은 없을 듯하다.

내가 선택한 것은 json-lib 2.2.2

우선 json-lib 및 기타 필요한 라이브러리를 받자.
http://json-lib.sourceforge.net/ 에서 json-lib을 받고, json-lib가 Jakarta common library 및 ezmorph를 필요로 하므로 http://commons.apache.org/에서 

 

를 받고,


 

를 받는다.

추가적으로, JSON과 XML 사이의 변환이 필요하다면 http://www.xom.nu/ 에서 

 

를 받는다.

 

그리고 이 라이브러리들을 java build path에 설정해준다.

 


이제 간단한 JSON 핸들링 예제를 작성해보자.

 


[간단한 JSONObject 생성 예제]
 

JSONObject jsonObj=new JSONObject();

jsonObj.put("JSON""Hello World!!");

String jsonStr = jsonObj.toString(); 
물론, Exception 처리를 위해 try-catch문으로 감싸줘야 한다.

이렇게 하면 jsonStr 문자열에는 {"JSON" : "Hello World!!"} 값이 들어가게 된다.
즉, "JSON" 이라는 key는 "Hello, World!!"라는 value를 갖는다.


이번에는 문자열로부터 JSONObject를 만들어보자.

String jsonStr="{\"JSON\" : \"Hello, World!! (String to JSON) \"}";  

JSONObject jsonObj = JSONObject.fromObject(JSONSerializer.toJSON(jsonStr)); 

JSONSerializer의 static 메소드 toJSON()을 사용한다.
(참고로 json-lib 2.2.1 버전에서는 new JSONObject(jsonStr)를 씀)

jsonObj를 출력하면 {"JSON":"Hello, World!! (String to JSON) "}가 된다.

객체와 JSON간의 변환, 그리고 XML과 JSON간의 변환은 내용이 길어지므로
다음 포스팅에서 이어서 한다.

 

 

 


 

 

 

객체와 JSON간의 변환 예제를 위해 다음과 같은 클래스 다이어그램을 가정하자.

 

 



Java 객체로부터 JSONObject 만들기

TestData data = new TestData();

data.setAuthor("Author1");

data.setTitle("Book Title");

data.setIsdn("ISDN NBR");

 

jsonObj = JSONObject.fromObject(JSONSerializer.toJSON(data));

기본적으로 toJSON 메소드의 parameter Object 타입이 가능하므로 스트링으로부터 JSONObject

객체 만들기와 같은 방식이다. JSONObject 객체의 static 메소드 fromObject()를 사용하고, 일반적인

get, set 메소드를 가진 value object 형태는 바로 JSONObject로 변환된다.


 

 

배열 형식 객체를 JSONObject로 만들기

 

JSON library에서는 배열 형식 객체를 JSON으로 만들기 위해 JSONArray라는 클래스를 제공한다.

ArrayList list=new ArrayList();

list.add(new ListTestData("A1","A2","A3"));

list.add(new ListTestData("B1","B2","B3"));

list.add(new ListTestData("C1","C2","C3"));

JSONArray jsonArray = JSONArray.fromObject( list );  

 


객체의 일부 속성이 배열 형식일 때 JSONObject 만들기

 

위의 TestData객체 처럼, 그 자체는 배열이 아니지만 속성 중 배열 형식이 있을 때는 

객체로부터 JSONObject 객체 만들기와 같은 방식으로 JSON 객체를 만들 수 있다.

이 때 배열 형식 객체는 자동으로 JSON의 배열 형식으로 변환된다.

 

예를 들어 위에서 인용한 TestData라는 클래스의 list라는 속성이 ArrayList 객체이고,
ArrayList의 각 엘리먼트에는 ListTestData라는 객체가 할당된다고 가정하자

TestData data=new TestData();

data.setAuthor("Author1");

data.setTitle("Book Title");

data.setIsdn("ISDN NBR");

            

ArrayList list=new ArrayList();              

list.add(new ListTestData("A1","A2","A3"));

list.add(new ListTestData("B1","B2","B3"));

list.add(new ListTestData("C1","C2","C3"));

data.setList(list);

 

JSONObject jsonObj=new JSONObject();

jsonObj = JSONObject.fromObject(JSONSerializer.toJSON(data)); 

 

여기서 jsonObj를 출력하면 

 

     {"author":"Author1","isdn":"ISDN NBR","list":[{"a1":"A1","a2":"A2","a3":"A3"}, 

     {"a1":"B1","a2":"B2","a3":"B3"},{"a1":"C1","a2":"C2","a3":"C3"}],"title":"Book Title"}

 

로 나오므로 ArrayList 타입의 속성 list도 제대로 JSON 형식으로 변환된 것을 확인할 수 있다.

(JSON에서 배열 형식은 "[ ]"를 써서 표현함.)

 

 

 


JSONObject에서 데이터 처리하기


이제 JSON 형식으로 정의된 문자열 (json-lib에서는 JSONObject 객체에 이 문자열을 담음)을 파싱해서

특정 데이터를 읽거나 java 객체로 만드는 과정을 알아보자.

 

그런데 XML과는 달리 JSON은 자체적으로 스키마를 정의하는 형식이 없으므로 프로그래머가 JSON 형식

문자열의 각 key와 value가 어떤 객체의 어떤 속성과 값에 해당하는지 알아야 한다.

예를 들어 위에서 처럼 

 

  {"author":"Author1","isdn":"ISDN NBR","list":[{"a1":"A1","a2":"A2","a3":"A3"},

  {"a1":"B1","a2":"B2","a3":"B3"},{"a1":"C1","a2":"C2","a3":"C3"}],"title":"Book Title"}

 

라는 JSON 문자열을 받았을 때 이것이 TestData 객체에 할당되어야 하고 "author" key의 값은 author 속성의 값이 되어야 하며 "list" 키에 할당된 배열 값은 ArrayList 타입인 list 속성에 ArrayList의 각 엘리먼트로

들어간다는 것이 미리 약속되어 있어야 하는 것이다.

이런 번거로움과 비슷한 코드를 계속 개발해야 하는 문제를 해결 하기 위해서 프로젝트에서 표준으로

객체의 속성명과 JSON의 key 이름을 같게 하도록 정의하고, 각 JSON문자열마다 id를 부여하고 marshalling되는 객체의 클래스명을 정의하는 등 몇 가지 규칙과 정보를 제공하면 JSON 문자열로부터

해당 객체를 생성하는 프로그램을 만들어서 공통으로 사용할 수 있을 것이다. 

간단하게 JSON 문자열의 key, value를 읽어서 출력하는 예제 프로그램이다.

       public void getJSON(String json){      

             JSONObject jsonObj = JSONObject.fromObject(JSONSerializer.toJSON(json));

             Iterator itr=jsonObj.keys();            

             while(itr.hasNext()){

                    Object key=itr.next();

                    System.out.println("\t key : "+key+" , value : "+jsonObj.get(key));

                    if(jsonObj.get(key).getClass().equals(new JSONArray().getClass())){

                           this.showList((JSONArray)jsonObj.get(key));

                    }

             }            

       }      

       public void showList(JSONArray jsonArray){

             ListIterator itr=jsonArray.listIterator();            

             while(itr.hasNext()){

                    JSONObject obj=(JSONObject)itr.next();

                    System.out.println("Element "+jsonArray.indexOf(obj)+" : ");

                    this.getJSON(obj.toString());                   

             }

      

 


 

showList는 배열 형식 데이터가 표현된 경우에 별도로 핸들링하도록 만든 메소드이고, getJSON 메소드에서 사용한 것처럼 iterator를 써서 모든 key와 value를 읽어오는 방법도 있고 필요시 get() 메소드를 써서
get("author") 형식으로 특정 key의 값을 가져올 수도 있다. (필요하다면 특정 java 객체의 특정 속성에
이렇게 읽어온 값을 할당하면 된다.)

 

 

 

JSONObject에서 XML 만들기

  

XMLSerializer 객체의 write() 메소드를 쓰면 되는데, 주지하다시피 JSON에는 XML같은 스키마나
네임스페이스 같은 개념이 없으므로 네임스페이스가 정의되지 않은 plain XML 형태가 나온다.

String xml = new XMLSerializer().write(jsonObj);

예를 들어 위의 xml 문자열을 출력해보면 

<?xml version="1.0" encoding="UTF-8"?>
<o><author type="string">Author1</author><intVar type="number">1</intVar><isdn type="string">ISDN NBR</isdn><list class="array"><e class="object"><a1 type="string">A1</a1><a2 type="string">A2</a2><a3 type="string">A3</a3></e><e class="object"><a1 type="string">B1</a1><a2 type="string">B2</a2><a3 type="string">B3</a3></e><e class="object"><a1 type="string">C1</a1><a2 type="string">C2</a2><a3 type="string">C3</a3></e></list><title type="string">Book Title</title></o>

과 같이 나온다.

 



 

XML에서 JSONObject 만들기


마찬가지로, XML에서 JSONObject를 만들 때도 스키마나 네임스페이스 정보는 누락되고 데이터만
JSON 형태로 변환된다.
XML 스트링을 바로 JSONObject로 변환할 때는 XMLSerializer 객체의 read()
메소드에 XML 스트링을 파라미터로 쓴다.

JSONObject jsonObj = (JSONObject)new XMLSerializer().read(xml);

System.out.println(jsonObj);



다음으로, XML 파일을 읽어서 JSONObject 를 만드는 예제를 살펴보자.
JSONObject jsonObj = (JSONObject)new XMLSerializer().readFromFile("..\\..\\src\\test\\xmlTest.txt");  


XMLSerializer 객체의 readFromFile() 메소드를 쓰고 File 객체나 파일 경로가 담긴 string을 파라미터로 
지정하면 된다.

[참고] json-lib은 Apache Software License version 2.0을 따르고 있으며
상세한 API는 javadoc http://json-lib.sourceforge.net/apidocs/jdk15/index.html을 참조할 수 있다.

이상으로 간단하게 json-lib 2.2.2를 써서 Java에서 JSON 데이터를 처리하는 방법을 살펴보았다.

JSON은 단순함과 가벼움이 장점인 만큼 데이터 형식 validation 기능을 별도 구현해야 하는 부담이나
네임스페이스 개념 부재 등으로 XML보다 제한된 데이터 포맷임은 분명하다.


그러나, 엄격한 스키마 validation이 필요하지 않거나, 데이터 validation에 대한 부담보다 XML 처리에
따르는 리소스 문제가 더 크다면, 그리고 단지 데이터를 전달하고 읽는 목적에만 맞다면 JSON이 XML에
비해 가볍고 쉬운 대안이 될 수 있을 것이다. 


또한 자체 데이터 포맷을 정의할 때보다 오픈소스 파서 라이브러리가 많으므로 파서 개발 및 검증에 따르는
부담을 덜 수 있고 여러 웹 서비스에서 현재 사용되고 있는 검증된 데이터 포맷이라는 장점도 있다.


이런 여러 관점에서 살펴서 적절한 용도에 사용한다면 상당히 유용한 데이터 형식이라는 생각이 든다.

 

 

commons-collections-3.2.jar
0.54MB
xom-1.2.7.jar
0.3MB
commons-lang-2.3.jar
0.23MB
ezmorph-1.0.4.jar
0.08MB
commons-beanutils.jar
0.18MB
commons-logging-1.1.1.jar
0.06MB