2015-07-26 6 views
0

У меня есть JSON, как следующее:Джексон Stateful Десериализация

{ 
    systemId: 7 
    name: "Phil" 
    data: "XYZ" 

    pointers: [ 
     { 
      systemId: 23 
      name: "Peter" 
     }, 
     { 
      systemId: 27 
      name: "Jeroen" 
     } 
    ] 
} 

В POJO эквивалент выше JSON, все поля являются окончательными. Теперь, во время десериализации, я хочу иметь возможность модифицировать поле systemId, прежде чем он будет установлен на POJO by Jackson. Кроме того, измененная системаId будет фактически предоставляться объектом с сохранением состояния как функцией текущей системы Id из JSON. Например, новый SYSTEMID быть установлен на десериализованном POJO может быть предоставлен экземпляром класса, например следующим образом:

public class SystemIdProvider { 
    ... 
    public long getNewSystemId(long oldSystemId) { 
     // do something with the oldSystemId and 
     // the current state of this object to get the newSystemId 
     return newSystemId; 
    } 
} 

Есть ли способ, я могу предоставить экземпляр указанного класса Джексону, когда он десериализует JSON и заставляет Джексона использовать этот объект, чтобы получить newSystemId, прежде чем устанавливать его на POJO, который он создает?

Обратите внимание, что JSON выше - это всего лишь небольшой фрагмент фактического JSON и, следовательно, может содержать сотни таких объектов, как указано выше. И я хочу предоставить НОВЫЙ экземпляр класса SystemIdProvider для десериализации, поскольку «состояние», которое он поддерживает, также основано на идентификаторах системы, с которыми он столкнулся до сих пор. Таким образом, для каждой десериализации она должна начинаться с чистого состояния.

Любые входы оцениваются.

+0

Я думаю, что вам нужно, чтобы исследовать некоторые из упомянутых здесь родственной, но не та же проблема - варианты http://stackoverflow.com/questions/7105745/how-to-specify-jackson- только для пользы-полей-желательно-глобально –

+0

спасибо Wand Maker. Я уже знаю эти параметры конфигурации. – Skylark

ответ

1

Для этого вам нужно написать специальный десериализатор. Давайте предположим, что у вас есть следующий POJO:

public class MyPojo { 

    private final long systemId; 
    private final String foo; 

    public MyPojo(long systemId, String foo) { 
     this.systemId = systemId; 
     this.foo = foo; 
    } 

    // getters and other methods 
} 

Написать собственный десериализатор для systemId поля:

public class SystemIdDeserializer extends StdDeserializer<Long> { 

    public SystemIdDeserializer() { 
     super(Long.class); 
    } 

    @Override 
    public Long deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { 
     SystemIdProvider systemIdProvider = (SystemIdProvider) ctxt.getAttribute("systemIdProvider"); 
     Long oldSystemId = _parseLong(jp, ctxt); 
     return systemIdProvider.getNewSystemId(oldSystemId); 
    } 
} 

Используйте @JsonDeserialize аннотацию на systemId поля для регистрации десериализатора:

@JsonDeserialize(using = SystemIdDeserializer.class) 
private final long systemId; 

Чтобы сделать SystemIdProvider доступным в DeserializationContext, позвоните в Jackson's mapper lik е это:

ObjectMapper mapper = new ObjectMapper(); 
MyPojo deserialized = mapper.reader(MyPojo.class) 
     .withAttribute("systemIdProvider", new SystemIdProvider()) 
     .readValue(json); 
+0

Большое спасибо за ответ и примеры кода. Мне нужен новый экземпляр SystemIdProvider каждый раз, когда я десериализую JSON, потому что он строит свое состояние, используя systemIds, с которым он столкнулся до сих пор в JSON. Это не синглтон. Возникает моя проблема. Мне интересно, могу ли я как-то «ввести» его в DeserializationContext. – Skylark

+0

Другое дело, я хочу использовать пользовательскую десериализацию только для одного поля, а именно systemId, а не для всего класса. – Skylark

+0

См. Мой обновленный ответ. – hzpz

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