Evan,
Glad to know you're seeing some successes. Hope that is an ongoing trend.
As far as a web of robot legs, often it might seem worse than it is, given a few mitigating factors:
1) if you're building a web app, then typically you will be able to make use of request scoped values, given that often the object graph with which you want to process a request is dependent on the type of request received.
As a contrived example, imagine if you had a sharded database of users. Also imagine that the user for which you were processing a request was easily identified from its URL (such as "
www.yourapp.com/process-user?user-id=123"). In this example, you want to determine which database to use for each request, given each user might map to a different physical database. You could add a Filter to perform the work of mapping user-id => shard, and then you could seed the calculated value into RequestScope.
This means that your robot legs problem is effectively solved by scoping, given you could change your "static" PrivateModule bindings to use a scoped value. For example, you might now have:
public class DatabaseConnectionSupplier {
private final Provider<String> databaseNameProvider;
// always be keeping your ctr's package private!
@Inject DatabaseConnection(
Named("database_name") Provider<String> databaseNameProvider) {
this.databaseNamedProvider = databaseNameProvider;
}
public DatbaseConnection supplyDatabaseConnection() {
// we know we're in scope now, so we can call .get()
String databaseName = databaseNameProvider.get();
.....
}
}
Of course this would be horrible inefficient, but it illustrates the scoping point, I hope. Practically, you'd probably have a singleton pool and simply dispatch from Map<String, DatabaseConnection>.
I've added an example on the Guice wiki that shows how to do this with a Filter:
2) MapBinder
MapBinder is powerful! It boils down to having a Map that can be populated in a plugin-style fashion. In the context of this thread, it allows you to have multiple object graphs pre-constructed, keyed off a value that you would know at the time you need to decide which leg to use.
In the example above, a class that needs a DatabaseConnection might itself be injected with:
Map<String, DatabaseConnection> connectionsByName;
Here, each DatabaseConnection would have the relevant name injected into it upon construction (ala the PrivateModule solution). The DatabaseClient class could then learn which DatabaseConnection it should use at runtime, such as:
public class DatabaseClient {
@Inject DatabaseClient(Map<String, DatabaseConnection> cnxsByName) { ...}
public doSomethingRequiringTheDatabase(Integer userId) {
String databaseOfUser = shardingService.getShardForUser(userId);
DatabaseConnection databaseConnection =
cnxsByName.get(databaseOfUser);
.....
}
}
The difference here is ultimately a design question: whether to hide the configuration behind a scope or to have it explicit within blogic is the choice to make. A good rule of thumb to use is this:
if a value is required in several packages, or at least across several classes, then scoping is often the best idea. otherwise, passing a value directly is probably going to be more straightforward, and therefore the better choice.
In other words, use scope judiciously, as, end of the day, it really is a glorified global variable (but not in the pejorative sense), and this can make it confusing to see where a scoped value "comes from."
* * *
To answer your other question, ServletModule goes well with GWT, mainly because the two are somewhat independent. You'll want to use Google-Gin for your client side injections, as it deals with the issues of GWT that drive us all subtly mad (i.e., those issues requiring the java to be compilable to js).
On the server side you can easily configure your resource servlets and remote logging servlets with ServletModule, and I absolutely recommend you do that!
The ServletListener, btw, is used only to bootstrap the app within a servlet container. If you're not running within a container, such as using an "embedded" servlet engine, you can do something programmatic, such as
this. Either way, certainly it is advantageous to use ServletModule.
-Fred