【问题标题】:SpringBoot rest validation does not fail on wrong enum inputSpring Boot 休息验证不会因错误的枚举输入而失败
【发布时间】:2020-07-07 12:09:37
【问题描述】:

我有一个 SpringBoot rest POST 端点,我在正文中发布一个枚举值。此调用不会因错误的值输入而失败。我希望其余调用失败,而不是为无法反序列化的值返回 null。

我已尝试使用以下自定义 ObjectMapper 配置,但我将任何错误输入作为枚举反序列化为 null。

@Bean
@Primary
public ObjectMapper customJsonObjectMapper() {
    Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
    ObjectMapper objectMapper = builder.build();
    objectMapper.configure(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL, false);
    SimpleModule module = new SimpleModule();
    objectMapper.registerModule(module);
    return objectMapper;
}

例如,如果我有枚举:

public enum CouponOddType {
  BACK("back"),
    LAY("lay");

  private String value;

  CouponOddType(String value) {
    this.value = value;
  }

  @Override
  @JsonValue
  public String toString() {
    return String.valueOf(value);
  }

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

请求映射到的dto:

    @ApiModel(description = "Filter used to query coupons. Filter properties are combined with AND operator")
@Validated
@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2020-07-07T13:12:58.487+02:00[Europe/Ljubljana]")
public class CouponQueryFilter   {
  
  @JsonProperty("statuses")
  @Valid
  private List<CouponStatus> statuses = null;

  @JsonProperty("oddTypes")
  @Valid
  private List<CouponOddType> oddTypes = null;

  public CouponQueryFilter statuses(List<CouponStatus> statuses) {
    this.statuses = statuses;
    return this;
  }

  public CouponQueryFilter addStatusesItem(CouponStatus statusesItem) {
    if (this.statuses == null) {
      this.statuses = new ArrayList<>();
    }
    this.statuses.add(statusesItem);
    return this;
  }

  /**
   * Get statuses
   * @return statuses
  **/
  @ApiModelProperty(value = "")
      @Valid
    public List<CouponStatus> getStatuses() {
    return statuses;
  }

  public void setStatuses(List<CouponStatus> statuses) {
    this.statuses = statuses;
  }

  public CouponQueryFilter oddTypes(List<CouponOddType> oddTypes) {
    this.oddTypes = oddTypes;
    return this;
  }

  public CouponQueryFilter addOddTypesItem(CouponOddType oddTypesItem) {
    if (this.oddTypes == null) {
      this.oddTypes = new ArrayList<>();
    }
    this.oddTypes.add(oddTypesItem);
    return this;
  }

  /**
   * Get oddTypes
   * @return oddTypes
  **/
  @ApiModelProperty(value = "")
      @Valid
    public List<CouponOddType> getOddTypes() {
    return oddTypes;
  }

  public void setOddTypes(List<CouponOddType> oddTypes) {
    this.oddTypes = oddTypes;
  }

}

在 POST 请求中,我将枚举值放入 json 数组中:

{
 
    "statuses": [
       "wrong value"
    ],
    "oddTypes": [
       "wrong value"
    ]
}

我希望这种类型的请求会导致 HTTP 404 错误,而不是反序列化为 null。

【问题讨论】:

  • 你能举出完整的例子吗?因为反序列化应该失败
  • @user7294900 我已经更新了问题,也许问题是枚举值是数组的一部分,在这种情况下反序列化的方式不同?
  • 您能展示一下您的 dto 的样子吗? json根本不显示genderFilter的类型
  • @PatrickMagee 我已经用我们使用的一些真实的 DTO 和枚举更新了 questoin,我怀疑问题是数组值解析??

标签: spring-boot rest validation enums


【解决方案1】:

在这种情况下,Jackson 实际上的行为符合预期,并且您的反序列化逻辑存在问题。最终,您希望错误的枚举值引发错误并将该错误返回给用户。这实际上是 spring 和 jackso 的默认行为,将导致 HTTP 400 BAD REQUEST 错误。 IMO 这是返回的适当错误(不是 404),因为用户提供了错误的输入。

除非有特定原因让您在枚举类中实现自定义 @JsonCreator,否则我会摆脱它。这里发生的事情是,Jackson 被告知使用此方法将字符串转换为枚举值,而不是使用默认方法。当传递的文本不是您的枚举的有效值时,您将返回 null,这会导致该值反序列化为 null。

快速解决方法是删除JsonCreator 并允许杰克逊使用其默认行为来处理枚举。在大多数情况下,您添加的额外属性方法是不必要的

ublic enum CouponOddType {
  BACK("back"),
    LAY("lay");

  private String value;

  CouponOddType(String value) {
    this.value = value;
  }
}

如果您出于其他原因需要保留创建者,则需要添加业务逻辑以确定数组中的任何 enum 值是否评估为 null。

private Response someSpringRestEndpoint(@RequestBody CouponQueryFilter filter){
  if (filter.getOddTypes() != null && filter.getOddTypes().contains(null){
   throw new CustomException()
  }

  if (filter.getStatuses() != null && filter.getStatuses().contains(null){
   throw new CustomException()
  }

  //... other business logic
}

【讨论】:

  • aha ok ...这里的问题是我们通过 SpringCodegen 从预定义的模式生成这个枚举对象......我需要更改 codegen 模板,因为 codegen 中的模板是小胡子格式。感谢您为我指明了正确的方向。
  • @simonC,我只想将第二步添加到您的业务逻辑中,以检测过滤器数组中的空值
  • aha 好的,这可能是一个解决方案是的
猜你喜欢
  • 1970-01-01
  • 2020-07-02
  • 1970-01-01
  • 1970-01-01
  • 2018-02-23
  • 1970-01-01
  • 2015-07-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多