Джексон json deserialization, игнорировать корневой элемент из json
Как игнорировать родительский тег из json?
Вот мой json
String str = "{\"parent\": {\"a\":{\"id\": 10, \"name\":\"Foo\"}}}";
И вот класс, который должен отображаться из json.
public class RootWrapper {
private List<Foo> foos;
public List<Foo> getFoos() {
return foos;
}
@JsonProperty("a")
public void setFoos(List<Foo> foos) {
this.foos = foos;
}
}
Вот тест открытый класс JacksonTest {
@Test
public void wrapRootValue() throws Exception {
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationConfig.Feature.UNWRAP_ROOT_VALUE, true);
mapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
String str = "{\"parent\": {\"a\":{\"id\": 10, \"name\":\"Foo\"}}}";
RootWrapper root = mapper.readValue(str, RootWrapper.class);
Assert.assertNotNull(root);
}
Я получаю ошибку::
org.codehaus.jackson.map.JsonMappingException: Root name 'parent' does not match expected ('RootWrapper') for type [simple type, class MavenProjectGroup.mavenProjectArtifact.RootWrapper]
Я нашел решение, данное аннотацией Джексона::
(a) Annotate you class as below
@JsonRootName(value = "parent")
public class RootWrapper {
(b) It will only work if and only if ObjectMapper is asked to wrap.
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationConfig.Feature.UNWRAP_ROOT_VALUE, true);
Работа выполнена!
Еще одна икота с Джексонским способом десериализации: (
Если "DeserializationConfig.Feature.UNWRAP_ROOT_VALUE настроен", он распаковывает все jsons, хотя мой класс не аннотируется с @JsonRootName (value = "rootTagInJson" ), не привязывается.
Я хочу развернуть корневой тег только в том случае, если класс аннотируется с @JsonRootName в противном случае, не распаковывайте.
Итак, ниже приведена утилита для разворачивания корневого тега.
###########################################################
Unwrap only if the class is annotated with @JsonRootName.
############################################################
Я сделал небольшое изменение в ObjectMapper исходного кода Джексона и создал новую версию jar. 1. Поместите этот метод в ObjectMapper
// Ash:: Wrap json if the class being deserialized, are annotated
// with @JsonRootName else do not wrap.
private boolean hasJsonRootName(JavaType valueType) {
if (valueType.getRawClass() == null)
return false;
Annotation rootAnnotation = valueType.getRawClass().getAnnotation(JsonRootName.class);
return rootAnnotation != null;
}
2. Edit ObjectMapper method ::
Replace
cfg.isEnabled(DeserializationConfig.Feature.UNWRAP_ROOT_VALUE)
with
hasJsonRootName(valueType)
3. Build your jar file and use it.
Ответы
Ответ 1
Пример, взятый из TestRootName.java в https://github.com/FasterXML/jackson-databind, может дать лучший способ сделать это. В частности, используя withRootName (""):
private ObjectMapper rootMapper()
{
ObjectMapper mapper = new ObjectMapper();
mapper.configure(SerializationFeature.WRAP_ROOT_VALUE, true);
mapper.configure(DeserializationFeature.UNWRAP_ROOT_VALUE, true);
return mapper;
}
public void testRootUsingExplicitConfig() throws Exception
{
ObjectMapper mapper = new ObjectMapper();
ObjectWriter writer = mapper.writer().withRootName("wrapper");
String json = writer.writeValueAsString(new Bean());
assertEquals("{\"wrapper\":{\"a\":3}}", json);
ObjectReader reader = mapper.reader(Bean.class).withRootName("wrapper");
Bean bean = reader.readValue(json);
assertNotNull(bean);
// also: verify that we can override SerializationFeature as well:
ObjectMapper wrapping = rootMapper();
json = wrapping.writer().withRootName("something").writeValueAsString(new Bean());
assertEquals("{\"something\":{\"a\":3}}", json);
json = wrapping.writer().withRootName("").writeValueAsString(new Bean());
assertEquals("{\"a\":3}", json);
bean = wrapping.reader(Bean.class).withRootName("").readValue(json);
assertNotNull(bean);
}
Ответ 2
У меня возникла аналогичная проблема, создающая успокоительное приложение в Spring. Я должен был поддерживать очень разнородный API, некоторые из них имели корневые элементы, а другой - нет. Я не мог найти лучшего решения, чем настроить это свойство в реальном времени. Очень жаль, что в Джексоне нет поддержки для развертывания корневого элемента для каждого класса. В любом случае, кто-то может найти это полезным.
@Component
public class ObjectMapper extends com.fasterxml.jackson.databind.ObjectMapper {
private void autoconfigureFeatures(JavaType javaType) {
Annotation rootAnnotation = javaType.getRawClass().getAnnotation(JsonRootName.class);
this.configure(DeserializationFeature.UNWRAP_ROOT_VALUE, rootAnnotation != null);
}
@Override
protected Object _readMapAndClose(JsonParser jsonParser, JavaType javaType) throws IOException, JsonParseException, JsonMappingException {
autoconfigureFeatures(javaType);
return super._readMapAndClose(jsonParser, javaType);
}
}