Skip to content

Commit

Permalink
Prefer to load custom property codec providers before default codec p…
Browse files Browse the repository at this point in the history
…roviders. (#3038)

* Prefer to load custom property codec providers before default codec providers.

---------

Co-authored-by: Justin Lee <evanchooly@users.noreply.github.com>
  • Loading branch information
danielmerchant and evanchooly committed May 23, 2024
1 parent dec7d40 commit 23b0583
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,14 @@ public MorphiaCodecProvider(Datastore datastore) {
this.datastore = datastore;
this.mapper = datastore.getMapper();

propertyCodecProviders.addAll(List.of(new MorphiaMapPropertyCodecProvider(),
new MorphiaCollectionPropertyCodecProvider()));

// Load user-provided custom codecs first, to prevent the defaults from overriding them.
ServiceLoader<MorphiaPropertyCodecProvider> providers = ServiceLoader.load(MorphiaPropertyCodecProvider.class);
providers.forEach(provider -> {
propertyCodecProviders.add(provider);
});

propertyCodecProviders.addAll(List.of(new MorphiaMapPropertyCodecProvider(),
new MorphiaCollectionPropertyCodecProvider()));
}

protected Map<Class<?>, Codec<?>> getCodecs() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package dev.morphia.mapping.codec;

import java.util.List;

import dev.morphia.Datastore;
import dev.morphia.test.TestBase;

import org.bson.codecs.pojo.PropertyCodecProvider;
import org.testng.annotations.Test;

import static org.testng.AssertJUnit.assertEquals;
import static org.testng.AssertJUnit.assertTrue;

public class MorphiaCodecProviderTest extends TestBase {

@Test
public void ensureCustomCodedProvidersComeFirst() {
// given a custom 'no-op' codec is provided in the service configuration
// (see META-INF/services/dev.morphia.mapping.codec.MorphiaPropertyCodecProvider)
// when we instantiate a morphia codec provider
Datastore datastore = getDs();
MorphiaCodecProvider provider = new MorphiaCodecProvider(datastore);

// then we expect that the custom provider we provided is the first codec in the list
List<PropertyCodecProvider> providers = provider.getPropertyCodecProviders();
assertEquals(providers.size(), 3);
assertTrue(providers.get(0) instanceof NoOpMorphiaPropertyCodecProvider);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package dev.morphia.mapping.codec;

import org.bson.BsonReader;
import org.bson.BsonWriter;
import org.bson.codecs.Codec;
import org.bson.codecs.DecoderContext;
import org.bson.codecs.EncoderContext;
import org.bson.codecs.pojo.PropertyCodecRegistry;
import org.bson.codecs.pojo.TypeWithTypeParameters;

public class NoOpMorphiaPropertyCodecProvider extends MorphiaPropertyCodecProvider {

@Override
public <T> Codec<T> get(TypeWithTypeParameters<T> typeWithTypeParameters,
PropertyCodecRegistry propertyCodecRegistry) {
if (NoOpClass.class.isAssignableFrom(typeWithTypeParameters.getType())) {
return (Codec<T>) new NoOpCodec();
}

return null;
}

static class NoOpCodec implements Codec<NoOpClass> {

@Override
public NoOpClass decode(BsonReader bsonReader, DecoderContext decoderContext) {
return null;
}

@Override
public void encode(BsonWriter bsonWriter, NoOpClass unused, EncoderContext encoderContext) {

}

@Override
public Class<NoOpClass> getEncoderClass() {
return NoOpClass.class;
}
}

static class NoOpClass {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
dev.morphia.mapping.codec.NoOpMorphiaPropertyCodecProvider

0 comments on commit 23b0583

Please sign in to comment.