-->

 

[Spring/Kotlin] form data array 바인딩 실패

view에서 multipart를 첨부하려고 form 데이터를 보내다가 에러를 마주했다. 

{
    "hashtagText": "",
    "postTags[0].postTagSeq": "0",
    "postTags[0].atrcTagSeq": "1142",
    "postTags[0].checked": "false",
    "postTags[1].postTagSeq": "0",
    "postTags[1].atrcTagSeq": "1143",
    "postTags[1].checked": "false",
    "postTags[2].postTagSeq": "1020",
    "postTags[2].atrcTagSeq": "1144",
    "postTags[2].checked": "true",
    "postTags[3].postTagSeq": "1021",
    "postTags[3].atrcTagSeq": "1145",
    "postTags[3].checked": "true",
    "postTags[4].postTagSeq": "0",
    "postTags[4].atrcTagSeq": "1146",
    "postTags[4].checked": "false",
    "postTags[5].postTagSeq": "1022",
    "postTags[5].atrcTagSeq": "1147",
    "postTags[5].checked": "true",
    "postTitle": "숨이 막혀 메이데이~!~",
    "postText": "따따따따따",
    "attachment": []
}

 

백엔드에서 데이터를 받기 위한 DTO를 다음과 같이 설정했다.

data class postUpdateReq(
    @Schema(defaultValue = "상태", required = true) val status: Status,
    @Schema(description = "어드민 ID", required = true) var adminId: String?,
    @Schema(description = "포스트 태그") val postTags: List<postTagReq>?,
    @Schema(description = "첨부파일") val attachment: MultipartFile?,
)

data class postTagReq(
    @Schema(description = "포스트 태그 번호") val postTagSeq: Long,
    @Schema(description = "상위게시글 태그 번호") val upperPostTagSeq: Long,
    @Schema(description = "포스트 체크 여부") val checked: Boolean,
)

보면 알다시피 List DTO를 선언했다.

그리고 컨트롤러 단에는 평소에 많이 사용하는 @RequestBodty  대신 @ModelAttribute  로 매핑하였다.

@PutMapping("/{postSeq}")
    @Operation(summary = "포스트 수정", description = "포스트를 수정한다.")
    fun updatepost(
    	@PathVariable postSeq: Long,
        @ModelAttribute req: postUpdateReq
    ): BaseResponse<postDetailRes> {
...
}

 

이렇게 설정하면 된다고 생각하고 호출을 보냈는데 에러가 발생했다.

org.springframework.beans.InvalidPropertyException: Invalid property 'postTags[0]' of bean class [core.models.dto.postUpdateReq]: Illegal attempt to get property 'postTags' threw exception

Caused by: java.lang.IllegalStateException: Default value must not be null

default value가 null 이라니..?? 난 파라미터를 정확히 세팅해서 보냈는데 왜 null로 세팅이 됐을까.

@ModelAttribute  는 값을 객체로 바인딩할 때 프로퍼티 접근법을 사용한다. 프로퍼티 접근법에서는 해당 객체를 기본 생성자로 생성하고 setter를 사용하여 파라미터로 전달한 값을 객체에 주입한다.

코틀린 data class에서 val  로 선언하면 getter만 생성되고 setter가 생성되지 않는다. 그래서 바인딩이 되지 않았던 것이다.

 

data class postUpdateReq(
    @Schema(defaultValue = "상태", required = true) val status: Status,
    @Schema(description = "어드민 ID", required = true) var adminId: String?,
    @Schema(description = "포스트 태그") var postTags: List<postTagReq>?,
    @Schema(description = "첨부파일") val attachment: MultipartFile?,
)

그래서 위와 같이 라이드 태그를 var  로 선언하였으나 또 에러가 발생했다.

org.springframework.beans.NullValueInNestedPathException: Invalid property 'postTags' of bean class [core.models.dto.postUpdateReq]: Could not instantiate property type [core.models.dto.postTagReq] to auto-grow nested property path
 org.springframework.web.servlet.mvc.method.annotation.ServletModelAttributeMethodProcessor.bindRequestParameters(ServletModelAttributeMethodProcessor.java:167)
    at org.springframework.web.method.annotation.ModelAttributeMethodProcessor.resolveArgument(ModelAttributeMethodProcessor.java:153)
Caused by: java.lang.NoSuchMethodException: core.models.dto.postTagReq.<init>()
    at java.base/java.lang.Class.getConstructor0(Class.java:3761)
    at java.base/java.lang.Class.getDeclaredConstructor(Class.java:2930)
    at org.springframework.beans.AbstractNestablePropertyAccessor.newValue(AbstractNestablePropertyAccessor.java:925)
    ... 55 more

 

List로 들어갈 DTO의 기본생성자가 없기 때문이다. 그래서 아래와 같이 수정해야 한다.

data class postTagReq(
    @Schema(description = "포스트 태그 번호") val postTagSeq: Long = 0L,
    @Schema(description = "상위게시글 태그 번호") val upperPostTagSeq: Long = 0L,
    @Schema(description = "포스트 체크 여부") val checked: Boolean? = null,
)

아니면 constructor 를 선언해도 된다.

 

물론 multipart 파일은 @RequestPart 으로 세팅하고 dto를 @RequestBody  데이터를 보내는 방법도 있다.

그러면 form에 선언한 파라미터를 한꺼번에 보내지 못하고 자바스크립트 조작을 해야한다.

프론트에서 Content-type은 한가지만 설정할 수 있기 때문이다.

무엇보다 이 원인을 해결하지 못하고 우회하는 것 같아 사용하지 않았다.

+ Recent posts