web-dev-qa-db-fra.com

Désérialisation de Jackson json, ignorer l'élément racine de json

Comment ignorer la balise 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 classe publique 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);
}

Je reçois 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 accompli!!

Un autre problème avec la méthode de désérialisation de Jackson :(

si 'DeserializationConfig.Feature.UNWRAP_ROOT_VALUE est configuré', il déballe tous les jsons, même si ma classe n'est pas annotée avec @JsonRootName (valeur = "rootTagInJson"), n'est pas activé.

Je souhaite décompresser la balise racine uniquement si la classe est annotée avec @JsonRootName sinon, ne décompressez pas.

Vous trouverez ci-dessous le cas d'utilisation de la balise racine non emballée.

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

J'ai fait un petit changement dans le code source ObjectMapper de Jackson et créé une nouvelle version de jar . 1. Placez 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.
37
Ash

Un exemple tiré de TestRootName.Java dans https://github.com/FasterXML/jackson-databind peut être un meilleur moyen de le faire. En utilisant spécifiquement 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);
}
32
portforwardpodcast

J'ai rencontré un problème similaire lors du développement d'une application reposante au printemps. Je devais prendre en charge une API très hétérogène, dont certaines avaient des éléments racines, d'autres pas. Je n'ai pas pu trouver de meilleure solution que de configurer cette propriété en temps réel. Il est vraiment dommage qu’il n’y ait pas de prise en charge du décompression d’élément racine par classe dans Jackson. Quoi qu'il en soit, quelqu'un peut trouver cela 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);
    }

}
12
Segabond

En tant que mise à jour de l'article de Seagabond, si vous voulez avoir le même effet lorsque vous écrivez des valeurs de paramètre, vous pouvez remplacer 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
wdb