Как переименовать корневой ключ в JSON-сериализации с помощью Jackson
Я использую Jackson для сериализации JSON списка объектов.
Вот что я получаю:
{"ArrayList":[{"id":1,"name":"test name"}]}
Но я хочу это:
{"rootname":[{"id":1,"name":"test name"}]} // ie showing the string I want as the root name.
Ниже мой подход к этому:
Интерфейс:
public interface MyInterface {
public long getId();
public String getName();
}
Класс реализации:
@JsonRootName(value = "rootname")
public class MyImpl implements MyInterface {
private final long id;
private String name;
public MyImpl(final long id,final name) {
this.id = id;
this.name = name;
}
// getters
}
Сериализация JSon:
public class MySerializer {
public static String serializeList(final List<MyInterface> lists) {
//check for null value.Throw Exception
final ObjectMapper mapper = new ObjectMapper();
mapper.configure(SerializationConfig.Feature.WRAP_ROOT_VALUE, true);
return mapper.writeValueAsString(lists);
}
}
Тест:
final List<MyInterface> list = new ArrayList<MyImpl>();
MyImpl item = new MyImpl(1L,"test name");
list.add(item);
final String json = MySerializer.serializeList(list);
System.out.println(json);
Вот что я получаю:
{"ArrayList":[{"id":1,"name":"test name"}]}
Но я хочу это:
{"rootname":[{"id":1,"name":"test name"}]} // ie showing the string I want as the root name.
Я пробовал все предлагаемые решения, которые я мог найти, но не смог достичь своей цели. Я посмотрел:
Или я что-то упускаю? Для этого я использую jackson 1.9.12. Любая помощь в этом отношении приветствуется.
Ответы
Ответ 1
Хорошо, по умолчанию Джексон использует одну из двух аннотаций при попытке определить имя корня, которое будет отображаться для обернутых значений - @XmlRootElement
или @JsonRootName
. Он ожидает, что эта аннотация будет иметь тип, который будет сериализован, иначе он будет использовать простое имя этого типа в качестве корневого имени.
В вашем случае вы сериализуете список, поэтому корневое имя является "ArrayList" (простое имя сериализуемого типа). Каждый элемент в списке может быть типа, аннотированного с @JsonRootName, но сам список не.
Когда корневое значение, которое вы пытаетесь обернуть, представляет собой коллекцию, вам необходимо определить способ обертывания:
Класс держателя/обертки
Вы можете создать класс-оболочку для хранения списка с аннотацией для определения желаемого имени свойства (вам нужно использовать этот метод, если у вас нет прямого управления процессом преобразования ObjectMapper
/JSON):
class MyInterfaceList {
@JsonProperty("rootname")
private List<MyInterface> list;
public List<MyInterface> getList() {
return list;
}
public void setList(List<MyInterface> list) {
this.list = list;
}
}
final List<MyInterface> lists = new ArrayList<MyInterface>(4);
lists.add(new MyImpl(1L, "test name"));
MyInterfaceList listHolder = new MyInterfaceList();
listHolder.setList(lists);
final String json = mapper.writeValueAsString(listHolder);
Объект Writer
Это предпочтительный вариант. Используйте сконфигурированный ObjectWriter
экземпляр для создания JSON. В частности, нас интересует метод withRootName
:
final List<MyInterface> lists = new ArrayList<MyInterface>(4);
lists.add(new MyImpl(1L, "test name"));
final ObjectWriter writer = mapper.writer().withRootName("rootName");
final String json = writer.writeValueAsString(lists);
Ответ 2
Я знаю, я опаздываю, но у меня есть лучший подход, который не требует класса Holder/Wrapper. Он выбирает корневой ключ из аннотации.
package com.test;
import com.fasterxml.jackson.annotation.JsonRootName;
@JsonRootName("Products")
public class ProductDTO {
private String name;
private String description;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}
Вот тестовый класс: -
package com.test;
import java.io.IOException;
import java.util.ArrayList;
import org.junit.Test;
import com.fasterxml.jackson.annotation.JsonRootName;
import com.fasterxml.jackson.core.JsonGenerationException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
public class ProductDTOTestCase {
@Test
public void testPersistAndFindById() throws JsonGenerationException, JsonMappingException, IOException {
ObjectMapper mapper = new ObjectMapper();
ProductDTO productDTO = new ProductDTO();
productDTO.setDescription("Product 4 - Test");
ArrayList<ProductDTO> arrayList = new ArrayList<ProductDTO>();
arrayList.add(productDTO);
String rootName = ProductDTO.class.getAnnotation(JsonRootName.class).value();
System.out.println(mapper.writer().withRootName(rootName).writeValueAsString(arrayList));
}
}
Он даст следующий результат
{"Products":[{"name":null,"description":"Product 4 - Test"}]}
Ответ 3
Вам нужно использовать эту аннотацию в верхней части класса
@JsonTypeName("rootname")
Ответ 4
@JsonTypeName("usuarios")
@JsonTypeInfo(include= JsonTypeInfo.As.WRAPPER_OBJECT,use= JsonTypeInfo.Id.NAME)
public class UsuarioDT extends ArrayList<Usuario> {
@JsonProperty("rowsAffected")
private Integer afectados;
public Integer getAfectados() {
return afectados;
}
public void setAfectados(Integer afectados) {
this.afectados = afectados;
}
}