"안녕, 친구!"

"야, 디에고."

"여기서 JSON 직렬화의 기본 사항을 배웠습니까?"

"'기본'이 무슨 뜻이야? 많이 알아!"

"너무 순진하군요. 당신은 그것의 절반도 모릅니다. 기껏해야 10퍼센트입니다."

"농담이야. 또 뭐가 있니?"

"객체 계층의 역직렬화(다형성 역직렬화), 컬렉션의 역직렬화, 그리고 훨씬 더! Jackson 프레임워크는 크고 강력합니다. 솔직히, 당신은 표면을 긁기 시작했을 뿐입니다."

"좋아, 그럼 그것에 대해 말해줘. 나는 귀가 멀었어."

"매 레슨을 통해 점점 더 똑똑해지는 것이 정말 즐겁습니다!"

"글쎄, 도와주게 되어 기쁩니다, 로봇 친구!"

"준비됐어? 그럼 잘 들어."

"이미 배운 것처럼 주석은 직렬화와 역직렬화 모두에 사용됩니다. 실제로 직렬화에는 역직렬화보다 훨씬 적은 정보가 필요합니다. 예를 들면 다음과 같습니다."

자바 클래스 JSON
class Cat
{
 public String name = "missy";
 public Cat[] cats = new Cat[0];
}
{
 "name": "missy",
 "cats": []
}
class Cat
{
 public String name = "missy";
 public List cats = new ArrayList<Cat>();
}
{
 "name": "missy",
 "cats": []
}
class Cat
{
 public String name = "missy";
 public List cats = new LinkedList<Cat>();
}
{
 "name": "missy",
 "cats": []
}

"Array, ArrayList, LinkedList 및 기타 클래스의 인스턴스는 JSON 배열로 변환됩니다."

"하지만 JSON 배열을 역직렬화할 때 ArrayList 또는 LinkedList 중 어떤 개체를 만들어야 합니까?"

"맞아요. 클래스 멤버가 인터페이스(예: public List<Cat> cats )인 경우 어떤 개체에 속성을 부여해야 합니까?"

"직렬화 해제 중에 필드에 추가 주석을 추가하거나 대상 클래스를 명시적으로 나타낼 수 있습니다. 다음 예를 보십시오."

JSON에서 개체 변환
public static void main(String[] args) throws IOException
{
 String jsonString = ""{\"name\":\"Missy\",\"cats\":[{\"name\":\"Timmy\"},{\"name\":\"Killer\"}]}"";
 StringReader reader = new StringReader(jsonString);
 ObjectMapper mapper = new ObjectMapper();
 Cat cat = mapper.readValue(reader, TypeFactory.collectionType(ArrayList.class, Cat.class));
}
개체가 JSON에서 역직렬화되는 클래스
@JsonAutoDetect
class Cat {
 public String name;
 public List&ltCat> cats = new ArrayList<>();
 Cat() {
 }
}

"즉, 매퍼 .readValue 메서드의 두 번째 매개변수를 사용하여 역직렬화 중에 사용할 클래스 목록을 전달할 수 있습니다. "

"좋습니다. 편리합니다. 따라서 JSON 배열을 ArrayList 또는 LinkedList 등 필요한 모든 것으로 역직렬화할 수 있습니다.

"주석 사용에 대해서도 언급하셨는데 어떻게 하시나요?"

"쉽습니다. 예를 들면 다음과 같습니다."

JSON에서 개체 변환
public static void main(String[] args) throws IOException
{
 String jsonString = ""{\"name\":\"Missy\",\"cats\":[{\"name\":\"Timmy\"},{\"name\":\"Killer\"}]}"";
 StringReader reader = new StringReader(jsonString);

 ObjectMapper mapper = new ObjectMapper();

 Cat cat = mapper.readValue(reader, Cat.class);
}
개체가 JSON에서 역직렬화되는 클래스
@JsonAutoDetect
class Cat
{
 public String name;
 @JsonDeserialize(as = ArrayList.class, contentAs = Cat.class)
 public List&ltCat> cats = new ArrayList<>();
 Cat() {
 }
}

" 사용할 List 인터페이스의 구현을 나타내기 위해 @JsonDeserialize(as = ArrayList.class, contentAs = Cat.class) 주석을 5행에 추가하기만 하면 됩니다 ."

"아. 그렇구나. 정말 간단하다."

"하지만 더 있습니다. List의 데이터 유형이 인터페이스이기도 하다고 가정해 보겠습니다. 어떻게 하시겠습니까?"

"여기에서도 주석을 사용합니까?"

"예, 동일합니다. 매개변수 유형을 나타내는 데 사용할 수도 있습니다. 다음과 같습니다."

컬렉션 유형 데이터 유형을 설정하는 방법
목록 @JsonDeserialize(contentAs = ValueTypeImpl.class)
지도 @JsonDeserialize(keyAs = KeyTypeImpl.class)

"멋지다! 예측할 수 없는 다양한 상황에 필요한 주석이 정말 많다."

"그게 전부가 아닙니다. 이것이 우리를 주요 과정으로 인도합니다. 실제 프로젝트에서 클래스는 거의 모든 곳에서 사용되는 동일한 기본 클래스 또는 인터페이스를 상속하는 경우가 많습니다. 이제 이러한 클래스를 포함하는 데이터 구조를 역직렬화해야 한다고 상상해 보십시오. 예를 들어:"

개체를 JSON으로 변환
public static void main(String[] args) throws IOException
{
 Cat cat = new Cat();
 cat.name = "Missy";
 cat.age = 5;

 Dog dog = new Dog();
 dog.name = "Killer";
 dog.age = 8;
 dog.owner = "Bill Jefferson";

 ArrayList<Pet> pets = new ArrayList<Pet>();
 pets.add(cat);
 pets.add(dog);

 StringWriter writer = new StringWriter();
 ObjectMapper mapper = new ObjectMapper();
 mapper.writeValue(writer, pets);
 System.out.println(writer.toString());
}
개체가 JSON으로 변환되는 클래스
@JsonAutoDetect
class Pet
{
 public String name;
}

@JsonAutoDetect
class Cat extends Pet
{
 public int age;
}

@JsonAutoDetect
class Dog extends Pet
{
 public int age;
 public String owner;
}
직렬화 결과 및 화면 출력:
[
 { "name" : "Missy", "age" : 5},
 { "name" : "Killer", "age" : 8 , "owner" : "Bill Jeferson"}
]

"연재 결과에 주목하라."

"이 데이터는 기본적으로 다른 클래스의 데이터와 구별할 수 없기 때문에 이 데이터를 Java 개체로 역직렬화할 수 없습니다."

"몇 가지 구별되는 기능이 있습니다. Dog에는 소유자 필드가 있습니다."

"예, 하지만 이 필드는 null이거나 직렬화 중에 완전히 건너뛸 수 있습니다."

"음, 우리가 알고 있는 주석을 사용하여 데이터 유형을 지정할 수 없습니까?"

"아니오. 역직렬화 후에 단일 컬렉션에는 다양한 Cat 및 Dog 개체와 Pet에서 상속할 수 있는 12개의 다른 클래스가 있어야 합니다."

"도대체 여기서 무엇을 할 수 있습니까?"

"여기서는 두 가지를 사용합니다."

"먼저 한 유형을 다른 유형과 구별하기 위해 특정 필드를 선택합니다. 필드가 없으면 생성됩니다."

"두 번째로, «다형성 역직렬화» 프로세스를 제어할 수 있는 특수 주석이 있습니다. 수행할 수 있는 작업은 다음과 같습니다."

개체를 JSON으로 변환
public static void main(String[] args) throws IOException
{
 Cat cat = new Cat();
 cat.name = "Missy";
 cat.age = 5;

 Dog dog = new Dog();
 dog.name = "Killer";
 dog.age = 8;
 dog.owner = "Bill Jeferson";

 House house = new House();
 house.pets.add(dog);
 house.pets.add(cat);

 StringWriter writer = new StringWriter();
 ObjectMapper mapper = new ObjectMapper();
 mapper.writeValue(writer, house);
 System.out.println(writer.toString());
}
개체가 JSON으로 변환되는 클래스
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
@JsonSubTypes({
@JsonSubTypes.Type(value = Cat.class, name = "cat"),
@JsonSubTypes.Type(value = Dog.class, name = "dog")
})
class Pet
{
 public String name;
}

class Cat extends Pet
{
 public int age;
}

class Dog extends Pet
{
 public int age;
 public String owner;
}

class House
{
 public List&ltPet> pets = new ArrayList<>();
}
직렬화 결과 및 화면 출력:
{
 "pets" : [
 {"type" : "dog", "name" : "Killer", "age" : 8, "owner" : "Bill Jeferson"},
 {"type" : "cat", "name" : "Missy", "age" : 5}
]
}

주석을 사용하여 JSON 표현에 Cat 클래스 에 대한 cat 값 과 Dog 클래스 에 대한 dog 값을 보유할 type 이라는 특수 필드가 포함됨을 나타냅니다 . 이 정보는 개체를 적절하게 역직렬화하는 데 충분합니다. 역직렬화 중에 생성할 개체의 유형은 유형 필드의 값에 따라 결정됩니다.

"종종 클래스 이름이 유형 필드(예: «com.example.entity.Cat.class»)의 값으로 사용되지만 이는 좋은 방법이 아닙니다. JSON을 수신하는 외부 애플리케이션이 다음의 이름을 어떻게 알 수 있습니까? 설상가상으로, 클래스는 때때로 이름이 변경됩니다. 특정 클래스를 식별하기 위해 고유한 이름을 사용하는 것이 좋습니다."

"멋지다! 한숨. 역직렬화가 이렇게 복잡한지 몰랐다. 그리고 미세 조정할 수 있는 것이 이렇게 많다."

"네. 이것은 당신에게 새로운 개념이지만 이것은 당신을 천재 프로그래머로 만들어 줄 실용적인 지식입니다."

"아미고는 멋진 프로그래머야. 멋지다!"

"알았어. 가서 쉬어."