给定的测试失败,但我认为应该不会。
当数据对象转换为常规的非生成器类时,测试通过(源:https://pastebin.com/pBkTb6HW)。
要使构建器对象通过测试,必须在@JsonTypeInfo
接口上添加Animal
批注。这意味着Zoo
不能完全通用,但需要所有动物的通用超类型。
似乎这种差异不应该存在?
杰克逊版:2.10
错误:
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `JacksonTest$Animal` (no Creators, like default construct, exist): abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information
at [Source: (String)"{"animals":[{"@type":"Dog","name":"doggo"},{"@type":"Cat","name":"cat"}]}"; line: 1, column: 13] (through reference chain: JacksonTest$Zoo$Builder["animals"]->java.util.ArrayList[0])
完整测试用例:
public class JacksonTest {
@Test
void test() throws JsonProcessingException {
ObjectMapper m = new ObjectMapper();
m.findAndRegisterModules();
List<Animal> animals = List.of(
Dog.builder().name("doggo").build(),
Cat.builder().name("cat").build()
);
Zoo z = Zoo.builder().animals(animals).build();
String json = m.writeValueAsString(z);
Zoo deser = m.readValue(json, Zoo.class);
assertThat(z).isEqualTo(deser);
}
@Value
@Builder(builderClassName = "Builder")
@JsonDeserialize(builder = Zoo.Builder.class)
static class Zoo {
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS)
List<Animal> animals;
@JsonPOJOBuilder(withPrefix = "")
public static class Builder {}
}
interface Animal {
String getName();
}
@Value
@Builder(builderClassName = "Builder")
@JsonDeserialize(builder = Dog.Builder.class)
static class Dog implements Animal {
String name;
@JsonPOJOBuilder(withPrefix = "")
public static class Builder {}
}
@Value
@Builder(builderClassName = "Builder")
@JsonDeserialize(builder = Cat.Builder.class)
static class Cat implements Animal {
String name;
@JsonPOJOBuilder(withPrefix = "")
public static class Builder {}
}
}
已修复,错误代码已注释掉并替换。添加评论。
版本:
package io.jeffmaxwell.stackoverflow;
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.util.List;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.JsonTypeInfo.Id;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder;
import lombok.Builder;
import lombok.Value;
import lombok.extern.log4j.Log4j2;
@Log4j2
public class Q62193465 {
static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
@BeforeAll
static void findAndRegistrerModules() {
OBJECT_MAPPER.findAndRegisterModules();
}
@Test
void test() throws JsonProcessingException {
List<Animal> animals = List.of(Dog.builder()
.name("doggo")
.build(),
Cat.builder()
.name("cat")
.build());
var zoo = Zoo.builder()
.animals(animals)
.build();
var zooAsJsonString = OBJECT_MAPPER.writeValueAsString(zoo);
LOGGER.info("zooAsJsonString {}", zooAsJsonString);
var zooFromJsonString = OBJECT_MAPPER.readValue(zooAsJsonString, Zoo.class);
assertEquals(zoo, zooFromJsonString);
}
@Value
@Builder(builderClassName = "Builder")
@JsonDeserialize(builder = Zoo.Builder.class)
public static class Zoo {
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS)
List<Animal> animals;
@JsonPOJOBuilder(withPrefix = "")
public static class Builder {
}
}
// Added
@JsonTypeInfo(use = Id.CLASS)
interface Animal {
String getName();
}
@Value
@Builder(builderClassName = "Builder")
// Was @JsonDeserialize(builder = Zoo.Builder.class)
@JsonDeserialize(builder = Dog.Builder.class)
static class Dog implements Animal {
String name;
@JsonPOJOBuilder(withPrefix = "")
public static class Builder {
}
}
@Value
@Builder(builderClassName = "Builder")
// Was @JsonDeserialize(builder = Zoo.Builder.class)
@JsonDeserialize(builder = Cat.Builder.class)
static class Cat implements Animal {
String name;
@JsonPOJOBuilder(withPrefix = "")
public static class Builder {
}
}
}