1. ObjectMapper 활용

1-1. 개요

  • JSON 컨텐츠Java 객체를 매핑하기 위한 Jackson 라이브러리의 클래스
  • 주의 할 점은 클래스 내부에서 많은 초기화가 일어나기 때문에 가능하다면 bean으로 등록하거나 static으로 사용하는게 성능상 유리

1-2. 코드

1) 객체 생성


import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
public class Member {
	private String name;
    private int age;
    private String userId;
    private String userPassword;
}

2) 적용

2-1) @bean으로 등록 후 적용

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.fasterxml.jackson.databind.ObjectMapper;

@Configuration
public class AppConfig {
    
    @Bean
    public ObjectMapper objectMapper() {
        return new ObjectMapper();
    }
}
import java.util.Map;
import org.springframework.stereotype.Controller;
import lombok.RequiredArgsConstructor;
import com.fasterxml.jackson.databind.ObjectMapper;

@Controller
@RequiredArgsConstructor
public class JoinController {
	
    private final ObjectMapper objectMapper;
    
    @PostMappping("/join")
    public String join(@RequestParam String param) {
   		objectMapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE);
        Member member = objectMapper.readValue(param, Member.class);
    }
    
}

2-2) static으로 선언 후 적용

import org.springframework.stereotype.Controller;
import lombok.RequiredArgsConstructor;
import com.fasterxml.jackson.databind.ObjectMapper;

@Controller
@RequiredArgsConstructor
public class JoinController {
	
    private static final ObjectMapper objectMapper = new ObjectMapper()
            .setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE);
    
    @PostMappping("/join")
    public String join(@RequestParam String param) {
   		objectMapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE);
        Member member = objectMapper.readValue(param, Member.class);
    }
    
}
객체를 JSON형태로 변경할 경우에는 writeValueAsString(객체) 형태로 사용

1-3. 작동 원리

1) 용어

  • 설명에 앞서 직렬화(serialize)라는 용어를 알 필요가 있습니다. 사전적인 의미로는 다음과 같습니다.

    • 직렬화(serialize) : 메모리를 디스크에 저장하거나 네트워크 통신에 사용하기 위한 형태로 변환
    • 역직렬화(deserialize) : 디스크에 저장한 데이터를 읽거나, 네트워크 통신으로 받은 데이터를 메모리에 쓸 수 있도록 변환
  • 해당 형태는 JSON, Byte, XML 등의 다양하게 변환이 됩니다. 하지만 SpringFramework에서는 주로 JSON 형태의 통신을 일컫기 때문에 해당 개념으로 보시면 좋을 것 같습니다.


2) HttpMessageConverter

  • 간단히 설명하자면 요청을 사용자가 지정한 형태로 변환시켜주는 역할을 수행합니다.
  • 하지만 요청의 key값이 다른 경우 자동으로 매핑이 불가능하기 때문에 ObjectMapper를 사용하게 됩니다.

3) 작동 원리

3-1) 직렬화(serialize)

  • HttpMessageConverter를 통해 들어온 요청을 ObjectMapperwriteValueAsString 이라는 메서드를 통해 객체로 접근하게 됩니다.
  • 접근 방식은 해당 객체의 get 함수를 통하게 되어 getter의 생성이 필수적입니다.
  • 이때 주의할 점으로는 public 필드의 변수나 get으로 시작하는 메서드는 모두 추적되기 때문에 다음과 같은 객체에 접근 시 오류가 발생할 수 있다는 점입니다.

import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
public class Member {
	private String name;
    private int age;
    private String userId;
    private String userPassword;
    
    public String getBirthDay(int age) {
        int currentYear = LocalDate.now().getYear();
        LocalDate today = LocalDate.now();
        
        return String.valueOf(currentYear - age);
    }
}
해당 함수의 결과값이 JSON으로 파싱될 수 있다는 점을 항상 유의하여 get 으로 시작하는 메서드명 사용을 지양 습관도 좋은 방법이 될 수 있을것 같습니다.

3-2) 역직렬화(deserialize)

  • HttpMessageConverter를 통해 들어온 요청을 ObjectMapperreadValue 라는 메서드를 통해 객체로 접근하게 됩니다.
  • 접근 방식은 해당 객체의 기본 생성자 를 통하게 되며 역직렬화 또한 직렬화와 마찬가지로 getter/setter의 생성이 필수적입니다.

4) 공통 클래스 생성

  • 앞선 설명처럼 bean/static의 형식으로 사용하는게 효율적입니다.
  • 그렇다면 공통 Util 객체로 만들어 사용하는 것도 하나의 방법이라 생각합니다.
import org.springframework.stereotype.Controller;
import lombok.RequiredArgsConstructor;
import com.fasterxml.jackson.databind.ObjectMapper;

public class JsonConverter {
	
    // bean 호출 혹은 static으로 선언
    private static final ObjectMapper objectMapper = new ObjectMapper()
            .setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE);
    
     public static Member fromJson(String json) throws JsonProcessingException {
        return objectMapper.readValue(json, Member.class);
    }

    public static String toJson(Object object) throws JsonProcessingException {
        return objectMapper.writeValueAsString(object);
    }
    
}
  • 여기서 주의할 점은 Object로 여러 객체를 담을 수 있도록 매개변수를 설정하였기 때문에 발생 할 수 있는 오류에 대한 정밀한 처리가 필요하다는 점입니다.




2. 어노테이션 활용

2-1. 개요

  • ObjectMapper를 통한 역할을 어노테이션을 통한 JSON 컨텐츠Java 객체를 매핑

1) 종류

1-1) @JsonNaming

클래스 단위 작동 방식으로 매핑하려는 JSON의 키값이 일정할 경우 사용

1-2) @JsonProperty

필드 단위 작동 방식으로 매핑하려는 JSON의 키값이 일정할 경우 사용

2-2. 코드

1) 객체 생성

1-1) @JsonNaming


import com.fasterxml.jackson.databind.PropertyNamingStrategies;
import com.fasterxml.jackson.databind.annotation.JsonNaming;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
public class Member {
	private String name;
    private int age;
    private String userId;
    private String userPassword;
}

1-2) @JsonProperty


import com.fasterxml.jackson.databind.PropertyNamingStrategies;
import com.fasterxml.jackson.databind.annotation.JsonProperty;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
public class Member {

	private String name;
    private int age;
    
    @JsonProperty("user_id")
    private String userId;
    
    @JsonProperty("user_password")
    private String userPassword;
}

3. 결론

  • ObjectMapper어노테이션 방식을 선택하는 기준은 개인적인 생각으로는 다음과 같습니다.
    • ObjectMapper는 로직상의 개별 커스텀이 필요하거나 예외 처리를 직접 커스텀 하는 경우 등 세밀한 조정이 필요한 경우
    • 어노테이션 해당 객체가 통신 결과값을 주고 받는 것에만 사용되거나 키값 형태의 통일성이 높은 경우
profile
개발 학습

0개의 댓글

Powered by GraphCDN, the GraphQL CDN