Skip to content

Instantly share code, notes, and snippets.

@christophstrobl
Created November 20, 2015 10:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save christophstrobl/7299a1e28aee18af14ff to your computer and use it in GitHub Desktop.
Save christophstrobl/7299a1e28aee18af14ff to your computer and use it in GitHub Desktop.
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