It's Ward

JAVA ObjectMapper 직렬화 구현 (Basic) 본문

Java/Java 기본

JAVA ObjectMapper 직렬화 구현 (Basic)

I'm ward 2022. 5. 26. 04:22

 

ObjectMappersJSON 형식을 사용할 때, 들어온 데이터를 직렬화(Serialize) 하거나 요청들을 역직렬화(Deserialize)를 할 때 사용되는 클래스이다.

간단하게 JSON , 직렬화, 역직렬화에 대해 설명하자면

1. JSON (JavaScript Object Notation)

이름은 자바 스크립트에서만 사용할 것 같지만 그렇지않다. 

원래는 자바 스크립트로부터 만들어진 것은 맞지만, 직관적이고 프로그래밍 언어에 독립적으로 사용할 수 있는 데이터 포멧 방식이라는 점에서 현재는 서버와 웹 통신등에서 굉장히 많이 사용되고 있다.

단순하게 "키 : 값" 이렇게 쌍으로 이루어져 있는 텍스트 방식의 포멧이다.

["id" : "cvxkjv293jcv"]
"number" : 123

 

2. 직렬화(Serialize)

데이터를 전송하거나 저장 할 때, 문자열(String) = 텍스트 형식이여야 하기때문에 데이터들을 문자열로 바꿔주는 작업이다.

Object -> String

3. 역직렬화(Deserialize)

프로그램에서 사용할 수 있도록 요청데이터(텍스트형식)를 다시 데이터로 바꿔주는 작업이다.

String -> Object

 

이 중 직렬화 프로그램을 구현하였다. 

  String Integer Boolean array[] hashmap<?, ?>
직렬화 String "문자열" 12 true / false [12, "문자열"] {"key", "value"}

다음과같이 간단한 예시로 Object가 들어왔을 때, String이면 양 옆에 " "를 추가하거나 array인 경우 [] 를 추가하여 어떤 데이터인지 확인 할 수 있도록 하는 프로그램이다.

가장 간단하게, String의 경우

 public String stringify(Object data) {

        final char quotes = '"';
//        //입력 데이터 문자열
        if (data instanceof String)
            return quotes + data.toString() + quotes;
}

다음과 같이 데이터 양 옆에 큰따옴표("")를 추가하였다. 

Integer와 Boolean의 경우에는 valeOf를 사용해 데이터를 가지고 왔다.

if (data instanceof Integer || data instanceof Boolean)
   return String.valueOf(data);

array[] 인경우에는 다음과 같이 작성하였다.

if (data instanceof Object[]) {
    String result = "";

    for (Object o : (Object[]) data)
        result += stringify(o) + ",";

    if(result.length() > 0)
        result = result.substring(0,result.length() -1);

    return "[" + result + "]";
}

array[] 인경우 고쳐야 할점이 있다.

Json을 사용하는 방식은 대용량의 데이터가 들어올 텐데 String을 +로 붙히는 작업은 굉장한 속도저하를 일으키기 때문이다. 물론 적은 데이터는 표시도 안난다 

자세한 내용은 아래를 참조하자

2022.05.26 - [Java/Java 기본] - JAVA String, StringBuilder, StringBuffer

그렇기 때문에 추후에 해당 내용은 수정하기로 하였다.

문제의 hashMap이다. 풀이방법이 굉장히 다양한데, 

단순 형 변환

if (data instanceof HashMap) {
    String result = "";
    String key = "";
    String set = "";
    for(Map.Entry<?,?> entry : ((HashMap<?, ?>) data).entrySet()) {
        key = stringify(entry.getKey());
        set = stringify(entry.getValue());
        result += key + ":" + set + ",";
    }

    if(result.length() > 0)
        result = result.substring(0,result.length() -1);

    return "{" + result + "}";
}

LinkedHashMap +  toString

if (data instanceof HashMap){
  HashMap<String, String> newHashMap = new LinkedHashMap<>();

  for(Object d :  ((HashMap<?, ?>) data).keySet()){
    newHashMap.put(stringify(d), stringify(((HashMap<?, ?>)data).get(d)));
  }

  return newHashMap.toString().replace("=", ":").replace(" ", "");
}

JAVA8 Stream

if (data instanceof HashMap){
String str=((HashMap<?, ?>) data).entrySet()
.stream()
.map(e-> stringify(e.getKey()) + ":" + stringify(e.getValue()))
.collect(Collectors.joining(","));
  return "{" + str + "}";
}

셋 다 동일한 코드임을 확인하였다. 하지만 모두 빌드 후 적은 테스트케이스로 확인하였을 때

LinkedHashMap +  toString > JAVA8 Stream > 단순 형 변환 순으로 성능이 좋은것을 확인하였다.(시간 측정)

물론 단순 형 변환도 위에 언급한 것 처럼 String + 부분을 없에면 빨라질 여지도 있지만, LinkedHashMap의 가장 큰 장점은, 굉장히 직관적이고 간단하게 해결하였다는 점이 마음에 들었다.

다양한 방법들을 익히고, 더 고민해보아야 겠다.

Comments