Подтвердить что ты не робот

Использовать имя класса в качестве корневого ключа для сериализации 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 действительно неорганизована и в основном устарела.

4b9b3361

Ответ 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());