MongoDB更新含抽象类的集合时触发MappingInstantiationException问题
问题解决:MongoDB更新抽象子类包装对象时无法实例化抽象类报错
错误信息
"Failed to instantiate com.models.Task using constructor public com.models.Task() with arguments "
类定义
WrapperTask
@Data @Document(collection="tasks") public class WrapperTask { @Id private ObjectId id; @BsonProperty(useDiscriminator = true) private Task task; public WrapperTask() { } public String getId() { return Utils.ObjectId(this.id); } }
抽象类Task
@Data @JsonTypeInfo( use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type") @JsonSubTypes({ @Type(value = UploadTask.class, name = "uploadTask"), //more classes }) @BsonDiscriminator public abstract class Task { private TaskStatus status; public int totalCount; public int completedCount; public Task() { this.status = TaskStatus.NEW; } }
子类UploadTask
@Data @EqualsAndHashCode(callSuper = true) @Document(collection = "tasks") @TypeAlias("uploadTask") @BsonDiscriminator public class UploadTask extends Task { private LinkedList<Document> documents = new LinkedList<>(); public UploadTask(int totalCount) { super(); this.totalCount = totalCount; } public UploadTask() { super(); } }
更新逻辑
Query query = new Query(Criteria.where("_id").is(taskId)); Update update = new Update(); update = update.set("task.status", "some status"); if (taskType == UploadTask.class) { Criteria criteria = Criteria.where("document.index").is(index); update = update.set("task.documents.$[document].status", "some status"); update = update.set("task.documents.$[document].statusMessage", "some message").filterArray(criteria); } mongoOperations.findAndModify(query, update, options().upsert(false), WrapperTask.class);
解决方案
核心原因
报错本质是findAndModify方法会返回更新后的文档,Spring Data MongoDB在反序列化文档时,试图实例化抽象类Task——但抽象类无法被实例化。问题出在反序列化阶段,而非更新操作本身。
方案1:改用不返回结果的更新方法(推荐)
如果业务不需要获取更新后的对象,直接使用updateFirst替代findAndModify,避免触发反序列化流程:
mongoOperations.updateFirst(query, update, WrapperTask.class);
方案2:修复反序列化的鉴别器配置(需返回对象时使用)
如果必须获取更新后的对象,需要确保Spring Data MongoDB能根据鉴别器字段正确识别子类:
- 修正抽象类
Task的鉴别器配置:显式指定鉴别器字段名,与JSON序列化的type字段保持一致:@BsonDiscriminator(key = "type") // 明确指定鉴别器字段为"type" @JsonTypeInfo( use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type") @JsonSubTypes({ @Type(value = UploadTask.class, name = "uploadTask"), // 其他子类 }) public abstract class Task { // ... 原有代码 } - 移除子类的
@Document注解:子类是嵌入在WrapperTask中的对象,不需要单独标注@Document:@Data @EqualsAndHashCode(callSuper = true) @TypeAlias("uploadTask") @BsonDiscriminator public class UploadTask extends Task { // ... 原有代码 } - 验证MongoDB文档结构:确保集合中
task字段下存在type字段(如"type": "uploadTask"),Spring会根据该字段实例化对应的子类而非抽象类。
内容的提问来源于stack exchange,提问作者Luis Lavieri
相关产品推荐
相关产品推荐

