이번에는 안드로이드 UrlQuerySanitizer를 Url Query를 파싱하는데 사용하지 않을 때 생긴 문제를 다루고자 한다.
문제 발생 배경
최근 새 프로젝트를 진행 중, API 응답이 json, xml, csv와 같은 형식이 아닌
URL의 GET method 사용 시 붙어있는 Query 형식으로 body 값을 주는 녀석이 있었다.
물론 반복문을 사용해서 일일히 파싱할 수도 있었지만,
Retrofit에서 json, xml 형식을 곧장 객체로 변환해주는 기능을 맛 본 이상 그 전으로 돌아가긴 싫었다.
그래서 찾다 보니 우회할 방법으로써 찾은 녀석이 UrlQuerySanitizer였다.
알고 보니 API level 1부터 유구한 역사를 가진 친구였지만 처음 들어봤다.(^^)
UrlQuerySanitizer.getValue 메소드를 사용해
어떤 파라미터의 값을 가져오려 했는데 그 값이 한글인 경우 제대로 파싱하지 못했다.
그럼 이제 뭐가 문제의 원인이었을까?
문제 원인
UrlQuerySanitizer 객체 생성 시, url를 파싱하는데 이 안에서 parseQuery 메소드를 호출한다.
문제는 parseQuery 메소드 안에서 StringTokenizer에서 if-else 문을 통해 parseEntry 메소드를 호출하는 부분이다.
그럼 다시, parseEntry에서 parameter와 value를 unescape 메소드로 통과시키는데
이 때, unescape 메소드는 ASCII 코드 내의 문자열을 처리할 수 있기 때문에
UTF-8 방식의 다른 문자열이 들어오면 이상한 값이 리턴된다.
해결
그럼 결국 unescape 메소드를 통과하면 안되는데 이를 어떻게 해결할까 고민했다.
답은 parseQuery 메소드를 그대로 가져오자!
val queryString = HashMap<String, String>()
val tokenizer = StringTokenizer(response.body(), "&")
while (tokenizer.hasMoreElements()) {
val attributeValuePair = tokenizer.nextToken()
if (attributeValuePair.isNotEmpty()) {
val assignmentIndex = attributeValuePair.indexOf('=')
if (assignmentIndex < 0) {
queryString[attributeValuePair] = ""
} else {
queryString[attributeValuePair.substring(0, assignmentIndex)] =
attributeValuePair.substring(assignmentIndex + 1)
}
}
}
여기서 response.body() 는 눈치가 빠른 사람이라면 Retrofit의 Response body 값이다.
짧은 예시를 들면 아래와 같은 바디 값을 queryString.getValue 메소드를 호출해서 파싱할 수 있다.
count=3&sentiment=보통&weather=맑음&account=normal
역시 라이브러리를 가져다 쓸 때는 원래 의도한 용도대로 쓰는 것이 정신 건강에 좋을 것 같다.
어쩌다 보니 자충수를 둔 것 같지만 나름 좋은 공부가 되었다.
'Android' 카테고리의 다른 글
Android Selector 사용 시 주의사항 (1) | 2024.04.06 |
---|---|
Android Change TextField Cursor Color (0) | 2024.03.13 |
Android ADB로 크래시 로그 저장하기 (0) | 2024.02.03 |
Android ADB로 스크린샷 저장하기 (0) | 2024.02.01 |
Android TextClock format 지정하기 (1) | 2024.01.01 |