๐ŸŒฑ @JsonProperty, @JsonNaming


์ด ๊ธ€์„ ์“ด ๋ฐฐ๊ฒฝโ€ฆ

ํด๋ผ์ด์–ธํŠธ์—์„œ HTTP Body์— Json์„ ์‹ค์–ด ์š”์ฒญ์„ ์‹ค์–ด ๋ณด๋‚ด๊ณ  ์ด๋ฅผ ๋ฐ›๋Š” DTO๋ฅผ ๋งŒ๋“ค์–ด ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์—ˆ๋‹ค.
ํ•˜์ง€๋งŒ API ๋ช…์„ธ๋กœ ํด๋ผ์ด์–ธํŠธ์—์„œ๋Š” key ๋„ค์ด๋ฐ์œผ๋กœ ์Šค๋„ค์ดํฌ ์ผ€์ด์Šค๋ฅผ ์‚ฌ์šฉํ•˜๊ณ ,
DTO ํ•„๋“œ๋กœ๋Š” ์Šค๋„ค์ดํฌ ์ผ€์ด์Šค๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์— Jackson์ด DTO์— ์ œ๋Œ€๋กœ ๋งคํ•‘ํ•˜์ง€ ๋ชปํ•ด ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ–ˆ๋‹ค.

๊ทธ๋ž˜์„œ API ๋ช…์„ธ์—์„œ, ํด๋ผ์ด์–ธํŠธ๊ฐ€ key๋ฅผ ์Šค๋„ค์ดํฌ ์ผ€์ด์Šค๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ณด๋‚ด์ฃผ๋„๋ก ๋ฐ”๊พธ๋ ค ํ•˜์˜€์œผ๋‚˜,
๋˜‘๋˜‘ํ•œ ์Šคํ”„๋ง์€ ์ด๋ฅผ ์œ„ํ•œ ์–ด๋…ธํ…Œ์ด์…˜์„ ์ œ๊ณตํ•ด์ฃผ๊ณ  ์žˆ์—ˆ๋‹ค.

๋ฌธ์ œ ์ƒํ™ฉ ํ…Œ์ŠคํŠธ

TestDto

public class TestDto {
    private Long testId;

    public TestDto() {
    }

    public TestDto(Long testId) {
        this.testId = testId;
    }

    public Long getTestId() {
        return testId;
    }

    public void setTestId(Long testId) {
        this.testId = testId;
    }
}
  • ํ•„๋“œ๊ฐ€ ์Šค๋„ค์ดํฌ ์ผ€์ด์Šค

Test2Dto

public class Test2Dto {
    private Long test_id;

    public Test2Dto() {
    }

    public Test2Dto(Long test_id) {
        this.test_id = test_id;
    }

    public Long getTest_id() {
        return test_id;
    }

    public void setTest_id(Long test_id) {
        this.test_id = test_id;
    }
}
  • ํ•„๋“œ๊ฐ€ ์นด๋ฉœ ์ผ€์ด์Šค

TestController

@RestController
public class TestController {
    @GetMapping("/test")
    public ResponseEntity<TestDto> test() {
        return ResponseEntity.ok().body(new TestDto(10L));
    }

    @PostMapping("/test")
    public ResponseEntity<TestDto> test(@RequestBody TestDto testDto) {
        System.out.println(testDto.getTestId());
        return ResponseEntity.ok().body(new TestDto(10L));
    }

    @GetMapping("/test2")
    public ResponseEntity<Test2Dto> test2() {
        return ResponseEntity.ok().body(new Test2Dto(10L));
    }

    @PostMapping("/test2")
    public ResponseEntity<Test2Dto> test2(@RequestBody Test2Dto testDto) {
        System.out.println(testDto.getTest_id());
        return ResponseEntity.ok().body(new Test2Dto(10L));
    }
}

์ด ๋•Œ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ํ…Œ์ŠคํŠธ๋ฅผ ๋Œ๋ ค๋ณธ๋‹ค.

@Test
void postTest() throws Exception {
    // given
    Test2Dto testDto = new Test2Dto(10L);
    String json = new ObjectMapper().writeValueAsString(testDto);
    System.out.println(json);

    // then
    mockMvc.perform(MockMvcRequestBuilders
            .post("/test")
            .content(json)
            .header("Content-Type", "application/json"))
            .andDo(print())
            .andExpect(status().isOk())
            .andExpect(jsonPath("$.test_id").value(10L));
}

๊ฒฐ๊ณผ๋Š” ์‹คํŒจํ•œ๋‹ค!
์™œ๋ƒํ•˜๋ฉด ํด๋ผ์ด์–ธํŠธ๋Š” ์Šค๋„ค์ดํฌ ์ผ€์ด์Šค๋กœ ํ‚ค ๊ฐ’์„ ๋ณด๋‚ด๊ณ  ์‘๋‹ต์— ๋Œ€ํ•œ ํ‚ค ๊ฐ’๋„ ์Šค๋„ค์ดํฌ ํ‘œ๊ธฐ๋ฒ•์ด์—ˆ๋Š”๋ฐ,
๋ฐ˜ํ™˜ํ•˜๋Š” DTO์˜ ํ•„๋“œ๊ฐ€ ์นด๋ฉœ ์ผ€์ด์Šค์ด๊ธฐ ๋•Œ๋ฌธ์— ์ž๋™์œผ๋กœ ํ‚ค ๊ฐ’์ด ์นด๋ฉœ ์ผ€์ด์Šค๋กœ ์žกํžˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

ํ”„๋ก ํŠธ์—์„œ๋Š” ์Šค๋„ค์ดํฌ ์ผ€์ด์Šค๊ฐ€ ์ปจ๋ฒค์…˜์ด๊ณ , ์šฐ๋ฆฌ ์ž๋ฐ”์—์„œ๋Š” ์นด๋ฉœ ์ผ€์ด์Šค๊ฐ€ ์ปจ๋ฒค์…˜์ธ๋ฐโ€ฆ
๊ทธ๋Ÿผ DTO์˜ ํ•„๋“œ๋ฅผ ์Šค๋„ค์ดํฌ๋กœ ๋ฐ”๊ฟ”์•ผ ํ•˜๋‚˜? ํ˜น์€ ์š”์ฒญ์˜ ํ‚ค ๊ฐ’์„ ์นด๋ฉœ๋กœ ๋ฐ”๊ฟ”์•ผ ํ•˜๋‚˜? ๐Ÿคทโ€โ™€๏ธ


@JsonProperty

๋งŒ๋Šฅ ์Šคํ”„๋ง์€ ์—ญ์‹œ ์ด์— ๋Œ€ํ•œ ์–ด๋…ธํ…Œ์ด์…˜์„ ์ œ๊ณตํ•ด์ค€๋‹ค.
@JsonProperty ๋Š” JSON ๋ณ€ํ™˜ ์‹œ key ์ด๋ฆ„์„ ์šฐ๋ฆฌ๊ฐ€ ์›ํ•˜๋Š” ๋Œ€๋กœ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค€๋‹ค.
์ด ์–ด๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” jackson ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ์•ผ ํ•˜์ง€๋งŒ, ์ด๋ฏธ ์Šคํ”„๋ง ๋‚ด๋ถ€์—์„œ๋Š” jackson์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋‹ค.

์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ์›ํ•˜๋Š” ํ•„๋“œ์— ํ•ด๋‹น ์–ด๋…ธํ…Œ์ด์…˜์„ ๋‹ฌ๊ณ , ๋งคํ•‘ํ•  key ์ด๋ฆ„์„ ์˜ต์…˜์œผ๋กœ ์ค€๋‹ค.

public class TestDto {
    @JsonProperty("test_id")
    private Long testId;

    public TestDto() {
    }

    public TestDto(Long testId) {
        this.testId = testId;
    }

    public Long getTestId() {
        return testId;
    }

    public void setTestId(Long testId) {
        this.testId = testId;
    }
}

์ด๋ ‡๊ฒŒ ๋˜๋ฉด ํ…Œ์ŠคํŠธ ์„ฑ๊ณต์ด๋‹ค!

๊ทธ๋Ÿฌ๋ฉด ํ•„๋“œ ํ•˜๋‚˜ํ•˜๋‚˜์— ์ด๋ ‡๊ฒŒ ๋งคํ•‘ํ•ด์ฃผ์–ด์•ผํ•˜๋‚˜โ€ฆ?


@JsonNaming

๋‹คํ–‰ํžˆ๋„ ์ด๋Ÿฐ ์ค‘๋ณต๋˜๋Š” ์ž‘์—…์„ ์Šคํ”„๋ง ์–ด๋…ธํ…Œ์ด์…˜์œผ๋กœ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค.
ํด๋ž˜์Šค์— @JsonNaming ์„ ๋ถ™์ด๋ฉด ๋ชจ๋“  ํ•„๋“œ์— ๋Œ€ํ•œ ํ‘œ๊ธฐ๋ฒ• ๋งคํ•‘์„ ์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.databind.annotation.JsonNaming;

@JsonNaming(value = PropertyNamingStrategy.SnakeCaseStrategy.class)
public class TestDto {
    private Long testId;

    public TestDto() {
    }

    public TestDto(Long testId) {
        this.testId = testId;
    }

    public Long getTestId() {
        return testId;
    }

    public void setTestId(Long testId) {
        this.testId = testId;
    }
}

์ฐธ๊ณ ๋กœ ํ‘œ๊ธฐ๋ฒ• ์ „๋žต์€ SnakeCaseStrategy ๋ง๊ณ ๋„ ๋‹ค์–‘ํ•˜๋‹ค!

์ „์—ญ์ ์œผ๋กœ ์„ค์ •ํ•˜๊ณ  ์‹ถ์–ด!

application.properties ์—์„œ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์„ค์ •์œผ๋กœ ๋‘˜ ์ˆ˜๋„ ์žˆ๋‹ค.
์ด๋Ÿฌ๋ฉด ๊ฐ๊ฐ์˜ ํด๋ž˜์Šค์— ์–ด๋…ธํ…Œ์ด์…˜์„ ๋‹ฌ์•„์ฃผ์ง€ ์•Š์•„๋„ ๋ชจ๋“  ํ‚ค ๋งคํ•‘์— ๋Œ€ํ•œ ์ฒ˜๋ฆฌ๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค!

spring.jackson.property-naming-strategy=SNAKE_CASE