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

Spring Boot在Cosmos DB存储含集合的HashMap字段报错求助

问题解决:Cosmos DB存储HashMap<String, List<自定义对象>>时$hashCodeCache报错

错误原因

报错Invalid BSON field name $hashCodeCache是因为Java HashMap的内部私有字段(如hashCodeCache)被序列化到BSON中,而Cosmos DB(兼容Mongo API)禁止字段名包含$符号。当Map的值为自定义对象AppRegistration时,序列化逻辑会把HashMap的内部状态也纳入序列化范围;而值为字符串时不会触发该问题。

可行解决方案

方案1:快速忽略HashMap内部字段

在appRegistrationList字段上添加Jackson注解,排除HashMap的内部私有字段,只序列化键值对:

@Document(collection = "tenant")
@Getter @Setter @ToString
public class Tenant extends DateAudit {
    @Id
    private String tenantId=UUID.randomUUID().toString();

    @Indexed(unique = true)
    @Field("name")
    private String name;

    @Field("app_registration_list")
    @JsonIgnoreProperties({"hashCodeCache", "loadFactor", "threshold", "modCount"})
    private HashMap<String, ArrayList<AppRegistration>> appRegistrationList = new HashMap<>();
}

方案2:全局配置Map序列化规则

通过Spring配置修改Map的序列化逻辑,确保只处理键值对,不序列化Map的内部状态:

@Configuration
public class CosmosDbConfig {
    @Bean
    public MappingMongoConverter mappingMongoConverter(MongoDbFactory dbFactory, MongoMappingContext mappingContext) {
        MappingMongoConverter converter = new MappingMongoConverter(new DefaultDbRefResolver(dbFactory), mappingContext);
        // 配置ObjectMapper,自定义Map序列化
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.registerModule(new SimpleModule()
                .addSerializer(Map.class, new StdSerializer<Map>(Map.class) {
                    @Override
                    public void serialize(Map value, JsonGenerator gen, SerializerProvider provider) throws IOException {
                        gen.writeStartObject();
                        for (Map.Entry<?, ?> entry : value.entrySet()) {
                            gen.writeObjectField(entry.getKey().toString(), entry.getValue());
                        }
                        gen.writeEndObject();
                    }
                }));
        converter.setObjectMapper(objectMapper);
        return converter;
    }
}

之后Tenant类的字段可以直接保留Map<String, List<AppRegistration>>类型,无需额外注解。

方案3:改用List+自定义实体类重构结构

创建一个存储键值对的实体类,用List替代Map,彻底避免HashMap的序列化问题:

// 自定义键值对实体
@Getter @Setter
public class AppRegistrationEntry {
    private String key;
    private List<AppRegistration> registrations;
}

// 修改后的Tenant类
@Document(collection = "tenant")
@Getter @Setter @ToString
public class Tenant extends DateAudit {
    @Id
    private String tenantId=UUID.randomUUID().toString();

    @Indexed(unique = true)
    @Field("name")
    private String name;

    @Field("app_registration_list")
    private List<AppRegistrationEntry> appRegistrationList = new ArrayList<>();
}

这种方式存储的BSON结构更直观,每个元素包含key和registrations字段,完全满足键值对+列表的业务需求。

内容的提问来源于stack exchange,提问作者fireball.1

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 22:05:21