简体   繁体   中英

Guice method injection using annotations

I have two Runnable classes, and I want to inject a dependency between them, so that the SecondProcedure runs using the Table created by the FirstProcedure .

class FirstProcedure implements Runnable {
    private Table composers = new Table();

    public void run() {
        // populates the composers table
    }

    public Table getComposers() {
        return composers;
    }
}


class SecondProcedure implements Runnable {
    private Table composers;

    public void run() {
        // writes the name of each composer to the console
    }

    public Table setComposers(final Table composers) {
        this.composers = composers;
    }
}

The idea is that in my main class I can instantiate both of the procedures, inject the relevant table (which should reference correctly even though it won't be populated by this point), work out the dependencies between the two procedures, and then run them in the right order. ie there will be a unique instance of each of these two procedures (but I'm intentionally avoiding the Singleton (anti)pattern so that I can have proper unit tests).

How can I go about this using Guice? Can I annotate the setComposers method with something like:

@InjectTable(procedure=FirstProcedure.class, name="composers")
public Table setComposers(final Table composers) {
    this.composers = composers;
}

and have a Guice module which will bind the Table in the SecondProcedure based on the class and name of the provided field?

I don't see anything which quite fits this paradigm in the bind() methods of AbstractModule .

(Aside from this, I'm not too keen on the design for this annotation itself, with the name of the field being in a string, instead of referring to the method explicitly somehow.)

I think you might be over-complicating the problem.

It looks like SecondProcedure has a simple dependency on Table:

class SecondProcedure {
  @Inject
  SecondProcedure(Table table) {
    this.table = table;
  } 
}

And FirstProcedure is a Provider of Table:

class FirstProcedure implements Provider<Table> {
  public Table get() {
    return buildTheTable();
  }
}

Your module then just needs to bind the provider:

class SomeModule extends AbstractModule {
  protected void configure() {
    bind(Table.class).toProvider(FirstProcedure.class);
  }
}

A JIT binding of the @Inject annotated constructor will provide SecondProcedure, so you don't need to bind it explicitly.

Once you've done this, you might consider changing the name of FirstProcedure to TableProvider.

To use the FirstProcedure, you then just inject it, or get it from the injector:

injector.getInstance(FirstProcedure.class).run();

As an aside, the Guice singleton pattern (@Singleton scope) is not an anti-pattern as it's confined to the injector. There are plenty of cases where it's appropriate, and the Guice singleton implementation doesn't get in the way of testing.

Perhaps the thing you should be concerned about is static state. Guice itself provides a good explanation of why it is bad: http://code.google.com/p/google-guice/wiki/AvoidStaticState

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM