Spring Boot Rest Controller返回JSON时仅返回HashMap属性最后一个条目问题排查
Spring Boot Rest Controller返回JSON时仅返回HashMap属性最后一个条目问题排查
兄弟,我之前也踩过类似的坑!先给你捋清楚问题根源和解决办法:
问题根源
你碰到的不是Spring Boot Controller的限制,而是Jackson(Spring Boot默认的JSON序列化库)处理自定义对象作为Map键时的默认行为导致的:
- 当Map的键是自定义对象时,Jackson默认会调用该对象的
toString()方法生成JSON中的键字符串。 - 你提到键对象里的嵌套对象和枚举属性相同,但其他属性不同——如果你的
toString()方法只包含了这两个重复的属性,或者这两个属性的toString()输出一致,Jackson就会把这些键判定为重复的,后面的条目会直接覆盖前面的,最后就只剩最后一个条目了。 - 哪怕你的自定义键在Java层面通过
equals()和hashCode()能正确区分(所以Repository返回的Map是正常的),但Jackson序列化时只认toString()的结果,这就出现了“Java里正常,JSON里丢数据”的矛盾。
解决方案
给你几个可行的解决方向,按需选择:
1. 修正自定义键对象的toString()方法
确保toString()包含所有能唯一标识该键的属性,让不同的键生成的字符串完全不同。比如你的键对象有nestedObj、enumVal、uniqueProp三个属性,那toString()要把这三个都加进去:
@Override public String toString() { return "MyKey{" + "nestedObj=" + nestedObj + ", enumVal=" + enumVal + ", uniqueProp='" + uniqueProp + '\'' + '}'; }
同时别忘了同步修正equals()和hashCode(),确保Java层面的键唯一性也没问题(虽然你说Repository返回正常,但检查下更稳妥)。
2. 自定义Jackson键序列化器
如果不想修改toString(),可以给自定义键对象配置专属的序列化器,控制Jackson如何生成键字符串。比如写一个KeySerializer的实现:
public class MyKeySerializer extends StdSerializer<MyKey> { public MyKeySerializer() { super(MyKey.class); } @Override public void serialize(MyKey value, JsonGenerator gen, SerializerProvider provider) throws IOException { // 把所有唯一属性拼接成一个唯一字符串,比如用JSON格式包裹 String keyStr = String.format("{\"nestedObj\":\"%s\",\"enumVal\":\"%s\",\"uniqueProp\":\"%s\"}", value.getNestedObj(), value.getEnumVal(), value.getUniqueProp()); gen.writeFieldName(keyStr); } }
然后在键对象上加上注解:
@JsonSerialize(keyUsing = MyKeySerializer.class) public class MyKey { // ... 你的属性和方法 }
3. 替换为String类型的Map键
如果业务允许,在Service层把自定义对象键转换成唯一的字符串(比如拼接所有唯一属性、生成哈希值或者UUID),直接用Map<String, List>代替Map<Object, List>。这种方式最直接,能从根源上避免自定义键的序列化问题。
总结
这个问题本质是JSON序列化时的键处理逻辑导致的,和Spring Boot Controller本身无关。只要调整Jackson对自定义键的序列化方式,或者修正键对象的标识方法,就能让所有Map条目正常出现在JSON响应里啦!
备注:内容来源于stack exchange,提问作者abdlost
相关产品推荐
相关产品推荐

