GOOGLE ADS

четверг, 28 апреля 2022 г.

@JsonIdentityInfo не может десериализовать сечения объектов в том же файле

Я разбираю объект JSON с помощью Java ObjectMapper. Некоторые объекты должны использоваться повторно, поэтому я использую @JsonIdentityInfoдля разрешения ссылок на них (я могу определить их как встроенные или как ссылки). Сначала это работало.

Однако у меня есть 2 типа объектов, и они могут ссылаться друг на друга (там есть наследование, а некоторые объекты являются составными объектами).

Мой входной файл разделен на разделы. Теперь моя проблема заключается в перекрестных ссылках между разделами. Если указанный объект читается в 1-м разделе, все в порядке. Однако, если указанный объект находится во 2-м разделе, это не будет разрешено. Я не хочу наводить порядок, так как могут быть перекрестные ссылки.

Есть ли способ заставить ObjecMapper просмотреть весь ввод перед сбоем?

Например, это мои классы (очень упрощенный вариант использования):

@Getter
@Setter
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
property = "@type",
visible = true)
@JsonSubTypes({
@JsonSubTypes.Type(value = AValue.class, name = "AValue"),
@JsonSubTypes.Type(value = AReferenceToB.class, name = "AReferenceToB"),
})
@JsonIdentityInfo(scope = A.class, generator = ObjectIdGenerators.PropertyGenerator.class)
public abstract class A {
@JsonProperty("@id")
private String id;
@JsonProperty("@type")
private String type;
}
@Getter
@Setter
public class AValue extends A {
@NonNull
String value;
@JsonCreator
public AValue(@JsonProperty(value = "value", required = true) @NonNull String value) {
this.value = value;
}
}
@Getter
@Setter
public class AReferenceToB extends A{
@NonNull
B b;
@JsonCreator
public AReferenceToB(@JsonProperty(value = "b", required = true) @NonNull B b) {
this.b = b;
}
}
@Getter
@Setter
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
property = "@type",
visible = true)
@JsonSubTypes({
@JsonSubTypes.Type(value = BValue.class, name = "BValue"),
@JsonSubTypes.Type(value = BReferenceToA.class, name = "BReferenceToA"),
})
@JsonIdentityInfo(scope = B.class, generator = ObjectIdGenerators.PropertyGenerator.class)
public class B {
@JsonProperty("@id")
private String id;
@JsonProperty("@type")
private String type;
}
@Getter
@Setter
public class BValue extends B {
int value;
@JsonCreator
public BValue(@JsonProperty(value = "value", required = true) int value) {
this.value = value;
}
}
@Getter
@Setter
public class BReferenceToA extends B {
@NonNull
A a;
@JsonCreator
public BReferenceToA(@JsonProperty(value = "a", required = true) @NonNull A a) {
this.a = a;
}
}

И это класс, в который я прочитал JSON:

@Getter
@Setter
public class File {
@NonNull
private List<A> as;
@NonNull
private List<B> bs;
@JsonCreator
public File(@JsonProperty(value = "as", required = true) @NonNull List<A> as,
@JsonProperty(value = "bs", required = true) @NonNull List<B> bs) {
this.as = as;
this.bs = bs;
}
}

Чтение этого файла выполняется без a2, но не с a2. Это не будет работать, если я поменяю местами asи bsтакже.

{
"as": [
{
"@id": "a1",
"@type": "AValue",
"value": "test"
},
{
"@id": "a2",
"@type": "AReferenceToB",
"b": "b1"
}
],
"bs": [
{
"@id": "b1",
"@type": "BValue",
"value": 1
},
{
"@id": "b2",
"@type": "BReferenceToA",
"a": "a1"
}
]
}

Отказ:

com.fasterxml.jackson.databind.exc.InvalidTypeIdException: Could not resolve subtype of [simple type, class A]: missing type id property '@type' (for POJO property 'as')
at [Source: (File); line: 12, column: 9] (through reference chain: File["as"]->java.util.ArrayList[1])

Код:

ObjectMapper mapper = new ObjectMapper();
final File file = mapper.readValue(Paths.get("test.json").toFile(), File.class);


Решение проблемы

Вступление

Давайте рассмотрим следующее подмножество зависимостей Maven как текущую версию библиотеки Джексона:

<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.13.2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.13.2.2</version>
</dependency>

Отвечать

Похоже, что в настоящее время такое использование @JsonProperty, @JsonIdentityInfoи коллекции ( List<E>интерфейса) не поддерживается библиотекой Джексона.

Пожалуйста, ознакомьтесь с открытой проблемой GitHub: правильно десериализовать прямые @JsonIdentityInfoссылки при использовании @JsonCreator· Issue #3030 · FasterXML/jackson-databind.

Обратите внимание на комментарий к проблеме GitHub:

cowtowncoder прокомментировал 30 января 2021 г.

Правильно: могут быть случаи с комбинацией @JsonCreator, идентификационной информации и упорядоченных коллекций ( Lists и массивов), которые могут вообще не поддерживаться. Вызов конструктора невозможен без фактического объекта, и, наоборот, значения коллекций должны быть десериализованы по порядку. Возможно, вам придется изменить использование, чтобы рассматриваемые Listсвойства передавались сеттерами или полями; или, возможно, используйте стиль Builder, если требуется неизменность (построители работают до тех пор, пока сам встроенный тип не использует идентификатор объекта; его свойства могут использовать их).

Обходные пути

Некоторые обходные пути описаны в уже упомянутом комментарии к проблеме GitHub.

Пример обходного пути: используйте поле вместо конструктора для десериализации

Пример отлично работает после обновления AReferenceToBкласса для использования поля вместо конструктора для десериализации:

@Getter
@Setter
public class AReferenceToB extends A {
@JsonProperty(value = "b", required = true)
@NonNull
B b;
}

Недостатки обходного пути:


  • Он вводит изменчивость. Класс AReferenceToBстал изменчивым.

Комментариев нет:

Отправить комментарий

Laravel Datatable addColumn returns ID of one record only

Я пытаюсь использовать Yajra Datatable для интеграции DataTable на свой веб-сайт. Я смог отобразить таблицу, но столкнулся с проблемой. В по...