Jackson json 反序列化,忽略来自 json 的根元素

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/8837018/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 18:08:24  来源:igfitidea点击:

Hymanson json deserialization, ignore root element from json

jsonHymanson

提问by Ash

How to ignore parent tag from json??

如何忽略来自 json 的父标签?

Here is my json

这是我的 json

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

And here is the class to be mapped from json.

这是要从 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;
  }
 }

Here is the test public class HymansonTest {

这是测试公共类 HymansonTest {

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

I get the error ::

我收到错误::

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

I found the solution given by Hymanson annotation::

我找到了 Hymanson 注释给出的解决方案:

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

Job Done!!

任务完成!!

Another hiccup with Hymanson way of Deserialization :(

Hyman逊反序列化方式的另一个问题:(

if 'DeserializationConfig.Feature.UNWRAP_ROOT_VALUE configured', it unwrap all jsons, eventhough my class in not annotated with @JsonRootName(value = "rootTagInJson"), isn't weired.

如果 'DeserializationConfig.Feature.UNWRAP_ROOT_VALUE 已配置',它会解开所有 jsons,即使我的类没有用 @JsonRootName(value = "rootTagInJson") 进行注释,也不是 weired。

I want to unwrap root tag only if the class is annotated with @JsonRootName otherwise, don't unwrap.

只有当类用@JsonRootName 注释时,我才想解开根标签,否则不要解开。

So below is the usecase for unwrap root tag.

所以下面是解包根标签的用例。

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

I did a small change in ObjectMapper of Hymanson source code and created a new version of jar. 1. Place this method in ObjectMapper

我在 Hymanson 源代码的 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.

回答by portforwardpodcast

An example taken from TestRootName.java in https://github.com/FasterXML/Hymanson-databindmay give a better way of doing this. Specifically using withRootName(""):

https://github.com/FasterXML/Hymanson-databind 中的TestRootName.java 中获取的示例 可能会提供更好的方法。具体使用 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);
}

回答by Segabond

I experienced a similar problem developing a restful application in Spring. I had to support a very heterogeneous API, some of it had root elements, another did not. I could not find a better solution than to configure this property realtime. It's a great pity there is no support for per-class root element unwrapping in Hymanson. Anyway, somebody may find this helpful.

我在 Spring 中开发一个安静的应用程序时遇到了类似的问题。我必须支持一个非常异构的 API,其中一些有根元素,另一些没有。我找不到比实时配置此属性更好的解决方案。很遗憾在 Hymanson 中不支持每类根元素展开。无论如何,有人可能会发现这很有帮助。

@Component
public class ObjectMapper extends com.fasterxml.Hymanson.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);
    }

}

回答by wdb

As an update Seagabond's post, if you want to have the same effect when you write parameter values you can override the additional write methods.

作为更新 Seagabond 的帖子,如果您想在写入参数值时具有相同的效果,您可以覆盖额外的写入方法。

@Component
public class ObjectMapper extends com.fasterxml.Hymanson.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);
    }

}

回答by Alan Sereb

Its very simple:

它非常简单:

Create an instance of object mapper and enable wrapping and unwrapping root value

创建对象映射器的实例并启用包装和解包根值

ObjectMapper mapper = new ObjectMapper();
mapper.enable(SerializationFeature.WRAP_ROOT_VALUE);
mapper.enable(DeserializationFeature.UNWRAP_ROOT_VALUE);

Add @JsonRootName("yourname")annotation to you DTO

@JsonRootName("yourname")为您的 DTO添加注释

@JsonRootName("root")
public class YourDto {
    // ...
}