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
相关产品推荐
相关产品推荐

