Полиморфна десериализация на Jackson (където класът зависи от JSON ключа)

TL;DR

основно проблемът ми е, че имам списък с обекти-обвивки

{"stuff": [
  {"foobar" : {someObjectOfTypeA}},
  {"barfoo" : {someObjectOfTypeB}},
  {"foobar" : {someObjectOfTypeA}}
]}

и типът на someObjectOfTypeX зависи от стойността на ключа "foobar" или "barfoo". как мога да десериализирам това? (за сега) сериализирането не е проблем.


дълга версия

Не познавам достатъчно Джаксън, за да реша следния проблем. пробвах, но закъсах.

json структурата, която искам да анализирам, изглежда така:

{
  "id": "foobar",
  "responses": [
    {
      "responseType1": {
        "code": 0,
        "foo": "bar"
      }
    },
    {
      "responseType2": {
        "code": 1,
        "bar": {"foo": ...}
      }
    },
    {
      "responseType1": {
        "code": 1,
        "foo": "foobar"
      }
    }
  ]
}

Опитах се да го десериализирам с помощта на пълно обвързване на данни на Jacksons. похосите ми са:

// pseudocode

// the outermost object
@JsonCreator
ServiceResponse(
  @JsonProperty("id") String id, 
  @JsonProperty("responses") ArrayList<ResponseWrapper> responses)

// every response has a wrapper. the wrapper is an object with just one key and one value. the value is an object of a certain class (ResponseTypeX extends AResponse), and the exact ResponseType is identified by the key (the key isn't the class name though). 
@JsonCreator
ResponseWrapper(AResponse keyDependsOnTypeOfAResponse ???)

// base class for all responseTypeX classes
// all subclasses of AResponse have a code and a complex payload object
@JsonCreator
AResponse (
  @JsonProperty("code") int code)

// one response type
// here, the payload is just a string, in reality it's a deep structure, so i dont want to parse this manually
@JsonCreator
ResponseType1 extends AResponse (
  @JsonProperty("code") int code,
  @JsonProperty("foo") String foo)

// one response type
@JsonCreator
ResponseType2 extends AResponse (
  @JsonProperty("code") int code,
  @JsonProperty("bar") SomeOtherObject foo)

както можете да видите, responses е масив от обвиващи обекти; класът "полезен товар" на обекта на обвивката се идентифицира от ключа (но ключовете не са съвпадение 1:1 с имената на класовете). моите ResponseTypeX са ограничени, има около 20 от тях, така че ако трябва да направя ръчна идентификация на тип ключ:стойност, ще се радвам.

но възможно ли е да напишете ръчен десериализатор за обекта WrapperResponse и да продължите да десериализирате неговите деца с пълно обвързване на данни? ако да как?


Опитах се просто да накарам Wrapper да приеме всички възможни ResponseTypes като свойства, надявайки се, че просто ще анулира "незададените", напр.

@JsonCreator
ResponseWrapper(
  @JsonProperty("responseKey1") ResponseType1 response1,
  @JsonProperty("responseKey2") ResponseType2 response2,
  @JsonProperty("responseKey3") ResponseType3 response3,
  ...)

но това не успя, вероятно защото всички ResponseTypes са подкласове на AResponse и по този начин Джаксън се обърква.


person stefs    schedule 05.12.2012    source източник


Отговори (1)


Необходима е известна персонализирана обработка на десериализация. Бих препоръчал да включите прост регистър (карта) на записи за foobar/barfoo-to-type в решението, подобно на шестия пример в старата ми публикация в блога от 25 май 2011 г., „Десериализиране на JSON с Jackson в полиморфни типове – пълен пример“.

person Programmer Bruce    schedule 08.12.2012
comment
Благодаря ти много! Вече прочетох някои от вашите статии по темата, но изглежда съм пропуснал тази. - person stefs; 10.12.2012