Jackson JSON deserialization, ignore l'élément racine de json

comment ignorer l'étiquette parent de json??

Voici mon json

String str = "{"parent": {"a":{"id": 10, "name":"Foo"}}}";

et voici la classe à cartographier à partir de 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;
  }
 }

Voici le test public class 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);
}

j'obtiens l'erreur ::

 org.codehaus.jackson.map.JsonMappingException: Root name 'parent' does not match expected ('RootWrapper') for type [simple type, class MavenProjectGroup.mavenProjectArtifact.RootWrapper]

j'ai trouvé la solution donnée par Jackson annotation::

  (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);

Travail Fait!!

un Autre hoquet avec Jackson chemin de la Désérialisation :(

si "DeserializationConfig.Caractéristique.UNWRAP_ROOT_VALUE configuré', il unwrap tous les jsons, même si ma classe dans pas annoté avec @JsonRootName (valeur = "rootTagInJson"), n'est pas weired.

je veux déballer l'étiquette racine seulement si la classe est annotée avec @JsonRootName sinon, ne déballez pas.

voici donc l'usecase pour l'étiquette racine non emballée.

  ###########################################################
     Unwrap only if the class is annotated with @JsonRootName.
  ############################################################

j'ai fait un petit changement dans ObjectMapper du code source de Jackson et j'ai créé une nouvelle version de jar. 1. Lieu cette méthode dans 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.
35
demandé sur Ash 2012-01-12 18:51:25

3 réponses

un exemple tiré de TestRootName.java https://github.com/FasterXML/jackson-databind peut donner une meilleure façon de le faire. Plus précisément à l'aide de 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);
}
27
répondu portforwardpodcast 2012-07-26 04:20:24

j'ai éprouvé un problème similaire en développant une application reposante au printemps. J'ai dû prendre en charge une API très hétérogène, certains D'entre eux ayant des éléments racine, d'autres non. Je n'ai pas pu trouver une meilleure solution que de configurer cette propriété en temps réel. C'est dommage qu'il n'y ait pas de support pour un déballage d'éléments racinaires par classe à Jackson. De toute façon, quelqu'un pourrait trouver ça utile.

@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);
    }

}
11
répondu Segabond 2014-12-29 11:56:02

en tant que mise à jour post de Seagabond, si vous voulez avoir le même effet lorsque vous écrivez des valeurs de paramètre, vous pouvez outrepasser les méthodes d'écriture supplémentaires.

@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);
    }

}
0
répondu wdb 2018-06-18 16:25:41