【问题标题】:Boolean and array data binding using Jackson使用 Jackson 的布尔值和数组数据绑定
【发布时间】:2023-03-19 07:11:01
【问题描述】:

我正在尝试反序列化从 API 调用返回的结果。但是,结果可以包含布尔值或数组。

如果结果是布尔值,则响应中收到的 JSON 内容如下所示:

{
  "succeeded": true,
  "version": 1.0
}

如果结果是一个数组,响应中收到的 JSON 格式如下:

{
  "succeeded": {
  "current_page": 1,
  "per_page": 100,
  "results": [
    {
      "get_info": {
        "fieldA": "4198126",
        "fieldB": "2016-05-25T22:43:52Z",
        "fieldC": "iws-user-cfg-proxy-beta",
        "updated_at": "2016-05-25T22:43:52Z"
      }
    },
    {
      "get_info": {
        "fieldA": "4551542",
        "fieldB": "2016-07-27T22:26:27Z",
        "fieldC": "silkRoot",
        "updated_at": "2016-07-27T22:26:27Z"
      }
    }
  ]
},
"version": 1.0
}

我想读取与“成功”字段关联的值。有没有办法在映射类中处理这个问题?

我目前的映射类如下:

 public class ServResp {

public final static String TYPE1_EXCEPTION = "Type1Exception";
public final static String TYPE2_EXCEPTION = "Type2Exception";

public final int httpStatusCode;
public final boolan succeeded;
public final String version;
public final String exception;
public final String exceptionMessage;

private ServResp(Builder builder) {
    this.httpStatusCode = builder.httpStatusCode;
    this.succeeded = builder.succeeded;
    this.version = builder.version;
    this.exception = builder.exception;
    this.exceptionMessage = builder.exceptionMessage;
}

public Builder modify() {
    return new Builder(this);
}

@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + ((exception == null) ? 0 : exception.hashCode());
    result = prime * result + ((exceptionMessage == null) ? 0 : exceptionMessage.hashCode());
    result = prime * result + httpStatusCode;
    result = prime * result + (succeeded ? 17 : 19);
    result = prime * result + ((version == null) ? 0 : version.hashCode());
    return result;
}

@Override
public boolean equals(Object obj) {
    if (this == obj)
        return true;
    if (obj == null)
        return false;
    if (getClass() != obj.getClass())
        return false;
    ServResp other = (ServResp) obj;
    if (exception == null) {
        if (other.exception != null)
            return false;
    } else if (!exception.equals(other.exception))
        return false;
    if (exceptionMessage == null) {
        if (other.exceptionMessage != null)
            return false;
    } else if (!exceptionMessage.equals(other.exceptionMessage))
        return false;
    if (httpStatusCode != other.httpStatusCode)
        return false;
    if (succeeded != other.succeeded)
        return false;
    if (version == null) {
        if (other.version != null)
            return false;
    } else if (!version.equals(other.version))
        return false;

    return true;
}

public static class Builder {

    private int httpStatusCode;
    private boolean succeeded;
    private String version;
    private String exception;
    private String exceptionMessage;

    public Builder() {
    }

    public Builder(ServResp other) {
        this.httpStatusCode = other.httpStatusCode;
        this.version = other.version;
        this.exception = other.exception;
        this.exceptionMessage = other.exceptionMessage;
    }

    public Builder setHttpStatusCode(int httpStatusCode) {
        this.httpStatusCode = httpStatusCode;
        return this;
    }

    public Builder setSucceeded(boolean succeeded) {
        this.succeeded = succeeded;
        return this;
    }

    public Builder setVersion(String version) {
        this.version = version;
        return this;
    }

    public Builder setException(String exception) {
        this.exception = exception;
        return this;
    }

    public Builder setExceptionMessage(String exceptionMessage) {
        this.exceptionMessage = exceptionMessage;
        return this;
    }

    public ServResp build() {
        return new ServResp(this);
    }
}}

如果我按原样执行程序,我会收到以下错误:

原因:org.codehaus.jackson.map.JsonMappingException:无法从 START_OBJECT 令牌中反序列化 java.lang.boolean 实例

有没有办法解决这个问题?

【问题讨论】:

    标签: java json data-binding jackson databinder


    【解决方案1】:

    您可以尝试将Builder.succeeded 的类型更改为Object,然后添加一些代码以供稍后阅读。这听起来像是未来 bug 的来源,但如果您不控制 API,那么它可能是您的最佳选择。

    public class Foo {
        private Object overRiddenJsonType;
    
        public Object getOverRiddenJsonType() {
            return overRiddenJsonType;
        }
    
        public void setOverRiddenJsonType(Object overRiddenJsonType) {
            this.overRiddenJsonType = overRiddenJsonType;
        }
    }
    
    public class FooConsumer {
        public void consumeFoo(Foo foo) {
            Boolean b = false;
            Bar bar = null;
            if (foo.getOverRiddenJsonType() instanceof Boolean) {
                b = (Boolean)foo.getOverRiddenJsonType();
                // Worry about an NPE from unboxing later...
            } else if (foo.getOverRiddenJsonType() instanceof Bar) {
                bar = (Bar)foo.getOverRiddenJsonType();
            }
            // ...
        }
    }
    

    另一方面,如果您确实控制了 API,那么更好的解决方案是重构您的 JSON,使 success 始终为 boolean,而其余数据要么是顶级字段或results的成员:

    {
      "succeeded": true,
      "version": 1.0,
      "current_page": 1,
      "per_page": 100,
      "results": [
        {
          "get_info": {
            "fieldA": "4198126",
            ...
          }
       ]
    }
    

    【讨论】:

    • 我可以控制 API...我认为您的第二种方法要好得多...会尝试...谢谢
    【解决方案2】:

    我建议使用工具 JSONschema2POJO 为下面的 JSON 内容生成一个普通的 POJO

    在生成 POJO 时,您可以选择 Source type 作为 JSONAnnotation style 作为 none。 p>

    {
        "succeeded": {
            "current_page": 1,
            "per_page": 100,
            "results": [
                {
                    "get_info": {
                      "fieldA": "4198126",
                      "fieldB": "2016-05-25T22:43:52Z",
                      "fieldC": "iws-user-cfg-proxy-beta",
                      "updated_at": "2016-05-25T22:43:52Z"
                    }
                },
                {
                    "get_info": {
                      "fieldA": "4551542",
                      "fieldB": "2016-07-27T22:26:27Z",
                      "fieldC": "silkRoot",
                      "updated_at": "2016-07-27T22:26:27Z"
                    }
                }
            ]
        }
    }
    

    将生成的 bean 添加到项目后,您可以在映射器类中添加这个重载方法:

    private Succeeded succeeded;
    
    /**
     *
     * @return
     *     The succeeded
     */
    public Succeeded getSucceeded() {
        return succeeded;
    }
    
    /**
     *
     * @param succeeded
     *     The succeeded
     */
    public void setSucceeded(Succeeded succeeded) {
        this.succeeded = succeeded;
    }
    

    【讨论】:

    • 感谢您的建议。该工具可用于将 json 转换为可用作基线的 POJO 对象
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-11-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-23
    • 2022-07-18
    • 2011-01-27
    相关资源
    最近更新 更多