为了账号安全,请及时绑定邮箱和手机立即绑定

杰克逊:向地图序列化添加动态字段

杰克逊:向地图序列化添加动态字段

慕容3067478 2022-09-22 16:34:00
类似于简化版本的@JsonAppendpublic class Bean {    @JsonAppend(key = [...], value = [...])    public Map<?, ?> map = new HashMap<>();}那就太好了 - 任何简单的方法来实现这一目标?但发现没有任何东西符合我的需求。我提出请求的原因是,无法区分某些给定的JSON是否源自Map或POJO序列化。如果这是必要的(在极少数情况下),在地图上添加一个神奇的额外字段将是实现这一目标的简单方法。
查看完整描述

1 回答

?
梵蒂冈之花

TA贡献1900条经验 获得超5个赞

好问题!是的,这是(以某种方式)可能的。以下公开的方法维护标准序列化行为,同时在其上添加注释定义的键值对。


创建自定义批注。我来称呼它MapAppender


@Target(ElementType.FIELD)

@Retention(RetentionPolicy.RUNTIME)

public @interface MapAppender {

    String[] keys();

    String[] values();

}

如您所见,我们定义了键值数组,这些数组将按索引匹配。

我们被迫使用字段而不是更通用的 ,但这是每个注释设计。StringObject


创建自定义 .我来称呼它JsonSerializer<Map>MapAppenderSerializer


public class MapAppenderSerializer

        extends StdSerializer<Map>

        implements ContextualSerializer {

    private static final long serialVersionUID = 1L;


    private final String[] keys;

    private final String[] values;


    // No-arg constructor required for Jackson

    MapAppenderSerializer() {

        super(Map.class);

        keys = new String[0];

        values = new String[0];

    }


    MapAppenderSerializer(

            final String[] keys,

            final String[] values) {

        super(Map.class);

        this.keys = keys;

        this.values = values;

    }


    @Override

    public void serialize(

            final Map value,

            final JsonGenerator jsonGenerator,

            final SerializerProvider serializerProvider) throws IOException {

        // Create a copy Map to avoid touching the original one

        final Map hashMap = new HashMap<>(value);


        // Add the annotation-specified key-value pairs

        for (int i = 0; i < keys.length; i++) {

            hashMap.put(keys[i], values[i]);

        }


        // Serialize the new Map

        serializerProvider.defaultSerializeValue(hashMap, jsonGenerator);

    }


    @Override

    public JsonSerializer<?> createContextual(

            final SerializerProvider serializerProvider,

            final BeanProperty property) {

        MapAppender annotation = null;


        if (property != null) {

            annotation = property.getAnnotation(MapAppender.class);

        }


        if (annotation != null) {

            return new MapAppenderSerializer(annotation.keys(), annotation.values());

        }


        throw new UnsupportedOperationException("...");

    }

}

现在,使用您的类示例,使用注释字段并定义自定义序列化程序BeanMap@MapAppender@JsonSerialize


public class Bean {

    public String simpleField;


    @MapAppender(keys = {"test1", "test2"}, values = {"value1", "value2"})

    @JsonSerialize(using = MapAppenderSerializer.class)

    public Map<Object, Object> simpleMap = new HashMap<>();

}

就是这样。序列化 的实例Bean


final ObjectMapper objectMapper = new ObjectMapper();

final String string = objectMapper.writeValueAsString(new Bean());

结果


{"simpleField":null,"simpleMap":{"test2":"value2","test1":"value1"}}

另一个示例,在序列化之前用值填充Map


final ObjectMapper objectMapper = new ObjectMapper();

final Bean value = new Bean();

value.simpleMap.put("myKey", "myValue");


final String string = objectMapper.writeValueAsString(value);

结果


{"simpleField":null,"simpleMap":{"test1":"value1","test2":"value2","myKey":"myValue"}}


查看完整回答
反对 回复 2022-09-22
  • 1 回答
  • 0 关注
  • 66 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信