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

Spring Boot+MongoDB中JSON反序列化为POJO失败求助

问题分析与解决方案

核心问题

  1. 控制器代码冗余且错误:你手动用Jackson序列化再反序列化repository.findAll()的结果,不仅完全多余(Spring MVC会自动处理JSON序列化),还错误地将Collection<UserPreferences>反序列化为单个UserPreferences对象,导致返回类型不匹配。
  2. MongoDB抽象类映射缺失:Preference是抽象类,Spring Data MongoDB默认无法识别存储在Mongo中的文档对应的子类——Jackson的多态注解仅作用于JSON序列化/反序列化,对Mongo的文档映射无效,因此读取时出现String转Preference的转换器错误。

修复步骤

第一步:修正控制器代码

移除多余的手动序列化逻辑,直接返回Repository查询结果:

@GetMapping
Collection<UserPreferences> allPreferences() {
    return repository.findAll();
}

第二步:解决MongoDB抽象类多态映射问题

提供两种可行方案,任选其一即可:

方案1:使用Spring Data MongoDB的类型别名配置

  1. 给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
}
  1. 配置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子类的转换逻辑:

  1. 编写读取转换器(从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);
        };
    }
}
  1. 编写写入转换器(从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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 12:15:18