Kopring 쿼리파라미터를 오브젝트로 역직렬화하기

는 사실 Pageable 하면서 여러번 해봤는데 이번에 할 건 다음과 같다.

  1. 파라미터 모델이 졸라 많다.
  2. 각 파라미터 모델은 일부 intersection들이 있다.
  3. 각 프로퍼티의 역직렬화/직렬화 키는 같을 수도 있고 다를 수도 있다.

이럴때는 상속을 쓰는게 제일 나은데 인터페이스에 JsonProperty를 적용하면 그게 그걸 구현하는 클래스에서도 유지되는지 아리까리해서 그냥 간단하게 테스트…

일단 직렬화/역직렬화 키가 다르므로 이건 getter와 setter로 나눠서 JsonProperty를 설정하면 된다.

코틀린의 인터페이스는 프로퍼티를 가질 수 있으므로 @get:JsonProperty와 @set:JsonProperty는 쓸 수 있으나 @param:JsonProperty (생성자 프로퍼티용)은 붙일 수 없다. 따라서 이러한 인터페이스는 일반 클래스를 써야 하고 데이터 클래스로는 구현할 수 없다.

그래서 코드

@Target(AnnotationTarget.VALUE_PARAMETER)
@Retention(AnnotationRetention.RUNTIME)
annotation class QueryObject

구현할 MethodHandlerArgumentResolver에서 역직렬화할 파라미터를 구분하는 용도로 사용할 어노테이션이다.

class QueryObjectResolver(private val objectMapper: ObjectMapper): HandlerMethodArgumentResolver {
    override fun supportsParameter(parameter: MethodParameter): Boolean {
        return parameter.hasParameterAnnotation(QueryObject::class.java)
    }

    override fun resolveArgument(parameter: MethodParameter, mavContainer: ModelAndViewContainer?, webRequest: NativeWebRequest, binderFactory: WebDataBinderFactory?): Any? {
        return if (webRequest is ServletWebRequest) {
            val queryParams = webRequest.parameterMap.mapValues { it.value.firstOrNull() }
            objectMapper.convertValue(queryParams, parameter.nestedParameterType)
        } else {
            null
        }
    }
}

역직렬화하는애다. 사실 resolveArgument 쪽은 좀 더 복잡해야하나 테스트용으로 간단하게 만들었다. 얘는 WebMvcConfigurerer의 addArgumentResolvers에 넣어주면 된다.

interface CommonParams {
 @set:JsonProperty("foo")
 @get:JsonProperty("bar")
 var testParam: String?
}

class CommonParamsImpl: CommonParams {
 override var testParam: String? = null
}

쿼리 파라미터 키는 foo이지만 객체화한 이후로는 bar로 넘기게 만든다.

@RestController
@RequestMapping("/test")
class TestController {
 @GetMapping
 fun test(@QueryObject queryObject: CommonParamsImpl) = queryObject
}

테스트 컨트롤러다. 그 다음 /test?foo=2로 요청하면

{
 "bar": 2
}

가 나온다.

끗.

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다