andrew.z
andrew.z

Reputation: 1059

Can I do this with GUICE

Suppose I have the following classes defined:

public interface A {}

public class A1 implements A {}

public class A2 implements A {}

public class XServlet<T extends A> extends HttpServlet {
    public XServlet(T delegate){}
}

Additionally in one of my Guice modules I have the foollowing bindings:

bind(A.class).annotatedWith(Names.named("a1")).to(A1.class);
bind(A.class).annotatedWith(Names.named("a2")).to(A2.class);

Now I need to create a ServletModule that defines two instances of "XServlet" with different arguments. For "/x" pattern I want it to use whatever is bound to A.class annotated with "a1", and for "/y" pattern whatever is bound to A.class and annotated with "a2". Something like:

serve("/x").with(???);
serve("/y").with(???);

What should be there instead of '???'? Is it possible at all?

Upvotes: 2

Views: 177

Answers (1)

Jeff Bowman
Jeff Bowman

Reputation: 95614

Two problems here: One is varying the binding annotation of XServlet with the serve method, and the other is varying the binding of A based on the annotation of XServlet.

The serve method half is pretty straightforward to solve: Manually create a Key. This binds "/x" to @Named("a1") XServlet.

serve("/x").with(Key.get(XServlet.class, Names.named("a1")));

The second half is known as the "robot legs problem" and is fixable using private modules:

install(new PrivateModule() {
  @Override void configure() {
    // These are only bound within this module, and are not visible outside.
    bind(A.class).to(A1.class);
    bind(XServlet.class).annotatedWith(Names.named("a1"));
    // But you can expose bindings as you'd like.
    expose(XServlet.class).annotatedWith(Names.named("a1"));
  }
});

UPDATE: If the named bindings you mentioned before cannot be moved to the private module, you can always bind the non-annotated binding in the private module to the annotated binding in another module. The binding in the private module should look like this:

// Fulfill requests for an unannotated A by looking up @Named("a1") A,
// though @Named("a1") A is bound elsewhere.
bind(A.class).to(Key.get(A.class, Names.named("a1")));

If you're trying to bind a dozen of these, you may find it easier to create a private static function that looks like:

private static Module moduleForServlet(
    final Class<? extends A> aClass, final String namedAnnotationString) {
  return new PrivateModule() { /* see above */ };
}

Docs:

Upvotes: 1

Related Questions