类似于@JsonAppend的简化版本

public class Bean {

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


会很棒-任何简单的方法来实现这一目标?

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


Add dynamic fields to Spring JSON view response
Jackson: How to add custom property to the JSON without modifying the POJO
Jackson's @JsonAppend with default value
Jackson :: adding extra fields to an object in serialization
How to use extended Jackson MapSerializer in Hashmap
Jackson custom annotation for custom value serialization


但没有找到符合我需求的东西。

我请求的原因是,给定的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类示例,用Map注释@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"}}

09-30 15:40
查看更多