오늘은 Spring
프레임워크에 빼놓을 수 없는 라이브러리중 하나인 Jackson
에 대해 간단하게 포스팅 합니다.
주의!! 해당 포스팅은
Jackson
의 라이브러리 2.9.7 버전을 다룹니다.또한, 프로젝트에
Jackson
라이브러리의 설치 방법에 대해서는설명하지 않습니다.
패키지 매니저를 쓰면 너무 간단하며, 구글에 검색해보면 엄청 많이 나와요우우
Jackson
라이브러리?
Spring
개발을 하다 보면, 컨트롤러 text/html 형식이 아닌 데이터 전달 목적으로 사용하고 싶을 때가 있습니다. 물론, 쌩 문자열인 plain/text 형식으로 보내도 상관은 없습니다만, 보통은 데이터 구조를 표현하는 방식인 XML
또는 JSON
형태로 많이 보냅니다.
데이터의 구조를 표현하는 이유는 데이터 표현도 있지만, 사실상 데이터를 사용하는 대상이 편하게 사용하기 위해서 입니다.
이 두개 중 Jackson
은 JSON
데이터 구조를 처리해주는 라이브러리 입니다.
만약 JSON
으로 데이터 구조를 표현 한다면, 아래와 같습니다.
{
"name": "Mommoo",
"age": 28,
"isDeveloper": true,
"equipment": ["NoteBook", "Mouse", "SmartPhone"],
"etc": {
"favoriteFood": 'Coffee'
}
}
Jackson
라이브러리의 없이, JSON
데이터를 작성해보자.
Java
에서 데이터를 저장할 때는, 아래와 같이 인스턴스를 사용합니다.
public class Person {
private String name;
private String job;
public Person(String name, String job) {
this.name = name;
this.job = job;
}
public String getName(){
return name;
}
public String getJob() {
return job;
}
}
public static void main(String[] args) {
Person person = new Person("Mommoo", "Developer");
}
JSON
데이터를 어떻게 작성할까요? 그냥 작성해야 합니다... 아래와 같이요
미친짓이니 따라하지 마세요
String JSON = "\"{"+
"\"name\": \"" + person.getName() + "\","+
"\"job\": \"" + person.getJob() + "\""+
"}\"";
Java
는 Single Quotes즉, 쌍따옴표(""
)를 정말 문자열로 사용하고 싶을때는 위와 같이 \
문자를 붙여줘야 합니다. 끔찍한 코딩은 덤
항상 저렇게 코딩 할 순 없으니, JSON
변환용 클래스를 따로 만들고 그 클래스안에 저장된 멤버변수를 이용하여 JSON
데이터를 출력하는 클래스를 생각하게 됩니다.
대표적인 클래스가 Google 이 만든 GSON
또는 SimpleJSON
등이 있습니다.
SimpleJSON
을 예로 든다면, 윗 코딩이 아래와 같이 바뀝니다.
JSONObject jsonObject = new JSONObject();
jsonObject.put("name", person.getName());
jsonObject.put("job", person.getJob());
String JSON = jsonObject.toString();
해당 방식은 지금도 많이 쓰입니다.
물론 Spring
컨트롤러에 위와 같이 코딩하여 리턴하더라도, 충분합니다.
그렇다면, Jackson
은 무엇을 더 제공하길래 Spring
은 Jackson
을 더 선호하는 것일까요?
Jackson
과 기존 GSON
or SimpeJSON
과의 차이?
사실 차이는 없습니다.
Jackson
도 ObjectMapper
API를 사용하여, 여타 GSON
or SimpeJSON
과 같이 객체에 데이터를 셋팅해줘야 하는건 마찬가지 입니다.
특별한 점은 Spring
프레임워크와 Jackson
의 관계로부터 장점이 있습니다.
Spring
3.0 이후로부터, Jacskon
과 관련된 API를 제공함으로써, Jackson
라이브러리를 사용할때, 자동화 처리가 가능하게 되었습니다.
덕분에, JSON
데이터를 직접 만들던가, GSON
or SimpleJSON
방식과 같이 직접 키와 벨류를 셋팅하는 방식에서 한단계 더 발전한 방식이 가능해졌습니다.
어떤 방식이길래 발전했을까요? 아래의 Jackson
의 동작 원리와 함께 설명할까 합니다.
Jackson
은 어떻게 동작하는가?
Spring
3.0 이후로 컨트롤러의 리턴 방식이 @RequestBody
형식이라면, Spring
은 MessageConverter
API 를 통해, 컨트롤러가 리턴하는 객체를 후킹 할 수 있습니다.
Jackson
은 JSON
데이터를 출력하기 위한 MappingJacksonHttpMessageConverter
를 제공합니다. 만약 우리가 스프링 MessageConverter를 위의 MappingJacksonHttpMessageConverter
으로 등록한다면, 컨트롤러가 리턴하는 객체를 다시 뜯어(자바 리플렉션 사용), Jackson
의 ObjectMapper API로 JSON 객체
를 만들고 난 후, 출력하여 JSON
데이터를 완성합니다.
더욱 편리해진 점은, Spring
3.1 이후로 만약 클래스패스에 Jackson
라이브러리가 존재한다면, ( 쉽게 말해Jackson을 설치했느냐 안했느냐 ) 자동적으로 MessageConverter가 등록된다는 점입니다.
"/json") (
()
public Object printJSON() {
Person person = new Person("Mommoo", "Developer");
return person;
}
이제는 그냥 데이터 인스턴스만 리턴 하더라도 JSON
데이터가 출력됩니다. 엄청나죠ㄷㄷ
위에서 설명한 방식보다 매우 진보한 방식인걸 알 수 있습니다.
다만, Jackson
을 더 잘쓰기 위해서는 알아야 하는 기본 지식이 몇가지 존재합니다.
Jackson
을 사용하기 위해 알아야 하는 기본지식
소개하는 기본 지식은 순전히 제 생각입니다... 의견이 다를 수 있습니다.
Jackson
은 기본적으로 프로퍼티로 동작합니다.
Java
는 프로퍼티를 제공하는 문법이 없습니다. ( 멤버변수랑은 다릅니다. )
Java
의 프로퍼티는 보통 Getter
와 Setter
의 이름 명명 규칙으로 정해집니다.
문법적으로 정해지는것이 아니다 보니, 개발자가 일일이 신경써줘야 하는게 자바의 단점 중 하나입니다.
Person
같은 경우는 Getter
만 존재 하므로, Getter
를 기준으로 프로퍼티를 도출 할 수 있습니다. 즉 Name 과 Job이 Person 프로퍼티
입니다.
Person의 멤버변수 이름도 똑같이 name, job이지만,
앞서 설명했드시 프로퍼티는 Getter, Setter기준이므로 멤버변수 이름을 변경하더라도 상관 없습니다.
갑자기 프로퍼티를 설명한 이유는 많은 라이브러리가 해당 프로퍼티 개념으로 작동하기 때문입니다.
Jackson
라이브러리도 마찬가지 입니다. JSON
데이터로 출력되기 위해서는 멤버변수의 유무가 아닌 프로퍼티 즉, Getter
, Setter
를 기준으로 작동합니다.
예로 아래와 같이 코딩하더라도 전혀 문제가 없습니다.
public class Person {
public String getName() {
return "Mommoo";
}
public String getJob() {
return "Developer";
}
}
"/json") (
()
public Object printJSON() {
return new Person();
}
결론적으로 Jackson
을 사용한다면, Getter
에 신경쓰셔야 합니다!!.
Jackson
의 데이터 매핑을 Getter
가 아닌 멤버변수
로 하고 싶다면?
그렇다면, 이번에는 Jackson
의 매핑을 프로퍼티가 아닌 멤버변수로 할 수 있는 방법은 무엇일까요? Jackson
은 이와 관련하여 @JsonProperty
어노테이션 API를 제공합니다. 아래와 같이 멤버변수 위에 프로퍼티 이름과 함께 선언해준다면, JSON
데이터로 출력 됩니다.
public class Person {
("name")
private String myName = "Mommoo";
}
위의 예시는 {"name": "Mommoo"}로 출력 됩니다.
그렇다면 JSON
매핑을 멤버변수로 하고 싶다면, 매번 @JsonProperty
를 선언 해야 할까요? 귀찮습니다. 애초에 Jackson
매핑 구조를 바꾸면 어떨까 하는 생각이 듭니다.
Jackson
의 데이터 매핑 법칙 변경하기
Jackson
은 매핑 법칙을 바꿀 수 있는 @JsonAutoDetect
API를 제공합니다.
위 예시와 같이 멤버변수로만 Jackson을 구성하고 싶은 경우 @JsonProperty
를 일일이 붙이는 것보다 아래와 같이 설정하는 것이 더 편리합니다.
fieldVisibility = JsonAutoDetect.Visibility.ANY) (
public class Person {
private String myName = "Mommoo";
}
@JsonAutoDetect
는 멤버변수 뿐만 아니라, Getter
, Setter
의 데이터 매핑 정책도 정할 수 있습니다. 만약 아래의 경우는 멤버변수 뿐만 아니라, 기본정책인 Getter
역시 데이터 매핑이 진행됩니다.
fieldVisibility = JsonAutoDetect.Visibility.ANY) (
public class Person {
private String myName = "Mommoo";
public String getJob() {
return "Developer";
}
}
Getter
를 제외하고 싶다면, @JsonIgnore
API를 쓰셔도 됩니다.
fieldVisibility = JsonAutoDetect.Visibility.ANY) (
public class Person {
private String myName = "Mommoo";
public String getJob() {
return "Developer";
}
}
하지만, 역시 일일이 붙여야 하는 상황이 온다면 매핑 정책을 바꾸시는게 좋습니다.
fieldVisibility = JsonAutoDetect.Visibility.ANY, getterVisibility = JsonAutoDetect.Visibility.NON_PRIVATE) (
public class Person {
private String myName = "Mommoo";
public String getJob() {
return "Developer";
}
}
Getter
정책으로 private 만 데이터 바인딩에 제외 하였습니다.이렇듯, 제외 범위를 설정할 수 있습니다. 자세한건 아래를 참고해 주세요.
Jackson
의 데이터 상태에 따른 포함 관계 설정
만약 Jackson
데이터 매핑시 NULL 값 과 같은 특정 데이터 상태인 경우 제외하고 싶다면 어떻게 해야 할까요?
Jackson
은 이와 관련하여 @JsonInclude
API를 제공합니다.
NULL을 클래스 전반적으로 제외하고 싶다면, 클래스 위에 선언하면 됩니다.
또한 특정 프로퍼티가 NULL일때 해당 프로퍼티만을 제외하고 싶다면 역시 해당 프로퍼티위에 선언하면 됩니다.
JsonInclude.Include.NON_NULL) (
public class Person {
private String myName = "Mommoo";
public String getJob() {
return "Developer";
}
}
public class Person {
private String myName = "Mommoo";
JsonInclude.Include.NON_NULL) (
public String getJob() {
return "Developer";
}
}
JsonInclude.Include
속성은NON_NULL
뿐만 아니라 몇몇 개가 더 존재합니다.자세한건 아래를 참고 해주세요.
제가 준비한 Jackson
포스팅은 여기까지 입니다.
간단하게 하려 했는데 쓸때 없이 글이 길어진건 아닌가 싶네요.
'Spring' 카테고리의 다른 글
[Spring] @Transactional 사용시 주의해야할 점 (14) | 2020.01.26 |
---|---|
[SpringBoot] SpringBoot로 MongoDB 데이터 메서드로 주입하기 (0) | 2018.12.04 |
[SpringBoot] application.properties 파일 읽기 (0) | 2018.11.29 |
[SpringBoot] SpringBoot와 MongoDB 연동하기 (1) | 2018.11.27 |
포스팅이 도움 되셨다면, 커피 한잔 후원해주세요!
더 좋은 포스팅 작성에 큰 힘이 됩니다.