Использовать имя класса в качестве корневого ключа для сериализации 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 действительно неорганизована и в основном устарела.
Ответы
Ответ 1
Я не использую jackson, но поиск нашел эту конфигурацию, которая, кажется, вам нужна: WRAP_ROOT_VALUE
Функция, которая может быть включена для создания значения root (обычно JSON Object, но может быть любого типа), завернутого в один объект JSON объекта, где ключ как "корневое имя", как определено интроспектором аннотации (например, для JAXB, который использует @XmlRootElement.name) или резервное (неквалифицированное имя класса). Функция в основном предназначена для совместимости с JAXB.
Значение по умолчанию - false, то есть root значение не обернуто.
Чтобы вы могли настроить mapper:
objectMapper.configure(SerializationConfig.Feature.WRAP_ROOT_VALUE, true);
Надеюсь, это поможет вам...
Ответ 2
Добавив аннотацию jackson @JsonTypeInfo
на уровне класса, вы можете получить ожидаемый результат. я просто добавил никаких изменений в свой класс.
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
}
}
Ответ 3
Ниже приведен способ достижения этого
Map<String, MyPojo> singletonMap = Collections.singletonMap("mypojo", mp);
System.out.println(mapper.writeValueAsString(singletonMap));
Выход
{ "mypojo": { "id": 4}}
Здесь преимущество заключается в том, что мы можем дать наше имя для корневого ключа json-объекта. В приведенном выше коде mypojo будет корневым ключом. Этот подход будет наиболее полезен, если мы используем шаблон java script, такой как Mustache.js для итерации объектов json
Ответ 4
Для этого есть также хорошая аннотация:
@JsonRootName(value = "my_pojo")
public class MyPojo{
...
}
будет генерировать:
{
"my_pojo" : {...}
}
Ответ 5
Как насчет простейшего возможного решения; просто используйте класс оболочки, например:
class Wrapper {
public MyPojo MyPojo;
}
и обертывание/разворачивание в вашем коде?
Помимо этого, это помогло бы узнать, ПОЧЕМУ вы хотели бы добавить дополнительную запись объекта json? Я знаю, что это делается с помощью libs, которые эмулируют json через xml api (из-за импеданса между xml и json из-за преобразования из xml в json), но для чистых json-решений обычно не требуется.
Позволяет ли вы выяснить, что такое фактический тип?
Если да, возможно, вы могли бы рассмотреть возможность включения информации о полиморфном типе, чтобы позволить Джексону обрабатывать ее автоматически? (подробнее см. 1.5 примечания к выпуску, запись для PTH).
Ответ 6
есть другой способ, который я использовал, и это сработало для меня.
Я работаю с сторонним банком, поэтому я не могу контролировать аннотации.
Так что я должен был написать немного взлома.
Переопределение: org.codehaus.jackson.map.ser.BeanSerializerFactory.findBeanProperties(SerializationConfig, BasicBeanDescription)
Добавьте свою собственность, как показано ниже
List<BeanPropertyWriter> 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;
Таким образом, я получаю больше контроля и также могу делать другие фильтры.
Ответ 7
Мне было бы интересно услышать решение OP для этого. У меня возникают аналогичные проблемы, когда мой веб-сервис RESTful сериализует объекты как XML или JSON для клиентов. Клиентам Javascript необходимо знать тип упаковки, чтобы он мог анализировать его. Связывание типа с шаблоном URI не является вариантом.
Спасибо.
Изменить: я заметил, что Spring MappingJacksonJsonMarshaller добавляет класс упаковки при сортировке, поэтому я прошел через код в отладке и заметил, что Spring проходит в HashMap с одной парой ключ-значение, так что ключ является имя упаковки и значение - это объект. Итак, я расширил JacksonJaxbJsonProvider, переопределив метод writeTo() и добавил следующее:
HashMap<String, Object> map = new HashMap<String, Object>();
map.put(value.getClass().getSimpleName(), value);
super.writeTo(map, type, genericType, annotations, mediaType, httpHeaders,entityStream);
Это немного взломать, но он прекрасно работает.
Ответ 8
@JsonTypeInfo(include=As.WRAPPER_OBJECT, use=Id.NAME)
Эта аннотация работает отлично, как предложил Арун Пракаш. Я пытался получить json в этой форме.
{"Rowset":{"ROW":{"receiptno":"881604199388936","status":"SUCCESS"}}}
но получится так:
{"ROW":{"receiptno":"881604199388936","status":"SUCCESS"}}}
Теперь, когда аннотация решила мою проблему.
Ответ 9
использовать с именем RootName.
objectMapper.writer().withRootName(MyPojo.class.getName());