특정 필드가 존재하는 경우 잭슨 다형성 역직렬화를 사용하여 서브타입으로 시리얼화할 수 있습니까?
동물원 예에서 스핀을 사용하여:
public class ZooPen {
public String type;
public List<Animal> animals;
}
public class Animal {
public String name;
public int age;
}
public class Bird extends Animal {
public double wingspan;
}
하여 구축하다Animal
되지 않은 및 "wingsspan" (wingsspan) " ""Bird
타입이 은 일반적으로 다음과 잭슨에서 타입이 없는 디시리얼라이제이션은 일반적으로 다음과 같습니다.
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY,
property = "wingspan",
visible = true,
defaultImpl = Animal.class
)
@JsonSubTypes({
@Type(value = Bird.class, name = "bird")
})
public class Animal {
...
}
wingspan 값은 어떤 것이든 상관없습니다.특정 일치하는 값이 없으면 Jackson은 defaultImpl 클래스로 폴백합니다.
는 아마 마마내 i i i를 사용할 수 있을 것이다.@JsonCreator
:
@JsonCreator
public static Animal create(Map<String,Object> jsonMap)
throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
if (jsonMap.get("wingspan") == null) {
// Construct and return animal
} else {
// Construct and return bird
}
}
그 , 이 경우 이 값을 사용할 수 있는지 하지 않습니다.Animal
나중에 제대로 연재될 겁니다.
서도 쓸 수 것 TypeResolver
또는, 하지만, 그것은 단순히 raw json을 역직렬화하는 것 보다 더 많은 작업이 될 것 같습니다.또한.TypeResolver
★★★★★★★★★★★★★★★★★」TypeIdResolver
타입 정보가 시리얼화되어 있다고 본질적으로 가정하고 있는 것 같기 때문에, 그것들을 사용하는 것은 좋지 않습니다.
타입을 지정하기 위해 라이프 사이클에 후크하면서 기본적인 잭슨 주석 처리 기능을 사용하는 나만의 방식을 구현할 수 있을까요?제가 계속 살펴봤는데, 그건 완전히 탈직렬화를 위임하는 것 같아요.TypeDeserializer
또, 어떤 타입을 사용할지 판단하기 전에, 오브젝트의 일부의 시리얼화를 해제하는 문제도 있습니다.
또는 동물원의 펜이 부모 물체에 있더라도 그것을 목표로 하는 방법이 있을 수 있습니다.
다형식 핸들링으로 원하는 것을 할 수 있는 방법이 있나요?
Jackson 2.12.2에서는 "추리 기반 다형성" 기능을 사용하여 다음과 같은 목표를 달성했습니다.속성이 에 고유한 경우Bird
"Subtype"(예: "Subtype"(예: "Subtype")wingspan
, 은 ), 「」, 「」가 Bird
않으면 ;가 될 이다.Animal
:
@JsonTypeInfo(use=Id.DEDUCTION, defaultImpl = Animal.class)
@JsonSubTypes({@Type(Bird.class)})
public class Animal {
public String name;
public int age;
}
연산에 기초한 다형성
차감 기반 다형성 기능은 특정 하위 유형에 고유한 속성이 있는지 여부에 따라 하위 유형을 추론합니다. 고유의으로 일의로 할 수 , 에 의해 ,defaultImpl
값이 사용됩니다.
공제 기반의 다형성 기능은 Jackson 2.12에서 잭슨 데이터바인드 #43에 따라 구현되었습니다.다음 2.12 릴리즈 노트에 요약되어 있습니다.
될 수 한 또는 을 생략할 수 (「」 「」 「ID」).
@JsonTypeInfo(use=DEDUCTION)
필드의 존재로부터).즉, 모든 서브타입에는 포함된 고유한 필드 세트가 있기 때문에 역직렬화 중에 고유하고 확실하게 검출할 수 있습니다.
Jackson 2.12.2에서는 고유 식별 가능한 서브타입이 없을 때 예외를 발생시키지 않고 기본유형을 지정하는 이 기능이 잭슨 2.12.2에서 잭슨-databind#3055에 의해 추가되었습니다.
한 도 없는
defaultImpl
적합성과 관계없이 대상 유형이어야 합니다.
추론 기반 다형성에 대한 조금 더 긴 설명은 잭슨 제작자가 쓴 "Jackson 2.12 Most Want (1/5) : 추론 기반 다형성" 기사에 나와 있습니다.
편집: 잭슨의 최신 릴리스 후보를 사용할 수 있으면 문제가 해결됩니다.https://github.com/MariusSchmidt/de.denktmit.stackoverflow/tree/main/de.denktmit.jackson에서 간단한 데모를 준비했습니다.
이 스레드(https://github.com/FasterXML/jackson-databind/issues/1627,)는 고객의 문제에 대해 설명하고 해결책을 제안합니다.Merge라는 것이 있는데, https://github.com/FasterXML/jackson-databind/pull/2813에서 볼 때 유망해 보입니다.따라서 @JsonTypeInfo(= DEUPTION 사용) 경로를 따를 수 있습니다.
Jackson의 최신 버전을 사용할 수 없는 경우 다음과 같이 처리하겠습니다.
병합 요청 백포트(OR)
- 잭슨을 사용하여 입력을 일반 JsonNode로 역직렬화합니다.
- 하나 이상의 속성이 존재하는지 https://github.com/json-path/JsonPath 체크를 사용합니다.일부 컨테이너 클래스는 클래스 유형을 고유하게 식별하는 데 필요한 모든 경로를 래핑할 수 있습니다.
- JsonNode를 여기에 설명된 대로 결정된 클래스에 매핑 JsonNode를 POJO로 변환
이렇게 하면 낮은 수준의 매핑 로직을 처리하지 않고도 잭슨의 모든 기능을 활용할 수 있습니다.
안부 전합니다,
마리우스
동물
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.databind.ObjectMapper;
import de.denktmit.stackoverflow.jackson.polymorphic.deductive.Bird;
import de.denktmit.stackoverflow.jackson.polymorphic.deductive.Fish;
import org.junit.jupiter.api.Test;
import java.util.List;
import static com.fasterxml.jackson.annotation.JsonTypeInfo.Id.DEDUCTION;
import static org.assertj.core.api.Assertions.assertThat;
@JsonTypeInfo(use = DEDUCTION)
@JsonSubTypes( {@JsonSubTypes.Type(Bird.class), @JsonSubTypes.Type(Fish.class)})
public class Animal {
private String name;
private int age;
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 class Bird extends de.denktmit.stackoverflow.jackson.polymorphic.deductive.Animal {
private double wingspan;
public double getWingspan() {
return wingspan;
}
public void setWingspan(double wingspan) {
this.wingspan = wingspan;
}
}
물고기.
public class Fish extends de.denktmit.stackoverflow.jackson.polymorphic.deductive.Animal {
private boolean freshwater;
public boolean isFreshwater() {
return freshwater;
}
public void setFreshwater(boolean freshwater) {
this.freshwater = freshwater;
}
}
ZooPen
public class ZooPen {
private String type;
private List<de.denktmit.stackoverflow.jackson.polymorphic.deductive.Animal> animals;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public List<de.denktmit.stackoverflow.jackson.polymorphic.deductive.Animal> getAnimals() {
return animals;
}
public void setAnimals(List<de.denktmit.stackoverflow.jackson.polymorphic.deductive.Animal> animals) {
this.animals = animals;
}
}
테스트
import com.fasterxml.jackson.databind.ObjectMapper;
import de.denktmit.stackoverflow.jackson.polymorphic.deductive.Animal;
import de.denktmit.stackoverflow.jackson.polymorphic.deductive.Bird;
import de.denktmit.stackoverflow.jackson.polymorphic.deductive.Fish;
import de.denktmit.stackoverflow.jackson.polymorphic.deductive.ZooPen;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
public class DeductivePolymorphicDeserializationTest {
private static final String birdString = "{\n" +
" \"name\": \"Tweety\",\n" +
" \"age\": 79,\n" +
" \"wingspan\": 2.9\n" +
" }";
private static final String fishString = "{\n" +
" \"name\": \"Nemo\",\n" +
" \"age\": 16,\n" +
" \"freshwater\": false\n" +
" }";
private static final String zooPenString = "{\n" +
" \"type\": \"aquaviary\",\n" +
" \"animals\": [\n" +
" {\n" +
" \"name\": \"Tweety\",\n" +
" \"age\": 79,\n" +
" \"wingspan\": 2.9\n" +
" },\n" +
" {\n" +
" \"name\": \"Nemo\",\n" +
" \"age\": 16,\n" +
" \"freshwater\": false\n" +
" }\n" +
" ]\n" +
"}";
private final ObjectMapper mapper = new ObjectMapper();
@Test
void deserializeBird() throws Exception {
de.denktmit.stackoverflow.jackson.polymorphic.deductive.Animal animal = mapper.readValue(birdString, de.denktmit.stackoverflow.jackson.polymorphic.deductive.Animal.class);
assertThat(animal).isInstanceOf(de.denktmit.stackoverflow.jackson.polymorphic.deductive.Bird.class);
}
@Test
void deserializeFish() throws Exception {
de.denktmit.stackoverflow.jackson.polymorphic.deductive.Animal animal = mapper.readValue(fishString, de.denktmit.stackoverflow.jackson.polymorphic.deductive.Animal.class);
assertThat(animal).isInstanceOf(de.denktmit.stackoverflow.jackson.polymorphic.deductive.Fish.class);
}
@Test
void deserialize() throws Exception {
de.denktmit.stackoverflow.jackson.polymorphic.deductive.ZooPen zooPen = mapper.readValue(zooPenString, de.denktmit.stackoverflow.jackson.polymorphic.deductive.ZooPen.class);
assertThat(zooPen).isInstanceOf(de.denktmit.stackoverflow.jackson.polymorphic.deductive.ZooPen.class);
}
}
'는 않다'는가 있다고 생각합니다.@JsonCreator
:
@JsonCreator
public static Animal create(Map<String,Object> jsonMap) {
String name = (String) jsonMap.get("name");
int age = (int) jsonMap.get("age");
if (jsonMap.keySet().contains("wingspan")) {
double wingspan = (double) jsonMap.get("wingspan");
return new Bird(name, age, wingspan);
} else {
return new Animal(name, age);
}
}
JsonProcessingException
이 커스텀 디시리얼라이저는 내장된 Jackson 디시리얼라이저와 똑같은 이유로 실패합니다.즉, 예외 캐스팅입니다.복잡한 역직렬화에서는 코드를 이해하고 수정하는 것이 훨씬 쉬워지기 때문에 이 방법을 선호합니다.
pretius-jdl deserialization을 사용하여 목표를 달성할 수 있습니다.나는 그것이 어떻게 작동하는지 보여주기 위해 학급 계층을 조금 확장했다.다음은 샘플 코드입니다.
public class SOAnswer3 {
@ToString @Getter @Setter
@AllArgsConstructor @NoArgsConstructor
public static class Animal {
String name;
int age;
}
@ToString(callSuper = true) @Getter @Setter
@AllArgsConstructor @NoArgsConstructor
public static class Bird extends Animal {
double wingspan;
}
@ToString(callSuper = true) @Getter @Setter
@AllArgsConstructor @NoArgsConstructor
public static class Elephant extends Animal {
double trunkLength;
}
public static void main(String[] args) {
String json = "[{"
+ " \"name\": \"Marty\","
+ " \"age\": 3"
+ "},"
+ "{"
+ " \"name\": \"Danny\","
+ " \"age\": 7,"
+ " \"wingspan\": 1.4159"
+ "},{"
+ " \"name\": \"King\","
+ " \"age\": 21,"
+ " \"trunkLength\": 2.11"
+ "}]";
// create a deserializer instance
DynamicObjectDeserializer deserializer = new DynamicObjectDeserializer();
// runtime-configure deserialization rules
deserializer.addRule(DeserializationRuleFactory.newRule(1, // priority
DeserializationCriterionFactory.targetClassIsAssignableFrom(Animal.class)
.and((e) -> e.getJsonNode().has("wingspan")),
DeserializationActionFactory.objectToType(Bird.class)));
deserializer.addRule(DeserializationRuleFactory.newRule(1,
DeserializationCriterionFactory.targetClassIsAssignableFrom(Animal.class)
.and((e) -> e.getJsonNode().has("trunkLength")),
DeserializationActionFactory.objectToType(Elephant.class)));
List<Animal> deserializedObjects = deserializer.deserializeArray(json, Animal.class);
for (Animal obj : deserializedObjects) {
System.out.println("Deserialized Class: " + obj.getClass().getSimpleName()+";\t value: "+obj.toString());
}
}
}
결과:
Deserialized Class: Animal; value: SOAnswer3.Animal(name=Marty, age=3)
Deserialized Class: Bird; value: SOAnswer3.Bird(super=SOAnswer3.Animal(name=Danny, age=7), wingspan=1.4159)
Deserialized Class: Elephant; value: SOAnswer3.Elephant(super=SOAnswer3.Animal(name=King, age=21), trunkLength=2.11)
pretius-jdl의 Maven defendency(maven.org/jddl에서 최신 버전을 확인합니다).
<dependency>
<groupId>com.pretius</groupId>
<artifactId>jddl</artifactId>
<version>1.0.0</version>
</dependency>
잭슨과 결혼하지 않았다면 FlexJSON을 사용하면 이와 비슷한 일을 할 수 있다고 생각합니다.
http://flexjson.sourceforge.net/javadoc/flexjson/JSONDeserializer.html
비슷한 작업을 수행하는 Jackson의 방법은 익숙하지 않지만 FlexJSON은 매우 성능이 뛰어나고 일반적으로 직렬화/직접적으로 사용할 수 있습니다.
안녕 Shaun 당신은 실제로 상속을 사용하는 잭슨과 함께 매우 쉽게 이 행동을 할 수 있습니다.저는 동물과 새의 시나리오를 모델링했습니다.
임플란트 내의 생성자는 동물의 올바른 인스턴스를 인스턴스화할 수 있습니다(이름과 나이가 존재하는 경우 An An Animal, 이름 나이와 날개 길이 있는 경우 Bird).이것은 Jersey와 같은 것을 사용하여 API를 통해 값을 검색하는 경우에도 동일하게 동작합니다.
@com.fasterxml.jackson.annotation.JsonSubTypes({
@com.fasterxml.jackson.annotation.JsonSubTypes.Type(AnimalImpl.class)
})
@com.fasterxml.jackson.databind.annotation.JsonDeserialize(as = AnimalImpl.class)
public interface Animal {
public String getName();
public int getAge();
}
public class AnimalImpl implements Animal {
private final String name;
private final int age;
public AnimalImpl(
@JsonProperty("name") final String name,
@JsonProperty("age") final int age
) {
this.name = Objects.requireNonNull(name);
this.age = Objects.requireNonNull(age);
}
@Override
public String getName() {
return name;
}
@Override
public int getAge() {
return age;
}
}
@com.fasterxml.jackson.annotation.JsonSubTypes({
@com.fasterxml.jackson.annotation.JsonSubTypes.Type(BirdImpl.class)
})
@com.fasterxml.jackson.databind.annotation.JsonDeserialize(as = BirdImpl.class)
public interface Bird extends Animal {
public double getWingspan();
}
public class BirdImpl extends AnimalImpl implements Bird {
private final double wingspan;
public BirdImpl(
@com.fasterxml.jackson.annotation.JsonProperty("name") final String name,
@com.fasterxml.jackson.annotation.JsonProperty("age") final int age,
@com.fasterxml.jackson.annotation.JsonProperty("wingspan") final double wingspan
) {
super(name, age);
this.wingspan = wingspan;
}
@Override
public double getWingspan() {
return wingspan;
}
}
public class Test {
public static void main(final String[] args) throws java.io.IOException {
final com.fasterxml.jackson.databind.ObjectMapper objectMapper
= new com.fasterxml.jackson.databind.ObjectMapper();
final String animalJson = "{\"name\": \"the name\", \"age\": 42}";
final Animal animal = objectMapper.readValue(animalJson, Animal.class);
System.out.println(animal);
final String birdJson = "{\"name\": \"the name\", \"age\": 42, \"wingspan\": 21}";
final Bird bird = objectMapper.readValue(birdJson, Bird.class);
System.out.println(bird);
}
}
언급URL : https://stackoverflow.com/questions/16488951/can-jackson-polymorphic-deserialization-be-used-to-serialize-to-a-subtype-if-a-s
'programing' 카테고리의 다른 글
응답 입력 onChange 지연 (0) | 2023.04.03 |
---|---|
Woocommerce 3에서 환불된 주문 및 환불된 주문 항목 세부 정보 확인 (0) | 2023.04.03 |
Typescript, React 및 Webpack을 사용하여 CSS 모듈을 Import하는 방법 (0) | 2023.04.03 |
Wordpress와 Cakephp를 통합하는 방법 (0) | 2023.04.03 |
React가 관리하는 자녀가 있는 contentEditable 구성 요소에 대해 경고하는 이유는 무엇입니까? (0) | 2023.04.03 |