对于 AI 代理:可在 https://www.mongodb.com/zh-cn/docs/llms.txt 获取文档索引—通过在任何 URL 路径后添加 .md 可获取所有页面的 Markdown 版本。
Docs 菜单

使用类型编解码器对数据进行编码

在本指南中,您可以了解编解码器和支持类,这些类在 MongoDB Java 驱动程序中处理 Java 对象与 BSON 数据之间的编码和解码。Codec 抽象类允许您将任何 Java 类型映射到相应的 BSON 类型。您可以用它来将域对象直接映射到 BSON,或从 BSON 直接映射到域对象,而无需使用 DocumentBsonDocument 等基于中间映射的对象。

可以了解如何使用 Codec 抽象类来指定自定义编码和解码逻辑,并在以下部分中查看示例实施:

如果您要为普通的旧 Java 对象 (POJO) 自定义编码和解码逻辑,请阅读我们的 POJO 自定义指南。

Codec 接口包含用于将 Java 对象序列化和反序列化为 BSON 数据的抽象方法。您可以在该接口的实现中定义 BSON 和 Java 对象之间的转换逻辑。

要实现 Codec 接口,请覆盖 encode()decode()getEncoderClass() 抽象方法。

encode() 方法需要使用以下参数:

Parameter Type
说明

writer

实施 BsonWriter 的类的实例,该接口类型公开用于编写 BSON 文档的方法。例如,BsonBinaryWriter 实施写入二进制数据流。使用此实例通过适当的写入方法写入 BSON 值。

value

实施所编码的数据。该类型必须与分配给您的实施的类型变量相匹配。

encoderContext

包含编码为 BSON 的 Java 对象数据的相关元信息,包括是否将当前值存储在 MongoDB 集合中。

此方法使用 BsonWriter 实例将编码值发送到 MongoDB,并且不返回值。

decode() 方法返回使用 BSON 数据中的值填充的 Java 对象实例。此方法需要以下参数:

Parameter Type
说明

bsonReader

实现 BsonReader 的类的实例,该接口类型公开用于读取 BSON 文档的方法。例如,BsonBinaryReader 实施从二进制数据流中读取。

decoderContext

包含有关解码为 Java 对象的 BSON 数据的信息。

getEncoderClass() 方法返回该 Java 类的一个类实例,因为 Java 由于类型擦除而无法推断类型。

请参阅以下代码示例,这些示例展示了如何实施自定义 Codec

PowerStatus 枚举包含值“打开”和“关闭”来表示电气开关的状态。

public enum PowerStatus {
ON,
OFF
}

PowerStatusCodec 类实现 Codec,以便将 Java enum 值转换为相应的 BSON 布尔值。encode() 方法将 PowerStatus 转换为 BSON 布尔值,decode() 方法则执行相反方向的转换。

public class PowerStatusCodec implements Codec<PowerStatus> {
@Override
public void encode(BsonWriter writer, PowerStatus value, EncoderContext encoderContext) {
if (value != null) {
writer.writeBoolean(value.equals(PowerStatus.ON) ? Boolean.TRUE : Boolean.FALSE);
}
}
@Override
public PowerStatus decode(BsonReader reader, DecoderContext decoderContext) {
return reader.readBoolean() ? PowerStatus.ON : PowerStatus.OFF;
}
@Override
public Class<PowerStatus> getEncoderClass() {
return PowerStatus.class;
}
}

您可以将 PowerStatusCodec 实例添加到 CodecRegistry,其中包含 Codec 与其所应用的 Java 对象类型之间的映射。继续访问本页的 CodecRegistry 部分,看看如何包含您的 Codec

有关此部分中的类和接口的更多信息,请参阅以下 API 文档:

CodecRegistryCodec 实例的不可变集合,这些实例对其指定的 Java 类进行编码和解码。您可以使用以下任一 CodecRegistries 类静态工厂方法,从关联类型中包含的 Codec 实例构造 CodecRegistry

  • fromCodecs()

  • fromProviders()

  • fromRegistries()

以下代码片段演示如何使用 fromCodecs() 方法构造 CodecRegistry

CodecRegistry codecRegistry = CodecRegistries.fromCodecs(new IntegerCodec(), new PowerStatusCodec());

在前面的示例中,我们为 CodecRegistry 分配以下 Codec 实施:

  • IntegerCodec,一个用于转换 IntegersCodec,并且是 BSON 软件包的一部分。

  • PowerStatusCodec,我们的示例 Codec 用于将某些 Java 字符串转换为 BSON 布尔值。

您可以使用以下代码从上一示例中的 CodecRegistry 实例中检索 Codec 实例:

Codec<PowerStatus> powerStatusCodec = codecRegistry.get(PowerStatus.class);
Codec<Integer> integerCodec = codecRegistry.get(Integer.class);

如果您尝试检索未注册的类的 Codec 实例,则 get() 方法会引发 CodecConfigurationException 异常。

有关此部分中的类和接口的更多信息,请参阅以下 API 文档:

CodecProvider 是接口,其中包含创建 Codec 实例并将其分配给 CodecRegistry 实例的抽象方法。与 CodecRegistry 类似,BSON 库使用 get() 方法检索的 Codec 实例在 Java 和 BSON 数据类型之间进行转换。

但是,如果你添加的类包含需要对应 Codec 对象的字段,则需要确保在实例化该类的 Codec 之前为类字段实例化 Codec 对象。你可以使用 get() 方法中的 CodecRegistry 参数传递 Codec 依赖的任何 Codec 实例。

以下代码示例展示了如何实现 CodecProvider 以将其在CodecRegistry 实例(例如前面示例中的 PowerStatusCodec)所需的任何 Codec 实例传递给MonolightCodec

public class MonolightCodecProvider implements CodecProvider {
public MonolightCodecProvider() {}
@Override
@SuppressWarnings("unchecked")
public <T> Codec<T> get(Class<T> clazz, CodecRegistry registry) {
if (clazz == Monolight.class) {
return (Codec<T>) new MonolightCodec(registry);
}
// return null when not a provider for the requested class
return null;
}
}

要查看演示使用这些 Codec 类进行读写操作的可运行示例,请参阅本指南的自定义编解码器示例一节。

使用 POJO 时,请考虑使用 PojoCodecProvider 最大限度地减少重复代码,以转换常用数据类型并自定义其行为。有关更多信息,请参阅我们的“POJO 定制”指南

默认编解码器注册表是一组 CodecProvider 类,用于指定常用 Java 和 MongoDB 类型之间的转换。除非您指定不同的注册表,否则驱动程序会自动使用默认的编解码器注册表。

如果你需要覆盖一个或多个 Codec 类的行为,但保留其他类的默认编解码器注册表中的行为,则可以按优先顺序指定所有注册表。例如,假设你想要使用自定义 MyEnumCodec 替换枚举类型的 Codec 的默认提供商行为,则必须将其添加到默认编解码器注册表之前的注册表列表中,如以下示例所示:

CodecRegistry newRegistry = CodecRegistries.fromRegistries(
CodecRegistries.fromCodecs(new MyEnumCodec()),
MongoClientSettings.getDefaultCodecRegistry());

有关此部分中的类和接口的更多信息,请参阅以下 API 文档部分:

BsonTypeClassMap 类包含 BSON 和 Java 类型之间的推荐映射。可以在自定义 CodecCodecProvider 中使用此类来帮助管理哪些 Java 类型可将 BSON 类型解码为能够实现 IterableMap 的容器类,例如 Document 类。

您可以通过传递包含新条目或替换条目的 Map 来添加或修改 BsonTypeClassMap 默认映射。

以下代码片段显示了如何检索与默认 BsonTypeClassMap 实例中的 BSON 类型相对应的 Java 类类型:

BsonTypeClassMap bsonTypeClassMap = new BsonTypeClassMap();
Class<?> clazz = bsonTypeClassMap.get(BsonType.ARRAY);
System.out.println("Java type: " + clazz.getName());

此代码输出以下内容:

Java type: java.util.List

可以通过在 BsonTypeClassMap 构造函数中指定替换项来修改实例中的这些映射。以下代码段展示了如何将 BsonTypeClassMap 实例中的 ARRAY 的映射替换为 Set 类:

Map<BsonType, Class<?>> replacements = new HashMap<BsonType, Class<?>>();
replacements.put(BsonType.ARRAY, Set.class);
BsonTypeClassMap bsonTypeClassMap = new BsonTypeClassMap(replacements);
Class<?> clazz = bsonTypeClassMap.get(BsonType.ARRAY);
System.out.println("Java type: " + clazz.getName());

此代码输出以下内容:

Java type: java.util.Set

请参阅 BsonTypeClassMap API 文档,获取默认映射的完整列表。

有关 Document 类如何使用 BsonTypeClassMap 的示例,请参阅以下类的驱动程序源代码:

在本部分中,我们将展示如何实施 CodecCodecProvider 来定义自定义 Java 类的编码和解码逻辑。我们还展示了如何指定和使用自定义实施来执行插入和检索操作。

以下代码片段显示名为 Monolight 的示例自定义类以及我们要在 MongoDB 集合中存储和检索的字段:

public class Monolight {
private PowerStatus powerStatus = PowerStatus.OFF;
private Integer colorTemperature;
public Monolight() {}
// ...

此类包含以下字段,我们需要为每个字段分配一个 Codec

  • powerStatus 描述灯是“开”还是“关”,为此我们使用 PowerStatusCodec 将特定枚举值转换为 BSON 布尔值。

  • colorTemperature 描述灯光的颜色并包含一个 Integer 值,我们使用 BSON 库中包含的 IntegerCodec 对该值进行解码。

以下代码示例展示如何为 Monolight 类实施 Codec。请注意,构造函数需要一个 CodecRegistry 实例,从中检索对其字段进行编码和解码所需的 Codec 实例:

public class MonolightCodec implements Codec<Monolight>{
private Codec<PowerStatus> powerStatusCodec;
private Codec<Integer> integerCodec;
public MonolightCodec(CodecRegistry registry) {
this.powerStatusCodec = registry.get(PowerStatus.class);
this.integerCodec = registry.get(Integer.class);
}
// Defines an encode() method to convert Monolight enum values to BSON values
@Override
public void encode(BsonWriter writer, Monolight value, EncoderContext encoderContext) {
writer.writeStartDocument();
writer.writeName("powerStatus");
powerStatusCodec.encode(writer, value.getPowerStatus(), encoderContext);
writer.writeName("colorTemperature");
integerCodec.encode(writer, value.getColorTemperature(), encoderContext);
writer.writeEndDocument();
}
// Defines a decode() method to convert BSON values to Monolight enum values
@Override
public Monolight decode(BsonReader reader, DecoderContext decoderContext) {
Monolight monolight = new Monolight();
reader.readStartDocument();
while (reader.readBsonType() != BsonType.END_OF_DOCUMENT) {
String fieldName = reader.readName();
if (fieldName.equals("powerStatus")) {
monolight.setPowerStatus(powerStatusCodec.decode(reader, decoderContext));
} else if (fieldName.equals("colorTemperature")) {
monolight.setColorTemperature(integerCodec.decode(reader, decoderContext));
} else if (fieldName.equals("_id")){
reader.readObjectId();
}
}
reader.readEndDocument();
return monolight;
}
// Returns an instance of the Monolight class, since Java cannot infer the class type
@Override
public Class<Monolight> getEncoderClass() {
return Monolight.class;
}
}

为了确保字段的 Codec 实例可用于 Monolight,我们实施了以下代码示例中所示的自定义 CodecProvider

public class MonolightCodecProvider implements CodecProvider {
public MonolightCodecProvider() {}
@Override
@SuppressWarnings("unchecked")
public <T> Codec<T> get(Class<T> clazz, CodecRegistry registry) {
if (clazz == Monolight.class) {
return (Codec<T>) new MonolightCodec(registry);
}
// return null when not a provider for the requested class
return null;
}
}

定义转换逻辑后,我们可以执行以下操作:

  • 将来自 Monolight 实例的数据存储到 MongoDB 中

  • 将 MongoDB 中的数据提到实例 Monolight

以下示例类中包含的代码通过将 MonolightCodecProvider 传递给 withCodecRegistry() 方法,从而将其赋值给 MongoCollection 实例。该示例类还使用 Monolight 类和关联的编解码器插入和检索数据:

public class MonolightCodecExample {
public static void main(String[] args) {
String uri = "<MongoDB connection URI>";
try (MongoClient mongoClient = MongoClients.create(uri)) {
CodecRegistry codecRegistry = CodecRegistries.fromRegistries(
CodecRegistries.fromCodecs(new IntegerCodec(), new PowerStatusCodec()),
CodecRegistries.fromProviders(new MonolightCodecProvider()),
MongoClientSettings.getDefaultCodecRegistry());
MongoDatabase database = mongoClient.getDatabase("codecs_example_products");
MongoCollection<Monolight> collection = database.getCollection("monolights", Monolight.class).withCodecRegistry(codecRegistry);
// construct and insert an instance of Monolight
Monolight myMonolight = new Monolight();
myMonolight.setPowerStatus(PowerStatus.ON);
myMonolight.setColorTemperature(5200);
collection.insertOne(myMonolight);
// retrieve one or more instances of Monolight
List<Monolight> lights = new ArrayList<>();
collection.find().into(lights);
System.out.println(lights);
}
}
}

运行前一示例应能看到以下输出:

[Monolight [powerStatus=ON, colorTemperature=5200]]

有关本节中提到的方法和类的详情,请参阅以下 API 文档: