杰克逊:将动态字段添加到 Map 序列化(如 @JsonAppend)



类似于@JsonAppend的简化版本

public class Bean {
    @JsonAppend(key = [...], value = [...])
    public Map<?, ?> map = new HashMap<>();
}

会很棒 - 有什么简单的方法可以实现这一目标吗?

我已经阅读了很多SO条目,例如。

  • 将动态字段添加到 Spring JSON 视图响应
  • 杰克逊:如何在不修改 POJO 的情况下将自定义属性添加到 JSON
  • 具有默认值的杰克逊@JsonAppend
  • 杰克逊 :: 在序列化中向对象添加额外字段
  • 如何在Hashmap中使用扩展的Jackson MapSerializer
  • 用于自定义值序列化的杰克逊自定义注释

但发现没有符合我的需求。

我请求的原因是,无法区分某些给定的 JSON 是否源自 Map 或 POJO 序列化。如果这是必要的(在极少数情况下(,向地图添加魔术额外字段将是实现此目的的简单方法。

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


创建自定义批注。我就叫它MapAppender

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MapAppender {
    String[] keys();
    String[] values();
}

如您所见,我们定义了键值数组,这些数组将按索引匹配。
我们被迫使用String字段而不是更通用的Object,但这是每个注释设计。

创建自定义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("...");
    }
}

现在,使用您的 Bean 类示例,使用 @MapAppender 批注Map字段,并使用 @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"}}

最新更新