有什么方法可以自动创建 Mongo 编解码器吗?
Is there any way for creating Mongo codecs automatically?
我愿意将我的代码从 mongojack 迁移到支持新异步 mongo 驱动程序的代码。但是我发现 encoding/decoding 的新方法是通过 Codec
s 并且我不认为自己为我的模型中的每个 class 写一个 Codec
。这就是为什么我宁愿编写一个给定 class 创建 Codec
的库。但是我不知道怎么做,也不知道是否已经有人在努力实现同样的目标。
是否有一些库可以实现我想要的?如果没有,实现它的最佳方法是什么。
(我知道我应该在那里的某个地方使用 CodecProvider
,但我仍然不知道从哪里开始)
是的,如果您使用 Jackson,您可以使用 https://github.com/ylemoigne/mongo-jackson-codec 中的 mongo-jackson-codec,它将自动为您处理。
这是我们解决这个问题的方法(最终结果在 Lombok、Jackson 和 MongoDB 之间非常流畅):
提供商:
public class JacksonCodecProvider implements CodecProvider {
private final ObjectMapper objectMapper;
public JacksonCodecProvider(final ObjectMapper bsonObjectMapper) {
this.objectMapper = bsonObjectMapper;
}
@Override
public <T> Codec<T> get(final Class<T> type, final CodecRegistry registry) {
return new JacksonCodec<>(objectMapper, registry, type);
}
}
编解码器本身:
class JacksonCodec<T> implements Codec<T> {
private final ObjectMapper objectMapper;
private final Codec<RawBsonDocument> rawBsonDocumentCodec;
private final Class<T> type;
public JacksonCodec(ObjectMapper objectMapper,
CodecRegistry codecRegistry,
Class<T> type) {
this.objectMapper = objectMapper;
this.rawBsonDocumentCodec = codecRegistry.get(RawBsonDocument.class);
this.type = type;
}
@Override
public T decode(BsonReader reader, DecoderContext decoderContext) {
try {
RawBsonDocument document = rawBsonDocumentCodec.decode(reader, decoderContext);
String json = document.toJson();
return objectMapper.readValue(json, type);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
@Override
public void encode(BsonWriter writer, Object value, EncoderContext encoderContext) {
try {
String json = objectMapper.writeValueAsString(value);
rawBsonDocumentCodec.encode(writer, RawBsonDocument.parse(json), encoderContext);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
@Override
public Class<T> getEncoderClass() {
return this.type;
}
}
结合 Lombok 和最新的 Jackson 注释,它允许我们做这样的事情(看起来不像 Java 代码,嗯?):
@JsonIgnoreProperties(ignoreUnknown=true)
@JsonDeserialize(builder = Account.AccountBuilder.class)
@Builder(toBuilder=true)
@Value
public class Account {
@JsonProperty private String _id;
@JsonProperty private long _version;
@JsonProperty private String organizationName;
@JsonPOJOBuilder(withPrefix = "")
public static final class AccountBuilder {
}
}
然后:
Account account = collection.find(eq("_id", id)).first();
System.out.println(account.getOrganizationName());
我愿意将我的代码从 mongojack 迁移到支持新异步 mongo 驱动程序的代码。但是我发现 encoding/decoding 的新方法是通过 Codec
s 并且我不认为自己为我的模型中的每个 class 写一个 Codec
。这就是为什么我宁愿编写一个给定 class 创建 Codec
的库。但是我不知道怎么做,也不知道是否已经有人在努力实现同样的目标。
是否有一些库可以实现我想要的?如果没有,实现它的最佳方法是什么。
(我知道我应该在那里的某个地方使用 CodecProvider
,但我仍然不知道从哪里开始)
是的,如果您使用 Jackson,您可以使用 https://github.com/ylemoigne/mongo-jackson-codec 中的 mongo-jackson-codec,它将自动为您处理。
这是我们解决这个问题的方法(最终结果在 Lombok、Jackson 和 MongoDB 之间非常流畅):
提供商:
public class JacksonCodecProvider implements CodecProvider {
private final ObjectMapper objectMapper;
public JacksonCodecProvider(final ObjectMapper bsonObjectMapper) {
this.objectMapper = bsonObjectMapper;
}
@Override
public <T> Codec<T> get(final Class<T> type, final CodecRegistry registry) {
return new JacksonCodec<>(objectMapper, registry, type);
}
}
编解码器本身:
class JacksonCodec<T> implements Codec<T> {
private final ObjectMapper objectMapper;
private final Codec<RawBsonDocument> rawBsonDocumentCodec;
private final Class<T> type;
public JacksonCodec(ObjectMapper objectMapper,
CodecRegistry codecRegistry,
Class<T> type) {
this.objectMapper = objectMapper;
this.rawBsonDocumentCodec = codecRegistry.get(RawBsonDocument.class);
this.type = type;
}
@Override
public T decode(BsonReader reader, DecoderContext decoderContext) {
try {
RawBsonDocument document = rawBsonDocumentCodec.decode(reader, decoderContext);
String json = document.toJson();
return objectMapper.readValue(json, type);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
@Override
public void encode(BsonWriter writer, Object value, EncoderContext encoderContext) {
try {
String json = objectMapper.writeValueAsString(value);
rawBsonDocumentCodec.encode(writer, RawBsonDocument.parse(json), encoderContext);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
@Override
public Class<T> getEncoderClass() {
return this.type;
}
}
结合 Lombok 和最新的 Jackson 注释,它允许我们做这样的事情(看起来不像 Java 代码,嗯?):
@JsonIgnoreProperties(ignoreUnknown=true)
@JsonDeserialize(builder = Account.AccountBuilder.class)
@Builder(toBuilder=true)
@Value
public class Account {
@JsonProperty private String _id;
@JsonProperty private long _version;
@JsonProperty private String organizationName;
@JsonPOJOBuilder(withPrefix = "")
public static final class AccountBuilder {
}
}
然后:
Account account = collection.find(eq("_id", id)).first();
System.out.println(account.getOrganizationName());