【问题标题】:Is there any way for creating Mongo codecs automatically?有什么方法可以自动创建 Mongo 编解码器?
【发布时间】:2015-09-05 20:12:05
【问题描述】:

我愿意将我的代码从 mongojack 迁移到支持新的异步 mongo 驱动程序的东西。然而我发现编码/解码的新方法是通过Codecs,我没有看到自己为模型中的每个类都写Codec。这就是为什么我宁愿写一个给定类的库创建一个Codec。但是我不知道如何,也不知道是否已经有一些努力试图实现同样的目标。 是否有一些库可以实现我想要的?如果没有,实现它的最佳方法是什么。

(我知道我应该在那里的某个地方使用CodecProvider,但我仍然不知道从哪里开始)

【问题讨论】:

  • 我不确定编解码器是做什么的,但你看过 Spring Data 映射器吗?
  • 我确实有,但这不是我需要的。新的 mongo java 驱动程序(版本 3+)使我们有机会通过 Codecs 将响应直接解析到我们的域类,而无需使用中间表示(DBObject)。但是您必须自己编写它们(mongodb.github.io/mongo-java-driver/3.0/bson/codecs)。我正在寻找一些自动编写这些编解码器的库,所以我不必手动进行。

标签: java mongodb asynchronous codec


【解决方案1】:

以下是我们解决此问题的方法(最终结果在 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());

【讨论】:

  • 这对我来说非常有效。这不是通过 Maven 打包和分发的好选择吗?我找不到可用的等价物。
【解决方案2】:

是的,如果您使用 Jackson,您可以使用来自 https://github.com/ylemoigne/mongo-jackson-codec 的 mongo-jackson-codec,它将自动为您处理。

【讨论】:

  • 警告:截至撰写本文时(2016 年 10 月 4 日),这个 mongo-jackson-codec 库有一个严重的缺陷,它只能弥合 mongo 编解码器和jackson 通过完整文档,即它不能在根级别序列化非文档 BSON 值。在您的findupdate 命令(使用本机Mongo Java 驱动程序时)中构建查询Bson 文档时,尝试使用Jackson 编解码器序列化java.time.Instant 等值时,此限制将发挥作用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-08-01
  • 2011-09-06
  • 2012-09-29
  • 2022-01-26
  • 1970-01-01
  • 2016-10-01
  • 1970-01-01
相关资源
最近更新 更多