Джексон и Итерибл: как десериализовать - PullRequest
0 голосов
/ 20 ноября 2018

У меня есть класс Box, который имеет поле elements, которое имеет тип Elements, который реализует Iterable (см. Код ниже).Последний содержит List, который также называется elements

Если я установлю поле elements из Elements равным private, то сериализация будет рассматривать его как массив, а не какPOJO

Сериализация выполнена версией A

{
  "elements" : [ "a", "b", "c" ]
}

Однако я не смог десериализовать эту строку.Ошибка была:

com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `ser_deser_test.Elements` out of START_ARRAY token
 at [Source: (String)"{
  "elements" : [ "a", "b", "c" ]
}"; line: 2, column: 16] (through reference chain: 

Если я вместо этого установлю elements равным public, тогда elements из Box будет рассматриваться как POJO, и у меня было два смешных уровняelements в нем.Однако десериализация в этом случае сработала.

Сериализация по версии B

{
  "elements" : {
    "elements" : [ "a", "b", "c" ]
  }
}

Мой вопрос: как заставить десериализацию работать для Версии A?

код

Box.java

package ser_deser_test;

public class Box {
    public Box() {
        super();
    }

    public Elements elements;

    public Box(Elements elements) {
        super();
        this.elements = elements;
    }

}

Elements.java

package ser_deser_test;

import java.util.Iterator;
import java.util.List;

import com.fasterxml.jackson.annotation.JsonFormat;

public class Elements implements Iterable<String> {
    // private List<String> elements; // Version A
    // public List<String> elements;  // Version B

    public Elements() {
        super();
    }

    public Elements(List<String> elements) {
        super();
        this.elements = elements;
    }

    @Override
    public Iterator<String> iterator() {
        return elements.iterator();
    }

}

TestSerDeser.java

package ser_deser_test;

import java.io.IOException;
import java.util.Arrays;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;

public class TestSerDeser {

    public static void main(String[] args) {
        Elements elements = new Elements(Arrays.asList("a", "b", "c"));
        Box      box = new Box(elements);

        ObjectMapper om = new ObjectMapper();

        om.enable(SerializationFeature.INDENT_OUTPUT);
        try {
            // Serialize
            String s = om.writeValueAsString(box);

            // Deserialize
            Box box2 = om.readValue(s, Box.class);

            boolean dummy = false;

        } catch (JsonProcessingException e2) {
            e2.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }         
    }
}

Ответы [ 2 ]

0 голосов
/ 20 ноября 2018

Ваш код отлично работает с:

package ser_deser_test;

import java.util.Iterator;
import java.util.List;

import com.fasterxml.jackson.annotation.JsonFormat;

public class Elements implements Iterable<String> {
    // private List<String> elements; // Version A
    public List<String> elements;  // Version B

    public Elements() {
        super();
    }

    public Elements(List<String> elements) {
        super();
        this.elements = elements;
    }

    @Override
    public Iterator<String> iterator() {
        return elements.iterator();
    }

}

и завершается неудачно с Version A, поскольку по умолчанию Джексон не имеет доступа к закрытым полям.Чтобы заставить его работать с Version A, измените класс TestSerDeser следующим образом:

ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);

, чтобы разрешить Джексону доступ к закрытому полю List<String> elements или, что еще лучше, добавьте для этого поля общедоступный метод получения.

0 голосов
/ 20 ноября 2018

Почему бы не использовать простое свойство List<String>?

public class Elements {

   public List<String> elements;

Или как комментарий @EugenCovaci, если вам не нужен конкретный объект

 public class Box {
   public List<String> elements; //directly into Box class

Для сохранения private List<String> elements; простодобавить геттер для использования в качестве свойства:

public List<String> getElements() {
   return elements;
}

Также вы можете добавить @ JsonProperty

  @JsonProperty
  private List<String> elements;
...