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 }, ...
核心需求
- 移除
settingsArrayList对应的[]包裹 - 移除
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
相关产品推荐
相关产品推荐

