Is there any way for creating Mongo codecs automatically?

余生长醉 提交于 2020-01-01 18:09:25

问题


I'm willing to migrate my code from mongojack to something that supports the new async mongo driver. Yet I find that the new way of encoding/decoding is through Codecs and I don't see myself writing a Codec for every class in my model. That's why I'd rather write a lib that given a class creates a Codec. However I don't know how, nor do I know if there's already some effort out there trying to achieve the same. Are there some libs that achieve what I want? if not, what's the best approach to achieve it.

(I know I should probably use CodecProvider somewhere in there, but I still don't know where to start)


回答1:


Yes, if you use Jackson you can use the mongo-jackson-codec from https://github.com/ylemoigne/mongo-jackson-codec which will handle it automatically for you.




回答2:


Well, I couldn't find any effort pointing in the direction I needed so I started my own. It creates the codecs automatically without the use of intermediate representations such a Document or DBObject. It uses Annotation Processing to create them at compile time.

https://github.com/caeus/vertigo

Hope it works for anyone else with the same needs.




回答3:


Here's how we address this (end result is super slick between Lombok, Jackson and MongoDB):

Provider:

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);

    }
}

And the Codec itself:

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;
    }
}

When combined with Lombok and the latest Jackson annotations, it allows us to do stuff like this (hardly looks like Java code, eh?):

@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 {
    }

}

Then:

Account account = collection.find(eq("_id", id)).first();
System.out.println(account.getOrganizationName());


来源:https://stackoverflow.com/questions/32417267/is-there-any-way-for-creating-mongo-codecs-automatically

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!