군만두의 IT 공부 일지

[Spring] ObjectMapper를 활용한 직렬화, 역직렬화 본문

개발일지/패스트캠퍼스

[Spring] ObjectMapper를 활용한 직렬화, 역직렬화

mandus 2024. 4. 15. 20:37

목차

    📅진행기간: 2024년 2월 5일 ~ 2024년 9월 20일

    ⭐요약


    • ObjectMapper를 활용한 직렬화와 역직렬화 과정을 통해서, 자바 객체를 JSON 형태로 변환하고 그 반대 과정을 어떻게 수행하는지를 학습함.

    ⭐ObjectMapper란?


    Spring Framework에서 데이터 전송은 주로 JSON 형태로 이루어지며, 이 데이터를 효율적으로 관리하기 위해 ObjectMapper 클래스를 사용함. ObjectMapper는 Jackson 라이브러리의 클래스로, 객체(DTO)를 JSON으로 변환하는 직렬화와 JSON을 객체(DTO)로 변환하는 역직렬화를 할 수 있음.

    ⭐ObjectMapper의 동작 원리


    ObjectMapper는 JSON과 자바 객체 간의 변환을 쉽게 만들어, 개발자는 데이터 포맷의 변환에 대해 걱정할 필요 없이 로직 구현에 더 집중할 수 있음.

     

    1) 직렬화: 자바 객체를 JSON으로 변환

    직렬화 과정에서 ObjectMapper는 다음 단계로 진행함.

    1. 객체 생성과 설정: 자바에서는 DTO 객체를 생성하고 초기화함. DTO는 각 필드가 JSON의 키와 매치됨.
    2. ObjectMapper 인스턴스 사용: ObjectMapper의 writeValueAsString() 메소드writeValue() 메소드를 사용하여 DTO를 JSON 문자열이나 스트림으로 변환함.
    3. 필드 추출과 JSON 생성: 리플렉션을 사용하여 객체의 필드를 읽고, 각 필드에 대한 get 메소드를 호출하여 데이터를 추출함. 이 데이터는 JSON 키-값 쌍으로 변환되며, @JsonProperty를 사용해 JSON 키 이름을 변경할 수 있음.

    예를 들어, 객체의 getName() 메소드에서 반환된 값은 JSON에서 'name' 키의 값으로 매핑됨. @JsonProperty("user_name") 어노테이션을 사용하여 JSON 키 이름을 'user_name'으로 변경할 수 있음.

     

    2) 역직렬화: JSON을 자바 객체로 변환

     

    역직렬화 과정은 다음 단계로 진행함.

    1. JSON 입력: 역직렬화 과정은 JSON 문자열이나 파일로부터 시작함.
    2. ObjectMapper 인스턴스 사용: ObjectMapper의 readValue() 메소드를 사용하여 JSON 데이터를 클래스 인스턴스로 변환함. 이 메소드는 JSON 키를 클래스의 필드와 매핑하고, 해당 필드에 적절한 데이터 유형으로 데이터를 설정함.
    3. 데이터 매핑과 객체 생성: ObjectMapper는 JSON 내의 각 키-값 쌍을 분석하여 해당 클래스의 필드에 할당함. 이 과정에서 @JsonNaming, @JsonProperty 등을 통해 필드 이름 매핑 규칙을 조정할 수 있음. 필드 타입에 맞게 자동으로 타입 변환을 수행함.

    예를 들어 JSON 데이터 {"user_name": "mandus"}을 객체로 변환할 때, 클래스에 setUserName(String userName) 메소드나 userName 필드가 존재해야 하며, @JsonProperty("user_name") 어노테이션이 적용되어 있어야 함.

     

    3) 유의사항

     

    • 날짜 및 시간 포맷: 날짜와 시간 데이터는 직렬화와 역직렬화 과정에서 포맷이 중요함. ObjectMapper는 @JsonFormat 어노테이션을 사용하여 이러한 필드의 포맷을 정의할 수 있음.
    • 무시할 필드 설정: 어떤 필드가 JSON에 포함되지 않도록 하거나 JSON에서 읽지 않도록 설정하려면 @JsonIgnore 어노테이션을 사용할 수 있음.
    • 커스텀 직렬화/역직렬화: 특정 필드나 클래스에 대한 직렬화 및 역직렬화 방식을 커스텀하고 싶다면 JsonSerializer와 JsonDeserializer를 구현할 수 있음.

    ⭐직렬화와 역직렬화


    직렬화 및 역직렬화 과정에는 다음과 같이 2개의 클래스가 필요함. 테스트는 main 패키지가 아닌, test 패키지 내 ApplicationTests 클래스를 실행할 것임.

    1. UserRequest 클래스 정의

    먼저, UserRequest 클래스는 Lombok 라이브러리의 @Data, @AllArgsConstructor, @NoArgsConstructor 어노테이션을 사용하여 간결하게 필드와 생성자, getter/setter 메소드를 자동으로 생성함. 그리고 Jackson의 @JsonNaming 어노테이션을 통해 JSON 키를 snake case 형식으로 자동 변환함.

    package com.example.demo.model;
    
    import com.fasterxml.jackson.databind.PropertyNamingStrategies;
    import com.fasterxml.jackson.databind.PropertyNamingStrategy;
    import com.fasterxml.jackson.databind.annotation.JsonNaming;
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
    public class UserRequest {
    
        private String userName;
        private Integer userAge;
        private String email;
        private Boolean isKorean;
    }

    2. 직렬화 테스트 코드

    Spring Boot의 테스트 환경에서 ObjectMapper를 사용하여 객체를 JSON 문자열로 변환하는 과정을 구현함.

    package com.example.demo;
    
    import com.fasterxml.jackson.databind.ObjectMapper;
    import org.junit.jupiter.api.Test;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    
    @SpringBootTest
    class DemoApplicationTests {
    
    	@Autowired
    	private ObjectMapper objectMapper;
    
    	@Test
    	void contextLoads() throws JsonProcessingException {
    
    		var user = new UserRequest();
    		user.setUserName("mandus");
    		user.setUserAge(10);
    		user.setEmail("test@gmail.com");
    		user.setIsKorean(true);
    
    		var json = objectMapper.writeValueAsString(user);
    		System.out.println(json);
    	}
    
    }

    코드를 실행하면 사진과 같이 UserRequest가 담고 있는 내용이 JSON으로 바뀐것을 확인할 수 있음.

    // 직렬화 결과
    {"user_name":"mandus","user_age":10,"email":"test@gmail.com","is_korean":true}

    3. 역직렬화 테스트 코드

    직렬화 코드에서 JSON 문자열을 UserRequest 클래스의 인스턴스로 변환하는 코드를 추가함.

    package com.example.demo;
    
    import com.fasterxml.jackson.databind.ObjectMapper;
    import org.junit.jupiter.api.Test;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    
    @SpringBootTest
    class DemoApplicationTests {
    
    	@Autowired
    	private ObjectMapper objectMapper;
    
    	@Test
    	void contextLoads() throws JsonProcessingException {
    
    		var user = new UserRequest();
    		user.setUserName("mandus");
    		user.setUserAge(10);
    		user.setEmail("test@gmail.com");
    		user.setIsKorean(true);
    
    		var json = objectMapper.writeValueAsString(user);
    		System.out.println(json);
            
    		var dto = objectMapper.readValue(json, UserRequest.class);
    		System.out.println(dto);
    	}
    
    }

    역직렬화 코드를 추가해서 실행하면 JSON으로 만들어진 내용이 다시 객체로 맵핑됨.

    // 역직렬화 결과
    UserRequest(userName=mandus, userAge=10, email=test@gmail.com, isKorean=true)

     

    Spring Boot는 기본적으로 ObjectMapper가 동작함. POST나 RequestBody에 있는 JSON 형태의 데이터들을 자바 객체(DTO)로 맵핑하는 역할(역직렬화)을 함. 반대로, 자바 객체를 JSON으로 변환하는 직렬화 과정도 ObjectMapper에 의해 자동으로 처리됨.

     

    이것은 주로 @RequestBody 어노테이션이 적용된 컨트롤러 메소드에서 HTTP 요청 본문의 JSON 데이터를 자바 객체로 변환할 때, 또는 @ResponseBody 어노테이션을 통해 자바 객체를 HTTP 응답 본문의 JSON으로 출력할 때 사용됨.

    ⭐JVM 경고 메시지 해결


    JUnit 테스트를 실행할 때 사진과 같은 JVM 관련 경고가 나타남.

    Java HotSpot(TM) 64-Bit Server VM warning: Sharing is only supported for boot loader classes because bootstrap classpath has been appended

    이것을 해결하기 위해 build.gradle 파일에 다음과 같은 설정을 추가함.

    tasks.named('test') {
        useJUnitPlatform()
        jvmArgs '-Xshare:off'
    }

    이렇게 클래스 데이터 공유 기능을 비활성화하면, 클래스 로더 관련 경고를 해결할 수 있음.

    ⭐후기


    • 직렬화와 역직렬화라는 개념에 대해서 이론만 알고 있었는데, 직접 코드로 구현해보면서 이해할 수 있었음.
    • Spring Boot에서 ObjectMapper를 사용하면 데이터의 직렬화와 역직렬화를 통해 웹 애플리케이션 간의 통신을 간소화하여 보다 효율적으로 데이터를 처리할 수 있다는 것을 알게 되었음.

    ⭐참고자료


    1) RyanGomdoriPooh, "Jackson ObjectMapper 정리", 2021.06.14, https://interconnection.tistory.com/137
    2) zooneon, "[Java] ObjectMapper를 이용하여 JSON 파싱하기", 2021.07.05, https://velog.io/@zooneon/Java-ObjectMapper를-이용하여-JSON-파싱하기

    3) 오늘도 개발자, "[Jackson]Custom Serializer, Deserializer 를 만들어 사용하기!", 2020.01.02, https://akageun.github.io/2020/01/02/java-jackson-custom-serialize.html

    4) jaemoon, "OpenJDK 64-bit Server VM warning: Sharing is only supported for boot loader classes because bootstrap classpath has been appended경고가 뜹니다.", 2024.02.06, https://www.inflearn.com/questions/1169397/openjdk-64-bit-server-vm-warning-sharing-is-only-supported-for-boot-loader-clas

     

    이 글은 패스트캠퍼스 백엔드 개발 캠프에서 공부한 내용을 작성한 것입니다.

     

    Comments