Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
ConverterFactroy wrapping MongoDB CodecRegistry to delegate conversions
/**
* @author Christoph Strobl
*/
public class CodecDelegatingMongoConverterTests {
MappingMongoConverter converter;
@Before
public void setUp() {
CodecRegistry reg = CodecRegistries.fromCodecs(new FooCodec());
MongoClient client = new MongoClient("localhost:27017", MongoClientOptions.builder().codecRegistry(reg).build());
SimpleMongoDbFactory factory = new SimpleMongoDbFactory(client, "spring-codec");
DefaultDbRefResolver dbRefResolver = new DefaultDbRefResolver(factory);
CustomConversions cc = new CustomConversions(Arrays.asList(new CodecAwareToDBOConverterFactory(reg),
new CodecAwareToObjectConverterFactory(reg)));
converter = new MappingMongoConverter(dbRefResolver, new MongoMappingContext());
converter.setCustomConversions(cc);
converter.afterPropertiesSet();
}
@Test
public void shouldUseConverterCodecRegistry() {
Foo foo = new Foo();
DBObject sink = new BasicDBObject();
converter.write(foo, sink);
assertThat(sink, isBsonObject().containing("customName", "o.O"));
Foo laoded = converter.read(Foo.class, sink);
assertThat(laoded.name, is("o.O"));
}
@Test
@Ignore("This one requires chages in MappingMongoConverter as we additionally need to check if the conversion service is capable of converting to the desired target type, as we register the converter for Object.class")
public void xxx() {
Nested source = new Nested();
source.oh = "oh";
DBObject sink = new BasicDBObject();
converter.write(source, sink);
assertThat(sink, isBsonObject().containing("oh", "oh"));
Nested laoded = converter.read(Nested.class, sink);
assertThat(laoded.oh, is("oh"));
}
@WritingConverter
static class CodecAwareToDBOConverterFactory implements ConverterFactory<Object, DBObject>, ConditionalConverter {
CodecRegistry registry;
public CodecAwareToDBOConverterFactory(CodecRegistry registry) {
this.registry = registry;
}
@Override
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
try {
return registry.get(sourceType.getType()) != null;
} catch (CodecConfigurationException ex) {}
return false;
}
class CodecAwareToToDBOConverter<T extends DBObject> implements Converter<Object, T> {
@Override
@SuppressWarnings({ "rawtypes", "unchecked" })
public T convert(Object source) {
Codec codec = registry.get(source.getClass());
StringWriter sw = new StringWriter();
codec.encode(new JsonWriter(sw), source, EncoderContext.builder().build());
sw.flush();
return (T) JSON.parse(sw.toString());
}
}
@Override
public <T extends DBObject> Converter<Object, T> getConverter(Class<T> targetType) {
return new CodecAwareToToDBOConverter<T>();
}
}
@ReadingConverter
static class CodecAwareToObjectConverterFactory implements ConverterFactory<DBObject, Object>, ConditionalConverter {
CodecRegistry registry;
public CodecAwareToObjectConverterFactory(CodecRegistry registry) {
this.registry = registry;
}
@Override
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
try {
return registry.get(targetType.getType()) != null;
} catch (CodecConfigurationException ex) {}
return false;
}
class CodecAwareToToObjectConverter<T extends Object> implements Converter<DBObject, T> {
Class<?> targetType;
public CodecAwareToToObjectConverter(Class<?> targetType) {
this.targetType = targetType;
}
@Override
@SuppressWarnings({ "unchecked", "rawtypes" })
public T convert(DBObject source) {
Codec codec = registry.get(targetType);
return (T) codec.decode(new JsonReader(new BasicDBObject(source.toMap()).toJson()), DecoderContext.builder()
.build());
}
}
@Override
public <T extends Object> Converter<DBObject, T> getConverter(Class<T> targetType) {
return new CodecAwareToToObjectConverter<T>(targetType);
}
}
static class Foo {
@Id String id;
String name;
Nested nested;
}
static class Nested {
String oh;
}
static class FooCodec implements Codec<Foo> {
@Override
public void encode(BsonWriter writer, Foo value, EncoderContext encoderContext) {
writer.writeStartDocument();
writer.writeObjectId("_id", new ObjectId());
writer.writeString("customName", "o.O");
writer.writeEndDocument();
}
@Override
public Class<Foo> getEncoderClass() {
return Foo.class;
}
@Override
public Foo decode(BsonReader reader, DecoderContext decoderContext) {
Foo foo = new Foo();
reader.readStartDocument();
foo.id = reader.readObjectId("_id").toHexString();
foo.name = reader.readString("customName");
reader.readEndDocument();
return foo;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment