2014-11-16 4 views
5

Я просмотрел много вопросов, связанных с этим, но я не могу найти этот конкретный прецедент. Успение здесь заключается в том, что я использую библиотеку Java Jackson.Специальная десериализация Джексона для полиморфных объектов

у меня есть следующие иерархии классов:

public class Event { 
    @JsonProperty("si") 
    String sessionId; 

    @JsonProperty("eventType") 
    String eventType; 
... 
} 

@JsonSerialize(include= JsonSerialize.Inclusion.NON_NULL) 
public class InitEvent extends Event 
{ 

    @JsonProperty("pm") 
    Params params; 

    public Params getParams() 
    { 
      return params; 
    } 

    ..... 
} 

@JsonSerialize(include= JsonSerialize.Inclusion.NON_NULL) 
public class RecoEvent extends Event 
{ 

    @JsonProperty("ti") 
    String targetId; 

    @JsonProperty("tt") 
    int targetType; 


    public String getTargetId() 
    { 
      return targetId; 
    } 

    .... 
} 

Правило десериализации является:

  • Если типСобытия == 0, то десериализации к InitEvent

  • Если типСобытия == 0 затем десериализовать в RecoEvent

Из разряда десериализация Джексона не будет работать, потому что он не знает, к какому классу десериализуем. Один из способов справиться с этим, делая как следует на базовый классе:

@JsonTypeInfo(use=JsonTypeInfo.Id.CLASS, include=JsonTypeInfo.As.PROPERTY, property="@class") 
@JsonSerialize(include= JsonSerialize.Inclusion.NON_NULL) 
public class Event 

Проблема этого решения заключается в предполагающем клиент будет сериализовать с тем же картографом, так как элемент @class должен присутствовать в настоящее время в формате JSON ,

Мой клиент не отправит дополнительный элемент @class во входящий JSON.

Какое необходимо разрешение?

Как я могу написать собственный десериализатор, который выбирает правильный производный класс на основе значения eventType?

Thx заранее

+0

Я нашел [этот образец] (https://github.com/fge/json-patch/blob/master/src/main/java/com/github/fge/jsonpatch/JsonPatchOperation.java) с открытым исходным кодом проект. Атрибут «op» настроен для использования в качестве подсказки типа для создания подтипа. Может быть, это помогает? С уважением, Marius –

ответ

2

В конце концов, я должен был написать свои собственные десериализации.

Это работает в 2 этапа, сначала реализует пользовательский десериализатор, а затем регистрирует его.

Реализация работает следующим образом:

public class EvtListDeserializer extends JsonDeserializer<EventList> 
{ 
    private static ObjectMapper mapper = new ObjectMapper(); 

    @Override 
    public EventList deserialize(JsonParser jsonParser, DeserializationContext context) throws IOException, JsonProcessingException 
    { 
     EventList eventList = new EventList(); 
     List<Event> listOfEvents = new ArrayList<Event>(); 
     ObjectCodec oc = jsonParser.getCodec(); 
     JsonNode eventListNode = oc.readTree(jsonParser); 
     ArrayNode node = (ArrayNode) eventListNode.get("evt"); 
     Iterator<JsonNode> events = node.elements(); 
     for (; events.hasNext();) 
     { 
      JsonNode eventNode = events.next(); 
      int eventType = eventNode.get("type").asInt(); 

      Event event; 
      if (eventType == EventTypes.MoveEvent.getValue()) 
      { 
       event = mapper.readValue(eventNode.toString(), MoveEvent.class); 
      } 
      else if (eventType == EventTypes.CopyEvent.getValue()) 
      { 
       event = mapper.readValue(eventNode.toString(), CopyEvent.class); 
      } 
      else 
      { 
       throw new InvalidEventTypeException("Invalid event type:" + eventType); 
      } 

      listOfEvents.add(event); 
     } 

     eventList.setEvents(listOfEvents); 

     return eventList; 
    } 
} 

Тогда вы просто зарегистрировать его как следует в классе, который использует ваш картографа:

public void init() 
{ 
    SimpleModule usageModule = new SimpleModule().addDeserializer(EventList.class, new EvtListDeserializer()); 
    mapper.registerModule(usageModule); 
} 

Это прекрасно работает.

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