Jackson DeSerializer for Class<? 扩展了Foo>



我想为类文字提供一个序列化程序和反序列化程序。它应该从/映射到 JSON 字符串。它还应该与泛型类一起使用。

尝试编写自定义反序列化程序,但它处理所有类,而不仅仅是我想要的类:

public class MyDeserializer extends JsonDeserializer<Class<? extends Foo>> {
    public Class<? extends Foo> deserialize(JsonParser jp, DeserializationContext ctxt) 
        throws IOException, JsonProcessingException {
        String token = jp.getText();
        switch(token) {
            case "FOO": return Foo.class;
            case "BAR": return Bar.class;
        }
        return null;
    }
}

杰克逊将为每个Class<?>调用此反序列化器。但我只是希望它被召唤Class<? extends Foo>.

顺便说一句:我想将其注册为全局反序列化程序。我不想到处都使用@JsonDeserialize

我怎样才能让它正常工作?

提前谢谢。

编辑:更多代码

波乔:

public class MyPOJO {
    public Class<? extends Foo> fooType;
}

杰森:

{
    "fooType": "FOO"
}

对象映射器用法:

MyPOJO pojo = new MyPOJO();
pojo.fooType = Foo.class;
ObjectMapper om = new ObjectMapper();
String json = om.writeValueAsString(pojo);

由于类型擦除,您尝试实现的目标似乎是不可能的,实际上在运行时,您的类MyDeserializer被视为JsonDeserializer<Class>,而您的字段fooType只是Class类型而不是Class<? extends Foo> 这实际上就是为什么每次Class<?>都调用反序列化器的原因。

在您的情况下,最好的解决方案是用 @JsonDeserialize(using = MyDeserializer.class) 注释类型为 Class<? extends Foo> 的字段,以便在运行时指示要使用的反序列化程序,但由于您不想这样做,作为解决方法,假设在给定类中,当您有类型 Class 的字段时,它们都将使用相同的反序列化程序(自定义或默认), 您可以简单地修改类MyDeserializer,首先检查当前的 Bean 类,以了解我们是否应该使用自定义反序列化程序或默认反序列化程序。

例如,您可以将其注册为:

ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule("MyModule")
    .addDeserializer(Class.class, new MyDeserializer());
mapper.registerModule(module);

然后,反序列化程序的代码将是:

public class MyDeserializer extends JsonDeserializer<Class<?>>  {
    // The default deserializer for a property of type Class
    private final FromStringDeserializer.Std defaultDeserializer;
    public MyDeserializer() {
        // Set the default deserializer
        this.defaultDeserializer = FromStringDeserializer.findDeserializer(Class.class);
    }
    public Class<?> deserialize(JsonParser jp, DeserializationContext ctxt) 
        throws IOException, JsonProcessingException {
        // Check whether we should used the custom or default deserializer
        // based on the bean class
        if (accept(jp.getCurrentValue().getClass())) {
            // The custom deserializer
            String token = jp.getText();
            switch(token) {
                case "FOO": return Foo.class;
                case "BAR": return Bar.class;
            }
            return null;
        }
        // Call the default deserializer
        return (Class<?>) defaultDeserializer.deserialize(jp, ctxt);
    }
    // Returns true if this bean class has fields of type Class that must
    // be deserialized with the custom deserializer, false otherwise
    public boolean accept(Class<?> beanClass) {
        // Implement your logic here
        // You could for example have all the bean classes in a Set and 
        // check that the provided class is in the Set 
    }
}

最新更新