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 Codec
s 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)
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());
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With