You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Jackson序列化配置展开问题:移除数组/对象包裹并自定义键名

问题

我在开发应用配置管理器时,使用Jackson序列化遇到格式不符的问题。以下是相关代码和当前结果:

ObjectMapper配置(Kotlin)

val mapper = ObjectMapper()

val jackson = mapper.setVisibility(
        mapper.getSerializationConfig().getDefaultVisibilityChecker()
            .withFieldVisibility(JsonAutoDetect.Visibility.NONE)
            .withGetterVisibility(JsonAutoDetect.Visibility.NONE)
            .withSetterVisibility(JsonAutoDetect.Visibility.NONE)
            .withCreatorVisibility(JsonAutoDetect.Visibility.NONE)
    )
    .configure(SerializationFeature.FAIL_ON_SELF_REFERENCES, false)
    .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
    .enable(SerializationFeature.INDENT_OUTPUT)

核心类定义

  • Module类包含配置列表:
@JsonProperty("config")  
public ArrayList<SettingAbstract> settings = new ArrayList<>( );
  • SettingAbstract抽象类及子类实现:
// SettingAbstract
@JsonProperty("property") 
public abstract String saveCfg();

// 子类实现
@Override
public String saveCfg() {
    return this.name + ": " + this.value;
}

当前序列化结果

..., {
  "enabled" : false,
  "name" : "ESP",
  "config" : [ {
    "property" : "Players: true"
  }, {
    "property" : "Mobs: false"
  }, {
    "property" : "Hostiles: false"
  } ],
  "currentSettingsPage" : 0
}, {
  "enabled" : false,
  "name" : "Custom Time",
  "config" : [ {
    "property" : "Ticks: 19000"
  } ],
  "currentSettingsPage" : 0
}, ...

期望格式

..., {
  "enabled" : false,
  "name" : "ESP",
  "Players": true,
  "Mobs": "false",
  "Hostiles": "false",
  "currentSettingsPage" : 0
}, {
  "enabled" : false,
  "name" : "Custom Time",
  "Ticks": "19000",
  "currentSettingsPage" : 0
}, ...

核心需求

  • 移除settings ArrayList对应的[]包裹
  • 移除SettingAbstract实例对应的{}包裹
  • 将每个Setting的name作为JSON键,value作为对应值,直接嵌入Module的JSON结构中

解决方案

1. 用@JsonAnyGetter实现动态键值对序列化

在Module类中移除settings字段的@JsonProperty("config")注解,新增一个返回Map的方法,Jackson会自动将Map中的键值对直接序列化到Module的JSON对象中,无需额外的数组和嵌套对象:

// 移除原有@JsonProperty("config")注解
public ArrayList<SettingAbstract> settings = new ArrayList<>( );

// 添加动态键值对Getter
@JsonAnyGetter
public Map<String, Object> getSettingsMap() {
    Map<String, Object> map = new HashMap<>();
    for (SettingAbstract setting : settings) {
        map.put(setting.name, setting.value);
    }
    return map;
}

2. 清理冗余的saveCfg方法和注解

删除SettingAbstract中的@JsonProperty("property")注解和saveCfg抽象方法,直接保留name和value字段即可:

public abstract class SettingAbstract {
    public String name;
    public Object value; // 可根据实际需求调整为具体类型(如String/Boolean/Integer)
}

3. 调整ObjectMapper可见性配置

原配置禁止了所有字段和Getter的访问,需要修改为允许Jackson访问所需的字段和方法:

val mapper = ObjectMapper()

val jackson = mapper.setVisibility(
        mapper.getSerializationConfig().getDefaultVisibilityChecker()
            .withFieldVisibility(JsonAutoDetect.Visibility.ANY) // 允许读取字段
            .withGetterVisibility(JsonAutoDetect.Visibility.ANY) // 允许读取Getter方法
            .withSetterVisibility(JsonAutoDetect.Visibility.NONE)
            .withCreatorVisibility(JsonAutoDetect.Visibility.NONE)
    )
    .configure(SerializationFeature.FAIL_ON_SELF_REFERENCES, false)
    .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
    .enable(SerializationFeature.INDENT_OUTPUT)

补充说明

如果value字段存在多类型(布尔、数字、字符串等),Jackson会自动匹配对应的JSON类型序列化;若需要自定义类型处理,可给value字段添加Jackson注解或自定义序列化器。


内容的提问来源于stack exchange,提问作者Bluecross

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 01:45:25