2013-09-03 4 views
3

У меня есть класс, который выглядит следующим образомGson: Пользовательские десериализации, если определенное поле присутствует

class Person { 
    Long id; 
    String firstName; 
    int age; 
} 

и мой вклад либо выглядит следующим образом:

{ "id": null, "firstName": "John", "age": 10 } 

или как это:

{ "id": 123 } 

Первый вариант представляет собой «новое» (не сохраняющееся) лицо, а второе относится к человеку по его идентификатору базы данных.

Если id не является нулевым, я хотел бы загрузить объект из базы данных во время десериализации, в противном случае - отменить регулярный синтаксический анализ и десериализовать его как новый объект.

Что я пробовал: Я в настоящее время JsonDeserializer для базы данных-десериализации, но, как я понимаю, нет никакого способа, чтобы «отступить» на регулярной разборе. Согласно this answer, я должен использовать TypeAdapterFactory и getDelegateAdapter. Моя проблема с этим подходом заключается в том, что мне присваивается JsonReader (а не, например, JsonElement), поэтому я не могу определить, содержит ли входной код действительный id без использования входных данных.

Любые предложения по тому, как это решить?

ответ

0

Думаю, мне удалось выяснить это с помощью ответа на вопрос here.

Вот рабочий тип адаптера завод:

new TypeAdapterFactory() { 
     @Override 
     public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) { 

      final TypeAdapter<T> delegate = gson.getDelegateAdapter(this, type); 
      final TypeAdapter<JsonElement> elementAdapter = 
        gson.getAdapter(JsonElement.class); 

      // Are we asked to parse a person? 
      if (!type.getType().equals(Person.class)) 
       return null; 

      return new TypeAdapter<T>() { 

       @Override 
       public T read(JsonReader reader) throws IOException { 

        JsonElement tree = elementAdapter.read(reader); 
        JsonElement id = tree.getAsJsonObject().get("id"); 

        if (id == null) 
         return delegate.fromJsonTree(tree); 

        return (T) findObj(id.getAsLong()); 
       } 

       @Override 
       public void write(JsonWriter writer, T obj) throws IOException { 
        delegate.write(writer, obj); 
       } 
      }; 
     } 
    } 

Я полностью не проверял еще и я вернусь, и пересмотреть его в случае необходимости. (Опубликовать его сейчас, чтобы открыть для обратной связи подход.)

0

Я не знаю, если я правильно понимаю ваш вопрос, но если у вас уже есть JsonDeserializer, вы должны иметь метод, как этот в там:

public Person deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) { ... } 

В этом методе вы имеете объект context типа JsonDeserializationContext, что позволяет вызывать десериализацию по умолчанию для заданного объекта.

Таким образом, вы могли бы сделать что-то вроде внутри пользовательского десериализатор:

//If id is null... 
Person person = context.deserialize(json, Person.class); 

JsonDeserializationContext documentation См.

+0

Я пробовал именно это, но я получаю исключение StackOverflowException из-за бесконечной рекурсии. Я думаю, что контекст представляет «этот» gson, а не то, что этот gson был бы без этого адаптера типа. – aioobe

+0

@aioobe: а как насчет создания нового объекта 'Gson' в' JsonDeserializer' и do 'Person person = new Gson(). FromJson (json, Person.class);'? – MikO

+1

Правильно, это сработало бы для простого примера, который я написал в моем вопросе. Однако в моем фактическом коде у меня есть ссылки на другие объекты (предположим, например, что «Лицо» будет иметь ссылку на «Личный родитель»). Если мы делегируем синтаксический анализ человека другому объекту 'gson', родительский элемент * не может быть загружен из базы данных. – aioobe

Смежные вопросы