본문 바로가기
Spring

GSON toJson, fromJson에 대한 ...삽질?!

by 작심평생 2020. 7. 25.
가변적(key, value변수가 어떤게 들어올지 모름..)으로 넘어오는 JSON 데이터가 있으며 특징으로는
upperCase에 underscope으로 Key값이 이뤄져있다. (이건 불변)
 
이때 카멜케이스로 만들어놓은 VO에 setting하는 과정 or Map으로 받는 과정에서 나름(...) 고민해본 흔적을 남기고자 한다...
 

 

[ FieldNamingStrategy 를 커스텀 하자! ]


    - toJson
        FieldNamingStrategy을 커스텀해서 내가 작성한 규칙으로 키값이 변경된 JSON 키값으로 변경 가능 


    - fromJson
        역직렬화 시 적용이 안되는데 이유를 모르겠다..

        ex. {“UP_DOWN" : “하하”} 인 경우, 맵핑하고자 하는 Class의 필드값이 upDown인 경우 맵핑이 안됨
        이때는 @SerializedName 이용

        @SerializedName(“UP_DOWN")
        private String upDown;

단점으로는….필드값이 많아지면….하나씩 선언해줘야할..꺼같다..(끔찍)
 


[ 상세 코드]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import com.google.gson.FieldNamingStrategy;
 
import java.lang.reflect.Field;
 
public class customNaming implements FieldNamingStrategy { // 커스텀 필드네이밍 전략 클래스
 
    // 대문자 언더스콥 -> 카멜케이스로
    @Override
    public String translateName(Field f) {
        int cnt = 0;
        StringBuilder tmpStr = new StringBuilder();
 
        String keyVal = f.getName(); // Json 데이터 키값 가져옴
        String[] splitVal = keyVal.toLowerCase().split("_");
 
        for (String str : splitVal) {
            if (cnt == 0) {
                tmpStr.append(str);
                cnt++;
            } else {
                str = str.trim();
                StringBuilder stringBuilder = new  StringBuilder(str);
                stringBuilder.setCharAt(0,  Character.toUpperCase(str.charAt(0))); // 맨 앞 한글자만 대문자로
                String afterStr = stringBuilder.toString();
                tmpStr.append(afterStr);
            }
        }
        return tmpStr.toString();
    }
//------------------------------------------
// 호출 부분
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.setFieldNamingStrategy(new customNaming());
 
Gson gson = gsonBuilder.create();
testVO testVO = gson.fromJson(str, testVO.class);
 
 

 
 
넘어오는 JSON데이터의 키값이 가변적인 경우
VO에 다 맵핑할 수 없다. 따라서 맵으로 받는 방식
 
[ 제이슨 String 데이터 -> 링크드해쉬맵(키값이 카멜 적용이된) 으로 변환 (순서성 지키기위해) ]

  • 상황설명
    • 뷰에서 Ajax를 이용하여 목록 클릭 시 테이블이 있는 레이어 팝업을 띄우는 상황
    • 데이터는 DB에서 조회함. TH 데이터(코드값과 코드값이 의미하는 한글명)와 JSON 형식의 문자열이 저장되어있다.
    • TH_CODE 값과 JSON 데이터의 키값이 다른 경우는 없다.
    • 테이블에 뿌려줄때 각 항목이 일치하게 뿌려줘야 한다.
[ 테이블 Th에 뿌려줄 데이터 DB 조회 결과]

  • 불특정 시기에 DB의 데이터들이 언제 UPDATE, INSERT, DELECT 될지 모르는 상황
TH_CODE
TH_NAME
UP_DOWN
제목
 
[ 백단으로 넘어온 JSON 데이터 DB 조회 결과]
  • JSON 데이터 내의 순서는 랜덤. (어느값이 먼저올지 모름)
  • 문자열로 된 json data이다.
{“USE_YES_NO” :”NO”, “UP_DOWN” : “DOWN" }
 
[ 상세 코드]


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
    // 테이블 컬럼은 안 바뀌는데 VO를 안쓰고 왜 굳이 Map을 쓴건지?
    //  - 순서성이 중요하기 때문에 DB조회 순서로 그대로 가져오기 위해 LinkedHashMap 이용
    List<LinkedHashMap<String, Object>> thList = new ArrayList<LinkedHashMap<String, Object>>();
    List<LinkedHashMap<String, Object>> jsonList = new ArrayList<LinkedHashMap<String, Object>>();
 
    String keyVal = ""// JSON 데이터가 있는 쿼리 DB조회 후 컬럼값을 담을 변수
    String makeJsonStr = "{"//json 형식으로 문자열 만들어줄 변수
    String jsonKeyStr = ""// JSON 데이터의 키값을 담을 변수
 
    for(Map<String, Object> vo : resultList){ // resultList : 한 컬럼에 제이슨 형식의 문자열이 들어있다. 또한 ROW가 여러줄이기 때문에 List<Map> 형태로 가져온다
        Iterator<String> itr = vo.keySet().iterator(); // 키 리스트 (== 컬럼 이름값들이 들어 있을 것)
        while(itr.hasNext()){
            keyVal = itr.next();
            if (!keyVal.equals("JSON_DATA")) { // 제이슨 데이터가 들어있는 컬럼이름이 아닌 경우
                continue;
            }
            JSONObject obj = new JSONObject(vo.get(keyVal)); // JSONOBJECT : JSON 문자열 형태를 KEY : VALUE 형태로 형 변환
            Iterator<String> itr2 = obj.keys();
 
            while(itr2.hasNext()){
                jsonKeyStr = itr2.next();
                makeJsonStr += "\'"+jsonKeyStr + "\' : \'" + obj.getString(jsonKeyStr) + "\',"// 카멜케이스를 적용하려면 jsonKeyStr 대신 JdbcUtils.convertUnderscoreNameToPropertyName(jsonKeyStr) 이용
 
            }
            makeJsonStr = makeJsonStr.substring(0,makeJsonStr.lastIndexOf(","))+"}";
 
            LinkedHashMap<String, Object> jsonVo = new Gson().fromJson(makeJsonStr, new TypeToken<LinkedHashMap<String, Object>>(){}.getType());
 
            // th 코드값과 map으로 변환된 json 카값을 맞는 값을 맵핑하는 과정
            // th 코드값기준으로 키값 비교 돌리는 중
            LinkedHashMap<String, Object> finalLinkMap = new LinkedHashMap<>();
            for(Map<String, Object> thMap : resultTh){ // resultTh : th의 코드와 한글 이름값을 가져온 쿼리. List<Map> 형태
                Iterator<String> itr3 = thMap.keySet().iterator();
                while(itr3.hasNext()){
                    String keyVal2 = itr3.next();
                    if (keyVal2.equals("TH_CODE")) { // th코드값이 들어있는 컬럼 이름인 경우
                        String seachKeyVal = String.valueOf(thMap.get(keyVal2)); // th코드값 할당
                        finalLinkMap.put(seachKeyVal, jsonVo.get(seachKeyVal)); // th코드값, th코드값에 해당하는 JSON value 값
                    }
                }
            }
            jsonList.add(finalLinkMap);
            makeJsonStr = "{"// 초기화
        }
    }
    map.put("jsonList", jsonList);
 
    return new Gson().toJson(map);
}




댓글