ObjectMapper无法处理具有旧式枚举(类)的映射对象

时间:2019-02-04 08:30:31

标签: java enums legacy objectmapper

我在为某些旧代码构建REST体系结构时遇到问题。 杰克逊ObjectMapper无法将我的自定义对象映射到旧版对象,因为“枚举”实际上是带有静态最终字段的类。

我尝试实现自定义转换器/反序列化器没有成功

在旧系统中,有些枚举看起来像这样:

public final class LegacyEnum extends LegacyEnumSuperclass {

    public static final LegacyEnum VALUE = new LegacyEnum("1");

我将这些“枚举”的值作为字符串接收,我将其转换为旧式枚举值(自定义反序列化器),并将其设置在自定义类中(我需要它,因为我使用的是杰克逊注释,但我没有访问或修改旧版代码的权限),这部分效果很好。当我尝试使用以下方式将自定义对象映射到旧版对象时:

objectMapper.convertValue(myCustomObject, LegacyObjectContainingEnums.class); 

我得到一个例外:

Can not construct instance of LegacyEnum: no suitable constructor found, can not deserialize from Object value (missing default constructor or creator, or perhaps need to add/enable type information?)

LegacyEnum类具有私有构造函数,而LegacyEnumSuperclass具有类似的受保护构造函数,因此我无法访问它们(ObjectMapper也不能)。我已经尝试实现一个自定义转换器,该转换器将跳过ObjectMapper映射的“创建新对象”部分,并且还尝试重用我的自定义解串器。我遇到了多个问题,但没有成功。

最烦人的部分是,当我使用ModelMapper库时,它就像一个魅力(它可能只是在旧对象中设置一个值,不需要像ObjectMapper一样创建新的LegacyEnum实例!),但是我试图解决该问题而无需添加新的依赖项。

有什么想法吗?

1 个答案:

答案 0 :(得分:0)

我通过使用MixIn和自定义解串器解决了这个问题,

public abstract class LegacyClassMixIn 
    @JsonDeserialize(using = LegacyEnumDeserializer.class)
    abstract LegacyEnum getLegacyEnum();

反序列化器:

public class LegacyEnumDeserializer extends JsonDeserializer<LegacyEnumSuperclass> implements ContextualDeserializer {

private JavaType valueType;

@Override
public JsonDeserializer createContextual(DeserializationContext context, BeanProperty property) {
    JavaType wrapperType = property.getType();
    LegacyEnumDeserializer deserializer = new LegacyEnumDeserializer();
    deserializer.valueType = wrapperType;

    return deserializer;
}

@Override
public LegacyEnumSuperclass deserialize(JsonParser parser, DeserializationContext context) throws IOException {
    return LegacyEnumSuperclass.getEnum(valueType.getRawClass(), parser.readValueAs(String.class));
}

valueType.getRawClass()返回LegacyEnum.class,这样,我就可以对所有继承LegacyEnumSuperclass类的“枚举”使用一个反序列化器。 getEnum是来自旧版代码的自定义方法。

在ObjectMapper Spring配置中注册MixIn:

@Configuration
public class ObjectMapperConfig {

    public ObjectMapperConfig(ObjectMapper objectMapper) {
        objectMapper.addMixIn(LegacyClass.class, LegacyClassMixIn.class);
    }
}

这样,我可以将LegacyClass用作Controller方法中的参数。 感谢您提供线索。