ํ˜„์žฌ ์กฐ์ง์—์„œ JPA ๋ผ๋Š” ORM ๊ธฐ์ˆ ์„ ํ™œ์šฉํ•˜๊ณ  ์žˆ์ง€ ์•Š์ง€๋งŒ ์˜ค๋žœ๋งŒ์— JPA๋ผ๋Š” ๊ธฐ์ˆ ์„ ํ†ตํ•ด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์™€ ํ†ต์‹ ํ•ด๋ณด๊ณ  ๊ฒฝํ—˜ํ•˜๊ฒŒ ๋œ ๋ฌธ์ œ์™€ ํ•ด๊ฒฐ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ๊ณต์œ ํ•ด๋ณด๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค. MySQL ๋˜๋Š” PostgreSQL ์—์„œ๋Š” JSON ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•˜๊ณ  ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” ํ•จ์ˆ˜๋ฅผ ์ œ๊ณตํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. PostgreSQL์—์„œ JSONB ์ปฌ๋Ÿผ์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๊ณผ์ •์—์„œ ๋ชจ๋ธ ํด๋ž˜์Šค์— ๋งž์ง€ ์•Š์€ ํ•„๋“œ๊ฐ€ ํฌํ•จ๋  ๋•Œ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋Š” UnrecognizedPropertyException ์˜ˆ์™ธ๋ฅผ ๊ฒฝํ—˜ํ–ˆ๋Š”๋ฐ์š”.

DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES

๋จผ์ €, ์Šคํ”„๋ง ๋ถ€ํŠธ ํ”„๋กœ์ ํŠธ์—์„œ ์ž๋™ ๊ตฌ์„ฑ์„ ํ†ตํ•ด ๊ธฐ๋ณธ์ ์œผ๋กœ ์ œ๊ณตํ•˜๋Š” ObjectMapper์— ๋Œ€ํ•ด์„œ ์•Œ ์ˆ˜ ์—†๋Š” ํ•„๋“œ๊ฐ€ ํฌํ•จ๋œ ๊ฒฝ์šฐ ์˜ค๋ฅ˜๋กœ ์ฒ˜๋ฆฌํ•˜์ง€ ์•Š๋„๋ก ์•„๋ž˜์™€ ๊ฐ™์ด ๋‹ค์–‘ํ•œ ๋ฐฉ๋ฒ•์œผ๋กœ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์€ ๋Œ€๋ถ€๋ถ„ ์ธ์ง€ํ•˜๊ณ  ์žˆ๋Š” ์ •๋ณด๋ผ๊ณ  ์ƒ๊ฐ๋ฉ๋‹ˆ๋‹ค.

  • @JsonIgnoreProperties(ignoreUnknown = true)
  • DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES
  • spring.jackson.deserialization.fail-on-unknown-properties
application.yml
spring.jackson.deserialization.FAIL_ON_UNKNOWN_PROPERTIES: false

ํ˜„์žฌ ์กฐ์ง์˜ ํ”„๋กœ์ ํŠธ์—์„œ๋Š” Jackson2ObjectMapperBuilder๋ฅผ ๋นˆ์œผ๋กœ ์ง์ ‘ ๋“ฑ๋กํ•˜์—ฌ ์ปค์Šคํ…€ ์˜ต์…˜์ด ์ ์šฉ๋œ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์–ด์š”!

JPA ์—์„œ๋Š” FAIL_ON_UNKNOWN_PROPERTIES ์„ค์ •์ด ์ ์šฉ๋˜์ง€ ์•Š์Œ

Caused by: java.lang.IllegalArgumentException: The given string value: {"active": true, "mfa_type": "email"} cannot be transformed to Json object
	... 79 common frames omitted
Caused by: com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "mfa_type" (class kr.kdev.demo.UserEntity$Metadata), not marked as ignorable (one known property: "active"])
 at [Source: REDACTED (`StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION` disabled); line: 1, column: 31] (through reference chain: kr.kdev.demo.UserEntity$Metadata["mfa_type"])

์œ„ ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๋Š” JPA ์—์„œ JSONB ์ปฌ๋Ÿผ์— ์˜ฌ๋ฐ”๋ฅด์ง€ ์•Š์€ ํ•„๋“œ๊ฐ€ ํฌํ•จ๋œ JSON์„ ๋ชจ๋ธ ํด๋ž˜์Šค๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ๊ณผ์ •์—์„œ ๋ฐœ์ƒํ•œ ๊ฒƒ ์ž…๋‹ˆ๋‹ค. ์•ž์„œ, ์Šคํ”„๋ง ๋ถ€ํŠธ์—์„œ ๊ธฐ๋ณธ์œผ๋กœ ์ œ๊ณตํ•˜๋Š” ObjectMapper์— FAIL_ON_UNKNOWN_PROPERTIES ๋ฅผ ์„ค์ •ํ–ˆ๋Š”๋ฐ ์™œ ์ ์šฉ์ด ์•ˆ๋˜๋Š”๊ฑธ๊นŒ์š”? ๊ทธ ์ด์œ ๋Š” JSON ๋ฐ์ดํ„ฐ๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด์„œ ์ ์šฉํ•œ Hypersistence Utils์—์„œ ์‚ฌ์šฉํ•˜๋Š” JacksonJsonFormatMapper ์—์„œ ์Šคํ”„๋ง ๋นˆ ํŒฉํ† ๋ฆฌ์—์„œ ๊ด€๋ฆฌํ•˜๋Š” ObjectMapper ์ธ์Šคํ„ด์Šค๊ฐ€ ์•„๋‹ˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

PostgreSQL JSONB ์ปฌ๋Ÿผ ๋งคํ•‘ ์‹œ ObjectMapper ๋ณ€๊ฒฝํ•˜๋Š” ๋ฐฉ๋ฒ•

JPA ์—์„œ JSON ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ ์‹œ ์‚ฌ์šฉํ•˜๋Š” ObjectMapper๋ฅผ ์Šคํ”„๋ง ๋ถ€ํŠธ์—์„œ ๋นˆ์œผ๋กœ ๊ด€๋ฆฌํ•˜๋Š” ์ธ์Šคํ„ด์Šค๋กœ ๋ณ€๊ฒฝํ•˜๋ ค๋ฉด ์•„๋ž˜์™€ ๊ฐ™์€ ๋ฐฉ๋ฒ•๋“ค์„ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

@Bean
public HibernatePropertiesCustomizer jsonFormatMapperCustomizer(ObjectMapper objectMapper) {
    return (properties) -> properties.put(AvailableSettings.JSON_FORMAT_MAPPER,
        new JacksonJsonFormatMapper(objectMapper));
}

์ €๋Š” ์Šคํ”„๋ง ๋ถ€ํŠธ ์ด์Šˆ ํ‹ฐ์ผ“์—์„œ ์•Œ๋ ค์ฃผ๋Š” HibernatePropertiesCustomizer๋กœ ObjectMapper๋ฅผ ์ ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค.