๊ฒฝ๋ก ์กฐํ ๋ฏธ์ ์งํ ๋์ค ๋ฐ์ ํผ๋๋ฐฑ
ํด๋น ๋ฆฌ๋ทฐ๋ DTO ์ ๊ธฐ๋ณธ ์์ฑ์์ ๋ํ ํผ๋๋ฐฑ์ด๋ค.
์คํ๋ง์ ์ตํ๋ ๊ฒ์ ๊ธ๊ธํ๋ค ๋ณด๋ ๋ง์ฐํ๊ฒ ๊ธฐ๋ณธ ์์ฑ์๋ฅผ ์ถ๊ฐํ๋ฉด @RequestBody
๊ฐ ์์์ ๊ฐ์ฒด๋ก ๋ณํ๋๋ค๋ ์ฌ์ค๋ง ์๊ณ ์ฌ์ฉํ๊ณ ์์๋ค.
์คํ๋ง์ ์ ์ฐจ ์ ์ํจ์ ๋ฐ๋ผ ๋ฌธ๋ ์ด๋ฐ ์ง๋ฌธ์ด ๋จธ๋ฆฟ์์ ๋ ์ค๋ฅธ๋ค.
@RequestBody
๋ก ๊ฐ์ฒด๋ฅผ ์ด๋ป๊ฒ ์์ฑํ๋๊ฑฐ์ง?
์ผ๋จ ๊ธฐ๋ณธ ์์ฑ์๊ฐ ์์ผ๋ฉด ์๋ํ์ง ์์ผ๋๊น, ๊ธฐ๋ณธ ์์ฑ์๋ก ์์ฑํ ๊ฒ ๊ฐ์.
๊ทผ๋ฐ ๊ธฐ๋ณธ ์์ฑ์๊ฐ
private
์ด์ด๋ ์๋ํ๋๋ฐ ์ด๋ป๊ฒ ์ ๊ทผํ๋๊ฑฐ์ง?
์ด๋ป๊ฒ ์์ฑํ๋ค๊ณ ํด๋ ๋ด DTO ๋
setter
๊ฐ ์๋๋ฐ ์ด๋ป๊ฒ ํ๋๊ฐ์ ํ ๋นํ ๊น?
ํด๋น ์ง๋ฌธ๋ค์ ์ ๋ฆฌํด๋ณด๋ฉด, ํฌ๊ฒ ๋ ๊ฐ์ง ์ง๋ฌธ์ผ๋ก ์ ๋ฆฌํ ์ ์๋ค.
- ๊ฐ์ฒด๋ฅผ ์์ฑํ๋ ๊ณผ์ ?
- ์์ฑ๋ ๊ฐ์ฒด์ ํ๋๊ฐ์ ํ ๋นํ๋ ๊ณผ์ ?
์์ ๊ฐ์ ๊ถ๊ธ์ฆ๋ค์ ํด๊ฒฐํ๊ธฐ ์ํด ์ฝ๋ ์ฌํ์ ๋ ๋๋ณด๊ธฐ๋ก ํ๋ค.
๊ฐ์ฒด ์์ฑํ๊ธฐ
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
- https://da-nyee.github.io/posts/woowacourse-why-the-default-constructor-is-needed/
- https://velog.io/@conatuseus/RequestBody์-๊ธฐ๋ณธ-์์ฑ์๋-์-ํ์ํ๊ฐ
- https://velog.io/@conatuseus/RequestBody์-์-๊ธฐ๋ณธ-์์ ์๋-ํ์ํ๊ณ -Setter๋-ํ์-์์๊น-2-ejk5siejhh
- https://velog.io/@conatuseus/RequestBody์-์-๊ธฐ๋ณธ-์์ฑ์๋-ํ์ํ๊ณ -Setter๋-ํ์-์์๊น-3-idnrafiw