jwa
jwa

Reputation: 3281

Guice IOC: Manual (and Optional) Creation of a Singleton

Trying to get started with Guice, and struggling to see how my use-case fits in.

I have a command-line application, which takes several optional parameters.

Let's say I've got the tool shows a customer's orders, for example

 order-tool display --customerId 123

This shows all the orders owned by customer with ID 123. Now, the user can also specify a user's name:

order-tool display --customerName "Bob Smith"

BUT the interface to query for orders relies on customer IDs. Thus, we need to map from a customer name to a customer ID. To do this, we need a connection to the customer API. Thus, the user has to specify:

order-tool display --customerName "Bob Smith" --customerApi "http://localhost:8080/customer"

When starting the application, I want to parse all the arguments. In the case where --customerApi is specified, I want to place a CustomerApi singleton in my IoC context - which is parameterized by the CLI arg with the API URL.

Then, when the code runs to display a customer by name - it asks the context if it has a CustomerApi singleton. If it doesn't it throws an exception, telling the CLI user that they need to specify --customerApi if they want to use --customerName. However, if one has been created - then it simply retrieves it from the IoC context.

Upvotes: 0

Views: 94

Answers (1)

Jeff Bowman
Jeff Bowman

Reputation: 95764

It sounds like "optionally creating a singleton" isn't exactly what you're trying to do here. I mean, it is, but that's as simple as:

if (args.hasCustomerApi()) {
  bind(CustomerApi.class).toInstance(new CustomerApi(args.getCustomerApi()));
}

To allow for optional bindings, you will probably need to annotate their use with @Nullable.

I think your real question is how to structure an application so that you can partially configure it, use the configuration to read and validate some command-line flags, then use the flags to finish configuring your application. I think the best way to do that is with a child injector.

public static void main(String[] args) {
  Injector injector = Guice.createInjector(new AModule(), new BModule(), ...);
  Arguments arguments = injector.getInstance(ArgParser.class).parse(args);
  validateArguments(arguments);  // throw if required arguments are missing
  Injector childInjector =
      injector.createChildInjector(new ArgsModule(arguments));
  childInjector.getInstance(Application.class).run();
}

Child injectors are just like normal injectors that defer to a parent if they don't contain the given bindings themselves. You can also read documents on how Guice resolves bindings.

Upvotes: 1

Related Questions