guice and MapDB's Maps: binding guice to a factory returning a generic type

50 views
Skip to first unread message

Geoff Groos

unread,
Jul 30, 2015, 7:16:08 AM7/30/15
to google-guice
Hey guys,

I've got a database (sigh), but its very small and very fast and interfaces as a java.util.Map (yay!) --or rather, the Database object interfaces a Map-Factory.

This means that I get to write the eminently testable code

public class CoolServiceOrController{

   
private final Map<UUID, ModelObject> modelStore;

   
@Inject
   
public class CoolServiceOrController(Map<UUID, ModelObject> modelStore){
       
this.modelStore = modelStore;
   
}

   
public void megaTransform(){
       
//load fortran code!
   
    //use weird stupid Intel MKL functions!
        //launch CUDA for good measure!
        //oops! rollback!
        //other complicated domain things!
   
}
}

which is really awesome because its stupidly easy to stub-out with test data. Very happy with my design decisions here.

What I would like to do is wire guice to resolve any request for a Map<UUID, Anything> to new StoreFacade(EventBus eb, SerializerFactory serializerFactory, Class<Anything> modelType, Database bigStupidSingletonThing). In the name principal-of-least-suprise I'm willing to use a BindingAnnotation along the lines of @DatabaseFacade on those maps to differentiate between regular Map<UUID, stuff> and Map<UUID, stuff> that should be using a database facade.

Having learned a little more about type erasure (largely because I was wondering why guice could see the generic types of things so often), I believe this is technically feasible from whiten guice. But it seems like guice's current approach to generics is to avoid them.

So the best approach I've managed to come up with is to manually enumerate those TAnythings with @Provides methods, which works, but is kloogy and requires changing bootstrapping logic for a lot of changes

public class MyModule extends Module{
    public void configure(){
        install(new FactoryModuleBuilder().implement(
                new TypeLiteral<org.mapdb.Serializer<OptimizationModel>>() {},
                new TypeLiteral<Serializer.MapDbXStreamBlobSerializer<OptimizationModel>>() {}
            ).build(new TypeLiteral<MapDBSerializerFactory<OptimizationModel>>() {})
        );
        install(new FactoryModuleBuilder().implement(
                new TypeLiteral<org.mapdb.Serializer<ProjectState>>() {},
                new TypeLiteral<Serializer.MapDbXStreamBlobSerializer<ProjectState>>() {}
            ).build(new TypeLiteral<MapDBSerializerFactory<ProjectState>>() {})
        );
        
        //...
    }
    
    //...
    
    @Provides
    public Map<UUID, OptimizationModel> getOptimizationMatStore(
            EventBus eventBus,
            MapDBSerializerFactory<OptimizationModel> serializer,
            LethargicDatabaseFacade db) {
            
        return new StoreFacade<>(eventBus, serializer, db, OptimizationModel.class);
    }
    @Provides
    public Map<UUID, ProjectState> getHistoryStore(
            EventBus eventBus,
            MapDBSerializerFactory<ProjectState> serializer,
            LethargicDatabaseFacade db){
            
        return new StoreFacade<>(eventBus, serializer, db, ProjectState.class);
    }
}

Is there a more elegant way to do this or is this as good as it (currently) gets?

Thanks for any help!

-Geoff
Reply all
Reply to author
Forward
0 new messages