matanc1
matanc1

Reputation: 7023

Does Guice support a way of method injection (non setter injection)?

From what I understand Guice supports injection for: Constructors, Setters (which they call method injection for some reason), fields.

Can it also inject method parameters? For example:

void foo(InterfaceA a, InterfaceA a1){
    ...
}


interface InterfaceA{
    ...
}


class A implements InterfaceA{
    ....
}

class B implements InterfaceA{
    ....
}

I want to be able to bind a in foo to type A and a1 to B (will probably need annotation but lets ignore that for a second). I want this to be done on invocation.

This seems different from the normal use cases (c'tor, fields, setters) in the sense that the dependency injection will happen on invocation rather than on object creation.

So is this possible?

Upvotes: 3

Views: 6730

Answers (2)

Jeff Bowman
Jeff Bowman

Reputation: 95614

Vladimir's answer is correct, but rather than injecting the injector, you can use field injection and Providers to do the same more concisely and to check that dependencies are satisfied at injector creation time. This code is the same as his, but modified to use Providers:

Injector injector = Guice.createInjector(b -> {
    b.bind(InterfaceA.class).annotatedWith(Names.named("a")).to(A.class);
    b.bind(InterfaceA.class).annotatedWith(Names.named("a1")).to(B.class);
    b.bind(Invoke.class);
});

public class Invoke {
    // Constructor injection works too, of course. These fields could also be
    // made private, but this could make things difficult to test.
    @Inject @Named("a") Provider<InterfaceA> aProvider;
    @Inject @Named("a1") Provider<InterfaceA> a1Provider;

    public void invoke() {
        this.foo(aProvider.get(), a1Provider.get());
    }

    void foo(InterfaceA a, InterfaceA a1){
        ...
    }
}

Upvotes: 6

Vladimir Matveev
Vladimir Matveev

Reputation: 127761

Well, you can do this:

Injector injector = Guice.createInjector(b -> {
    b.bind(InterfaceA.class).annotatedWith(Names.named("a")).to(A.class);
    b.bind(InterfaceA.class).annotatedWith(Names.named("a1")).to(B.class);
    b.bind(Invoke.class);
});


public class Invoke {
    private final Injector injector;

    @Inject
    Invoke(Injector injector) {
        this.injector = injector;
    }

    public void invoke() {
        this.foo(
            injector.getInstance(Key.get(InterfaceA.class, Names.named("a"))),
            injector.getInstance(Key.get(InterfaceA.class, Names.named("a1")))
        );
    }

    void foo(InterfaceA a, InterfaceA a1){
        ...
    }
}

But nothing more. Guice is a dependency injection framework and it usually means "construct objects with all their dependencies". While method parameters are dependencies formally (since the class is supposed to use them - this is the definition of dependency), they are not usually regarded as those by DI frameworks. It is understandable - this would make these frameworks much more complex for little to no gain, and also Java is not expressive enough language for such things not to look obscenely ugly.

Upvotes: 3

Related Questions