Джексон десериализует объект, реализующий интерфейс, и игнорирует свойства интерфейса.

У меня есть аннотированный класс, который реализует интерфейс со свойством только для чтения с именем .id(), которое является универсальным, поэтому я могу извлекать различные типы id в других частях программы.

Джексон должен игнорировать весь этот интерфейс. Но вместо этого я получаю следующее сообщение об ошибке:

java.util.concurrent.ExecutionException: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Невозможно создать экземпляр my.company.Identifiable (создатели, как и конструкции по умолчанию, не существуют): абстрактные типы либо должны быть сопоставлены с конкретными типами, иметь настраиваемый десериализатор или содержать дополнительную информацию о типе в [Источник: НЕИЗВЕСТНО; строка: -1, столбец: -1] (через цепочку ссылок: java.util.HashSet[0])

Я пробовал все найденные здесь решения при поиске этого исключения, а также все первые две страницы из Google. Ни один из них не решает точную проблему, с которой я сталкиваюсь, и я не смог найти решение для моей конкретной проблемы ни от одного из них, за исключением CustomDeserializer, который я бы предпочел не писать.

Я пытался использовать JsonTypeInfo, но мне никогда раньше не приходилось использовать эту аннотацию, и я не могу понять, что я должен с ней делать. Используемые решения немного отличаются от моих, где они на самом деле требуют свойство интерфейса, а не игнорируют его.

В некоторых классах нет фактической переменной-члена id, это просто method для возврата чего-то, что считается id для другой части программы. ID<String> в одних случаях и ID<Integer> в других.

Я пробовал аннотировать с помощью @JsonProperty(access = Access.READ_ONLY), а также @JsonIgnore и @JsonIgnoreProperties({"id"}), ни один из них не меняет исключения. Я также пробовал все настройки mode в @JsonCreator, ничего не сработало.

Интерфейс определяется как:

@JsonIgnoreProperties({"id"})
public interface Identifiable<T>
{
    @JsonIgnore
    public T id();
}

Пример класса определяется как:

@JsonIgnoreProperties(ignoreUnknown = true)
public class User implements Identifiable<ID<String>>
{
    @JsonCreator
    public User(@JsonProperty("LoginName") final String loginName,
                @JsonProperty("Title") final String name,
                @JsonProperty("Email") final String email)
/* lots of irrelevant code redacted */

    @JsonIgnore
    @Override
    public ID<String> id()
    {
        return new ID.from(this.name);
    }
}

Вот как выглядит код привязки:

final HttpResponse response = req.execute();
final JsonNode root = this.om.readTree(response.getContent());
final JsonNode results = root.get("d").get("results");
final Set<V> values = this.om.readValue(this.om.treeAsTokens(results), 
                                        new TypeReference<Set<V>>() {});

Где V — это User в данном случае, а results — это Array.

Десериализация этого и пары других классов работала нормально до того, как я добавил интерфейс Identifiable<T>, все они сломались с одним и тем же исключением.

Это не класс abstract, каждый метод реализован. Я думаю, что поставил @JsonIgnore везде, где это применимо.

Я все еще получаю это исключение и не знаю, как его решить.

У меня есть ощущение, что в аннотации @JsonTypeInfo есть что-то, что может это исправить, но примеры и javadoc не написаны для тех, кто еще не знает, когда и как использовать аннотацию.

Что мне не хватает?


person Community    schedule 21.09.2017    source источник
comment
Сделать id transient?   -  person Elliott Frisch    schedule 21.09.2017
comment
нет фактической переменной-члена id, это просто method для возврата чего-то, что считается id для другой части программы. ID<String> в одних случаях и ID<Integer> в других. Я изменил пример, чтобы показать этот случай.   -  person    schedule 21.09.2017
comment
Действительно ли V является переменной типа, которая extends Identifiable<Something>? И это связано с User на каком-то месте вызова? В этом случае TypeReference не может захватить User. Взлом токена типа захватывает фактический тип в исходном коде, который в данном случае будет V, из которого он будет извлекать любые общие границы и использовать их в меру своих возможностей. См. это и подобное для Gson это   -  person Sotirios Delimanolis    schedule 21.09.2017
comment
в данном случае V это User, это рабочая версия, в которой User было везде, где сейчас V. Я обобщил его, чтобы попробовать и использовать повторно, потому что мне нужно около дюжины классов, которые делают то же самое, за исключением типов.   -  person    schedule 21.09.2017
comment
Если я использую new TypeReference<Set<User>> (и некоторые другие базовые предположения), ваш образец прекрасно анализирует JSON. Если V является переменной типа (переменная общего типа метода или класс), она не будет, и я получаю описанное вами исключение (по причинам, которые я описал в своих предыдущих комментариях). Как всегда, этот минимально воспроизводимый пример имеет решающее значение :)   -  person Sotirios Delimanolis    schedule 21.09.2017
comment
Спасибо за все подсказки, я решил эту проблему и опубликую решение, когда у меня будет возможность завтра. Я полностью избавился от интерфейса Identifiable<T> и получил, как мне кажется, гораздо лучший дизайн. Избегание наследования всегда является лучшим способом сделать что-то.   -  person    schedule 21.09.2017


Ответы (1)


Вы пытаетесь привязать свой JSON к объекту типа Identifiable вместо объекта типа User, это не работает, потому что Identifiable — это интерфейс. Проблема не в аннотациях, а в том, где вы делаете привязку.

person Nyamiou The Galeanthrope    schedule 21.09.2017