Spring @RestController ์๋ต ์, ์ ์ ๋์ง ์์ ๊ฐ๋ ๊ฐ์ด ์๋ต๋๋ ์ด์
@Getter
@Setter
public class UserDomain {
private String name;
private int age;
public boolean isTwenties() {
if (this.age >= 20 && this.age < 30){
return true;
}
return false;
}
}
- ์์ ๊ฐ์ด, ๋๋ฉ์ธ ๊ฐ์ฒด ์์ ๋น์ฆ๋์ค ๋ก์ง์ด ํฌํจ๋ ๋ฉ์๋๊ฐ ์กด์ฌํ๋ค๊ณ ์์ํด๋ณด์.
- isTwenties() ๋ ํ์ฌ User์ ๋์ด๋ฅผ ํ๋จํ์ฌ 20๋์ธ์ง ์๋์ง๋ฅผ ์๋ ค์ฃผ๋ ๋ฉ์๋์ด๋ค.
@RestController
public class UserController {
@GetMapping("/user/{name}")
public UserDomain retrieveUserByName(String name){
UserDomain user = new UserDomain():
user.setName("test");
user.setAge(10);
return user;
}
}
๋ง์ฝ, RestController์์ UserDomain์ ์๋ต ๊ฐ์ฒด๋ก ์ฌ์ฉํ๊ฒ ๋๋ค๋ฉด HTTP ์๋ต์ผ๋ก ์ด๋ค ๊ฐ์ด ์๋ต๋ ๊น?
๋๋ ์ฒ์์ ์ด์ ๊ฐ์ ์๋ต์ ๊ธฐ๋ํ๋ค.
{
"name": "test",
"age" : 10
}
ํ์ง๋ง, ์ค์ ๋ก ์๋ต ๋ ๊ฐ์ ๊ทธ๋ ์ง ์์๋ค. ๐ง
{
"name": "test",
"age" : 10,
"Twenties" : false
}
์ ์ด๋ฐ ๊ฒฐ๊ณผ๊ฐ ๋์ค๊ฒ ๋์์๊น? ์ด์ ๋ฅผ ์๊ธฐ ์ํด์ @ResponseBody์ HttpMessageConverter์ ๋ํ ์ ํ ์ง์์ด ์ด์ง ํ์ํ๋ค.
@ResponseBody
Spring์ HTTP ์์ฒญ์ ๋ฐ์์ ๋ ๊ทธ ์๋ต์ผ๋ก (1) ์ ์ ๋ฆฌ์์ค (2) ๋ทฐ ํ ํ๋ฆฟ์ ์๋ตํ๊ฑฐ๋ ํน์ (3) HTTP Body ๊ฐ์ ์๋ตํ ์ ์๋ค.
์ด๋ (3) HTTP Body ๊ฐ์ ์๋ตํ๋ ค๋ฉด, @ResponseBody ์ด๋ ธํ ์ด์ ์ ๋ฉ์๋ ์๋จ์ ๋ถ์ฌ์ผ ํ๋ค.
๊ทธ๋ฆฌ๊ณ , ํด๋์ค ์๋จ์ @RestController ์ ๋ ธํ ์ด์ ์ ์ฌ์ฉํ๋ฉด ํด๋น ์ปจํธ๋กค๋ฌ์ ๋ชจ๋ ๋ฉ์๋์ @ResponseBody๊ฐ ์ ์ฉ๋๋ ํจ๊ณผ๊ฐ ์๋ค
(@Controller๋ method return type์ด String์ด๋ฉด ๋ทฐ ์ด๋ฆ์ผ๋ก ์ธ์ํด, ๋ทฐ๋ฅผ ์ฐพ๊ณ ๋ทฐ๋ฅผ ๋๋๋ง ํ๋ค. @RestController ๋ ๋ฐํ ๊ฐ์ผ๋ก ๋ทฐ๋ฅผ ์ฐพ๋ ๊ฒ์ด ์๋๋ผ, HTTP ๋ฉ์์ง ๋ฐ๋์ ๋ฐ๋ก ์ ๋ ฅํ๋ค.)
HttpMessageConverter
Spring์ ์๋ต๊ฐ์ ์์ฑํ ๋, ReturnValueHandler๊ฐ RequestMapping์ผ๋ก ์๋ณ๋ ๋ฉ์๋์ ์๋ต ํ์ ์ ํ์ธํ๊ณ , ํด๋น ์๋ต ํ์ ์ ์ง๋ ฌํ ํ ์ ์๋ HttpMessageConverter๋ฅผ ์ฐพ์ ์คํํ๋ค.
-> ์์ ๊ฐ์ ์ํฉ์ผ ๋๋ MappingJackson2HttpMessageConverter ๊ฐ ์คํ ๋๋ค.
์๋ฌดํผ, ์์๋ก ๋ UserController๊ฐ @RestController์ด๊ณ ๋ฉ์๋์ ์๋ต๊ฐ์ด ๊ฐ์ฒด์ด๊ธฐ ๋๋ฌธ์, MappingJackson2HttpMessageConverter ๊ฐ UserDomain ๊ฐ์ฒด๋ฅผ ์ง๋ ฌํ ํ๊ฒ ๋๋ค.
์ด๋ ๋ฌธ์ ๋, ํ๋ ๊ธฐ๋ฐ์ผ๋ก ๊ฐ์ ์ง๋ ฌํ ํ๋๊ฒ ์๋๋ผ get ํค์๋๋ก ์์ํ๋ ๋ฉ์๋๋ฅผ 'ํ๋'๋ผ๊ณ ์ธ์ํ๊ณ ์ง๋ ฌํ ํ๊ฒ ๋๋ค๋ ์ ์ด๋ค.
@Getter
@Setter
public class UserDomain {
private String name;
private int age;
public boolean isTwenties() {
if (this.age >= 20 && this.age < 30){
return true;
}
return false;
}
}
์ฆ, ์์ ์์ ์์ lombok์ @Getter ๋ฅผ ํตํด ๊ฐ ํ๋์ getter๊ฐ ์์ฑ๋๊ณ
MappingJackson2HttpMessageConverter ์ ObjectMapper๊ฐ ์์ฑ๋ getter ๋ค์ ์ฐธ์กฐํ์ฌ JSON ํ์์ผ๋ก ์ง๋ ฌํ ํ๊ฒ ๋๋ค.
@Getter
@Setter
public class UserDomain {
private String name;
private int age;
public boolean isTwenties() {
if (this.age >= 20 && this.age < 30){
return true;
}
return false;
}
// ๋กฌ๋ณต์ด ์์ฑํ getter
public String getName(){
return this.name;
}
// ๋กฌ๋ณต์ด ์์ฑํ getter
public String getAge(){
return this.age;
}
}
์ด๋, isTwenties ๋ boolean ํ์ ์ getter๋ผ๊ณ ์ธ์๋์ด, ๋ฉ์๋๊ฐ ์คํ๋๊ณ ํด๋น isTwenties ์ ๋ฆฌํด๊ฐ ๋ํ ๊ฐ์ด JSON ๋ฐ์ดํฐ์ ๋ค์ด๊ฐ๊ฒ ๋ ๊ฒ์ด๋ค.
MappingJackson2HttpMessageConverter ์ ObjectMapper ๊ฐ ์ด๋ค ํจ์๋ฅผ getter๋ก ์ธ์ํ๋์ง๋ ์ค์ ์ฝ๋๋ฅผ ๊น๋ด์ผ ์ ํํ ์ ์ ์๊ฒ ์ง๋ง, ์๋ง public + parameter๋ ์๊ณ () + ๋ฉ์๋๋ช ์ด get์ผ๋ก ์์ํ๋ค๋ฉด getter๋ก ์ธ์ํ์ง ์์๊น ์ถ๋ค. (boolean์ ๊ฒฝ์ฐ is๋ก ์์ํ๋ ๊ฒฝ์ฐ๋ ํฌํจ)
- ์ถํ, ์ค์ ๋ก ์ฝ๋๋ฅผ ํ์ธํด๋ณด๊ณ ์ถ๊ฐํด ๋๊ฒ ๋ค.
- ํ์ธ๊ฒฐ๊ณผ โฌ๏ธ
- ์์ฝ : ์ค์ ๋ก ํ๋ผ๋ฏธํฐ์ ๊ฐ์ ํ์ธ ๋ฐ getterPrefix์ ๊ฐ์ผ๋ก getter์ธ์ง ํ์ธํ๋ ๋ก์ง์ด ์๋ค.
- ์์ธํ ๋ก์ง์ ๋๋ฒ๊น ๊ณผ ํจ๊ป ํ์ธ ๊ฐ๋ฅํ๋ ๋๋ฌด ๋ณต์ก

objectMapper.writeValueAsString(manager);
// ์ํ ๊ฒฐ๊ณผ
// POJOPropertiesCollector.collectAll ์ํ
protected void collectAll() {
LinkedHashMap<String, POJOPropertyBuilder> props = new LinkedHashMap();
this._addFields(props); // ํ๋๊ฐ ๊ฐ์ ธ์์ props์ ์ถ๊ฐ
this._addMethods(props); // ๋ฉ์๋๋ก ํ๋๊ฐ ์ถ๊ฐํจ <- ์ฌ๊ธฐ์ getter, setter ํ์ธํด์ getter๋ง ์์ด๋ ์ถ๊ฐ๋จ
if (!this._classDef.isNonStaticInnerClass()) {
this._addCreators(props);
}
// ์๋ต
}
protected void _addMethods(Map<String, POJOPropertyBuilder> props) {
Iterator var2 = this._classDef.memberMethods().iterator();
while(var2.hasNext()) {
AnnotatedMethod m = (AnnotatedMethod)var2.next();
int argCount = m.getParameterCount();
// ํ๋ผ๋ฏธํฐ๊ฐ 0๊ฐ์ด๋ฉด getter๋ก ํ๋จ
if (argCount == 0) {
this._addGetterMethod(props, m, this._annotationIntrospector);
} else if (argCount == 1) {
this._addSetterMethod(props, m, this._annotationIntrospector);
} else if (argCount == 2 && Boolean.TRUE.equals(this._annotationIntrospector.hasAnySetter(m))) {
if (this._anySetters == null) {
this._anySetters = new LinkedList();
}
this._anySetters.add(m);
}
}
}
protected void _addGetterMethod(Map<String, POJOPropertyBuilder> props, AnnotatedMethod m, AnnotationIntrospector ai) {
Class<?> rt = m.getRawReturnType();
if (rt != Void.TYPE && (rt != Void.class || this._config.isEnabled(MapperFeature.ALLOW_VOID_VALUED_PROPERTIES))) {
if (Boolean.TRUE.equals(ai.hasAnyGetter(m))) {
if (this._anyGetters == null) {
this._anyGetters = new LinkedList();
}
this._anyGetters.add(m);
} else if (Boolean.TRUE.equals(ai.hasAsKey(this._config, m))) {
if (this._jsonKeyAccessors == null) {
this._jsonKeyAccessors = new LinkedList();
}
this._jsonKeyAccessors.add(m);
} else if (Boolean.TRUE.equals(ai.hasAsValue(m))) {
if (this._jsonValueAccessors == null) {
this._jsonValueAccessors = new LinkedList();
}
this._jsonValueAccessors.add(m);
} else {
PropertyName pn = ai.findNameForSerialization(m);
boolean nameExplicit = pn != null;
boolean visible;
String implName;
if (!nameExplicit) {
implName = ai.findImplicitPropertyName(m);
if (implName == null) {
// ์ฌ๊ธฐ์ get์ผ๋ก ์์ํ๋์ง ํ๋จํด์ implName์ ์ธํ
ํ๋ค
implName = this._accessorNaming.findNameForRegularGetter(m, m.getName());
}
if (implName == null) {
implName = this._accessorNaming.findNameForIsGetter(m, m.getName());
if (implName == null) {
return;
}
visible = this._visibilityChecker.isIsGetterVisible(m);
} else {
visible = this._visibilityChecker.isGetterVisible(m);
}
} else {
implName = ai.findImplicitPropertyName(m);
if (implName == null) {
implName = this._accessorNaming.findNameForRegularGetter(m, m.getName());
if (implName == null) {
implName = this._accessorNaming.findNameForIsGetter(m, m.getName());
}
}
if (implName == null) {
implName = m.getName();
}
if (pn.isEmpty()) {
pn = this._propNameFromSimple(implName);
nameExplicit = false;
}
visible = true;
}
implName = this._checkRenameByField(implName);
boolean ignore = ai.hasIgnoreMarker(m);
this._property(props, implName).addGetter(m, pn, nameExplicit, visible, ignore);
}
}
}
ํด๊ฒฐ๋ฐฉ๋ฒ
์ด๋ฐ ๊ฒฝ์ฐ, ์ฌ์ค ๊ฐ์ฅ ๊ฐ๋จํ ํด๊ฒฐ ๋ฐฉ๋ฒ์ DTO ๊ฐ์ฒด๋ฅผ ์์ฑํ๊ณ ๋น์ฆ๋์ค ๋ก์ง์ ๋ชจ๋ ์ ๊ฑฐ ํ ๋ฐ์ดํฐ ์ ๋ฌ์ฉ์ผ๋ก ์ฌ์ฉํ๋๊ฒ ์๋๊น ์ถ๋ค.
๊ทธ๋ด์ ์๋ ์ํฉ์ด๋ผ๋ฉด @JsonIgnore ๋ฅผ ๋ถ์ด๊ฑฐ๋, ObjectMapper์ ์ค์ ์ ๋ฐ๊พธ๋ ๋ฐฉ๋ฒ๋ ์กด์ฌํ๋ค.
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.NONE);
objectMapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
๐ Reference
Does Jackson serialize getter property for an undefined field?
Does Jackson serialize getter property for an undefined field?
I have a class with the following fields and their respective getters, plus an additional method getTotalBalance for which I don't have any field but a custom implementation. public class demo{...
stackoverflow.com
Spring @RestController ์๋ต ์, ์ ์ ๋์ง ์์ ๊ฐ๋ ๊ฐ์ด ์๋ต๋๋ ์ด์
@Getter
@Setter
public class UserDomain {
private String name;
private int age;
public boolean isTwenties() {
if (this.age >= 20 && this.age < 30){
return true;
}
return false;
}
}
- ์์ ๊ฐ์ด, ๋๋ฉ์ธ ๊ฐ์ฒด ์์ ๋น์ฆ๋์ค ๋ก์ง์ด ํฌํจ๋ ๋ฉ์๋๊ฐ ์กด์ฌํ๋ค๊ณ ์์ํด๋ณด์.
- isTwenties() ๋ ํ์ฌ User์ ๋์ด๋ฅผ ํ๋จํ์ฌ 20๋์ธ์ง ์๋์ง๋ฅผ ์๋ ค์ฃผ๋ ๋ฉ์๋์ด๋ค.
@RestController
public class UserController {
@GetMapping("/user/{name}")
public UserDomain retrieveUserByName(String name){
UserDomain user = new UserDomain():
user.setName("test");
user.setAge(10);
return user;
}
}
๋ง์ฝ, RestController์์ UserDomain์ ์๋ต ๊ฐ์ฒด๋ก ์ฌ์ฉํ๊ฒ ๋๋ค๋ฉด HTTP ์๋ต์ผ๋ก ์ด๋ค ๊ฐ์ด ์๋ต๋ ๊น?
๋๋ ์ฒ์์ ์ด์ ๊ฐ์ ์๋ต์ ๊ธฐ๋ํ๋ค.
{
"name": "test",
"age" : 10
}
ํ์ง๋ง, ์ค์ ๋ก ์๋ต ๋ ๊ฐ์ ๊ทธ๋ ์ง ์์๋ค. ๐ง
{
"name": "test",
"age" : 10,
"Twenties" : false
}
์ ์ด๋ฐ ๊ฒฐ๊ณผ๊ฐ ๋์ค๊ฒ ๋์์๊น? ์ด์ ๋ฅผ ์๊ธฐ ์ํด์ @ResponseBody์ HttpMessageConverter์ ๋ํ ์ ํ ์ง์์ด ์ด์ง ํ์ํ๋ค.
@ResponseBody
Spring์ HTTP ์์ฒญ์ ๋ฐ์์ ๋ ๊ทธ ์๋ต์ผ๋ก (1) ์ ์ ๋ฆฌ์์ค (2) ๋ทฐ ํ ํ๋ฆฟ์ ์๋ตํ๊ฑฐ๋ ํน์ (3) HTTP Body ๊ฐ์ ์๋ตํ ์ ์๋ค.
์ด๋ (3) HTTP Body ๊ฐ์ ์๋ตํ๋ ค๋ฉด, @ResponseBody ์ด๋ ธํ ์ด์ ์ ๋ฉ์๋ ์๋จ์ ๋ถ์ฌ์ผ ํ๋ค.
๊ทธ๋ฆฌ๊ณ , ํด๋์ค ์๋จ์ @RestController ์ ๋ ธํ ์ด์ ์ ์ฌ์ฉํ๋ฉด ํด๋น ์ปจํธ๋กค๋ฌ์ ๋ชจ๋ ๋ฉ์๋์ @ResponseBody๊ฐ ์ ์ฉ๋๋ ํจ๊ณผ๊ฐ ์๋ค
(@Controller๋ method return type์ด String์ด๋ฉด ๋ทฐ ์ด๋ฆ์ผ๋ก ์ธ์ํด, ๋ทฐ๋ฅผ ์ฐพ๊ณ ๋ทฐ๋ฅผ ๋๋๋ง ํ๋ค. @RestController ๋ ๋ฐํ ๊ฐ์ผ๋ก ๋ทฐ๋ฅผ ์ฐพ๋ ๊ฒ์ด ์๋๋ผ, HTTP ๋ฉ์์ง ๋ฐ๋์ ๋ฐ๋ก ์ ๋ ฅํ๋ค.)
HttpMessageConverter
Spring์ ์๋ต๊ฐ์ ์์ฑํ ๋, ReturnValueHandler๊ฐ RequestMapping์ผ๋ก ์๋ณ๋ ๋ฉ์๋์ ์๋ต ํ์ ์ ํ์ธํ๊ณ , ํด๋น ์๋ต ํ์ ์ ์ง๋ ฌํ ํ ์ ์๋ HttpMessageConverter๋ฅผ ์ฐพ์ ์คํํ๋ค.
-> ์์ ๊ฐ์ ์ํฉ์ผ ๋๋ MappingJackson2HttpMessageConverter ๊ฐ ์คํ ๋๋ค.
์๋ฌดํผ, ์์๋ก ๋ UserController๊ฐ @RestController์ด๊ณ ๋ฉ์๋์ ์๋ต๊ฐ์ด ๊ฐ์ฒด์ด๊ธฐ ๋๋ฌธ์, MappingJackson2HttpMessageConverter ๊ฐ UserDomain ๊ฐ์ฒด๋ฅผ ์ง๋ ฌํ ํ๊ฒ ๋๋ค.
์ด๋ ๋ฌธ์ ๋, ํ๋ ๊ธฐ๋ฐ์ผ๋ก ๊ฐ์ ์ง๋ ฌํ ํ๋๊ฒ ์๋๋ผ get ํค์๋๋ก ์์ํ๋ ๋ฉ์๋๋ฅผ 'ํ๋'๋ผ๊ณ ์ธ์ํ๊ณ ์ง๋ ฌํ ํ๊ฒ ๋๋ค๋ ์ ์ด๋ค.
@Getter
@Setter
public class UserDomain {
private String name;
private int age;
public boolean isTwenties() {
if (this.age >= 20 && this.age < 30){
return true;
}
return false;
}
}
์ฆ, ์์ ์์ ์์ lombok์ @Getter ๋ฅผ ํตํด ๊ฐ ํ๋์ getter๊ฐ ์์ฑ๋๊ณ
MappingJackson2HttpMessageConverter ์ ObjectMapper๊ฐ ์์ฑ๋ getter ๋ค์ ์ฐธ์กฐํ์ฌ JSON ํ์์ผ๋ก ์ง๋ ฌํ ํ๊ฒ ๋๋ค.
@Getter
@Setter
public class UserDomain {
private String name;
private int age;
public boolean isTwenties() {
if (this.age >= 20 && this.age < 30){
return true;
}
return false;
}
// ๋กฌ๋ณต์ด ์์ฑํ getter
public String getName(){
return this.name;
}
// ๋กฌ๋ณต์ด ์์ฑํ getter
public String getAge(){
return this.age;
}
}
์ด๋, isTwenties ๋ boolean ํ์ ์ getter๋ผ๊ณ ์ธ์๋์ด, ๋ฉ์๋๊ฐ ์คํ๋๊ณ ํด๋น isTwenties ์ ๋ฆฌํด๊ฐ ๋ํ ๊ฐ์ด JSON ๋ฐ์ดํฐ์ ๋ค์ด๊ฐ๊ฒ ๋ ๊ฒ์ด๋ค.
MappingJackson2HttpMessageConverter ์ ObjectMapper ๊ฐ ์ด๋ค ํจ์๋ฅผ getter๋ก ์ธ์ํ๋์ง๋ ์ค์ ์ฝ๋๋ฅผ ๊น๋ด์ผ ์ ํํ ์ ์ ์๊ฒ ์ง๋ง, ์๋ง public + parameter๋ ์๊ณ () + ๋ฉ์๋๋ช ์ด get์ผ๋ก ์์ํ๋ค๋ฉด getter๋ก ์ธ์ํ์ง ์์๊น ์ถ๋ค. (boolean์ ๊ฒฝ์ฐ is๋ก ์์ํ๋ ๊ฒฝ์ฐ๋ ํฌํจ)
- ์ถํ, ์ค์ ๋ก ์ฝ๋๋ฅผ ํ์ธํด๋ณด๊ณ ์ถ๊ฐํด ๋๊ฒ ๋ค.
- ํ์ธ๊ฒฐ๊ณผ โฌ๏ธ
- ์์ฝ : ์ค์ ๋ก ํ๋ผ๋ฏธํฐ์ ๊ฐ์ ํ์ธ ๋ฐ getterPrefix์ ๊ฐ์ผ๋ก getter์ธ์ง ํ์ธํ๋ ๋ก์ง์ด ์๋ค.
- ์์ธํ ๋ก์ง์ ๋๋ฒ๊น ๊ณผ ํจ๊ป ํ์ธ ๊ฐ๋ฅํ๋ ๋๋ฌด ๋ณต์ก

objectMapper.writeValueAsString(manager);
// ์ํ ๊ฒฐ๊ณผ
// POJOPropertiesCollector.collectAll ์ํ
protected void collectAll() {
LinkedHashMap<String, POJOPropertyBuilder> props = new LinkedHashMap();
this._addFields(props); // ํ๋๊ฐ ๊ฐ์ ธ์์ props์ ์ถ๊ฐ
this._addMethods(props); // ๋ฉ์๋๋ก ํ๋๊ฐ ์ถ๊ฐํจ <- ์ฌ๊ธฐ์ getter, setter ํ์ธํด์ getter๋ง ์์ด๋ ์ถ๊ฐ๋จ
if (!this._classDef.isNonStaticInnerClass()) {
this._addCreators(props);
}
// ์๋ต
}
protected void _addMethods(Map<String, POJOPropertyBuilder> props) {
Iterator var2 = this._classDef.memberMethods().iterator();
while(var2.hasNext()) {
AnnotatedMethod m = (AnnotatedMethod)var2.next();
int argCount = m.getParameterCount();
// ํ๋ผ๋ฏธํฐ๊ฐ 0๊ฐ์ด๋ฉด getter๋ก ํ๋จ
if (argCount == 0) {
this._addGetterMethod(props, m, this._annotationIntrospector);
} else if (argCount == 1) {
this._addSetterMethod(props, m, this._annotationIntrospector);
} else if (argCount == 2 && Boolean.TRUE.equals(this._annotationIntrospector.hasAnySetter(m))) {
if (this._anySetters == null) {
this._anySetters = new LinkedList();
}
this._anySetters.add(m);
}
}
}
protected void _addGetterMethod(Map<String, POJOPropertyBuilder> props, AnnotatedMethod m, AnnotationIntrospector ai) {
Class<?> rt = m.getRawReturnType();
if (rt != Void.TYPE && (rt != Void.class || this._config.isEnabled(MapperFeature.ALLOW_VOID_VALUED_PROPERTIES))) {
if (Boolean.TRUE.equals(ai.hasAnyGetter(m))) {
if (this._anyGetters == null) {
this._anyGetters = new LinkedList();
}
this._anyGetters.add(m);
} else if (Boolean.TRUE.equals(ai.hasAsKey(this._config, m))) {
if (this._jsonKeyAccessors == null) {
this._jsonKeyAccessors = new LinkedList();
}
this._jsonKeyAccessors.add(m);
} else if (Boolean.TRUE.equals(ai.hasAsValue(m))) {
if (this._jsonValueAccessors == null) {
this._jsonValueAccessors = new LinkedList();
}
this._jsonValueAccessors.add(m);
} else {
PropertyName pn = ai.findNameForSerialization(m);
boolean nameExplicit = pn != null;
boolean visible;
String implName;
if (!nameExplicit) {
implName = ai.findImplicitPropertyName(m);
if (implName == null) {
// ์ฌ๊ธฐ์ get์ผ๋ก ์์ํ๋์ง ํ๋จํด์ implName์ ์ธํ
ํ๋ค
implName = this._accessorNaming.findNameForRegularGetter(m, m.getName());
}
if (implName == null) {
implName = this._accessorNaming.findNameForIsGetter(m, m.getName());
if (implName == null) {
return;
}
visible = this._visibilityChecker.isIsGetterVisible(m);
} else {
visible = this._visibilityChecker.isGetterVisible(m);
}
} else {
implName = ai.findImplicitPropertyName(m);
if (implName == null) {
implName = this._accessorNaming.findNameForRegularGetter(m, m.getName());
if (implName == null) {
implName = this._accessorNaming.findNameForIsGetter(m, m.getName());
}
}
if (implName == null) {
implName = m.getName();
}
if (pn.isEmpty()) {
pn = this._propNameFromSimple(implName);
nameExplicit = false;
}
visible = true;
}
implName = this._checkRenameByField(implName);
boolean ignore = ai.hasIgnoreMarker(m);
this._property(props, implName).addGetter(m, pn, nameExplicit, visible, ignore);
}
}
}
ํด๊ฒฐ๋ฐฉ๋ฒ
์ด๋ฐ ๊ฒฝ์ฐ, ์ฌ์ค ๊ฐ์ฅ ๊ฐ๋จํ ํด๊ฒฐ ๋ฐฉ๋ฒ์ DTO ๊ฐ์ฒด๋ฅผ ์์ฑํ๊ณ ๋น์ฆ๋์ค ๋ก์ง์ ๋ชจ๋ ์ ๊ฑฐ ํ ๋ฐ์ดํฐ ์ ๋ฌ์ฉ์ผ๋ก ์ฌ์ฉํ๋๊ฒ ์๋๊น ์ถ๋ค.
๊ทธ๋ด์ ์๋ ์ํฉ์ด๋ผ๋ฉด @JsonIgnore ๋ฅผ ๋ถ์ด๊ฑฐ๋, ObjectMapper์ ์ค์ ์ ๋ฐ๊พธ๋ ๋ฐฉ๋ฒ๋ ์กด์ฌํ๋ค.
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.NONE);
objectMapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
๐ Reference
Does Jackson serialize getter property for an undefined field?
Does Jackson serialize getter property for an undefined field?
I have a class with the following fields and their respective getters, plus an additional method getTotalBalance for which I don't have any field but a custom implementation. public class demo{...
stackoverflow.com