2016-11-21 2 views
0

В нашем проекте мы разбираем JSON с Jackson. Мы устанавливаем поле saved по полю channelId. Проблема в том, что поле channelId анализируется позже, чем saved. Поэтому в то время, когда мы хотим установить поле saved, поле channelId - null. Как мы можем установить зависимость поля в десериализации JSON, так что поле saved будет установлено после channelId?Deserialize JSON с Джексоном с полевой зависимостью

Это часть наших данных JSON:

"message":{ 
      "data":{ 
       "text":"Some text" 
      }, 
      "saved_by":[ 
       2715, 
       1234 
      ], 
      "some_boolean_field":false, 
      "channel_id":8162 
      } 

Это наша сущность класс:

@JsonIgnoreProperties(ignoreUnknown = true) 
@org.parceler.Parcel(org.parceler.Parcel.Serialization.BEAN) 

public class Message { 

    @JsonProperty("channel_id") 
    protected long channelId; 

    protected boolean saved; 

    @JsonSetter("saved_by") 
    public void setSavedBy(Set<Long> savedBy) { 
     saved = savedBy.contains(getUserIdByChannelId(channelId)); 
    } 

    public long getChannelId() { 
     return channelId; 
    } 

    public void setChannelId(long channelId) { 
     this.channelId = channelId; 
    } 

    public boolean isSaved() { 
     return saved; 
    } 

    public void setSaved(boolean saved) { 
     this.saved = saved; 
    } 

    public void setData(JsonNode data) throws JsonProcessingException { 
     JsonNode textNode = data.get("text"); 
     text = textNode != null ? textNode.asText() : ""; 

     components = new ArrayList<>(); 
     JsonNode mediaNode = data.get("media"); 
     if (mediaNode != null) { 
      MessageComponent[] parsedComponents = AppSession.getInstance().getObjectMapper().treeToValue(mediaNode, MessageComponent[].class); 
      List<MessageComponent> components = Arrays.asList(parsedComponents).subList(0, parsedComponents.length < 4 ? parsedComponents.length : 4); 

      this.components.addAll(components); 
     } 

     mediaCount = components.size(); 
    } 

    } 

Полного JSON:

{ 
    "data":{ 
     "serial":66, 
     "updated_entity":"bookmark", 
     "bookmark":{ 
     "message":{ 
      "data":{ 
       "text":"hello" 
      }, 
      "counted_serial":748, 
      "saved_by":[ 
       26526, 
       27758 
      ], 
      "type":"UserMessage", 
      "is_reviewed":false, 
      "channel_id":8128, 
      "id":2841531, 
      "replied_message_data":null, 
      "is_blocked":false, 
      "is_deleted":false, 
      "updated_at":"2016-11-21T05:59:52.471Z", 
      "spam_reported_by":[ 

      ], 
      "created_at":"2016-11-19T15:40:17.027Z", 
      "uuid":"0b6ba58e-f5e1-4ee5-a9da-041dfc2c85cd", 
      "liked_by":[ 

      ], 
      "user":{ 
       "last_name":"M", 
       "id":4537, 
       "first_name":"John", 
       "is_deleted":false, 
       "avatar_thumb":"https:\/\/cdn.site.org\/uploads\/99ef4d68-6eaf-4ba6-aafa-74d1cf895d71\/thumb.jpg" 
      }, 
      "serial":934 
     }, 
     "id":6931, 
     "created_at":"2016-11-21T05:59:52.459Z", 
     "is_deleted":false, 
     "updated_at":"2016-11-21T05:59:52.459Z" 
     } 
    }, 
    "type":"action_performed" 
} 
+0

Можно ли восстановить это из конструктора, а не путем установки полей? – chrylis

+0

Если поле 'saved' ** всегда ** зависит от' channelId', то почему бы не установить поле 'saved' в' setChannelId() '? –

+0

Заказ JSON не гарантируется. Например, в некоторых телефонах я получил правильный порядок поля, в других телефонах порядок отличается. –

ответ

1

Это немного хак, но, сделав класс Message - собственный десериализатор-строитель, вы получаете своего рода «готовый к созданию бобов» - тот, в котором вы имеете ess для всех свойств.

Мое предложение состоит в том, что вы пытаетесь следующее:

@JsonDeserialize(builder = Message.class) 
public class Message { 

    ... 

    @JsonSetter("saved_by") 
    public void setSavedBy(Set<Long> savedBy) { 
     // Merely store the value for later use. 
     this.savedBy = savedBy; 
    } 

    ... 

    public Message build() { 
     // Calculate value of "saved" field. 
     this.saved = this.savedBy.contains(getUserIdByChannelId(this.channelId)); 
     return this; 
    } 

    // Handling the added challenge. 
    @JsonProperty("data") 
    public void setData(JsonNode data) throws JsonProcessingException { 
     ... 
    } 
} 

выше использует в своих установках по умолчанию в JsonPOJOBuilder аннотацию, а именно, что значение по умолчанию для buildMethodName является build.

+0

Я пробовал ваш код, но объект не задавал все поля. Нужно ли устанавливать все поля в метод 'build()'? –

+0

Нет, пока есть сеттеры, они должны использоваться. Вы пытались установить пару контрольных точек, чтобы увидеть, попали ли они? – Henrik

+0

Я только что запустил тесты на песочницу, и они определенно работают. Вы видите ошибки? Разделяйте десериализацию следующим образом: 'Message message = om.readValue (json, Message.class);'? – Henrik

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