0

Following the documentation of OptionalBinder

An API to bind optional values, optionally with a default value. OptionalBinder fulfills two roles:

  1. It allows a framework to define an injection point that may or may not be bound by users.
  2. It allows a framework to supply a default value that can be changed by users.

I am trying to follow up on the first point above for which I have the following setup:

interface Reporting<R> {} // service to be bind optionally

class InternalServiceImpl implements InternalService {
    @Inject
    Reporting reporting;
    ... // use this in a method
}

public class FrameworkModule extends AbstractModule {
   protected void configure() {
     OptionalBinder.newOptionalBinder(binder(), Reporting.class);
   }
}

in the user modules(class UserWorkingModule) if I do not provide a binding such as

bind(new TypeLiteral<Reporting<ReportingEvent>>(){}).to(ReportingImpl.class).in(Singleton.class);

the application fails to start with the following logs:

1) No implementation for Reporting was bound.   while locating Reporting
    for field at InternalServiceImpl.reporting(InternalServiceImpl.java:21) at
FrameworkModule.configure(FrameworkModule.java:55) (via modules: UserWorkingModule -> FrameworkModule)

Is it still a must to provide a binding for Reporting in the UserWorkingModule?

Naman
  • 27,789
  • 26
  • 218
  • 353
  • On a question, where I have shared what works and what doesn't with minimal code. I don't get the reason behind the downvote! – Naman Jan 31 '20 at 14:02

2 Answers2

1
bind(new TypeLiteral<Reporting<ReportingEvent>>(){}).to(ReportingImpl.class).in(Singleton.class);

is a binding for the generic Reporting<ReportingEvent>, while

OptionalBinder.newOptionalBinder(binder(), Reporting.class);

is actually specifying the raw type, Reporting. Instead, you want to use the overload for newOptionalBinder which specifies a TypeLiteral arg, so that you are talking about the same thing in both the optional request and the binding:

OptionalBinder.newOptionalBinder(binder(), new TypeLiteral<Reporting<ReportingEvent>>(){});

Without this, you are basically saying "any binding to Reporting will satisfy this requirement", even something like Reporting<Object> - and what happens if you bind more than one?


On the other hand, if you actually want to allow any binding of any Reporting type (which is what your error suggests, then instead the opposite thing is wrong: instead of binding to raw Reporting, you specified the generic impl instead. Change that bind() call to say "this actually only works for raw requests":

bind(Reporting.class).to(ReportingImpl.class).in(Singleton.class);
Colin Alworth
  • 17,801
  • 2
  • 26
  • 39
  • Thank you for taking out time to answer. Did you mean to say that with `OptionalBinder.newOptionalBinder(binder(), new TypeLiteral>(){});` in `FrameworkModule`, I wouldn't require to bind in the `UserWorkingModule`? – Naman Feb 03 '20 at 06:38
  • UserWorkingModule is not in your question, except for the stack trace, so I can't really say. Is it possible that this is the name of the class that the bind(..).to(..) call is in? If so, you still need that under either approach, but you need the newOptionalBinder(..) and bind(..).to(..) to agree, as they do not right now (and those further should agree with the injected site, in InternalServiceImpl and perhaps others). – Colin Alworth Feb 03 '20 at 17:22
  • Yes, I had mentioned that in *"the user modules if I do not provide a binding such as"*, its the name of the class where `bind(..).to(..)` is placed. I didn't get the part where you said *"you still need that under either approach"*. Isn't that what the documentation point (1) as linked in the question? and by the actual question as I posted I meant this only - **Is it still a must to provide a binding for Reporting in the UserWorkingModule?** – Naman Feb 03 '20 at 18:24
  • Oh I gotcha - I understood your question to be asking "Why do I get this error" (and the answer there is "your code doesn't match what you are requesting"), as opposed to "if this approach makes it optional, why does it still seem to be required", which has a separate answer. I'll update the answer accordingly. – Colin Alworth Feb 03 '20 at 21:27
0

You're not actually specifying a binding, when using the OptionalBinder. You still need to specify a default binding when using the OptionalBinder try:

     OptionalBinder.newOptionalBinder(binder(), Reporting.class)
        .setDefault()
        .to(ReportingImpl.class);
JSchlather
  • 1,564
  • 2
  • 13
  • 22