我有一个 SpringBoot 休息 POST 端点,在正文中我 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。
在这种情况下,Jackson 实际上按照预期行事,并且您的反序列化逻辑存在问题。最终,您希望错误的枚举值引发错误并将该错误返回给用户。这实际上是 spring 和 Jackson 的默认行为,并且会导致
HTTP 400 BAD REQUEST
错误。 IMO 这是返回的适当错误(不是 404),因为用户提供了错误的输入。
除非有特定原因需要您在枚举类中实现自定义
@JsonCreator
,否则我会删除它。这里发生的事情是 Jackson 被告知使用此方法将字符串转换为枚举值,而不是使用默认方法。当传递的文本不是枚举的有效值时,您将返回 null
,这会导致该值反序列化为 null。
一个快速修复方法是删除
JsonCreator
并允许 Jackson 使用其默认行为来处理枚举。在大多数情况下,您添加的额外属性方法是不必要的
public 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
}