Объект 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