使用Jackson的自定义JSON序列化/反序列化

Aioobe

我有一个类层次结构,如下所示:

interface MyEntity {
    ...
}

class MyEntityRef {
    String id;
    ...
}

class MyEntityImpl {
    String id;
    String name;
    ...
}

我想序列化为MyEntityRef纯字符串的实例

"someEntityId"

MyEntityImpl作为常规对象的实例

{
    id: "someEntityId",
    name: "someName"
}

然后是另一种方法:当反MyEntity序列化a时,MyEntityRef如果json是纯字符串,我希望将其反序列化为a MyEntityImpl如果它是常规json对象,则将其反序列化为a

在我实际的代码我有很多类型的实体(即多X/ XRef/XImpl三元组)。为了避免列出所有这些内容,我对接口进行了如下注释:

@MyEntityAnnotation(ref=MyEntityRef.class, impl=MyEntityImpl.class)
interface MyEntity {
    ...
}

凡是指出基于该注释信息为所有实体解决上述序列化/反序列化方法的人,都应格外注意。


我尝试过的:我能想到的一切(SimpleDeserializers/ SimpleSerializersBeanDeserializerModifier/ BeanSerializerModifierTypeSerializer/ TypeDeserializer

阿列克谢·加夫里洛夫(Alexey Gavrilov)

通过使用自定义反序列化器(请参见下文),从技术上讲这是可能的,但由于使用了反射和类型不安全的转换,因此似乎相当复杂且有些笨拙。使用双向引用可能会带来更好的运气,但这可能需要更改模型。

这是一个基于自定义反序列化器的示例:

public class JacksonEntity {

    @Retention(RetentionPolicy.RUNTIME)
    static public @interface MyAnnotation {
        Class<?> ref();
        Class<?> impl();
    }

    @MyAnnotation(ref = MyEntityRef.class, impl = MyEntityImpl.class)
    static public interface MyEntity {
    }

    static public class MyEntityRef implements MyEntity {
        private final String id;

        public MyEntityRef(String id) {
            this.id = id;
        }

        @JsonValue
        public String getId() {
            return id;
        }

        @Override
        public String toString() {
            return "MyEntityRef{" +
                    "id='" + id + '\'' +
                    '}';
        }
    }

    static public class MyEntityImpl implements MyEntity {
        public final String id;
        public final String name;

        @JsonCreator
        public MyEntityImpl(@JsonProperty("id") String id, @JsonProperty("name") String name) {
            this.id = id;
            this.name = name;
        }

        @Override
        public String toString() {
            return "MyEntityImpl{" +
                    "id='" + id + '\'' +
                    ", name='" + name + '\'' +
                    '}';
        }
    }

    static public class MyDeserializer extends JsonDeserializer<Object> {
        private final Class<?> refType;
        private final Class<?> implType;

        public MyDeserializer(MyAnnotation annotation) {
            this.refType = annotation.ref();
            this.implType = annotation.impl();
        }

        @Override
        public Object deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException {
            JsonToken jsonToken = jp.getCurrentToken();
            if (jsonToken == JsonToken.START_OBJECT) {
                return jp.readValueAs(implType);
            } else if (jsonToken == JsonToken.VALUE_STRING) {
                try {
                    return refType.getConstructor(String.class).newInstance(jp.getValueAsString());
                } catch (Exception e) {
                    throw new UnsupportedOperationException();
                }
            }
            return null;
        }
    }

    public static void main(String[] args) throws IOException {
        ObjectMapper mapper = new ObjectMapper();
        SimpleModule module = new SimpleModule();
        module.setDeserializerModifier(new BeanDeserializerModifier() {
            @Override
            public JsonDeserializer<?> modifyDeserializer(DeserializationConfig config,
                                                          BeanDescription beanDesc,
                                                          JsonDeserializer<?> deserializer) {
                MyAnnotation myAnnotation = beanDesc.getClassAnnotations().get(MyAnnotation.class);
                // it must be interface, otherwise getting meeting recursion
                if (myAnnotation != null && beanDesc.getBeanClass().isInterface()) {
                    return new MyDeserializer(myAnnotation);
                }
                return super.modifyDeserializer(config, beanDesc, deserializer);
            }
        });
        mapper.registerModule(module);

        MyEntityRef ref = new MyEntityRef("id1");
        MyEntityImpl impl = new MyEntityImpl("id2", "value");

        String jsonRef = mapper.writeValueAsString(ref);
        System.out.println(jsonRef);
        String jsonImpl = mapper.writeValueAsString(impl);
        System.out.println(jsonImpl);

        System.out.println(mapper.readValue(jsonRef, MyEntity.class));
        System.out.println(mapper.readValue(jsonImpl, MyEntity.class));
    }
}

输出:

"id1"
{"id":"id2","name":"value"}
MyEntityRef{id='id1'}
MyEntityImpl{id='id2', name='value'}

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

使用Jackson自定义JSON反序列化

使用Jackson自定义反序列化列表

使用Jackson自定义反序列化JSON字段

Jackson JSON无法使用自定义根名称反序列化元素数组?

在Java中使用Jackson进行JSON FIELD的自定义反序列化?

Jackson对多态对象的自定义反序列化

使用Jackson进行自定义反序列化:扩展默认反序列化器

自定义反序列化

如何使用尊重自定义注释的Jackson来执行自定义JSON反序列化?

Jackson 的多态序列化/反序列化和自定义序列化器/反序列化器

Ktor自定义json对象反序列化

自定义JSON.net序列化和反序列化

Go中接口的自定义JSON序列化和反序列化

自定义JSON序列化/反序列化,以多种可能的格式读取属性

自定义JSON序列化和反序列化

无效的JSON原语-自定义序列化/反序列化

使用自定义IXmlSerializer反序列化注释

使用GSON自定义反序列化枚举

Jackson-仅将自定义反序列化器用于特定的JSON

如何为Jackson编写自定义JSON反序列化器?

Jackson中的自定义JSON反序列化,排除invalide数组

使用杰克逊可自定义序列化和反序列化

使用 JQuery 序列化和反序列化自定义对象数组

如何使用Json.Net使用自定义键对字典进行序列化/反序列化?

某些字段的Jackson JSON自定义序列化

使用jackson-dataformat-xml自定义根元素的XML反序列化?

使用Jackson在Java中嵌套自定义反序列化

仅当存在某些字段时才使用自定义JSON反序列化(使用Jackson)

使用Jackson序列化自定义地图