Возможно ли иметь пользовательский десериализатор Джексона с конструктором не по умолчанию? - PullRequest
3 голосов
/ 16 октября 2011

Допустим, у меня есть следующие классы:

public class Person {

    String name;
    Set<Department> departments;

}

public class Department {

    String code;
    String name;

}

Итак, я хочу написать собственный десериализатор Отдела, чтобы аннотировать поле deparments в классе Person для его использования. Поскольку этот пользовательский десериализатор будет использоваться только для десериализации объектов Department, находящихся внутри объекта Person. Проблема заключается в том, что мой пользовательский десериализатор Department должен иметь DepartmentRepository, который необходимо передать в конструктор десериализатора. Как я могу это сделать? Это возможно? Я не хочу регистрировать десериализатор в сопоставителе объектов, потому что он должен использоваться только тогда, когда десериализованное поле из класса Person десериализовано.

ОБНОВЛЕНИЕ: Что мне нужно, кроме аннотирования поля отделов аннотацией JsonDeserialize с параметром contentUsing = MyCustomDepartmentDeserializer.class, это способ сообщить Джексону, что при создании объекта MyCustomDepartmentDeserializer он должен сделать это, вызвав конструктор, который получает DepartmentRepository. Десериализатор может быть примерно таким:

public class MyCustomDepartmentDeserializer extends JsonDeserializer<Department> {

    private final DepartmentRepository departmentRepository;

    public MyCustomDepartmentDeserializer(DepartmentRepository departmentRepository) {
        this.departmentRepository = departmentRepository;
    }

    @Override
    public Department deserialize(JsonParser jp, DeserializationContext ctxt)
    throws IOException, JsonProcessingException {
        //IMPLEMENTATION!
    }

}

Ответы [ 5 ]

1 голос
/ 30 сентября 2014

Вы можете добавить пользовательский сериализатор / десериализатор с конструктором не по умолчанию, зарегистрировав его как модуль с вами ObjectMapper.

SimpleModule simpleModule = new SimpleModule();
JsonDeserializer<MyObject> customDeserializer = new CustomDeserializer("Blah");
testModule.addDeserializer(MyObject.class, customDeserializer);
mapper.registerModule(simpleModule);

Вы также должны удалить аннотацию в классе MyObjectесли это там.

1 голос
/ 17 октября 2011

Перво-наперво: указать десериализатор для использования с содержимым массива, который вы можете использовать

@JsonDeserialize(contentUsing=MyDeserializer.class)
Set<Department> departments;

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

Что касается возможности использования конструкторов не по умолчанию, @JsonCreator позволяет это. Но чтобы передать объект контекста, вам может понадобиться Jackson 1.9, который может быть вашим другом (см. « обзор Jackson 1.9 »), который позволяет «внедрять» объекты за пределы JSON. Затем вы можете смешивать и сопоставлять вводимые значения и свойства JSON, например:

public class POJO {
  @JsonCreator // can also be used for static factory methods
  public POJO(@JacksonInject DepartmentRepository repo, @JsonProperty("value") int value) {
      ....
  }
}

Этого может быть достаточно, чтобы сделать то, что вы просите.

0 голосов
/ 13 декабря 2018

Нет, в самом начале можно обойтись без указания собственного десериализатора; Джексон может обнаружить ваше вложенное поле и правильно отобразить их, только тогда, когда все классы модели реализуют Serializable.

Итак, добавьте implements Serializable к Department и Person, и вы увидите, что Джексон работает из коробки.

0 голосов
/ 16 октября 2011

Вот десериализатор, который я только что написал. Обратите внимание на использование конструктора не по умолчанию.

public class SparseStringArrayVectorDeserializer extends JsonDeserializer<SparseStringArrayVector> {

@Override
public SparseStringArrayVector deserialize(JsonParser jp, DeserializationContext ctxt)
    throws IOException, JsonProcessingException {

    /* This isn't the most efficient way to do this, since we're building a tree of nodes that we will discard.
     * However, we need to change the order around, so something like this is hard to avoid.
     */
    JsonNode tree = jp.readValueAsTree();
    int tokenCount = tree.size();
    int[] indexes = new int[tokenCount];
    String[][] strings = new String[tokenCount][];
    Iterator<Entry<String, JsonNode>> fieldNameIt = tree.getFields();
    int slot = 0;
    while (fieldNameIt.hasNext()) {
        Entry<String, JsonNode> entry = fieldNameIt.next();
        int index = Integer.parseInt(entry.getKey());
        indexes[slot] = index;
        String[] thisTokenStrings = new String[entry.getValue().size()];
        for (int x = 0; x < thisTokenStrings.length; x++) {
            thisTokenStrings[x] = entry.getValue().get(x).getTextValue();
        }
        strings[slot] = thisTokenStrings;
        slot++;
    }
    return new SparseStringArrayVector(indexes, strings);
}
}

Используется со следующим. Обратите внимание, что при создании десериализатора и добавлении его в модуль можно использовать любой шаблон конструктора.

 ObjectMapper mapper = new ObjectMapper();
    SimpleModule module = new SimpleModule("ResultAccess", new Version(7, 4, 0, null));
    module.addDeserializer(SparseStringArrayVector.class, new SparseStringArrayVectorDeserializer());
    module.addDeserializer(AbstractResultAccess.class, new ProxyAbstractResultAccessDeserializer());
    mapper.registerModule(module);
0 голосов
/ 16 октября 2011

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...