Handling Null in Request DTO

About

Spring์˜ ์ปจํŠธ๋กค๋Ÿฌ์—์„œ @RequestBody ์–ด๋…ธํ…Œ์ด์…˜์„ ์ด์šฉํ•˜๋ฉด HTTP body์— ์žˆ๋Š” JSON ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ์ฒด๋กœ ๋ณ€ํ™˜ํ•ด ๋ฐ›์•„์˜ฌ ์ˆ˜ ์žˆ๋‹ค. JSON์— ์žˆ๋Š” ๋ชจ๋“  ๋ฐ์ดํ„ฐ๊ฐ€ ๊ผญ ํ•„์š”ํ•˜์ง€ ์•Š์•„์„œ ์˜ค์ง€ ์•Š์œผ๋ฉด ๋ฌด์‹œํ•˜๋Š” ๊ฒฝ์šฐ๋„ ์žˆ์ง€๋งŒ, ์ „๋ถ€ ํ•„์š”ํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

Java

Java์—์„œ๋Š” null checking์„ ์–ธ์–ด ์ฐจ์›์—์„œ ์ง€์›ํ•˜๊ณ  ์žˆ์ง€๋Š” ์•Š๋‹ค. ํ•˜์ง€๋งŒ Validation์˜ ์–ด๋…ธํ…Œ์ด์…˜์„ ํ†ตํ•ด ๊ฒ€์ฆํ•  ์ˆ˜ ์žˆ๋‹ค.

ProfileUpdateRequest.java
@Getter
@AllArgsConstructor
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class ProfileUpdateRequest {
    
    @NotNull
    private Int age;
    
    private String imageUrl;
}

@NotNull ์–ด๋…ธํ…Œ์ด์…˜์œผ๋กœ age๊ฐ€ null์ด๋ฉด ์˜ค๋ฅ˜๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

Kotlin

์ฝ”ํ‹€๋ฆฐ์—์„œ๋Š” nullable ํƒ€์ž…๊ณผ non-nullable ํƒ€์ž…์„ ๊ตฌ๋ถ„ํ•˜์—ฌ null safeํ•˜๊ฒŒ ๊ฐœ๋ฐœํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ์•ฝ๊ฐ„์˜ ์ฃผ์˜๊ฐ€ ํ•„์š”ํ•˜๋‹ค.

์ผ๋‹จ ์œ„์˜ ์ฝ”๋“œ๋ฅผ ์ฝ”ํ‹€๋ฆฐ์œผ๋กœ ๋ฐ”๋กœ ๋ฐ”๊พธ๋ฉด ์ด๋ ‡๊ฒŒ ๋  ๊ฒƒ์ด๋‹ค.

ProfileUpdateRequest.kt
data class ProfileUpdateRequest(
    @field:NotNull
    val age: Int

    val imageUrl: String
)

ํ•˜์ง€๋งŒ ์—ฌ๊ธฐ์„œ ์—ฌ๋Ÿฌ ๊ฐ€์ง€๋ฅผ ์ˆ˜์ •ํ•ด์•ผ ํ•œ๋‹ค.

  • ์ฝ”ํ‹€๋ฆฐ์€ nullable๊ณผ non-nullable ํƒ€์ž…์„ ํƒ€์ž… ๋’ค์— ?๋ฅผ ๋ถ™์ด๋Š” ๊ฒƒ์œผ๋กœ ๊ตฌ๋ถ„ํ•œ๋‹ค. ๋”ฐ๋ผ์„œ age๋Š” ์• ์ดˆ์— null์ด ๋  ์ˆ˜ ์—†๋‹ค.

  • ์ด๋ ‡๊ฒŒ ์ž‘์„ฑํ–ˆ์„ ๋•Œ age๊ฐ€ null๋กœ ๋“ค์–ด์˜ค๊ฒŒ ๋œ๋‹ค๋ฉด, @field:NotNull ์–ด๋…ธํ…Œ์ด์…˜์„ ํ†ตํ•ด validation ๋กœ์ง์ด ์‹คํ–‰๋˜๊ธฐ ์ „์— ๋ณ€์ˆ˜์— ๊ฐ’์„ ํ• ๋‹นํ•˜๋Š” ๊ณผ์ •๋ถ€ํ„ฐ ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค. ๋”ฐ๋ผ์„œ ์—ฌ๊ธฐ์„œ ์ด ์–ด๋…ธํ…Œ์ด์…˜์€ ์˜๋ฏธ๊ฐ€ ์—†๋‹ค.

  • ์›๋ž˜ @NotNull์ด ๋ถ™์–ด์žˆ์ง€ ์•Š์•˜๋˜ imageUrl์€ nullable ํƒ€์ž…์ด ๋˜์–ด์•ผ๊ฒ ๋‹ค.

์ˆ˜์ •์‚ฌํ•ญ์„ ๋ฐ˜์˜ํ•  ๋•Œ ์ด๋ ‡๊ฒŒ ํ•ด๊ฒฐํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ๋‹ค.

ProfileUpdateRequest.kt
data class ProfileUpdateRequest(
    @field:NotNull    
    val age: Int?,

    val imageUrl: String?
)

Solution

๋‚ด ์ƒ๊ฐ์—” ์ด ๋ฐฉ๋ฒ•์ด ๊ฐ€์žฅ ๊น”๋”ํ•  ๊ฒƒ ๊ฐ™๋‹ค. ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ง„ํ–‰ํ•˜์ž.

  • null๋กœ ๋ฐ›์•„๋„ ๋˜๋Š” ํ•„๋“œ๋Š” ๋‹จ์ˆœํžˆ ?๋ฅผ ๋ถ™์ธ๋‹ค. ์•„๋‹ˆ๋ฉด ๋ถ™์ด์ง€ ๋ง.

    ProfileUpdateRequest.kt
    data class ProfileUpdateRequest(
        val age: Int,
        
        val imageUrl: String?
    )
  • HttpMessageNotReadableException์„ exception handler์—์„œ ์žก๊ณ , ํ•„์š”ํ•˜๋‹ค๋ฉด ์ถ”๊ฐ€ ์ž‘์—…์„ ํ†ตํ•ด MissingKotlinParameterException์„ ๋‚ด๋ถ€์ ์œผ๋กœ ํƒ€์ž…์„ ์ฒดํฌํ•ด ๋ฉ”์‹œ์ง€๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

์ฐธ๊ณ ๋กœ, non-nullable ํƒ€์ž…์— null์ด ๋‹ด๊ธฐ๋ ค๊ณ  ํ•˜๋ฉด HttpMessageNotReadableException์ด ๋ฐœ์ƒํ•˜์ง€๋งŒ, ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•œ ์ง„์งœ ์›์ธ์ธ MissingKotlinParameterException๊ณผ๋Š” ์ง์ ‘์ ์ธ ํด๋ž˜์Šค ๊ด€๊ณ„๊ฐ€ ์—†๋‹ค.

REF

Last updated

Was this helpful?