Объект Umarshall JSON с полями подчеркивания и camelCase между Jackson и JAXB

Используя JAXB (2.2) и Jackson (1.9.13), у меня есть проблема с unmarshalling следующего объекта JSON для моих POJO

{
   "userId": "foo",
   "group_id": "bar"
}

Обратите внимание, что полезная нагрузка содержит как поле camelCase, так и подчеркивание.

POJO, созданный xjc для моей XML-схемы, выглядит следующим образом:

public class User {
    @XmlElement(required = true)
    protected String userId;
    @XmlElement(name = "group_id", required = true)
    protected String groupId;

    public String getUserId() { return userId; }       
    public void setUserId(String value) { this.userId = value; }
    public String getGroupId() { return groupId; }
    public void setGroupId(String value) { this.groupId = value; }
}

Джексон терпит неудачу со следующим исключением:

org.codehaus.jackson.map.exc.UnrecognizedPropertyException: Unrecognized field "group_id"

То, что я пробовал до сих пор и не удалось

1. Использовать привязку JAXB underscoreBinding="asCharInWord"

Использование следующей привязки JXB в моей XML-схеме

<jxb:globalBindings underscoreBinding="asCharInWord"/>

генерирует следующее POJO:

public class User {
    @XmlElement(required = true)
    protected String userId;
    @XmlElement(name = "group_id", required = true)
    protected String groupId;

    public String getUserId() { return userId; }
    public void setUserId(String value) { this.userId = value; }
    public String getGroup_Id() { return groupId; }
    public void setGroup_Id(String value) { this.groupId = value; }
}

Обратите внимание, что JAXB теперь генерирует сеттеры/геттеры с подчеркиванием для идентификаторов групп, но поле group_id все еще преобразуется в CamelCase. Объект Mapper объекта Jackson, похоже, игнорирует имена свойств getter/setter и не может отображать group_id в groupId.

2. Стратегия именования собственности Джексона

Использование Jackson PropertyNamingStrategy CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES Я могу преобразовать group_id в groupId, но теперь объект mapper не работает на userId Свойство JSON.

3. Добавьте аннотацию JSONProperty в группуId

Добавление JSONProperty в ванильную JAXB сгенерированную POJO фактически работает

public class User {
        /* ... */
        @XmlElement(name = "group_id", required = true)
        @JSONProperty("group_id")
        protected String groupId;
        /* ... */
   }

Однако моя XML-схема огромна, и ручная аппаратура сгенерированных классов не представляется возможной, поскольку мы часто генерируем наши классы.

Что мне делать?

Я вижу следующие две оставшиеся опции для решения этой проблемы:

  • Внедрение плагина JAXB, который добавляет аннотацию JSONProperty к каждому XMLElement с именами подчеркивания (мой предпочтительный следующий подход)
  • Используйте генератор настраиваемых имен для XJC, как описано в этом. Ответ на Stackoverflow.

Я пропустил очевидное? спасибо за ваши мысли.

Ответы

Ответ 1

Вы пробовали аннотировать атрибут groupId в своем пользовательском классе с помощью @JsonProperty("group_id"). Это должно работать (проверено и проверено)!

Если в атрибуте нет такой аннотации, то картограф Jackson просто рассмотрит имя атрибута как есть, иначе предоставленное значение будет использоваться для десериализации JSON. Вот как выглядит ваш класс User:

public class User {

private String userId;

@JsonProperty("group_id")
private String groupId;

Это должно отображаться на вашем JSON

{"userId": "foo","group_id": "bar"}

Если вы используете CXF (или любую другую структуру Rest) на основе Jackson, я предлагаю прочитать следующую короткую запись в блоге, в которой подробно описывается настройка JacksonJsonProvider в CXF для достижения сериализации и де-сериализации с/на Java с/к форматированным данным JSON Snake Case (подчеркивание)

https://mahichir.wordpress.com/2015/07/08/cxf-configuration-to-produce-json-snake-case-underscore-case-formatted-data-using-jackson-json-library/

Ответ 2

Я нашел возможное решение вашей проблемы из аналогичного случая в stackoverflow. Как извлечь ObjectMapper из клиента JAX-RS?

Как только у вас есть доступ к Object Mapper, вы можете установить собственный поставщик аннотаций. Тот, который теперь удален как отдельный модуль, так как jackson 2.0 является модулем jaxb.

Вот ответ, хотя я его модифицировал так, чтобы он соответствовал модулю Jackson Jaxb 2.4.4 и Jackson API 2.3.2:

public final static JacksonJsonProvider JACKSON_JSON_PROVIDER = new JacksonJaxbJsonProvider().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false).configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
public final static ObjectMapper OBJECT_MAPPER = JACKSON_JSON_PROVIDER.locateMapper(Object.class, MediaType.APPLICATION_JSON_TYPE);
public final static Client CLIENT = ClientBuilder.newClient().register(JACKSON_JSON_PROVIDER);

Для этого требуется jar: jackson-module-jaxb-annotations-2.x.x.jar, поэтому Джексон может загрузить его за сцену через интерфейс JacksonJaxbProvider.

Для вашей версии Jackson я думаю, что код jaxb все еще в нем. Таким образом, вы можете ссылаться на аналогичный способ, используя http://wiki.fasterxml.com/JacksonJAXBAnnotations