Сериализация Enum, реализующего интерфейс с Gson

У меня есть код библиотеки, который мне нужно сериализовать. Одно поле определено как интерфейс Foo, который является просто маркерным интерфейсом. Предполагается, что клиентский код создает Enum, реализующий Foo, чтобы они могли расширять список подтипов по мере необходимости.

Я не могу сериализовать это в Gson с помощью адаптера типа. Исключение, которое я получаю:

java.lang.IllegalStateException: не объект JSON: «SETUP»

где setup — это один элемент клиентского перечисления Bar.

Я добавил TypeAdapter, который определяет Foo как супертип, а Bar как подтип, используя код Gson RuntimeTypeAdapter (помощник Gson от Google). Любые идеи о том, что я делаю неправильно, или такая структура просто не поддерживается Gson?

Я считаю, что могу обойти это, сделав Foo абстрактным классом, а Setup подклассом, но это немного менее хорошо, поскольку перечисление на самом деле является просто токеном.


person L. Blanc    schedule 28.03.2017    source источник
comment
Было бы неплохо, если бы вы опубликовали трассировку стека исключений хотя бы по самой причине, MCVE и версии Gson, которую вы используете.   -  person Lyubomyr Shaydariv    schedule 28.03.2017


Ответы (1)


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

В любом случае, я думаю, что лучшим решением вашей проблемы может быть реализация собственного сериализатора/десериализатора для аннотации. Вашему интерфейсу потребуются подклассы для реализации метода name() (который вы уже должны были реализовать, поскольку это перечисление), а затем вызовите его для сериализации.

Вот пример:

public class MyInterfaceSerializer implements JsonSerializer<MyInterface> {

public JsonElement serialize(MyInterface src, Type typeOfSrc,
        JsonSerializationContext context) {

    return context.serialize(src.name());
}

Десериализация в основном такая же, но десериализатор (может и должен быть того же класса) будет реализовывать JsonDeserializer и создавать экземпляр вашего перечисления.

person Aurasphere    schedule 28.03.2017
comment
Вам удалось воспроизвести ошибку, которую получает OP? Я не мог воспроизвести ни сопоставление классов, ни одно значение перечисления. - person Lyubomyr Shaydariv; 28.03.2017
comment
Gson ожидает объект, но получает перечисление, вместо которого перечисление является объектом. - person Sean Patrick Floyd; 28.03.2017
comment
@LyubomyrShaydariv Я не мог, но я не знаю, какую версию Gson он использует. - person Aurasphere; 28.03.2017
comment
@Aurasphere LOL перечисление также является классом :-). Во время выполнения перечисление почти ничем не отличается от любого другого старого объекта. Это просто сахар компилятора. - person Sean Patrick Floyd; 28.03.2017
comment
@SeanPatrickFloyd, вы можете узнать, является ли класс anum во время выполнения, если вы используете instanceof. И я подозреваю, что это именно проблема ОП. - person Aurasphere; 28.03.2017
comment
@Aurasphere Я знаю и согласен с вашими выводами, только не с формулировкой - person Sean Patrick Floyd; 28.03.2017
comment
@SeanPatrickFloyd Извините, я не силен в формулировках... Вот почему я программист, а не поэт: Пахаха - person Aurasphere; 28.03.2017
comment
Кстати, последняя строка не скомпилируется, если в интерфейсе нет метода name(). Но вы можете заменить его на return context.serialize(Enum.class.cast(src).name()); - person Sean Patrick Floyd; 28.03.2017
comment
Вашему интерфейсу потребуются подклассы для реализации метода name() (который вы уже должны были реализовать, поскольку это перечисление), а затем вызовите его для сериализации. Ага, вот это я и имел в виду - person Aurasphere; 28.03.2017
comment
ах извините, пропустил это - person Sean Patrick Floyd; 28.03.2017
comment
Нет проблем, хотя могут быть и другие ошибки, так как я написал это на лету, и я не могу проверить это на этом компьютере, поэтому хорошо, что есть обзор! Спасибо! - person Aurasphere; 28.03.2017