본문 바로가기
Web/공부

[Java/Spring] JSON 파싱하기

by 소똥 2023. 9. 1.
아직 공부단계로 포스트 내용에 잘못되거나 미흡한 부분이 있다면 지적 부탁드립니다 :>
추가로 습득하는 내용이 있으면 계속 업데이트 하겠습니다.

 

JSON

JSON이란 Javascript 객체 문법을 따르는 문자기반의 데이터 포맷이다. (단순히 데이터를 표시하는 표현법 중 하나)

 

특징

  • 문자열 형태로 존재 -> 이러한 특징은 네트워크를 통해 전송시 유용
  • Parsing : 데이터를 읽기 위해서는 문자열을 JSON 객체로 변환
  • Stringfication : 네트워크로 전달하기 위해서는 JSON 객체를 문자열로 변환
  • MINE Type : application/json

 

구조

{
  "name": "soddong",
  "age": "25",
  "address": "seoul",
  "contact": {
    "phone_number": "010",
    "email": "soddong@email.com"
  },
  "job": {
    "working": true,
    "workplace": {
      "name": "univ",
      "position": "student"
    }
  }
}

위와 같이, "key" : "value" 의 형태를 가지는 데이터 포맷이다.

 

 

간단한 JSON 에 대한 설명은 위와 같고, 포스트의 목적인 JSON을 파싱하는 방법에 대해 알아보겠다.

 

1. JSONParser

2. ObjectMapper

3. Gson (추가 예정)

3. @ResponseBody (Spring)

 


JSONParser

// 1. JSON Object type
data = "{
	"name"   : "soddong",
    "age"    : "25",
    "gender" : "female"
}";
JSONParser parser = new JSONParser();
JSONObject obj = (JSONObject)parser.parse(data);

System.out.println("이름: " + obj.get("name"));

// 2. JSON Array type
data = "[
	{
        "name"   : "soddong",
        "age"    : "25"    	
    },
    {
        "name"   : "nooks",
        "age"    : "27" 
    },
    {
        "name"   : "suzzin",
        "age"    : "30" 
    }
]";
JSONParser parser = new JSONPareser();
JSONArray arr = (JSONArray)parser.parser(data);
for (JSONObject obj : arr){
	System.out.println("이름" + (String)obj.get("name"));
}

주의 할 점은, json이 array로 되어있느냐, object로 되어있느냐에 따라서 작업을 추가해주어야 한다. 

또한 이 방식은 기본적인 방식으로, json의 구조에 따라서 일일이 직접 parsing 해와야 한다. 따라서 더 간단하게 구현이 가능한 타 라이브러리를 많이 사용하는 듯 하다.

 


ObjectMapper

Jackson 라이브러리 내의 JSON 파싱에 사용되는 클래스로, 이 함수에서 자동으로 직렬화와 역직렬화를 해준다.

  • Java 객체 -> JSON 객체로 직렬화 (데이터 전송시 바이트 문자열이어야 하므로 문자열로 변환하는 작업) 
  • JSON 객체 -> Java 객체로 역직렬화 (데이터 수신시 문자열을 기존 객체로 변환하는 작업) 
public class ObjectMapper {
	public static void main(String[] args) {
    	
        ObjectMapper objectMapper = new ObjectMapper();
        
        // java -> json
        Member member = new Mmeber("soddong", "25", "seoul");
        String json = objectMapper.writeValueAsString(member);
        Member member = objectMapper.readValue(member, Member.class);
    }
}

public class Mmember {
	private String name;
    private String age;
    private String location;
}

이녀석을 통해 DTO객체로 전달받고 DTO객체를 쉽게 문자열로 변환하여 JSON 형태로 전달할 수 있다.

단, 매번 객체를 변환하는 과정을 거치다보니 비용이 비싸다는 단점이 있다.

 


Spring에서 사용하기 (@ResponseBody)

스프링에서 Json 객체 <-> DTO 객체 를 변환하는 과정은 더 쉽다.

@RequestMapping("/members")
@RestController
public class MemberController {
    @PostMapping
    public void create(@RequestBody MemberDto memberDto){
        memberDtos.add(memberDto);
    }
}s

위와 같이 작성시, 자동으로 @RequestBody 어노테이션에 의해 자동으로 전달된 객체 타입으로 변환이 된다. 이게 어떻게 가능한가? 에 대해서는 코드를 한번 파보자!

 

@RequestBody를 따라가 보면 인터페이스 설명에 "The body of the request is passed through an HttpMessageConverter" 와 같은 설명이 있다. 

HttpMessageConverter 인터페이스의 경우, 문자를 처리할 때는 StringHttpMessageConverter, 객체 처리에는 MappingJackson2HttpMessageConverter 를 사용한다.  

 

특히 객체 처리시 사용되는 클래스의 이름을 보면 jackson이 들어가 있다. 결국, spring도 까보면 jackson을 라이브러리로 맵핑을 한다는것을 유추해볼 수 있다.

public interface HttpMessageConverter<T> {

	/**
	 * Indicates whether the given class can be read by this converter.
	 * @param clazz the class to test for readability
	 * @param mediaType the media type to read (can be {@code null} if not specified);
	 * typically the value of a {@code Content-Type} header.
	 * @return {@code true} if readable; {@code false} otherwise
	 */
	boolean canRead(Class<?> clazz, @Nullable MediaType mediaType);

	/**
	 * Indicates whether the given class can be written by this converter.
	 * @param clazz the class to test for writability
	 * @param mediaType the media type to write (can be {@code null} if not specified);
	 * typically the value of an {@code Accept} header.
	 * @return {@code true} if writable; {@code false} otherwise
	 */
	boolean canWrite(Class<?> clazz, @Nullable MediaType mediaType);

	/**
	 * Read an object of the given type from the given input message, and returns it.
	 * @param clazz the type of object to return. This type must have previously been passed to the
	 * {@link #canRead canRead} method of this interface, which must have returned {@code true}.
	 * @param inputMessage the HTTP input message to read from
	 * @return the converted object
	 * @throws IOException in case of I/O errors
	 * @throws HttpMessageNotReadableException in case of conversion errors
	 */
	T read(Class<? extends T> clazz, HttpInputMessage inputMessage)
			throws IOException, HttpMessageNotReadableException;

	/**
	 * Write a given object to the given output message.
	 * @param t the object to write to the output message. The type of this object must have previously been
	 * passed to the {@link #canWrite canWrite} method of this interface, which must have returned {@code true}.
	 * @param contentType the content type to use when writing. May be {@code null} to indicate that the
	 * default content type of the converter must be used. If not {@code null}, this media type must have
	 * previously been passed to the {@link #canWrite canWrite} method of this interface, which must have
	 * returned {@code true}.
	 * @param outputMessage the message to write to
	 * @throws IOException in case of I/O errors
	 * @throws HttpMessageNotWritableException in case of conversion errors
	 */
	void write(T t, @Nullable MediaType contentType, HttpOutputMessage outputMessage)
			throws IOException, HttpMessageNotWritableException;

}

인터페이스를 간단히 살펴보면 HTTP 요청 메시지가 도착하면 canRead() 메서드를 호출하여 변환해주어야 할 클래스 타입 (DTO 등)의 지원여부를 확인하고, 조건 만족시 read() 메서드를 호출하여 해당 객체로 반환해 준다.

 

이 read 메서드 내부가 사실 궁금한데,,, 이건 다음에 알아보자. 

 

내가 그리는 아키텍쳐

1) 2) 의 경우, 컨트롤러안에서 라이브러리를 사용하여 객체들의 형태를 변환하여 client에게 전달될 수 있는 형태로 변환하는 구조 이므로 위와 같이 나타 낼 수 있다. 

 

3) 의 경우, Mapper의 역할을 Spring이 해준다고 할 수 있다. Spring은 라이브러리보다는 프레임워크 이므로 조금 더 복잡한 구조를 가지겠지만 간단히 나타내자면 이러하다.

 

 

** 스프링의 너무 단편적인 부분만 공부하고 있는 느낌이어서 답답한 느낌이 있다. 전체적인 큰그림을 그려가며 공부하는걸 좋아하는 사람으로서, 좀더 스프링의 개괄적인 부분을 공부해야겠다 싶다. **

 

 

참고)
About spring code: https://docs.spring.io/
About json:  https://developer.mozilla.org/ko/docs/Learn/JavaScript/Objects/JSON

'Web > 공부' 카테고리의 다른 글

[Spring] MVC 패턴과 Service, Domain, Repository  (1) 2023.09.06
[Web/CS] HTTP 통신에 대한 모든 것  (0) 2023.08.28