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

将BsonDocument转为指定Java类对象时解码异常的排查求助

问题排查:Mongo BsonDocument转POJO解码异常

异常信息

An exception occurred when decoding using the AutomaticPojoCodec.
Decoding into a 'CustomObject' failed with the following exception:

Failed to decode 'CustomObject'. Decoding 'name' errored with: readStartDocument can only be called when CurrentBSONType is DOCUMENT, not when CurrentBSONType is STRING.

A custom Codec or PojoCodec may need to be explicitly configured and registered to handle this type.

对应的Mongo文档结构

{
    "_id" : "6776734a086ac4106c0ca431",
    "custom_enum_field" : "custom_enum_1",
    "private_float_field" : 1.001,
    "private_int_field" : NumberLong(7),
    "int_field" : NumberLong(1),
    "string_field" : "text 4",
    "enum_field" : "ENUM2",
    "custom_object" : {
        "name" : "blah",
        "value" : "text",
        "id" : NumberInt(182761),
        "price" : 199.99,
        "discount" : 10.2,
        "quantity" : NumberLong(12882763230),
        "list" : null,
        "customSubObjectList" : [
            {
                "name" : "blah",
                "value" : "text",
                "id" : NumberInt(182761),
                "price" : 199.99,
                "discount" : 10.2,
                "quantity" : NumberInt(1288276323)
            }
        ],
        "dob" : NumberLong(1735816009154)
    },
    "bit_field" : true
}

目标Java类定义

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class CustomObject {
    private String name;
    private String value;
    private Integer id;
    private Float price;
    private Double discount;
    private Long quantity;
    private List<String> list;
    private List<CustomSubObject> customSubObjectList;
    private Date dob;
}

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
class CustomSubObject {
    private String name;
    private String value;
    private Integer id;
    private Float price;
    private Double discount;
    private Long quantity;
}

当前转换代码

private <T> T convertByteInDataForObject(ByteString data, Class<T> toType) {
    byte[] bsonBytes = data.toByteArray();
    ByteBuffer byteBuffer = ByteBuffer.wrap(bsonBytes);
    ByteBufferBsonInput bsonInput = new ByteBufferBsonInput(new ByteBufNIO(byteBuffer));
    BsonBinaryReader reader = new BsonBinaryReader(bsonInput);
    BsonDocumentCodec codec = new BsonDocumentCodec();
    BsonDocument bsonDocument = codec.decode(reader, DecoderContext.builder().build());

    CodecRegistry pojoCodecRegistry = CodecRegistries.fromRegistries(CodecRegistries.fromProviders(PojoCodecProvider.builder().automatic(true).build()));
    return pojoCodecRegistry.get(toType).decode(new BsonDocumentReader(bsonDocument), DecoderContext.builder().build());
}

问题根源

错误核心是:你把整个Mongo根文档直接解码为CustomObject,但根文档的_id是字符串类型,解码器试图将其映射到CustomObject的name字段时,发现类型不匹配——它期望读取一个文档结构,实际读到的是字符串,因此抛出异常。真正对应CustomObject的是根文档里的custom_object子字段。

修复方案

1. 提取正确的子文档

修改转换代码,从根BsonDocument中取出custom_object对应的子文档,再进行解码。同时加入Mongo默认CodecRegistry,增强类型支持。

2. 调整Java类的潜在问题

  • 将CustomSubObject改为public访问权限,避免反射实例化失败
  • 建议把CustomObject和CustomSubObject的price字段从Float改为Double,和Mongo中的数值类型完全匹配,避免精度损失

修复后的转换代码

private <T> T convertByteInDataForObject(ByteString data, Class<T> toType) {
    byte[] bsonBytes = data.toByteArray();
    ByteBuffer byteBuffer = ByteBuffer.wrap(bsonBytes);
    ByteBufferBsonInput bsonInput = new ByteBufferBsonInput(new ByteBufNIO(byteBuffer));
    BsonBinaryReader reader = new BsonBinaryReader(bsonInput);
    BsonDocumentCodec codec = new BsonDocumentCodec();
    BsonDocument rootBsonDoc = codec.decode(reader, DecoderContext.builder().build());

    // 提取对应CustomObject的子文档
    BsonDocument targetBsonDoc = rootBsonDoc.getDocument("custom_object");

    // 加入默认CodecRegistry,增强原生类型支持
    CodecRegistry pojoCodecRegistry = CodecRegistries.fromRegistries(
        MongoClientSettings.getDefaultCodecRegistry(),
        CodecRegistries.fromProviders(PojoCodecProvider.builder().automatic(true).build())
    );
    return pojoCodecRegistry.get(toType).decode(new BsonDocumentReader(targetBsonDoc), DecoderContext.builder().build());
}

调整后的Java类(关键修改)

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class CustomObject {
    private String name;
    private String value;
    private Integer id;
    // 改为Double匹配Mongo类型
    private Double price;
    private Double discount;
    private Long quantity;
    private List<String> list;
    private List<CustomSubObject> customSubObjectList;
    private Date dob;
}

// 修改为public访问权限
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class CustomSubObject {
    private String name;
    private String value;
    private Integer id;
    // 改为Double匹配Mongo类型
    private Double price;
    private Double discount;
    private Long quantity;
}

内容的提问来源于stack exchange,提问作者faisal pathan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 05:34:54