【问题标题】:Issue with de-serialization from json to object containing enums从 json 反序列化到包含枚举的对象的问题
【发布时间】:2019-12-07 06:21:35
【问题描述】:

使用 jackson2.9.8 进行枚举反序列化时遇到问题。同样适用于 Gson。 模型是根据 swagger api 定义自动生成的

使用 Gson,它工作正常。对于 jackson,它不适用于 011、013 和 019,但适用于其他值

Swagger api 定义的sn-p

服务代码: 类型:字符串 枚举: - “001” - “002” - “003” - “004” - “005” - “007” - “008” - “009” - “011” - “013” - “019”

自动生成的代码(为了可读性删除了getter/setter)

public class ProcessErrorTest1 {
    static String errorJson =
            "    {\n" +
            "      \"timestamp\": \"2019-07-29 11:55:48\",\n" +
            "      \"serviceCode\": \"019\",\n" +
            "      \"message\": \"service failed. \",\n" +
            "      \"rootException\": {\n" +
            "        \"source\": \"test\",\n" +
            "        \"reasonCode\": \"2131\",\n" +
            "        \"reasonText\": \"test\"\n" +
            "      }\n" +
            "}";

    public static void main(String[] args) throws Exception {
        ObjectMapper mapper = new ObjectMapper();
        AppErrorResponse error = mapper.readValue(errorJson, AppErrorResponse.class);
       // Gson gson = new Gson();
        //AppErrorResponse error = gson.fromJson(errorJson, AppErrorResponse.class);
        System.out.println("error::" + error);
    }
}

public class AppErrorResponse {

  @SerializedName("message")
  private String message = null;

  @SerializedName("rootException")
  private ErrorResponse rootException = null;
  /**
   * Gets or Sets serviceCode
   */
  @JsonAdapter(ServiceCodeEnum.Adapter.class)
  public enum ServiceCodeEnum {
    _001("001"),
    _002("002"),
    _003("003"),
     _004("004"),
    _005("005"),
    _007("007"),
    _008("008"),
    _009("009"),
    _011("011"),
    _013("013"),
   // @JsonProperty("019") if add this , it works fine. But can't modify the auto generated code as it is available as jar
    _019("019");
  }
  @SerializedName("serviceCode")
  private ServiceCodeEnum serviceCode = null;

  @SerializedName("timestamp")
  private String timestamp = null;

}

public class ErrorResponse {

  @SerializedName("reasonCode")
  private String reasonCode = null;

  @SerializedName("reasonText")
  private String reasonText = null;

  @SerializedName("source")
  private String source = null;
}

jersey1:jackson 生成的代码

import java.util.Objects;
import com.bt.consumer.appointment.dto.MAC2ErrorResponse;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue;
public class AppErrorResponse {
  @JsonProperty("message")
  private String message = null;

  @JsonProperty("rootException")
  private ErrorResponse rootException = null;

  public enum ServiceCodeEnum {
    _001("001"),
    _002("002"),
    _003("003"),
    _004("004"),
    _005("005"),
    _007("007"),
    _008("008"),
    _009("009"),
    _011("011"),
    _013("013"),
    _019("019");

    private String value;

    ServiceCodeEnum(String value) {
      this.value = value;
    }
    @JsonValue
    public String getValue() {
      return value;
    }

    @Override
    public String toString() {
      return String.valueOf(value);
    }
    @JsonCreator
    public static ServiceCodeEnum fromValue(String text) {
      for (ServiceCodeEnum b : ServiceCodeEnum.values()) {
        if (String.valueOf(b.value).equals(text)) {
          return b;
        }
      }
      return null;
    }

  }
  @JsonProperty("serviceCode")
  private ServiceCodeEnum serviceCode = null;

  @JsonProperty("timestamp")
  private String timestamp = null;
}

import java.util.Objects;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue;
public class ErrorResponse {
  @JsonProperty("reasonCode")
  private String reasonCode = null;

  @JsonProperty("reasonText")
  private String reasonText = null;

  @JsonProperty("source")
  private String source = null;
}

除了使用 jackson 的 _011、_013 和 _019 之外,它对所有人都适用 错误信息:- com.fasterxml.jackson.databind.exc.InvalidFormatException:无法从字符串“011”反序列化ServiceCodeEnum类型的值:值不是声明的枚举实例名称之一:[_011、_001、_002、_003、_004、_005、_007, _008、_009、_013、_019]

【问题讨论】:

    标签: java enums jackson swagger


    【解决方案1】:

    您的注释针对的是 Gson 而不是 Jackson,您应该为 Jackson 而不是 Gson 生成 pojo。 @JsonAdapter(ServiceCodeEnum.Adapter.class) 行是一个适配器,它为 Gson 处理该枚举的转换。


    查看 swagger codegen 文档,您会找到有关生成 https://github.com/swagger-api/swagger-codegen#customizing-the-generator 的部分

    据说:For all the unspecified options default values will be used.

    上面列出了下表:

    CONFIG OPTIONS
        modelPackage
            package for generated models
    
        apiPackage
            package for generated api classes
    ...... (results omitted)
        library
            library template (sub-template) to use:
            jersey1 - HTTP client: Jersey client 1.18. JSON processing: Jackson 2.4.2
            jersey2 - HTTP client: Jersey client 2.6
            feign - HTTP client: Netflix Feign 8.1.1.  JSON processing: Jackson 2.6.3
            okhttp-gson (default) - HTTP client: OkHttp 2.4.0. JSON processing: Gson 2.3.1
            retrofit - HTTP client: OkHttp 2.4.0. JSON processing: Gson 2.3.1 (Retrofit 1.9.0)
            retrofit2 - HTTP client: OkHttp 2.5.0. JSON processing: Gson 2.4 (Retrofit 2.0.0-beta2)
            google-api-client - HTTP client: google-api-client 1.23.0. JSON processing: Jackson 2.8.9
            rest-assured - HTTP client: rest-assured : 3.1.0. JSON processing: Gson 2.6.1. Only for Java8
    

    这行可能是正在使用的:

    okhttp-gson (default) - HTTP client: OkHttp 2.4.0. JSON processing: Gson 2.3.1

    你需要指定一个使用 Jackson 的库和你想要的 HTTP 客户端。

    【讨论】:

    • @Nandeesh jersey2 似乎没有指定杰克逊。你可以试试jersey1google-api-client
    • jersey2 确实使用了杰克逊。我可以看到导入 com.fasterxml.jackson.annotation.JsonCreator;在自动生成的类中。我会试试 jersey1
    • 与 jersey1 也是同样的问题。 ServiceCodeEnum from String value '019': value not one of declared Enum instance names: [001, 002, 003, 004, 005, 007, 008, 009, 011, 013, 019]
    • @Nandeesh 你能用 Jersey 生成的 DTO 更新你的问题吗?
    • @ug 我已经更新了使用 jersey1 生成的 DTO。如果我使用不属于枚举的 serviceCode 作为 010,我仍然会得到成功的响应,但将服务代码返回为 019 class AppErrorResponse { message: service failed. rootException: class ErrorResponse { reasonCode: 2131 reasonText: test source: test } serviceCode: 019 timestamp: 2019-07-29 11:55:48 }
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-09-01
    • 1970-01-01
    • 2015-06-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-10
    相关资源
    最近更新 更多