【问题标题】:Is there a custom Json Serializer pattern to serialize a property differently including the property's key name?是否有自定义 Json 序列化器模式来以不同方式序列化属性,包括属性的键名?
【发布时间】:2020-04-21 06:27:14
【问题描述】:

我有一个类需要序列化

public class Abc
{
 private long age;
 private JaxBElement<Foo> fooWrapper;
 // other properties
}

预期的输出 JSON 是

{
 "age": 24,
 "my_own_key": "my_own_value" // the key should not be "fooWrapper"

限制是不能修改原始类 Abc,因为它是从 xjc 生成的,我还不想使用绑定来探索自定义类。

我已经为 JaxBElement 尝试了自定义序列化程序、bean 修饰符等,所有这些都允许我控制序列化。但他们只在属性的VALUE上工作。他们不允许我更改“KEY-VALUE”级别的内容。这是问题的症结所在。在调用自定义序列化程序来控制值之前,已为属性写出键。

例如只有在 Jackson 系统发出密钥后才会调用我的自定义序列化程序

 "fooWrapper": // now for the value part, let me invoke the custom serializer 

所以输出的 JSON 总是包含“fooWrapper”键。

{ "fooWrapper": { "any-key": "any-value" } }
// the fooWrapper is already emitted out. That is what needs to be controlled.

我的要求是在更高级别控制序列化,以便可以控制键和值。所以当类 Abc 被序列化时,fooWrapper 属性根本不应该写成键,应该调用一些自定义序列化器。

另一个限制是像 Abc 这样的几个类可能有这样的 JaxBElement。不能提前知道。所以需要有一种通用的方法来附加自定义序列化程序。

伪问题实际上是我们能够将自定义序列化程序附加到具有匹配模式的属性的任何类,以便序列化程序可以控制写出的属性名称(或整个键值 blob) .

此外,该问题并非特定于 JaxBElement 本身。它可以是任何财产。问题更多是关于受控序列化,包括被写出的密钥。

【问题讨论】:

    标签: java json serialization jackson


    【解决方案1】:

    也许您只是使用了不正确的序列化程序。 This post,虽然有点老,但应该告诉你如何用StdSerializer做你想做的事。

    这种序列化器允许您同时控制键和值。

    【讨论】:

    • 感谢@Boris。上面的序列化程序允许我控制“值对象(foo)”的键名,而不是“fooWrapper”字段。例如。它以 { "fooWrapper": { "my_own_key": "my_own_value" } } 结尾
    • 我希望您需要为 fooWrapper 类型而不是特定属性定义自定义序列化程序
    • 序列化用于 fooWrapper。 Jackson 系统编写了 fooWrapper 键,然后使用 fooWrapper 的实例调用序列化,即 JaxBElement。所以无论我对这个对象做什么,fooWrapper 键都已经写好了。
    • 能否请您添加您使用的序列化器和反序列化器的代码,以便我们可以尝试指出您的改进?
    【解决方案2】:

    如果您想控制key-value 对的序列化,您不仅需要为JaxBElement&lt;Foo&gt; fooWrapper 还需要为Abc 类注册自定义序列化器以更改key 值。

    由于它不是通用解决方案,您也可以尝试创建MixIn 类或接口并提供额外配置:

    interface MixInA {
    
        @JsonSerialize(using = JAXBElementJsonSerializer.class)
        @JsonProperty("newProperty")
        JAXBElement<Foo> getFooWrapper();
    }
    

    另见:

    此解决方案的缺点是您必须找到必须为其注册MixIn 类或接口的所有类型。如果字段不同,您需要创建许多不同的getters 或许多不同的MixIn 接口来覆盖它们。

    因此,他们最灵活的解决方案可能是实现自定义com.fasterxml.jackson.databind.AnnotationIntrospector,并且对于给定的类型,您可以返回自定义序列化程序和自定义名称。简单例子:

    class DynamicJaxbAnnotationIntrospector extends AnnotationIntrospector {
    
        @Override
        public Version version() {
            return new Version(1, 0, 0, "Dynamic JaxbElement", "your.package", "jackson.dynamic.jaxb");
        }
    
        @Override
        public Object findSerializer(Annotated am) {
            if (am.getRawType() == JAXBElement.class) {
                return new JAXBElementJsonSerializer();
            }
            return super.findSerializer(am);
        }
    
        @Override
        public PropertyName findNameForSerialization(Annotated a) {
            if (a.getRawType() == JAXBElement.class) {
                return new PropertyName("newProperty");
            }
            return super.findNameForSerialization(a);
        }
    }
    

    如何使用它也可以看下面的文章:

    【讨论】:

    • 感谢@Michal。似乎遇到了2个问题。 1) 属性名称需要根据 jaxb 字段名称是动态的。 (Annotated a) 中没有实例信息 2) 'JAXBElementJsonSerializer' 仍然不能写入“仅值”。它也必须提供自己的密钥。让我知道。也许我仍然缺少一些东西。我基本上想要一个私有的 JaxBElement 动物;字段被 json 化为 { "dog": { "gem": true, "loyal": true } } }
    • @RajaNadar,在MixIn 示例中,我们有两个注释:JsonSerialize 定义value 的序列化和JsonProperty 定义新的key。你能用所有注释展示你现在的课程吗?你有什么期望?你有多少这样的课?它们之间有什么区别?在上面的示例中,您是如何获得dog 密钥的?
    猜你喜欢
    • 2023-03-09
    • 2017-04-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-27
    • 1970-01-01
    • 2021-08-27
    • 1970-01-01
    相关资源
    最近更新 更多