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

MongoDB Java驱动POJO序列化/反序列化DBRef报错的解决咨询

解决MongoDB Java驱动POJO反序列化DBRef的UnsupportedOperationException问题

问题原因

MongoDB Java驱动4.x版本自带的DBRefCodec仅支持将DBRef序列化为BSON,但不支持反向的反序列化(从BSON解码为DBRef对象),所以当POJO中定义DBRef类型字段时,查询后反序列化会抛出UnsupportedOperationException: DBRefCodec does not support decoding。


解决方案

方案一:自定义DBRef Codec(推荐,完整支持DBRef序列化/反序列化)

编写自定义的Codec实现DBRef的解码逻辑,然后注册到CodecRegistry中:

  1. 实现自定义DBRef Codec
import com.mongodb.DBRef;
import com.mongodb.client.MongoDatabase;
import org.bson.BsonDocument;
import org.bson.codecs.Codec;
import org.bson.codecs.DecoderContext;
import org.bson.codecs.EncoderContext;
import org.bson.codecs.BsonDocumentCodec;
import org.bson.types.ObjectId;
import org.bson.BsonReader;
import org.bson.BsonWriter;

public class CustomDBRefCodec implements Codec<DBRef> {
    private final DBRefCodec originalCodec;
    private final MongoDatabase database;

    public CustomDBRefCodec(DBRefCodec originalCodec, MongoDatabase database) {
        this.originalCodec = originalCodec;
        this.database = database;
    }

    @Override
    public DBRef decode(BsonReader reader, DecoderContext decoderContext) {
        // 读取DBRef对应的BSON文档
        BsonDocument dbRefDoc = new BsonDocumentCodec().decode(reader, decoderContext);
        String collectionName = dbRefDoc.getString("$ref").getValue();
        ObjectId refId = dbRefDoc.getObjectId("$id");
        // 构造DBRef对象
        return new DBRef(database.getCollection(collectionName), refId);
    }

    @Override
    public void encode(BsonWriter writer, DBRef value, EncoderContext encoderContext) {
        // 复用原生Codec的编码逻辑
        originalCodec.encode(writer, value, encoderContext);
    }

    @Override
    public Class<DBRef> getEncoderClass() {
        return DBRef.class;
    }
}
  1. 注册自定义Codec到POJO CodecRegistry
import com.mongodb.client.MongoClients;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.MongoCollection;
import org.bson.codecs.configuration.CodecRegistries;
import org.bson.codecs.configuration.CodecRegistry;
import org.bson.codecs.pojo.PojoCodecProvider;

public class MongoConfig {
    public static MongoCollection<Recipe> getRecipeCollection() {
        MongoClient mongoClient = MongoClients.create("mongodb://localhost:27017");
        MongoDatabase database = mongoClient.getDatabase("your_database_name");

        // 初始化原生DBRefCodec和自定义Codec
        DBRefCodec originalDBRefCodec = new DBRefCodec(database.getCodecRegistry());
        CustomDBRefCodec customDBRefCodec = new CustomDBRefCodec(originalDBRefCodec, database);

        // 组合CodecRegistry:默认Codec + 自定义DBRefCodec + POJO自动映射
        CodecRegistry codecRegistry = CodecRegistries.fromRegistries(
            MongoClientSettings.getDefaultCodecRegistry(),
            CodecRegistries.fromCodecs(customDBRefCodec),
            CodecRegistries.fromProviders(PojoCodecProvider.builder().automatic(true).build())
        );

        // 应用CodecRegistry到集合
        return database.getCollection("recipe", Recipe.class)
                       .withCodecRegistry(codecRegistry);
    }
}

方案二:改用Document存储DBRef(轻量方案)

将POJO中的DBRef字段替换为Document,在业务逻辑中手动转换为DBRef:

public class Recipe implements Comparable<Recipe> {
    private String id;
    private Document author; // 用Document存储DBRef的BSON结构

    // 手动转换为DBRef的方法
    public DBRef getAuthorDBRef(MongoDatabase database) {
        if (author == null) return null;
        String collection = author.getString("$ref");
        ObjectId id = author.getObjectId("$id");
        return new DBRef(database.getCollection(collection), id);
    }

    // 设置DBRef的方法
    public void setAuthorDBRef(DBRef authorRef) {
        this.author = new Document("$ref", authorRef.getCollectionName())
                        .append("$id", authorRef.getId());
    }

    // 其余代码省略
}

这种方式不需要修改Codec配置,仅在需要使用DBRef时手动转换,适合快速适配场景。


补充说明

之前使用BasicDBObject可以正常工作,是因为BasicDBObject直接操作BSON文档:保存时将DBRef写入为标准的DBRef结构,读取时则作为普通Document返回,不会触发POJO反序列化的Codec校验,因此不会报错。

内容的提问来源于stack exchange,提问作者Tiago Godoy

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 07:55:02