Я пытаюсь создать объектную модель, которая представляет иерархию вложенных расположений устройств. Например, «колода» содержит «лоток для слайдов», который содержит один или несколько «слайдов». Я хочу иметь возможность читать файл json, содержащий иерархию / конфигурацию системы. Я хочу использовать в своих классах конструкторы Lombok, чтобы при необходимости можно было безопасно генерировать файлы json в коде. Более распространенный вариант использования - это чтение файла json для создания pojo при запуске приложения. Создание файлов json с помощью построителя отлично работает. Однако мне не приходилось десериализовать файл обратно в файл pojo.
Вот ошибка, которую я получаю:
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `my.org.Deck$DeckBuilder` (no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
at [Source: (String)"{"type":"Deck","locNumber":1,
Суперкласс верхнего уровня:
package my.org;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import lombok.Getter;
import lombok.Singular;
import lombok.experimental.Accessors;
import lombok.experimental.SuperBuilder;
import java.awt.geom.Point2D;
import java.util.List;
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
@JsonSubTypes({
@JsonSubTypes.Type(value = Deck.class, name = "Deck"),
@JsonSubTypes.Type(value = SlideTray.class, name = "SlideTray"),
@JsonSubTypes.Type(value = Slide.class, name = "Slide"),
@JsonSubTypes.Type(value = NullLoc.class, name = "null"),
})
@SuperBuilder
@Getter
@Accessors(fluent = true, chain = true)
@JsonDeserialize(builder = BaseLocationType.BaseLocationTypeBuilder.class)
public class BaseLocationType<T extends BaseLocationType> {
@JsonProperty("locNumber")
private int locNumber;
@JsonProperty("posRelativeToParent")
private Point2D.Double positionRelativeToParent;
@Singular
@JsonProperty("childLocs")
private List<T> childLocs;
}
Подкласс колоды:
package my.org;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.experimental.Accessors;
import lombok.experimental.SuperBuilder;
@SuperBuilder
@Getter
@EqualsAndHashCode(callSuper = true)
@Accessors(fluent = true, chain = true)
@JsonDeserialize(builder = Deck.DeckBuilder.class)
public class Deck extends BaseLocationType<SlideTray> {
private String deckField1;
private String deckField2;
}
Подкласс SlideTray:
package my.org;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.experimental.Accessors;
import lombok.experimental.SuperBuilder;
@SuperBuilder
@Getter
@EqualsAndHashCode(callSuper = true)
@Accessors(fluent = true, chain = true)
@JsonDeserialize(builder = SlideTray.SlideTrayBuilder.class)
public class SlideTray extends BaseLocationType<Slide> {
private String slideTrayField1;
}
Подкласс Slide:
package my.org;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.experimental.Accessors;
import lombok.experimental.SuperBuilder;
@SuperBuilder
@Getter
@EqualsAndHashCode(callSuper = true)
@Accessors(fluent = true, chain = true)
@JsonDeserialize(builder = Slide.SlideBuilder.class)
public class Slide extends BaseLocationType<NullLoc> {
private String slideField1;
}
NullLo c:
package my.org;
import lombok.experimental.SuperBuilder;
@SuperBuilder
public class NullLoc extends BaseLocationType<NullLoc> {
// no fields or builder, etc
}
Тестовый код - сбой с указанным выше исключением в mapper.readValue ():
// create 1 deck with 1 slideTray that has 2 slides
Deck.DeckBuilder<?, ?> deckBuilder = Deck.builder()
.locNumber(1)
.positionRelativeToParent(new Point2D.Double(1.0, 1.0))
.deckField1("deck f1 data")
.deckField2("deck f2 data")
.childLoc(SlideTray.builder()
.locNumber(2)
.positionRelativeToParent(new Point2D.Double(2.0, 2.0))
.slideTrayField1("slide tray f1 data")
.childLoc(Slide.builder()
.locNumber(3)
.positionRelativeToParent(new Point2D.Double(3.0, 3.0))
.slideField1("child1-slide f1 data")
.build())
.childLoc(Slide.builder()
.locNumber(4)
.positionRelativeToParent(new Point2D.Double(4.0, 4.0))
.slideField1("child2-slide f1 data")
.build()).build());
Deck deckPojo = deckBuilder.build();
// serialize the pojo's
String json = new ObjectMapper().writeValueAsString(deckPojo);
// de-serialize the json back into the pojo's
ObjectMapper mapper = new ObjectMapper();
Deck deckPojoDeserialized = mapper.readValue(json, Deck.class);
Генерируется json:
{
"type": "Deck",
"locNumber": 1,
"posRelativeToParent": {
"x": 1.0,
"y": 1.0
},
"childLocs": [
{
"type": "SlideTray",
"locNumber": 2,
"posRelativeToParent": {
"x": 2.0,
"y": 2.0
},
"childLocs": [
{
"type": "Slide",
"locNumber": 3,
"posRelativeToParent": {
"x": 3.0,
"y": 3.0
},
"childLocs": []
},
{
"type": "Slide",
"locNumber": 4,
"posRelativeToParent": {
"x": 4.0,
"y": 4.0
},
"childLocs": []
}
]
}
]
}
примечание: я не вижу опции здесь, в stackoverflow, чтобы загрузить zip-файл демонстрационного проекта ... но при необходимости могу найти способ поделиться им. Спасибо!