Используйте @JacksonInject с @JsonCreator на карте верхнего уровня - PullRequest
6 голосов
/ 01 декабря 2011

С помощью библиотеки Джексона json можно десериализовать объект с помощью @JsonCreator и получить карту «верхнего уровня», представляющую входной json, следующим образом:

class MyClass {
    final int field;

    @JsonCreator
    public MyClass(Map<String, Object> map) {
        this.field = (int) map.get("theInt");
    }
}

илидаже при статическом заводском методе:

class MyClass {
    final int field;

    public MyClass(int theInt) {
        this.field = theInt;
    }

    @JsonCreator
    static MyClass create(Map<String, Object> map) {
        return new MyClass((int) map.get("theInt"));
    }
}

В предыдущих примерах может обрабатываться следующий тип ввода json:

{
    "key1":"value1",
    "key2":"value2",
    "key3":"value3"
}

Это особенно полезно в моем случае, потому что я хотел бы десериализоватьJSON, структура которого я не знаю.Получение доступа к тому, что я называю «картой верхнего уровня», упрощает процесс.

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

Затем, чтобы пойти дальше, я хотел бы добавить некоторую конфигурацию в мойфабричный метод, и Джексон позволяет это с помощью @JacksonInject и вызова withInjectableValues(InjectableValues) на ObjectMapper.

. В конечном итоге я хотел бы использовать такой код:

class MyClass {
    final MyField[] myFields;

    public MyClass(MyField... myFields) {
        this.myFields = myFields;
    }

    @JsonCreator
    static MyClass create(@JacksonInject("conf") Conf conf, Map<String, Object> map) {
        MyFields[] myFields;
        // initialize myFields (or any other object) based on the content of map
        // and also make use of the inject conf
        return new MyClass(myFields);
    }
}

К сожалению, Джексон выбрасывает следующие исключения:

  • при попытке обмануть конструктор

JsonMappingException: Argument #1 of constructor [constructor for MyClass, annotations: {JsonCreator=@JsonCreator()}] has no property name annotation; must have name when multiple-paramater constructor annotated as Creator

  • при попытке использовать трюк на заводском методе

JsonMappingException: Argument #1 of factory method [method create, annotations: {JsonCreator=@JsonCreator()}] has no property name annotation; must have when multiple-paramater static method annotated as Creator

Кто-нибудь знает, как я могу решить эту проблему?

Чтобы подвести итог требований,Мне нужно:

  • доступ к карте верхнего уровня (сделатьзаранее не знаю имен свойств json)
  • для создания неизменяемого объекта (поэтому нельзя использовать @JsonAnySetter)
  • для добавления некоторого conf в украшенный конструктор @JsonCreator илифабричный метод

Я не могу изменить формат ввода json, который выглядит следующим образом:

{
    "key1":"value1",
    "key2":"value2",
    "key3":"value3"
}

[EDIT]

Это известная проблема: http://jira.codehaus.org/browse/JACKSON-711 (еще не исправлено)

1 Ответ

4 голосов
/ 01 декабря 2011

Правильно, вы хотели бы использовать как «делегирующий» создатель (один аргумент, в который вводится вход JSON) - в отличие от «основанного на свойствах» создателя, где передается набор именованных параметров - и значение для инъекции с). В идеале это должно работать, но я думаю, что это может не сработать в настоящее время. Я думаю, что для этого введена Jira, так что вы можете проверить это (http://jira.codehaus.org/browse/JACKSON) out.

Просто чтобы убедиться: вы используете версию 1.9.2? В этом были некоторые исправления, начиная с 1.9.0; что, по крайней мере, даст лучшее сообщение об ошибке.

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