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

Spring Data MongoDB无法获取二级嵌套对象问题求助

Spring MongoDB二级嵌套DocumentReference转换失败问题解决

问题场景

实体类采用二级@DocumentReference关联:

@Data
@Builder
@Document(collection = "emitted")
@JsonInclude(JsonInclude.Include.NON_NULL)
public class Emitter{
    @Id
    private String id;

    @Field("installation")
    @DocumentReference(lazy = true)
    private Installation installation;

    // 其他字段
}
@Data
@Builder
@Document(collection = "installation")
@JsonInclude(JsonInclude.Include.NON_NULL)
public class Installation {
    @Id
    private String id;

    @Field("subject")
    @DocumentReference(lazy = true)
    private Subject subject;
    
    // 其他字段
}
@Data
@Builder
@Document(collection = "subject")
@JsonInclude(JsonInclude.Include.NON_NULL)
public class Subject {
    @Id
    private String id;

    // 其他字段
}

使用MapStruct处理嵌套对象映射避免循环引用,配置如下:

@ObjectFactory
public <T> T map(@NonNull final String id, @TargetType Class<T> type) {
    return mongoTemplate.findById(id, type);
}

现象:一级嵌套的Installation能正常获取,二级嵌套的Subject转换时抛出异常:

Caused by: org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [org.bson.types.ObjectId] to type [com.package.collections.Subject]
...
at org.springframework.data.mongodb.core.MongoTemplate.findById(MongoTemplate.java:922)
at com.package.myapp.services.mapper.ReferenceMapper.map(ReferenceMapper.java:26)
at com.package.myapp.services.mapper.InstallationMapperImpl.toEntity(InstallationMapperImpl.java:102)

解决方案

1. 修改MapStruct的ObjectFactory方法参数类型

二级嵌套时,MongoDB传递的ID是ObjectId对象而非String,原方法仅接受String类型导致转换失败。调整方法兼容ObjectId:

@ObjectFactory
public <T> T map(@NonNull final Object id, @TargetType Class<T> type) {
    String idStr = id instanceof ObjectId ? ((ObjectId) id).toHexString() : id.toString();
    return mongoTemplate.findById(idStr, type);
}

2. 新增ObjectId到实体类的类型转换器

为MapStruct添加专属转换器,处理ObjectId到Subject的转换:

@Converter
public class ObjectIdToSubjectConverter implements Converter<ObjectId, Subject> {
    private final MongoTemplate mongoTemplate;

    public ObjectIdToSubjectConverter(MongoTemplate mongoTemplate) {
        this.mongoTemplate = mongoTemplate;
    }

    @Override
    public Subject convert(ObjectId source) {
        return mongoTemplate.findById(source.toHexString(), Subject.class);
    }
}

在MapStruct的Mapper接口上指定使用该转换器:

@Mapper(componentModel = "spring", uses = {ObjectIdToSubjectConverter.class})
public interface InstallationMapper {
    // 映射方法定义
}

3. 触发懒加载初始化

由于使用了lazy=true,二级嵌套的Subject可能未被初始化。在MapStruct映射前手动触发加载:

// 在映射Installation前调用getSubject()触发懒加载
installation.getSubject();

关键原因

一级嵌套时,MapStruct传递的ID是String类型(Emitter中存储的Installation ID已被转换为String);二级嵌套时,Installation中存储的Subject ID是未转换的ObjectId对象,原MapStruct工厂方法无法处理该类型,导致转换器缺失异常。

内容的提问来源于stack exchange,提问作者Mario Biagioni

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 03:05:28