Spring Boot+MongoDB中JSON反序列化为POJO失败求助
问题分析与解决方案
核心问题
- 控制器代码冗余且错误:你手动用Jackson序列化再反序列化
repository.findAll()的结果,不仅完全多余(Spring MVC会自动处理JSON序列化),还错误地将Collection<UserPreferences>反序列化为单个UserPreferences对象,导致返回类型不匹配。 - MongoDB抽象类映射缺失:
Preference是抽象类,Spring Data MongoDB默认无法识别存储在Mongo中的文档对应的子类——Jackson的多态注解仅作用于JSON序列化/反序列化,对Mongo的文档映射无效,因此读取时出现String转Preference的转换器错误。
修复步骤
第一步:修正控制器代码
移除多余的手动序列化逻辑,直接返回Repository查询结果:
@GetMapping Collection<UserPreferences> allPreferences() { return repository.findAll(); }
第二步:解决MongoDB抽象类多态映射问题
提供两种可行方案,任选其一即可:
方案1:使用Spring Data MongoDB的类型别名配置
- 给
Preference的子类添加@TypeAlias注解,对应Jackson的name值:
import org.springframework.data.mongodb.core.mapping.TypeAlias; @TypeAlias("movie") public class MoviePreference extends Preference { // 子类字段、构造方法、getter/setter } @TypeAlias("genre") public class GenrePreference extends Preference { // 子类字段、构造方法、getter/setter }
- 配置Mongo映射上下文,启用类型信息存储:
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.mongodb.core.convert.DefaultDbRefResolver; import org.springframework.data.mongodb.core.convert.DefaultMongoTypeMapper; import org.springframework.data.mongodb.core.convert.MappingMongoConverter; import org.springframework.data.mongodb.core.mapping.MongoMappingContext; @Configuration public class MongoConfig { @Bean public MappingMongoConverter mappingMongoConverter(MongoMappingContext context, MongoDatabaseFactory databaseFactory, MongoCustomConversions conversions) { MappingMongoConverter converter = new MappingMongoConverter( new DefaultDbRefResolver(databaseFactory), context); converter.setCustomConversions(conversions); // 让Mongo在文档中存储类型别名信息,用于反序列化时识别子类 converter.setTypeMapper(new DefaultMongoTypeMapper("_class")); return converter; } }
方案2:自定义Mongo转换器
手动实现Mongo文档与Preference子类的转换逻辑:
- 编写读取转换器(从Mongo文档转Preference):
import org.bson.Document; import org.springframework.core.convert.converter.Converter; import org.springframework.data.convert.ReadingConverter; import org.springframework.stereotype.Component; @Component @ReadingConverter public class PreferenceReadConverter implements Converter<Document, Preference> { @Override public Preference convert(Document source) { String type = source.getString("type"); return switch (type) { case "movie" -> source.to(MoviePreference.class); case "genre" -> source.to(GenrePreference.class); default -> throw new IllegalArgumentException("未知偏好类型: " + type); }; } }
- 编写写入转换器(从Preference转Mongo文档):
import org.bson.Document; import org.springframework.core.convert.converter.Converter; import org.springframework.data.convert.WritingConverter; import org.springframework.stereotype.Component; @Component @WritingConverter public class PreferenceWriteConverter implements Converter<Preference, Document> { @Override public Document convert(Preference source) { Document doc = new Document(); if (source instanceof MoviePreference) { doc.put("type", "movie"); doc.putAll(new Document().from(source)); } else if (source instanceof GenrePreference) { doc.put("type", "genre"); doc.putAll(new Document().from(source)); } return doc; } }
为什么POST正常而GET失败?
POST请求时,JSON数据通过Jackson的多态注解(@JsonTypeInfo/@JsonSubTypes)正确反序列化为Preference子类,然后Spring Data MongoDB直接将对象写入数据库;但GET请求时,MongoDB返回的文档没有被Spring Data MongoDB识别为对应子类(缺少Mongo层面的多态映射配置),因此出现转换器错误。
内容的提问来源于stack exchange,提问作者maurice
相关产品推荐
相关产品推荐

