package com.mastfrog.giulius.mongojack; import com.fasterxml.jackson.databind.ObjectMapper; import com.google.inject.AbstractModule; import com.google.inject.Binder; import com.google.inject.Key; import com.google.inject.Provider; import com.google.inject.TypeLiteral; import com.google.inject.name.Named; import com.google.inject.name.Names; import com.mastfrog.acteur.mongo.GiuliusMongoModule; import com.mastfrog.acteur.mongo.MongoConfigModule; import com.mastfrog.acteur.mongo.MongoInitializer; import com.mongodb.DBCollection; import java.util.LinkedList; import java.util.List; import org.mongojack.JacksonDBCollection; /** * Wraps the Giulius mongo module with support for MongoJack which uses Jackson * to serialize/deserialize. * * @author Tim Boudreau */ public class MongoJacksonModule extends AbstractModule { private final List<Entry<?, ?>> entries = new LinkedList<>(); private final MongoConfigModule mongo; public MongoJacksonModule(String name) { this(new GiuliusMongoModule(name)); } public MongoJacksonModule(MongoConfigModule module) { mongo = module; } public MongoJacksonModule addInitializer(Class<? extends MongoInitializer> type) { mongo.addInitializer(type); return this; } public final <T, R> MongoJacksonModule bindCollection(String bindingName, TypeLiteral<JacksonDBCollection<T, R>> tl, Class<T> left, Class<R> right) { bindCollection(bindingName, bindingName, tl, left, right); return this; } public final <T, R> MongoJacksonModule bindCollection(String bindingName, String collectionName, TypeLiteral<JacksonDBCollection<T, R>> tl, Class<T> left, Class<R> right) { mongo.bindCollection(bindingName, collectionName); entries.add(new Entry<>(bindingName, tl, left, right)); return this; } public MongoJacksonModule bindCollection(String bindingName) { mongo.bindCollection(bindingName); return this; } public MongoJacksonModule bindCollection(String bindingName, String collectionName) { mongo.bindCollection(bindingName, collectionName); return this; } public final String getDatabaseName() { return mongo.getDatabaseName(); } @Override protected void configure() { install(mongo); Binder binder = binder(); for (Entry<?, ?> e : entries) { e.bind(binder); } entries.clear(); } private static final class Entry<T, R> { private final String bindingName; private final TypeLiteral<JacksonDBCollection<T, R>> tl; private final Class<T> left; private final Class<R> right; public Entry(String bindingName, TypeLiteral<JacksonDBCollection<T, R>> tl, Class<T> left, Class<R> right) { this.bindingName = bindingName; this.tl = tl; this.left = left; this.right = right; } void bind(Binder binder) { Named anno = Names.named(bindingName); Provider<DBCollection> collectionProvider = binder.getProvider(Key.get(DBCollection.class, anno)); Provider<JacksonDBCollection<T, R>> result = new JacksonDBCollectionProvider<>(collectionProvider, left, right, binder.getProvider(ObjectMapper.class)); binder.bind(tl).annotatedWith(anno).toProvider(result); } } private static final class JacksonDBCollectionProvider<T, R> implements Provider<JacksonDBCollection<T, R>> { private final Provider<DBCollection> dbCollection; private final Class<T> left; private final Class<R> right; private final Provider<ObjectMapper> mapper; private ObjectMapper mapperInstance; JacksonDBCollectionProvider(Provider<DBCollection> dbCollection, Class<T> left, Class<R> right, Provider<ObjectMapper> mapper) { this.dbCollection = dbCollection; this.left = left; this.right = right; this.mapper = mapper; } @Override public JacksonDBCollection<T, R> get() { DBCollection coll = dbCollection.get(); // Ensure we don't pollute the globally bound object mapper ObjectMapper m = mapperInstance == null ? mapperInstance = mapper.get().copy() : mapperInstance; return JacksonDBCollection.wrap(coll, left, right, m); } public String toString() { return "JacksonDbCollection<" + left.getName() + "," + right.getName() + ">"; } } }