Как распарсить полиморфный объект Jackson по наличию полей?
Из-за недостаточной эффективности Gson приходится переходить на что-то другое, и сейчас выбор пал на Jackson.
Как мне распарсить объекты одного массива?
От сервера приходит json:
{
documents: [
{
"id" : 1,
"number" : "12345",
"assure" : true
...
},
........
{
"id" : 5,
"number" : "123456",
"photo" : "https://link.com"
...
}
]
}
мне нужно их положить в такую структуру:
public abstract class Document{
long id;
String number;
}
public class Passport extends Document{
boolean assure;
}
public class Contract extends Document{
String photo;
}
В примерах в интернете показывают, что нужно создать ключевое поле и определять по его значению тип объекта. У меня api недоступно для изменения, и нужно парсить в зависимости от наличия того или иного поля. В Jackson'е 2 дня.
Буду благодарен за помощь и пояснение
Ответы (2 шт):
Судя по этой ссылке должно быть как-то так:
@JsonDeserialize(using = PropertyPresentDeserializer.class)
@JsonSubTypes({
@Type(name = "assure", value = Passport .class),
@Type(name = "photo", value = Contract .class)
})
public abstract class Document{
long id;
String number;
}
public class Passport extends Document{
boolean assure;
}
public class Contract extends Document{
String photo;
}
А вы не думали, над тем, чтобы сделать так:
import com.google.gson.Gson;
import java.util.List;
import java.util.stream.Collectors;
@lombok.Data
public class DocumentParser {
private List<DocumentJson> documents;
private final static Gson GSON = new Gson();
public static List<Document> parse(String json) {
return GSON.fromJson(json, DocumentParser.class).documents.stream()
.map(DocumentParser::getInstance)
.collect(Collectors.toList());
}
@lombok.Data
private static class DocumentJson {
private Long id;
private String number;
private Boolean assure;
private String photo;
}
//этот код может быть перенесен и реализован как паттерн фабричный метод
//в любом случае вам необходимо будет каким-то образом создавать экземпляры данных классов
private static Document getInstance(DocumentJson documentJson) {
if ((documentJson.getAssure()==null && documentJson.getPhoto()==null) ||
(documentJson.getAssure()!=null && documentJson.getPhoto()!=null))
throw new RuntimeException("Not supporetd...");
if (documentJson.getAssure()==null) return Contract.builder()
.id(documentJson.getId())
.number(documentJson.getNumber())
.photo(documentJson.getPhoto())
.build();
else return Passport.builder()
.id(documentJson.getId())
.number(documentJson.getNumber())
.assure(documentJson.getAssure())
.build();
}
}
@lombok.Data
@lombok.NoArgsConstructor
@lombok.AllArgsConstructor
public abstract class Document {
private Long id;
private String number;
}
@lombok.Data
@lombok.NoArgsConstructor
@lombok.EqualsAndHashCode(callSuper = true)
@lombok.ToString(callSuper = true)
public class Passport extends Document{
private Boolean assure;
@lombok.Builder
public Passport(Long id, String number, Boolean assure) {
super(id, number);
this.assure = assure;
}
}
@lombok.Data
@lombok.NoArgsConstructor
@lombok.EqualsAndHashCode(callSuper = true)
@lombok.ToString(callSuper = true)
public class Contract extends Document{
private String photo;
@lombok.Builder
public Contract(Long id, String number, String photo) {
super(id, number);
this.photo = photo;
}
}
Все дело в том, что у вас нет идентификатора, по которому можно определить, какой именно инстанс нужно создавать. Это значит, что вам нужно залезть в джейсон и создавать их по определенному условию. При таких исходных данных, как по мне , лучше написать логику на джаве. Она достаточно несложная. И это в любом случае проще и более читаемо, чем пытаться сконфигурировать Jackson либо любую другую библиотеку. мало того, как уже написано в комментариях, из метода getInstance достаточно легко сделать паттерн фабричный метод и использовать его для инстанциирования экземпляров классов данной иерархии в других случаях их использования. Это достаточно просто расширяется в случае добавления дополнительных наследников, а также добавляется другая логика инстанциирования. При этом код остается читаемым.