当前位置: 首页 > 知识库问答 >
问题:

Jackson:将动态字段添加到地图序列化(比如@JsonAppend)

凌永逸
2023-03-14

类似于@JsonAppend的简化版本

public class Bean {

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

太好了,有什么简单的方法可以实现吗?

我读过很多这样的文章。

  • 向Spring JSON视图响应添加动态字段

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

我请求的原因是,无法区分某些给定的JSON是源于Map还是POJO序列化。如果这是必要的(在极少数情况下),在地图上添加一个神奇的额外字段将是实现这一点的简单方法。

共有1个答案

董和风
2023-03-14

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

创建自定义注释。我称之为mappender

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

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

创建自定义JsonSerializer

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类示例,用@mapappener注释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"}}

另一个例子是,在序列化之前用值填充映射

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"}}

 类似资料:
  • 问题内容: 我有一个基于项目数组创建的。当网格滚动到底部时,我需要添加更多图像,但是我不确定该怎么做。 现在我了解以下内容: 我有一个适配器,可以解析该数组并向该类提供ImageIds,该类将返回 我必须以某种方式更改此数组并让适配器知道它,所以我的问题是,如何获得对该适配器的引用? 这是我的代码: 现在有一些冗余代码,但这是我的测试项目。我所知道的是,适配器的更新必须在何时(即何时到达底部)进行

  • 问题内容: 我的表格中有3个字段。我有一个提交按钮和一个“添加其他字段”按钮。我知道我可以使用表单类中的方法添加字段。 我是Python和Django的新手,并且陷入了一个初学者的问题;我的问题是: 当我单击“添加其他字段”按钮时,添加其他字段的过程是什么? 是否需要再次呈现表单? 我如何以及何时打电话,甚至必须打电话? 如何将参数传递给? 问题答案: 你的表单必须基于从POST传递给它的一些变量

  • 如果发生错误,数据栏将是这样的字符串: 如果成功,数据字段将是一个对象: 我使用以下Kotlin代码对其进行反序列化: 模型定义如下: 当没有错误发生时,上面的代码工作正常。但是当错误发生时,会引发异常: 有没有办法将字段反序列化为对象或任何对象,并通过代码手动确定其类型?

  • 问题内容: 如何将作为地图的属性序列化为地图的值列表?我已经能够使用吸气剂上的注释进行其他简单的转换。但是,我不确定我想做什么。 问题答案: 我们需要类似的东西,在我们的案例中,我们使用了您所评论的自定义项,这很简单: 使用它的代码:

  • 映射器: 要序列化的类: 我不懂这个领域: 从Jackson那里找到的?我用日志检查了我的本地地图,结果发现这个字段不存在,但在序列化过程中它出现了。

  • 因此,我的问题是面板被插入到JScrollPane中,这些面板的大小正在减小,但没有滚动条。 这是我的代码,我已经播种很远: