Как научить Джексона кастовать наследников абстрактного класса? - PullRequest
2 голосов

У меня есть класс:

@EqualsAndHashCode(callSuper = true)
@Data
public class AppealTemplateDto extends AbstractDto {

    private List<AbstractFieldDto> fields;
}

Этот класс содержит список AbstractFieldDto наследников, например ::

@EqualsAndHashCode(callSuper = true)
@Data
@NoArgsConstructor
public class InputFieldDto extends AbstractFieldDto {

    private String fieldType = FieldType.INPUT.name();
    private String text;
}

Всего существует около 6-7 наследников, и AbstractTemplateDto может содержать любой их набор.

Контроллер:

@PostMapping
public ResponseEntity<AppealTemplateDto> create(@RequestBody AppealTemplateDto dto) {
    return ResponseEntity.ok(service.save(dto));
}

Когда Джексон пытается разобрать AppealTemplateDto, происходит сбой за исключением:

вызвано: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: невозможно построить экземпляр ru.appeal.template.dto.field.AbstractFieldDto (Создатели, как и конструкция по умолчанию, не существуют): либо абстрактные типы необходимо сопоставить с конкретными типами, иметь собственный десериализатор или содержать дополнительную информацию о типе

Как я понимаю, Джексон не может определить, как разыгрывать входящие AbstractFieldDto. Посоветуйте, пожалуйста, что делать?

1 Ответ

1 голос
/ 31 мая 2019

Аннотации, которые вам нужны:

@JsonTypeInfo
@JsonSubType

@JsonTypeName

Некоторое объяснение: если у вас много реализаций вашего абстрактного типа, Джексон не может угадать, какой тип является вашим json, вам нужно добавить имя типав json, например, как новое свойство (это одна из стратегий):

//tell to jackson where to find the type name
@JsonTypeInfo(   use = JsonTypeInfo.Id.NAME, include = As.PROPERTY, property = "type")
// tell to jackson the implementations to scan
@JsonSubTypes({
    @JsonSubTypes.Type(value = InputFieldDto.class, name = "input")
    //, ...
})
public class AbstractFieldDto {
}

//tell to jackson what is the type name in json
@JsonTypeName("input")
public class InputFieldDto extends AbstractFieldDto {

    private String fieldType = FieldType.INPUT.name();
    private String text;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...