java - Jackson - 动态添加枚举值时,EnumValues 序列化失败
问题描述
我正在使用Spring Boot
,当它尝试将 a 转换Bean
为 JSON时出现错误Jackson
。
当这个函数(在 a 中@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;
...
}
杰克逊是否有枚举缓存,因此找不到新值?如果是这样,我可以刷新它吗?
编辑 :
我找到了问题的根源。
EnumSerializer
在序列化期间使用的 Jackson 内部,该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
条目。
有没有办法SerializationFeature.WRITE_ENUMS_USING_TO_STRING
只为某些人启用EnumSerializer
?因为如果我全局打开它可能会产生副作用。
解决方案
由于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
}
推荐阅读
- c++ - 如何增加数组的大小以适应从 1 开始以 100 为增量的所有素数(1、101、201、301.. 等等)?
- css - 如何更改 RMarkdown 中代码折叠按钮的位置?
- javascript - 一个提示代码有效,而另一个无效
- mysql - 在 MySQL 中无法从表中找到逗号分隔值
- android - Android导航组件视图决策
- mysql - 如何在 Rust 中从 MySQL 获取二进制列?
- c# - IXmlSerializable。XmlWriter。如何更改根元素?
- mongodb - 如何在ubuntu中安装mongodb-c驱动并在coturn服务器中使用
- python - 以下程序的时间复杂度是否为 O(1)?
- python - 尝试在 pyopengl 中缩放网格时出现 OpenGL 错误 1282