๊ฒฝ๋กœ ์กฐํšŒ ๋ฏธ์…˜ ์ง„ํ–‰ ๋„์ค‘ ๋ฐ›์€ ํ”ผ๋“œ๋ฐฑ


ํ•ด๋‹น ๋ฆฌ๋ทฐ๋Š” DTO ์˜ ๊ธฐ๋ณธ ์ƒ์„ฑ์ž์— ๋Œ€ํ•œ ํ”ผ๋“œ๋ฐฑ์ด๋‹ค.

์Šคํ”„๋ง์„ ์ตํžˆ๋Š” ๊ฒƒ์— ๊ธ‰๊ธ‰ํ•˜๋‹ค ๋ณด๋‹ˆ ๋ง‰์—ฐํ•˜๊ฒŒ ๊ธฐ๋ณธ ์ƒ์„ฑ์ž๋ฅผ ์ถ”๊ฐ€ํ•˜๋ฉด @RequestBody ๊ฐ€ ์•Œ์•„์„œ ๊ฐ์ฒด๋กœ ๋ณ€ํ™˜๋œ๋‹ค๋Š” ์‚ฌ์‹ค๋งŒ ์•Œ๊ณ  ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์—ˆ๋‹ค.

์Šคํ”„๋ง์„ ์ ์ฐจ ์ ์‘ํ•จ์— ๋”ฐ๋ผ ๋ฌธ๋“ ์ด๋Ÿฐ ์งˆ๋ฌธ์ด ๋จธ๋ฆฟ์†์— ๋– ์˜ค๋ฅธ๋‹ค.

@RequestBody ๋กœ ๊ฐ์ฒด๋ฅผ ์–ด๋–ป๊ฒŒ ์ƒ์„ฑํ•˜๋Š”๊ฑฐ์ง€?

์ผ๋‹จ ๊ธฐ๋ณธ ์ƒ์„ฑ์ž๊ฐ€ ์—†์œผ๋ฉด ์ž‘๋™ํ•˜์ง€ ์•Š์œผ๋‹ˆ๊นŒ, ๊ธฐ๋ณธ ์ƒ์„ฑ์ž๋กœ ์ƒ์„ฑํ•  ๊ฒƒ ๊ฐ™์•„.

๊ทผ๋ฐ ๊ธฐ๋ณธ ์ƒ์„ฑ์ž๊ฐ€ private ์ด์–ด๋„ ์ž‘๋™ํ•˜๋˜๋ฐ ์–ด๋–ป๊ฒŒ ์ ‘๊ทผํ•˜๋Š”๊ฑฐ์ง€?

์–ด๋–ป๊ฒŒ ์ƒ์„ฑํ–ˆ๋‹ค๊ณ ํ•ด๋„ ๋‚ด DTO ๋Š” setter ๊ฐ€ ์—†๋Š”๋ฐ ์–ด๋–ป๊ฒŒ ํ•„๋“œ๊ฐ’์„ ํ• ๋‹นํ• ๊นŒ?

ํ•ด๋‹น ์งˆ๋ฌธ๋“ค์„ ์ •๋ฆฌํ•ด๋ณด๋ฉด, ํฌ๊ฒŒ ๋‘ ๊ฐ€์ง€ ์งˆ๋ฌธ์œผ๋กœ ์ •๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.

  1. ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๊ณผ์ •?
  2. ์ƒ์„ฑ๋œ ๊ฐ์ฒด์— ํ•„๋“œ๊ฐ’์„ ํ• ๋‹นํ•˜๋Š” ๊ณผ์ •?

์œ„์™€ ๊ฐ™์€ ๊ถ๊ธˆ์ฆ๋“ค์„ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ์ฝ”๋“œ ์—ฌํ–‰์„ ๋– ๋‚˜๋ณด๊ธฐ๋กœ ํ–ˆ๋‹ค.

๊ฐ์ฒด ์ƒ์„ฑํ•˜๊ธฐ


RequestResponseBodyMethodProcessor.java

@ResponseBody ์˜ ๋ฐ”์ธ๋”ฉ ์ฒ˜๋ฆฌ ์ˆ˜ํ–‰ ์‹œ ์œ„ ๋ฉ”์„œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋œ๋‹ค.

AbstractMessageConverterMethodArgumentResolver.java

readWithMessageConverters() ๋Š” ํ•ด๋‹น ํด๋ž˜์Šค์—์„œ ์ˆ˜ํ–‰๋˜๋Š”๋ฐ, ๋ฉ”์„œ๋“œ ๋‚ด๋ถ€๋ฅผ ์‚ดํŽด๋ณด๋ฉด 10๊ฐœ์˜ messageConverters ๋ฅผ ์ˆœํšŒํ•˜๋ฉฐ ContentType ์œผ๋กœ ์ฝ์„ ์ˆ˜ ์žˆ๋Š” Converter ๋ฅผ ์ฐพ๋Š”๋‹ค.

JSON ์š”์ฒญ์ด๊ธฐ ๋•Œ๋ฌธ์— MappingJackson2HttpMessageConverter ๋กœ Body ๋ฅผ read() ํ•œ๋‹ค.

AbstractJackson@HttpMessageConverter.java

![[AbstractJackson@HttpMessageConverter.png]]

ํ•ด๋‹น ํด๋ž˜์Šค ๋‚ด๋ถ€์—์„œ read() ๋ฉ”์„œ๋“œ๋Š” readJavaType() ์„ ํ˜ธ์ถœํ•œ๋‹ค.

์ด ๋ฉ”์„œ๋“œ ๋‚ด๋ถ€์—์„œ ObjectMapper ์˜ readValue() ๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค.

์ž ๊นโ€ฆ ObjectMapper ๊ฐ€ ๋ญ์•ผ?

ObjectMapper ๋ž€ ๊ธฐ๋ณธ POJO(Plain Old Java Objects) ๋˜๋Š” JSON Tree Model ์—์„œ JSON ์„ ์ฝ๊ณ  ์“ฐ๋Š” ๊ธฐ๋Šฅ๊ณผ ๋ณ€ํ™˜ ์ˆ˜ํ–‰์„ ์œ„ํ•œ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜๋Š” ํด๋ž˜์Šค๋‹ค.

์ฆ‰, Java Object โ† โ†’ JSON ํŒŒ์‹ฑ์„ ๊ฐ„ํŽธํ•˜๊ฒŒ ํ•ด์ฃผ๋Š” ํด๋ž˜์Šค๋ผ๊ณ  ์ •๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.

ObjectMapper.java

readValue() ๋‚ด๋ถ€์—์„œ Request ์˜ Body ์˜ null ์ฒดํฌ๋งŒ ์ง„ํ–‰ํ•˜๊ณ  readMapAndClose() ๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค.

์ดํ›„ readMapAndClose() ๋‚ด๋ถ€์—์„œ _findRootDeserializer() ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋Š”๋ฐ, @RequestBody ๋กœ ๋ฐ”์ธ๋”ฉ ๋  ๊ฐ์ฒด์ธ RequestDto ๊ฐ€ ๋นˆ์ด๋ฏ€๋กœ ์ด ๋ฉ”์„œ๋“œ์—์„œ BeanDeserializer ๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

์ดํ›„ ๋ฐ˜ํ™˜๋ฐ›์€ BeanDeserializer ๋ฅผ readRootValue() ๋ฉ”์„œ๋“œ๋กœ ๋„˜๊ธด๋‹ค.

Deserialize? ๊ทธ๊ฑด ๋ญ์•ผ?

  • Serialize(์ง๋ ฌํ™”) - Java Object โ†’ JSON
  • Deserialize(์—ญ์ง๋ ฌํ™”) - JSON โ†’ Java Object

DefaultDeserializationContext.java

์ „๋‹ฌ๋ฐ›์€ BeanDeserializer ์˜ deserialize() ๋กœ JSON โ†’ Java Object ์—ญ์ง๋ ฌํ™”๋ฅผ ์ˆ˜ํ–‰ํ•œ๋‹ค.

BeanDeserializer.java

BeanDeserializer ์˜ deserialize() ๋‚ด๋ถ€์—์„œ p.isExpectedStartObjectToken() ์„ ํ†ตํ•ด JSON ์ด โ€œ{โ€ ๋กœ ์‹œ์ž‘ํ•˜๋Š”์ง€ ํ™•์ธํ•œ๋‹ค.

์ดํ›„ deserializeFromObject() ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค.

deserializeFromObject() ๋‚ด๋ถ€๋ฅผ ํ™•์ธํ•˜๋ฉด createUsingDefault() ๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

StdValueInstantiator.java

createUsingDefault() ๋‚ด๋ถ€์—์„œ ๊ฐ์ฒด์˜ ๊ธฐ๋ณธ์ƒ์„ฑ์ž์ธ _defaultCreator.call() ๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค.

AnnotatedConstructor.java

call() ๋ฉ”์„œ๋“œ ๋‚ด๋ถ€๋ฅผ ์‚ดํŽด๋ณด๋ฉด Java Reflection API ์˜ Constructor ํด๋ž˜์Šค์ธ _constructor ์˜ newInstance() ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค.

Constructor.java

ํ•ด๋‹น ๋ฉ”์„œ๋“œ ๋‚ด๋ถ€๋ฅผ ์‚ดํŽด๋ณด๋ฉด Reflection ์„ ํ†ตํ•ด ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

์ด๋กœ์จ, @RequestBody ๋ฐ”์ธ๋”ฉ ์ˆ˜ํ–‰ ๊ณผ์ •์—์„œ ํ•ด๋‹น ๊ฐ์ฒด๋ฅผ ์–ด๋–ป๊ฒŒ ์ƒ์„ฑํ•˜๋Š”์ง€ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

Reflection ์€ ๋ญ์•ผ?

Java Reflection ์ด๋ž€, ์ ‘๊ทผ ์ œ์–ด์ž์™€ ๊ด€๊ณ„ ์—†์ด ํด๋ž˜์Šค ๊ฐ์ฒด๋ฅผ ๋™์ ์œผ๋กœ ์ƒ์„ฑํ•˜๋Š”(๋Ÿฐํƒ€์ž„) Java API ๋‹ค.

Java ๋Š” ์ •์  ์–ธ์–ด์ด๊ธฐ ๋•Œ๋ฌธ์—, ์ปดํŒŒ์ผ ์‹œ์ ์— ๊ฐ์ฒด ํƒ€์ž…์„ ๊ฒฐ์ •ํ•œ๋‹ค.

Java Reflection ์€ ๊ตฌ์ฒด์ ์ธ ํด๋ž˜์Šค ํƒ€์ž…์„ ์•Œ์ง€ ๋ชปํ•ด๋„, ๊ทธ ํด๋ž˜์Šค์˜ ๋ฉ”์„œ๋“œ, ํƒ€์ž…, ๋ณ€์ˆ˜๋“ค์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค€๋‹ค.

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

๊ธฐ๋ณธ ์ƒ์„ฑ์ž๊ฐ€ ์—†๋‹ค๋ฉด?


BeanDeserializer.java

BeanDeserializer.java ์˜ _nonStandardCreation ๋ถ„๊ธฐ์— ๊ฑธ๋ ค deserializeFromObjectUsingNonDefault() ๋ฉ”์„œ๋“œ๋กœ ๊ฐ์ฒด ์ƒ์„ฑ์„ ์‹œ๋„ํ•œ๋‹ค.

BeanDeserializerBase.java

deserializeFromObjectUsingNonDefault() ๋‚ด๋ถ€๋ฅผ ์‚ดํŽด๋ณด๋ฉด, createUsingDelegate() ํ˜น์€ _deserializeUsingPropertyBased() ๋ฅผ ํ†ตํ•ด ๊ฐ์ฒด ์ƒ์„ฑ์„ ์‹œ๋„ํ•œ๋‹ค.

ํ˜„์žฌ ์‚ฌ์šฉํ•˜๋Š” RequestDTO ๋Š” delegate ์„ ํ•˜๊ฑฐ๋‚˜ property ์„ค์ •์„ ํ•ด์ค€ ๊ฒƒ์ด ์•„๋‹ˆ๊ธฐ ๋•Œ๋ฌธ์— ์ด ๋ถ€๋ถ„์—์„œ ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.

์—ฌ๊ธฐ๊นŒ์ง€ ๊ฐ์ฒด ์ƒ์„ฑ ๊ณผ์ • ์ •๋ฆฌ


  • @RequestBody ๋ฅผ ๋ฐ”์ธ๋”ฉํ•˜๊ธฐ ์œ„ํ•ด ObjectMapper ๋ฅผ ์‚ฌ์šฉํ•˜๋Š”๋ฐ, Java Reflection API ๋ฅผ ํ†ตํ•ด ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๊ธฐ๋ณธ ์ƒ์„ฑ์ž๊ฐ€ ํ•„์ˆ˜์ ์ด๋‹ค.
  • @JsonProperty @JsonAutoDetect ๋“ฑ์„ ์‚ฌ์šฉํ•œ propertBasedCreator ๋‚˜ ์ƒ์„ฑ์ž๊ฐ€ ์œ„์ž„๋˜์–ด delegateBasedCreator ๊ฐ€ ์žˆ๋‹ค๋ฉด ๊ธฐ๋ณธ ์ƒ์„ฑ์ž๊ฐ€ ์—†์–ด๋„ ๋œ๋‹ค.

์ƒ์„ฑ๋œ ๊ฐ์ฒด์— ํ•„๋“œ๊ฐ’ ์ฃผ์ž…ํ•˜๊ธฐ


ObjectMapper ๊ฐ€ JSON ๊ณผ Java Object ๋ฅผ ๋งค์นญํ•˜๋Š” ๋ฐฉ๋ฒ•?

๊ธฐ๋ณธ์ ์œผ๋กœ Jackson ์€ JSON ํ•„๋“œ์˜ ์ด๋ฆ„์„ Java Object ์˜ getter ์™€ setter ๋ฉ”์„œ๋“œ์™€ ์ผ์น˜์‹œ์ผœ ๊ฐ ํ•„๋“œ๊ฐ’์„ ๋งค์นญํ•œ๋‹ค.

Jackson ์€ getter ๋ฐ setter ๋ฉ”์„œ๋“œ์˜ "get" "set" ์„ ์ œ๊ฑฐํ•œ ํ›„ ๋‚˜๋จธ์ง€ ์ด๋ฆ„์˜ ์ฒซ ๋ฌธ์ž๋ฅผ ์†Œ๋ฌธ์ž๋กœ ๋ณ€ํ™˜ํ•˜์—ฌ JSON ํ•„๋“œ๊ฐ’๊ณผ ์ผ์น˜์‹œํ‚จ๋‹ค.

์ฆ‰, ๋™์ผํ•œ ์ด๋ฆ„์˜ ๋ณ€์ˆ˜๋ฅผ ์ง์ ‘ ์ฐพ์ง€ ์•Š๊ณ  getter ์™€ setter ๋ฅผ ํ†ตํ•ด ์ฐพ์•„ ๋งค์นญํ•œ๋‹ค.

BeanDeserializerFactory.java

buildBeanDeserializer() ๋ฉ”์„œ๋“œ ๋‚ด๋ถ€์—์„œ addBeanProps() ๋ฅผ ํ†ตํ•ด getter ์™€ setter ๋กœ Bean Property ๋ฅผ ์ฐพ๋Š” ๊ณผ์ •์„ ์ˆ˜ํ–‰ํ•œ๋‹ค.

BeanDeserializer.java

๋‹ค์‹œ BeanDeserializer.java ๋กœ ๋Œ์•„์™€์„œ, _beanProperties.find(propName) ์œผ๋กœ ์œ„์—์„œ ์ €์žฅํ–ˆ๋˜ Bean Property ๋ฅผ ๊ฐ€์ ธ์™€ SettableBeanProperty ๋ฅผ ๋งŒ๋“ ๋‹ค.

์ดํ›„, deserializeAndSet() ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด ํ•„๋“œ๊ฐ’์„ ์ฃผ์ž…ํ•œ๋‹ค.

FieldProperty.java

deserializeAndSet() ๋‚ด๋ถ€๋ฅผ ์‚ดํŽด๋ณด๋ฉด, _field.set() ์„ ํ†ตํ•ด ๊ฐ’์„ ์ฃผ์ž…ํ•˜๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

์—ฌ๊ธฐ์„œ _field ๋Š” Reflection API ์˜ Field ์ž๋ฃŒํ˜•์ด๋‹ค.

๋”ฐ๋ผ์„œ, Reflection API ๋ฅผ ํ†ตํ•ด ๊ฐ’์„ ์ฃผ์ž…ํ•˜๊ธฐ์— setter ๊ฐ€ ๋ถˆํ•„์š”ํ•˜๋‹ค๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

๊ฒฐ๋ก 


  • @RequestBody ๋ฅผ ๋ฐ”์ธ๋”ฉํ•˜๊ธฐ ์œ„ํ•ด ObjectMapper ๋ฅผ ์‚ฌ์šฉํ•˜๋Š”๋ฐ, Java Reflection API ๋ฅผ ํ†ตํ•ด ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๊ธฐ๋ณธ ์ƒ์„ฑ์ž๊ฐ€ ํ•„์ˆ˜์ ์ด๋‹ค.
  • @JsonProperty @JsonAutoDetect ๋“ฑ์„ ์‚ฌ์šฉํ•œ propertBasedCreator ๋‚˜ ์ƒ์„ฑ์ž๊ฐ€ ์œ„์ž„๋˜์–ด delegateBasedCreator ๊ฐ€ ์žˆ๋‹ค๋ฉด ๊ธฐ๋ณธ ์ƒ์„ฑ์ž๊ฐ€ ์—†์–ด๋„ ๋œ๋‹ค.
  • ObjectMapper ๋Š” Jackson ์„ ํ†ตํ•ด getter ์™€ setter ๋กœ DTO ํ•„๋“œ๊ฐ’์„ ๊ฐ€์ ธ์˜ค๋ฉฐ getter ํ˜น์€ setter ๋งŒ ์žˆ์–ด๋„ ๋œ๋‹ค.
  • Jaskson ์„ ํ†ตํ•ด ์ƒ์„ฑ๋œ Bean Property ์— Reflection ์„ ์‚ฌ์šฉํ•˜์—ฌ ํ•„๋“œ๊ฐ’์„ ์ฃผ์ž…ํ•œ๋‹ค.

์ถ”๊ฐ€์ ์œผ๋กœ ๊ณต๋ถ€ํ•  ๊ฒƒ

  • delegateBasedCreator, propertyBasedCreator
  • Reflection ์œผ๋กœ ์ฃผ์ž…ํ•˜๋Š” ๊ณผ์ •

References