Created
November 20, 2015 10:22
-
-
Save christophstrobl/7299a1e28aee18af14ff to your computer and use it in GitHub Desktop.
ConverterFactroy wrapping MongoDB CodecRegistry to delegate conversions
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* @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