Использовать имя класса в качестве корневого ключа для сериализации JSON Jackson - PullRequest
27 голосов
/ 12 марта 2010

Предположим, у меня есть 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}}

Я искал по всему, документация Джексонов действительно неорганизована и в основном устарела.

Ответы [ 11 ]

31 голосов
/ 01 июля 2015

Добавив аннотацию Джексона @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
    }
}
25 голосов
/ 12 марта 2010

Я не использую Джексона, но при поиске я обнаружил, что эта конфигурация выглядит так, как вам нужно: WRAP_ROOT_VALUE

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

По умолчанию установлено значение false, что означает root значение не переносится.

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

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

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

12 голосов
/ 10 июня 2013

Ниже приведен способ достижения этого

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

выход {"mypojo": {"id": 4}}

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

4 голосов
/ 01 февраля 2018

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

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

public class Bar(){
)
3 голосов
/ 17 апреля 2016

Есть также хорошая аннотация для этого:

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

сгенерирует:

{
  "my_pojo" : {...}
}
1 голос
/ 19 марта 2012

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

Переопределение: 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;

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

1 голос
/ 22 марта 2010

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

class Wrapper {
   public MyPojo MyPojo;
}

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

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

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

0 голосов
/ 14 августа 2018

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

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

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

  <component :is="child.componentType"/>.

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

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

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

0 голосов
/ 14 июля 2017

использовать с RootName.

objectMapper.writer().withRootName(MyPojo.class.getName());
0 голосов
/ 16 июня 2016
@JsonTypeInfo(include=As.WRAPPER_OBJECT, use=Id.NAME) 

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

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

но получается вот так:

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

Теперь эта аннотация решила мою проблему.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...