자바스크립트와 자바, 파이썬, C, C++등 다른 언어간 통신,즉 구성된 각각의 클라이언트와 서버간의 데이터 통신에서 자바스크립트의 데이터와 다른 프로그래밍언어에서의 데이터 처리가 다름으로, 이 차이를 통일시키기 위해 사용되는 것이 JSON
입니다.
예를 들어 자바는 Integer, Double, Boolean, String, 배열, 객체,...등등 자바만의 데이터타입이 존재하는데에 반해 자바스크립트는 단순히 변수, 배열, 객체...등등 자바스크립트만의 데이터타입이 존재함으로 이를 문자열로 통일 시켜 전송하고, 문자열을 자기만의 데이터타입으로 변환하기위해 사용되는 약속된 규칙입니다.
데이터 타입을 문자열로 바꾸었다고 하여 무조건 JSON
이 되는 것은 아닙니다.
"{"키1":null,"키2":true,"키3":"string","키4":30,"키5":[값1,값2,...],"키6":{
"키6-1":"string2","키6-2":[값1,값2,...],"키6-3":{키,값}}
등으로 JSON
에는 null
, Number(숫자)
, Boolean
, String
, Object
, Array
가 요소로 들어올 수 있습니다.
Array
나 Object
내부에는 또 다시 null
, Number(숫자)
, Boolean
, String
, Object
, Array
가 요소로 들어올 수 있습니다.
주의해야 할점은
1. JSON은 계층적인 데이터 구조(예를 들면 배열안의 배열안의 배열안의 .....)를 허용한다는점
2. 무조건 키
: 값
쌍으로만 이루어 진다는 점
3. 키
와 문자열
은 반드시 쌍따옴표""
로 묶고 키,값사이에는 띄어쓰기가 없어야 합니다.
우리가 흔히 사용하는 객체, 배열, 컬렉션 등등 자바환경에서 사용할때 모든 데이터들이 수평적이지 않고 배열 변수나, 객체에 계층적인 구조로 이루어 져있습니다. 이것을 전송과 자바스크립트에서의 읽기를 위해 모두 한줄의 문자열로 압축시키는 것을 Serialization
이라고 합니다. 반대로 한줄로 압축된 문자열을 다시 계층적인 구조로 복구시키는 것을 Deserialization
이라고 합니다.
자바 환경
-> Serialization
-> JSON
-> Deserialization
-> 자바스크립트 환경
자바스크립트 환경
-> Serialization
-> JSON
-> Deserialization
-> 자바 환경
의 과정으로 자바
와 자바스크립트
환경이 각각 JSON
으로 변환시켜 데이터를 주고받는 과정을 거칩니다.
Jackson
라이브러리는 간편하게 자바환경의 데이터를 간편하게 JSON으로 Serialization
시키고, 또 JSON을 간편하게 Deserialization
시키는 클래스와 메서드를 제공합니다.
ObjectMapper
클래스를 제공함으로써 해당클래스의 객체를 인스턴스화 하여 JSON변환을 손쉽게 사용할 수 있습니다.
ObjectMapper.writeValueAsString(Map)
: (키,값)쌍의 Map을 문자열로 변환 시킵니다.ObjectMapper.readValue(문자열,Map.class)
: JSON을 (키,값)상의 Map으로 변환 시킵니다.이외에도 readValue, WriteValue를 응용한 다양한 메서드들이 존재합니다.
앞서 설펴보았듯이 JSON은 null
, Number(숫자)
, Boolean
, String
, Object
, Array
가 요소로 들어올 수 있습니다. null
, Number(숫자)
, Boolean
, String
은 단일값을 가지므로 재귀적으로 표현할 수 없습니다.
불특정한 다수의 값을 가질 수 있는 Object
, Array
안에 존재하는 단일요소의 갯수만큼 재귀함수를 호출하여 구현할수 있을 것 같습니다.
또 JSON에서 Object
는 키 : 값
쌍으로 표현되므로 Map
컬렉션으로 표현할 수 있습니다.
//데이터의 타입이 배열일 경우
if(data instanceof Object[]){
//재귀함수 호출
return "[" + objectRecursive(data) + "]";
}
stringify(Object obj)
는 데이터의 타입을 구분하여 문자열을 반환하는 메서드입니다.
public String objectRecursive(Object data){
if(((Object[]) data).length == 0) return ""; //빈배열 -> 빈 문자열
if(((Object[]) data).length == 1) return stringify(((Object[])data)[0]); //['요소'] -> 재귀함수(['요소'])x , 재귀함수('요소')o
Object[] head = Arrays.copyOfRange((Object[])data, 0, 1); //head : 1
Object[] tail = Arrays.copyOfRange((Object[])data, 1, ((Object[]) data).length); //tail : n
/*
* [true, false, true, true]
* [true] [false,true,true]
* true [false][true,true]
* true false [true] [true]
* true false true [true]
* true false true true
* */
//head와 tail을 각각 문자열로
return objectRecursive(head) + "," + objectRecursive(tail);
}
피보나치를 응용하였습니다. 배열의 맨앞 요소만 따로 분리시켜 배열을 2개로 나누어 감소식을 구현하였고 빈 배열일땐 빈 문자열, 배열의 길이가 1일때 배열의 요소를 끄집어내어 해당 배열의 요소의 타입을 다시 분석하였습니다.
//입력된 값이 HashMap일 경우
if(data instanceof HashMap){
return "{" + mapRecursive(data) + "}";
}
stringify(Object obj)
는 데이터의 타입을 구분하여 문자열을 반환하는 메서드입니다.
public String mapRecursive(Object data){
//빈 해시 = 빈 문자열
if(((HashMap)data).isEmpty()) return "";
//하나의 해시맵 = 키 : 값 문자열
if(((HashMap)data).size()==1){
Iterator<Object> iter = ((HashMap)data).keySet().iterator();
String key = (String)(iter.next()); //키 가져오기
System.out.println(key);
return stringify((Object)key) + ":" + stringify((Object)(((HashMap)data).get(key))); //키 : 값
}
//2개 이상일 때 1(map) + n(data)개로 나눕니다.
HashMap<Object,Object> head = new HashMap<>(); //새로운 해시맵 head
Iterator<Object> iter = ((HashMap)data).keySet().iterator();
String key = (String)(iter.next()); //키 가져오기
head.put((Object)key,((HashMap)data).get(key)); //head에 1개 추가
((HashMap)data).remove(key);
return mapRecursive(head) + "," + mapRecursive(data);
}
배열과 마찬깆로 재귀적인 피보나치를 응용하였습니다. 맵의 1개 (키,값)쌍을 분리시켜 2개의 맵으로 나누어 감소식을 구현하였고 맵이 비어있을땐 단순히 빈 문자열을 반환, 1개 있을땐 키:값 문자열로 만들어 반환하여 종료조건을 구현하였습니다.
반복문을 이용하면 쉽게 구현할 수 있지만, 어제 배웠던 재귀문을 더욱 견고히 익히기 위해 반복문을 사용하지 않고 재귀만을 이용하여 구현하였습니다.
감소식
,종료조건
이 재귀함수의 핵심입니다.
없음!