动态添加枚举值时,Jackson-EnumValues序列化失败



我正在使用Spring Boot,当它试图用JacksonBean转换为JSON时,我遇到了一个错误。

当这个函数(位于@RestController内部(第一次被调用时,它工作得很好:

@GetMapping
public UserDto getUser() {
UserDto userDto = // get the user 
// userDto.getRoles() is an enum, let's call it XEnum, with 20 entries
return userDto;
}

在这之后,一个新的值被动态添加到XEnum,所以这个枚举现在有21个条目。

当调用上面的函数时,我得到这个错误:

org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: 41; nested exception is com.fasterxml.jackson.databind.JsonMappingException: 41 (through reference chain: ...UserDto["roles"]->java.util.ArrayList[21])
at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.writeInternal(AbstractJackson2HttpMessageConverter.java:296)
at org.springframework.http.converter.AbstractGenericHttpMessageConverter.write(AbstractGenericHttpMessageConverter.java:103)
at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:290)
at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.handleReturnValue(RequestResponseBodyMethodProcessor.java:180)
...
Caused by: java.lang.ArrayIndexOutOfBoundsException: 41
at com.fasterxml.jackson.databind.util.EnumValues.serializedValueFor(EnumValues.java:79)
at com.fasterxml.jackson.databind.ser.std.EnumSerializer.serialize(EnumSerializer.java:132)
at com.fasterxml.jackson.databind.ser.std.EnumSerializer.serialize(EnumSerializer.java:27)
at com.fasterxml.jackson.databind.ser.impl.IndexedListSerializer.serializeContentsUsing(IndexedListSerializer.java:142)

在我的实际情况中,41是枚举中新条目的序数。

UserDto类如下所示:

public class UserDto implements Serializable {
private static final long serialVersionUID = 475464704956181923L;
private XEnum currentRole;
private List<XEnum> roles;
...
}

Jackson是否有枚举的缓存,因此无法找到新值?如果是,我可以刷新它吗?

编辑:

我已经找到了问题的根源。

在序列化期间使用的JacksonEnumSerializer中,serialize方法如下所示:

@Override
public final void serialize(Enum<?> en, JsonGenerator gen, SerializerProvider serializers)
throws IOException
{
// [JACKSON-684]: serialize as index?
if (_serializeAsIndex(serializers)) {
gen.writeNumber(en.ordinal());
return;
}
// [databind#749]: or via toString()?
if (serializers.isEnabled(SerializationFeature.WRITE_ENUMS_USING_TO_STRING)) {
gen.writeString(en.toString());
return;
}
gen.writeString(_values.serializedValueFor(en)); // this line is evaluated !!
}

_values包含预先解析的值,并且不包含新的Enum条目。

有没有办法只为某些EnumSerializer启用SerializationFeature.WRITE_ENUMS_USING_TO_STRING?因为如果我在全球范围内打开它,它可能会有副作用。

由于EnumSerializer#serialize方法和com.fasterxml.jackson.databind.util.EnumValues类被标记为final,因此很难扩展它们的行为。在这种情况下,最简单的解决方案是为XEnum编写自定义串行器

class DynamicEnumJsonSerializer extends JsonSerializer<Enum> {
@Override
public void serialize(Enum value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
gen.writeString(value.toString());
}
}

你可以注册如下:

@JsonSerialize(using = DynamicEnumJsonSerializer.class)
enum XEnum {
X, Y, Z
}

最新更新