Использовать имя classа в качестве корневого ключа для сериализации JSON Jackson

Предположим, у меня есть pojo:

import org.codehaus.jackson.map.*; public class MyPojo { int id; public int getId() { return this.id; } public void setId(int id) { this.id = id; } public static void main(String[] args) throws Exception { MyPojo mp = new MyPojo(); mp.setId(4); ObjectMapper mapper = new ObjectMapper(); mapper.configure(SerializationConfig.Feature.WRAP_ROOT_VALUE, true); System.out.println(mapper.getSerializationConfig().isEnabled(SerializationConfig.Feature.WRAP_ROOT_VALUE)); System.out.println(mapper.writeValueAsString(mp)); } } 

Когда я сериализую использование Jackson ObjectMapper, я просто получаю

 true {"id":4} 

но я хочу

 true {"MyPojo":{"id":4}} 

Я искал всю информацию, документация Jacksons действительно неорганизована и в основном устарела.

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

 package com.test.jackson; import org.codehaus.jackson.map.ObjectMapper; import org.codehaus.jackson.map.SerializationConfig; import com.fasterxml.jackson.annotation.JsonTypeInfo; import com.fasterxml.jackson.annotation.JsonTypeInfo.As; import com.fasterxml.jackson.annotation.JsonTypeInfo.Id; @JsonTypeInfo(include=As.WRAPPER_OBJECT, use=Id.NAME) public class MyPojo { // Remain same as you have } 

вывод:

 { "MyPojo": { "id": 4 } } 

Я не использую jackson, но поиск нашел эту конфигурацию, которая, кажется, вам нужна: WRAP_ROOT_VALUE

Функция, которая может быть включена для создания значения root (обычно JSON Object, но может быть любого типа), завернутого в один объект JSON объекта, где ключ как «корневое имя», как определено интроспектором аннотаций (например, для JAXB, который использует @XmlRootElement .name) или резервное (неclassифицированное имя classа). Функция в основном предназначена для совместимости JAXB.

Значение по умолчанию – false, то есть значение корня не обернуто.

Чтобы вы могли настроить mapper:

 objectMapper.configure(SerializationConfig.Feature.WRAP_ROOT_VALUE, true); 

Надеюсь, это поможет вам …

Ниже приведен способ достижения этой цели.

 Map singletonMap = Collections.singletonMap("mypojo", mp); System.out.println(mapper.writeValueAsString(singletonMap)); 

Вывод {“mypojo”: {“id”: 4}}

Здесь преимущество состоит в том, что мы можем дать нам имя для корневого ключа json-объекта. В приведенном выше коде mypojo будет корневым ключом. Этот подход будет наиболее полезен, если мы используем шаблон скрипта java, например Mustache.js для итерации объектов json

Для этого есть также замечательная аннотация:

 @JsonRootName(value = "my_pojo") public class MyPojo{ ... } 

будет генерировать:

 { "my_pojo" : {...} } 

Для этого вам нужно использовать аннотацию JsonTypeInfo для вашего classа, и в частности WRAPPER_OBJECT

 @JsonTypeName("foo") @JsonTypeInfo(include = JsonTypeInfo.As.WRAPPER_OBJECT ,use = JsonTypeInfo.Id.NAME) public class Bar(){ ) 

Как насчет простейшего возможного решения; просто используйте class оболочки, например:

 class Wrapper { public MyPojo MyPojo; } 

и обертывание / разворачивание в вашем коде?

Помимо этого, это помогло бы узнать, ПОЧЕМУ вы хотели бы добавить дополнительную запись объекта json? Я знаю, что это делается с помощью libs, которые эмулируют json через xml api (из-за импеданса между xml и json, из-за преобразования из xml в json), но для чистых json-решений обычно не требуется.

Это позволяет вам выяснить, что такое фактический тип? Если да, возможно, вы могли бы рассмотреть возможность включения информации о полиморфном типе, чтобы позволить jacksonу обрабатывать ее автоматически? (подробнее см. 1.5 примечания к выпуску , запись для PTH).

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

Переопределить: org.codehaus.jackson.map.ser.BeanSerializerFactory.findBeanProperties(SerializationConfig, BasicBeanDescription)

Добавьте свою собственность, как показано ниже.

 List props = super.findBeanProperties(config, beanDesc); BeanPropertyWriter bpw = null; try { Class cc = beanDesc.getType().getRawClass(); Method m = cc.getMethod("getClass", null); bpw = new BeanPropertyWriter("$className", null, null, m, null,true, null); } catch (SecurityException e) { // TODO } catch (NoSuchMethodException e) { // TODO } props.add(bpw); return props; 

Таким образом, я получаю больше контроля и могу делать другие фильтры.

Мне было бы интересно услышать решение OP для этого. У меня возникают аналогичные проблемы, когда мой веб-сервис RESTful сериализует объекты как XML или JSON для клиентов. Клиентам Javascript необходимо знать тип упаковки, чтобы он мог анализировать его. Совмещение типа с шаблоном URI не является вариантом.

Благодарю.

Изменить: я заметил, что Spring MappingJacksonJsonMarshaller добавляет class упаковки при сортировке, поэтому я прошел через код в отладке и заметил, что Spring проходит в HashMap с одной парой ключ-значение, так что ключ является именем упаковки, а значение – объект. Итак, я расширил JacksonJaxbJsonProvider, переопределив метод writeTo () и добавил следующее:

 HashMap map = new HashMap(); map.put(value.getClass().getSimpleName(), value); super.writeTo(map, type, genericType, annotations, mediaType, httpHeaders,entityStream); 

Это немного взломать, но это работает хорошо.

 @JsonTypeInfo(include=As.WRAPPER_OBJECT, use=Id.NAME) 

Эта аннотация работает отлично, как предложил Арун Пракаш. Я пытался получить json в этой форме.

 {"Rowset":{"ROW":{"receiptno":"881604199388936","status":"SUCCESS"}}} 

но получаю вот так:

 {"ROW":{"receiptno":"881604199388936","status":"SUCCESS"}}} 

Теперь, когда аннотация решила мою проблему.

используйте withRootName.

 objectMapper.writer().withRootName(MyPojo.class.getName()); 

Я нашел на собственном опыте, что хорошая идея для всех JSON включать как бэкэнд-тип (как строку), так и тип компонента, используемый для рендеринга его в интерфейсе (при использовании чего-то вроде углового или Vue).

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

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

  . 

Для бэкэнд-систем и веб-сервисов я предпочитаю использовать один class процессора веб-сервисов, который обеспечивает ведение журнала, аудит и обработку исключений для всех веб-сервисов путем поиска соответствующего classа процессора на основе входящей полезной нагрузки. Это делает реализацию всех моих веб-сервисов одинаковой (около 3 строк кода), и я получаю подробное ведение журнала событий по жизненному циклу вызова без написания какого-либо кода службы для этого.

Имея тип упаковки, JSON делает его самостоятельной документацией. Если все, что вы видите, это свойства, вы не знаете, что ищете, пока не найдете соответствующую конечную точку.

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

  • Как десериализовать JSON с двойными именами свойств в одном и том же объекте
  • Пользовательский серализатор Gson для одной переменной (из многих) в объекте с использованием TypeAdapter
  • Удаление десериализации полиморфных classов json без информации о типе с использованием json.net
  • Рекомендации по сериализации объектов в пользовательский строковый формат для использования в выходном файле
  • JSON.Net выдает StackOverflowException при использовании
  • Как изменить имена свойств при сериализации с помощью Json.net?
  • Информация о сериализации типов кеша Json.NET?
  • Может ли Json.NET сериализовать / десериализовать в / из streamа?
  • Задача не сериализуема: java.io.NotSerializableException при вызове функции закрытие только для classов не объектов
  • Как сериализовать объект в CSV-файл?
  • Сериализация нулевого значения в JSON.NET
  • Давайте будем гением компьютера.