I'm in the process of creating a new application using Micronaut and MongoDB. I have to a bit of stalemate regarding some of my db objects.
I have an object that contains an enum field which I need to convert over to a value that can be saved (I'm planning to persist it as a string).
From what I understand and from the error message I'm getting, I need to create a new codec to handle this (similar to JPA converters). While I have found examples showing this, I'm a bit confused as to how I'm supposed to register the converter for the MongoClient.
I'm using the latest Micronaut version of both the framework and the respective MongoClient.
Below is the exception I'm getting for reference:
org.bson.codecs.configuration.CodecConfigurationException: Can't find a codec for class fts.marketing.models.CampaignEmailStatus.
at org.bson.codecs.configuration.CodecCache.getOrThrow(CodecCache.java:46)
at org.bson.codecs.configuration.ProvidersCodecRegistry.get(ProvidersCodecRegistry.java:63)
at org.bson.codecs.configuration.ProvidersCodecRegistry.get(ProvidersCodecRegistry.java:37)
at com.mongodb.client.model.BuildersHelper.encodeValue(BuildersHelper.java:37)
at com.mongodb.client.model.Filters$SimpleEncodingFilter.toBsonDocument(Filters.java:1109)
at com.mongodb.client.model.Filters$AndFilter.toBsonDocument(Filters.java:946)
at com.mongodb.internal.operation.Operations.createFindOperation(Operations.java:142)
at com.mongodb.internal.operation.Operations.find(Operations.java:130)
at com.mongodb.internal.operation.AsyncOperations.find(AsyncOperations.java:85)
at com.mongodb.async.client.FindIterableImpl.createFindOperation(FindIterableImpl.java:229)
at com.mongodb.async.client.FindIterableImpl.asAsyncReadOperation(FindIterableImpl.java:225)
at com.mongodb.async.client.MongoIterableImpl.batchCursor(MongoIterableImpl.java:161)
at com.mongodb.async.client.MongoIterableSubscription.requestInitialData(MongoIterableSubscription.java:46)
at com.mongodb.async.client.AbstractSubscription.tryRequestInitialData(AbstractSubscription.java:151)
at com.mongodb.async.client.AbstractSubscription.request(AbstractSubscription.java:84)
at com.mongodb.reactivestreams.client.internal.ObservableToPublisher$1$1.request(ObservableToPublisher.java:50)
at io.reactivex.internal.operators.flowable.FlowableToListSingle$ToListSubscriber.onSubscribe(FlowableToListSingle.java:84)
at com.mongodb.reactivestreams.client.internal.ObservableToPublisher$1.onSubscribe(ObservableToPublisher.java:39)
at com.mongodb.async.client.MongoIterableSubscription.<init>(MongoIterableSubscription.java:40)
at com.mongodb.async.client.Observables$1.subscribe(Observables.java:47)
at com.mongodb.reactivestreams.client.internal.ObservableToPublisher.subscribe(ObservableToPublisher.java:36)
at com.mongodb.reactivestreams.client.internal.FindPublisherImpl.subscribe(FindPublisherImpl.java:189)
I think it should be enough to create a class with the codec and have it injectable:
@Singleton
public class EnumCodec implements Codec<CampaignEmailStatus> {
@Override
public CampaignEmailStatus decode(BsonReader reader, DecoderContext decoderContext) {
String enumString = reader.readString();
return CampaignEmailStatus.valueOf(enumString);
}
@Override
public void encode(BsonWriter writer, CampaignEmailStatus value, EncoderContext encoderContext) {
String enumString = value.name();
writer.writeString(enumString);
}
@Override
public Class<CampaignEmailStatus> getEncoderClass() {
return CampaignEmailStatus.class;
}
}
The Mongo driver docs explaining Codecs are here: https://mongodb.github.io/mongo-java-driver/3.11/bson/codecs/
The injection of the codecs happens here
io.micronaut.configuration.mongo.reactive.DefaultReactiveMongoConfiguration#codecs
You should be able to debug it from there if it's not working
PS: I did not test the code above but it should give you an idea