Джексон JSON десериализации, игнорировать корневой элемент из JSON - PullRequest
37 голосов
/ 12 января 2012

Как игнорировать родительский тег из 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.

Ответы [ 3 ]

32 голосов
/ 26 июля 2012

Пример, взятый из 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);
}
13 голосов
/ 29 декабря 2014

У меня возникла похожая проблема при разработке успокоительного приложения в 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);
    }

}
0 голосов
/ 18 июня 2018

В качестве обновления поста Seagabond, если вы хотите иметь тот же эффект при записи значений параметров, вы можете переопределить дополнительные методы записи.

@Component
public class ObjectMapper extends com.fasterxml.jackson.databind.ObjectMapper {
    private void autoconfigureFeatures(Object value) {
        JavaType javaType = _typeFactory.constructType(value.getClass());
        autoconfigureFeatures(javaType);
    }
    private void autoconfigureFeatures(JavaType javaType) {
        Annotation rootAnnotation = javaType.getRawClass().getAnnotation(JsonRootName.class);
        this.configure(DeserializationFeature.UNWRAP_ROOT_VALUE, rootAnnotation != null);
    }

    @Override
    public void writeValue(DataOutput out, Object value) throws IOException {
        autoconfigureFeatures(value);
        super.writeValue(out, value);
    }

    @Override
    public void writeValue(Writer w, Object value) throws IOException, JsonGenerationException, JsonMappingException {
        autoconfigureFeatures(value);
        super.writeValue(w, value);
    }

    @Override
    public byte[] writeValueAsBytes(Object value) throws JsonProcessingException {
        autoconfigureFeatures(value);
        return super.writeValueAsBytes(value);
    }

    @Override
    public String writeValueAsString(Object value) throws JsonProcessingException {
        autoconfigureFeatures(value);
        return super.writeValueAsString(value);
    }

    @Override
    protected Object _readMapAndClose(JsonParser jsonParser, JavaType javaType) throws IOException, JsonParseException, JsonMappingException {
        autoconfigureFeatures(javaType);
        return super._readMapAndClose(jsonParser, javaType);
    }

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