티스토리 뷰

반응형

적용을 해보면서 object mapper에 대해 알아보자.

 

 

우선 프로젝트를 만들자.

 

 

 

 

 

 

위와 같이 프로젝트를 만들면 아래와 같이 gradle로 프로젝트가 만들어진다.

 

 

 

그리고 build.gradle을 보면 dependency라는 것이 있다. 보통 자바 프로젝트에서는 directory로 폴더를 하나 만들어서 lib이라 이름을 짓고 그 안에 라이브러리를 추가해 준다. 그러나 gradle이나 maven 프로젝트를 그럴 필요 없이 dependency만 추가해 주면된다.

 

이러한 것들은 아래와 사이트에서 가져오게 된다. 구글에 maven repository 라고 쳐보자.

 

 

https://mvnrepository.com/

 

이러한 사이트에서 maven 프로젝트를 검색할 수 있다. spring boot, object mapper등등으로 사용할 라이브러리들을 검색해서 사용해 볼 수 있다. 우리는 object mapper를 사용할 것이기 때문에 검색을 해보자. 그러면 아래와 같이 화면이 보일 것인데, 우리는 3. Jackson Databind를 사용할 것이다. 눌러서 usages가 많은 것과 RELEASE(릴리즈)된 것을 많이 사용한다. 그리고 완전최신을 사용하진 않는다. 

 

 

 

 

 

버전들이 많은데, 가장 많이 사용하고 있는 2.12.1 버전을 사용할 것이다. 버전을 눌러보면 아래와 같은 화면이 뜬다.

 

 

gradle을 눌러서 복사하고 아래와 같이 dependency에 넣고 빌드넣어주면 추가가 되는 것을 알 수 있다.

 

 

위와 같이 추가를 하고 오른 쪽위의 reload를 눌러주면 블럭처리된 부분들과 같이 jackson이 추가된 것을 확인 할 수 있다.

 

이제 object mapper를 사용할 준비는 끝났다. 그리고 아래와 같이 main/java밑에 main.java를 만들어 주고 아래와 같이 코드를 짠 후에 실행을 시켜보자. 그러면 main이 출력되는것을 확인 할 수 있을 것이다.

 

 

 

 

 

사용할 Json은 아래와 같다.

 

{
  "name" : "한파이",
  "age" : 30,
  "cars" : [
    {
      "name" : "제네시스",
      "car_number" : "12허 2222",
      "TYPE" : ""
    },
    {
      "name" : "그랜저",
      "car_number" : "11사 1111",
      "TYPE" : ""
    }
  ]
}

 

 

사용할 Json을 만들었으니 자동차 클래스와 사용자 클래스를 우선 만들자. 위의 Json을 보면 name, age, cars리스트가 하나의 object로 클래스를 만들어야 할 것 같고, cars 리스트 내부의 정보들도 하나씩 object로 만들어 줘야 할 것같다. 

 

dto 폴더를 만들고 Car와 User 클래스를 하나씩 만들자. 주의 할 점은 Car class를 먼저 만들고, 그 후에 User 내부에 Car에 대한 리스트를 넣어주면 된다.

 

그 후에 Code-generater-getter and setter를 설정해 주고 toString까지 해주면 아래와 같은 코드가 나올 것이다. 

 

위의 json에 대한 코드는 아래와 같다.

 

 

 

구조는 위와 같고

 

Car class

package dto;

public class Car {
    private String name;
    private String carNumber;
    private String type;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getCarNumber() {
        return carNumber;
    }

    public void setCarNumber(String carNumber) {
        this.carNumber = carNumber;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    @Override
    public String toString() {
        return "Car{" +
                "name='" + name + '\'' +
                ", carNumber='" + carNumber + '\'' +
                ", type='" + type + '\'' +
                '}';
    }
}

 

User class

package dto;

import java.util.List;

public class User {
    private String name;
    private int age;
    private List<Car> cars;


    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public List<Car> getCars() {
        return cars;
    }

    public void setCars(List<Car> cars) {
        this.cars = cars;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", cars=" + cars +
                '}';
    }
}

 

 

 

 

이제 object Mapper를 통해 만들어 보자. 객체부터 만들자. main.java를 아래와 같이 넣고 User가 잘만들어졌는지 print를 해보자

 

main.java

import com.fasterxml.jackson.databind.ObjectMapper;
import dto.Car;
import dto.User;

import java.util.Arrays;
import java.util.List;

public class main {
    public static void main(String args[]){
        System.out.println("main");

        ObjectMapper objectMapper = new ObjectMapper();

        User user = new User();
        user.setName("한파이");
        user.setAge(39);

        Car car1 = new Car();
        car1.setName("제네시스");
        car1.setCarNumber("11가 1111");
        car1.setType("세단");

        Car car2 = new Car();
        car2.setName("제네시스");
        car2.setCarNumber("11가 1111");
        car2.setType("세단");

        List<Car> carList = Arrays.asList(car1, car2);
        user.setCars(carList);

        System.out.println(user);

    }
}

 

 

실행을 하면 아래와 같은 에러가 발생한다.

 

 

에러는 인코딩에러이다. 윈도우에서 실행을 하면 UTF-8이 아니라 MS949라서 에러가 발생하는 것이다. 윈도우와 맥은 인코딩 방법이 다르다.

 

윈도우의 경우는 아래와 같이 file의 settings를 들어가서 encoding을 검색하자. 그러면 file encoding 부분을 눌러보자. 그러면 global encoding은 UTF-8이지만, Project Encoding은 949로 설정되어 있는 것을 확인 할 수 있다. 이부분을 아래의 그림처럼 UTF-8로 변경해 주자. 아래의 Properties Files에도 넣어주자.

 

 

 

그리고 Help-find action을 눌러주자. 검색창이 뜨면 edit custom VM otion을 검색해서 눌러주자. 그러면 아래와 같은 창이 뜰 것이다.

 

 

아래에 -Dfile.encoding=UTS-8를 추가해준다.

 

 

 

 

그리고 인텔리제이를 모두 종료하고 다시 열고, 실행을 해보면, 아래와 같이 정상적으로 작동하는 것을 알 수 있다. ObjectMapper를 사용할 때도 UTF-8이 기본이라는 것을 이해하자. 자바프로젝트에서 설정을 해주면 되고, 스프링 같은 경우는 기본적으로 설정이 되어있다.

 

- JSON 형태로 먼가 보낸다

- JAVA 코드로 클라이언트와 HTTP 통신을 한다

 

위의 경우면 UTF-8로 변경을 해줘야 에러가 발생안한다. (MAC은 상관 없다.)

 

 

다시 돌아와서 ObjectMapper를 활용하여 JSON으로 변경하는 코드는 다음과 같다.

 

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import dto.Car;
import dto.User;

import java.util.Arrays;
import java.util.List;

public class main {
    public static void main(String args[]) throws JsonProcessingException {
        System.out.println("main");

        ObjectMapper objectMapper = new ObjectMapper();

        User user = new User();
        user.setName("한파이");
        user.setAge(39);

        Car car1 = new Car();
        car1.setName("제네시스");
        car1.setCarNumber("11가 1111");
        car1.setType("세단");

        Car car2 = new Car();
        car2.setName("제네시스");
        car2.setCarNumber("11가 1111");
        car2.setType("세단");

        List<Car> carList = Arrays.asList(car1, car2);
        user.setCars(carList);

        //System.out.println(user);

        String json = objectMapper.writeValueAsString(user);
        System.out.println(json);

    }
}

 

writeValueAsString 부분을 보면 에러를 방지하기 위해서 alt+enter를 활용해서 throws로 사용한 것을 알 수 있다. 아래의 그림을 보면 참으로 나온 것을 알 수 있다.

 

 

 

그리고 JSON이 잘 작성 됐나 확인을 하려면, JSON validation을 구글에 쳐서 들어가서 확인하면 된다. 예시는 아래와 같다.

 

https://jsonformatter.curiousconcept.com/

 

JSON Formatter & Validator

Format and validate JSON data so that it can easily be read by human beings.

jsonformatter.curiousconcept.com

 

출력 값을 넣어서 확인해 보면 아래와 같다.

 

 

 

아쉬운 점은 snake case가 아닌 카멜케이스로 들어간 것을 알 수 있다. 여러 방법 중에 타입에 이름을 바로 붙여 줄 것이다.

 

 

Car.java에 @JsonProperty를 아래와 같이 붙여준다.

 

package dto;

import com.fasterxml.jackson.annotation.JsonProperty;

public class Car {
    private String name;

    @JsonProperty("car_number")
    private String carNumber;

    @JsonProperty("TYPE")
    private String type;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getCarNumber() {
        return carNumber;
    }

    public void setCarNumber(String carNumber) {
        this.carNumber = carNumber;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    @Override
    public String toString() {
        return "Car{" +
                "name='" + name + '\'' +
                ", carNumber='" + carNumber + '\'' +
                ", type='" + type + '\'' +
                '}';
    }
}

 

 

그리고 실행을 해주면 아래와 같이 잘 나온 것을 알 수 있다.

 

 

 

위의 방법이 ObjectMapper의 방식이다. 이제 순스하게 노드로 접근하는 방법을 해보자. 아래의 JSON을 보면, 첫번쨰 JSON 노드는 전체이고 그 값이 name, age, cars ...가 된다는 것을 알 수 있다. 

 

{
   "name":"한파이",
   "age":39,
   "cars":[
      {
         "name":"제네시스",
         "carNumber":"11가 1111",
         "type":"세단"
      },
      {
         "name":"제네시스",
         "carNumber":"11가 1111",
         "type":"세단"
      }
   ]
}

 

이제 파싱을 해보자.

 

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import dto.Car;
import dto.User;

import java.util.Arrays;
import java.util.List;

public class main {
    public static void main(String args[]) throws JsonProcessingException {
        System.out.println("main");

        ObjectMapper objectMapper = new ObjectMapper();

        User user = new User();
        user.setName("한파이");
        user.setAge(39);

        Car car1 = new Car();
        car1.setName("제네시스");
        car1.setCarNumber("11가 1111");
        car1.setType("세단");

        Car car2 = new Car();
        car2.setName("제네시스");
        car2.setCarNumber("11가 1111");
        car2.setType("세단");

        List<Car> carList = Arrays.asList(car1, car2);
        user.setCars(carList);

        //System.out.println(user);

        String json = objectMapper.writeValueAsString(user);
        System.out.println(json);



        JsonNode jsonNode = objectMapper.readTree(json);
        String _name = jsonNode.get("name").asText();
        int _age = jsonNode.get("age").asInt();
        System.out.println("name : "+_name);
        System.out.println("age : "+_age);

        // 객체 리스트 파싱
        JsonNode cars = jsonNode.get("cars");
        ArrayNode arrayNode = (ArrayNode) cars;

        List<Car> _cars = objectMapper.convertValue(arrayNode, new TypeReference<List<Car>>() {});
        System.out.println(_cars);

        ObjectNode objectNode = (ObjectNode) jsonNode;
        objectNode.put("name", "steve");
        objectNode.put("age", 20);

        System.out.println(objectNode.toPrettyString());
    }
}


// output
> Task :main.main()
main
{"name":"한파이","age":39,"cars":[{"name":"제네시스","car_number":"11가 1111","TYPE":"세단"},{"name":"제네시스","car_number":"11가 1111","TYPE":"세단"}]}
name : 한파이
age : 39
[Car{name='제네시스', carNumber='11가 1111', type='세단'}, Car{name='제네시스', carNumber='11가 1111', type='세단'}]
{
  "name" : "steve",
  "age" : 20,
  "cars" : [ {
    "name" : "제네시스",
    "car_number" : "11가 1111",
    "TYPE" : "세단"
  }, {
    "name" : "제네시스",
    "car_number" : "11가 1111",
    "TYPE" : "세단"
  } ]
}

 

 

위의 코드를 보면 get을 이용해서 그냥 이름을 가져오면 된다. 그리고 asText()로 텍스트로 변경해 달라고 하는 것이다. asInt()는 숫자로 변경해 달라는 것이다. 이러한 방식은 변수 타입을 미리 알 때만 사용할 수 있는 것이다. 즉, 직접 반복문 같은 것들을 해서 직접 노드를 건드릴 때 이런 것들을 할 수 있다.

 

리스트는 약간 다르다. 리스트인 cars의 내부를 보면 새로운 JSON의 노드들이 들어 있다고 볼 수 있다. 즉 배열안에 노드들이 들어 있는 것이다. 배열의 노드니까 ArrayNode라는 objectmapper의 클래스가 있다. 이것을 활용하여 변환 시켜주면 된다. 이것으로 파씽을 해서 강제 타입 변환을 시킬 것이다. 그리고 objectMapper의 convertValue를 활용해서 원래 원했던 type으로 변환이 가능하다. TypeReference안에는 변환을 원하는 타입을 넣어주면 된다.

 

정리하면 위의 코드는 JSON의 스팩을 기본적으로 알고 있어야한다. Json 노드에 접근하는 법과 ArrayNode 사용법을 다시한번 체크하자. 그리고 파씽 시에는 convertValue에 object에 넣어서 TypeReference로 변경한다는 것을 알자.

 

기본적으로 Json은 특정 객체를 변경할 수 없다. 그러나 이것을 바꿀 수 있는 클래스가 존재한다. 그것이 바로 ObjectNode이다. jsonNode(위의 JSON 전체)를 형변환 시켜보자. name과 age를 변경한 것이다. put 매소드를 이용해서 활용하면 된다.

 

toPrettyString은 Json을 예쁘게 출력한다는 의미로 생각을 해주면 된다.

 

 

정리하면, 전체를 objectmapper로 파싱을 할수도 있지만, 각각의 노드에 접근하여 변경하거나 치환할 수 있음을 알자.

반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
글 보관함