Support mixed injection and manual wiring #231

Closed
gissuebot opened this Issue Jul 7, 2014 · 11 comments

Comments

Projects
None yet
1 participant
@gissuebot

From crazyboblee on August 06, 2008 20:57:09

There are cases where you want most members injected in a given class and
then to do some manual wiring (you may have a couple different bindings
that are wired slightly differently). Right now, it's an all or nothing
proposition.

For a class FooImpl, I should be able to bind a provider to FooImpl, and in
the provider, I should be able to get an injected instance of FooImpl that
I can further work on and return.

Original issue: http://code.google.com/p/google-guice/issues/detail?id=231

@gissuebot

This comment has been minimized.

Show comment
Hide comment
@gissuebot

gissuebot Jul 7, 2014

From limpbizkit on August 07, 2008 18:44:10

We discussed this today, and our best idea is to have an @New annotation (not a binding annotation) for provider
methods, plus a toConstant() bind target.

From limpbizkit on August 07, 2008 18:44:10

We discussed this today, and our best idea is to have an @New annotation (not a binding annotation) for provider
methods, plus a toConstant() bind target.

@gissuebot

This comment has been minimized.

Show comment
Hide comment
@gissuebot

gissuebot Jul 7, 2014

From limpbizkit on August 07, 2008 18:46:01

I mistyped: I meant a toConstructor() bind target.

From limpbizkit on August 07, 2008 18:46:01

I mistyped: I meant a toConstructor() bind target.

@gissuebot

This comment has been minimized.

Show comment
Hide comment
@gissuebot

gissuebot Jul 7, 2014

From sven.linstaedt on August 08, 2008 08:06:51

Just for clarification: Are you discussing

  1. a kind of post construction hook (which was also discussed in other issues and
    could be realized using scopes),
  2. a solution for the so called robot-leg problem, that only needs one injector
    (parent injector concept comes along with the "one injector per leg"-problem)
  3. or something completely different?

From sven.linstaedt on August 08, 2008 08:06:51

Just for clarification: Are you discussing

  1. a kind of post construction hook (which was also discussed in other issues and
    could be realized using scopes),
  2. a solution for the so called robot-leg problem, that only needs one injector
    (parent injector concept comes along with the "one injector per leg"-problem)
  3. or something completely different?
@gissuebot

This comment has been minimized.

Show comment
Hide comment
@gissuebot

gissuebot Jul 7, 2014

From limpbizkit on November 28, 2008 11:30:35

Plan:
We'll Introduce a special binding annotation called '@New'. It is an error to bind to @New by hand; ie. it's an
error to do this:
  bind(Foo.class).annotatedWith(New.class).to(...)
When an injection point asks for an @New Foo, we create a default binding for the constructor of Foo. Foo
must always be a concrete class with a Guice-invokable constructor (ie. @Inject or public no-args).

Complications:
What happens if Foo.class is annotated @Singleton? Do I get the same instance each time I inject @New Foo?
Or different ones?
Suppose I inject both Foo and @New Foo. If Foo.class is annotaed @Singleton, do I get the same instance?

SPI Considerations:
I'm tempted to make it so @New is 1:1 with constructor bindings. For example, given this code:
   bind(Bar.class).to(BarImpl.class);
Guice would create 3 bindings:
   Bar.class linked to BarImpl.class (explicit)
   BarImpl.class linked to @New BarImpl.class (default)
   @New BarImpl to its own constructor (built-in)

Syntactic Sugar:
We confound linked bindings and constructor bindings in the current Guice. It means you can't solve the
turkey bacon problem [ http://tinyurl.com/turkeybaconproblem ]. So I'd like to introduce some syntactic sugar
related to @New:
  bind(Bar.class).toConstructor(BarImpl.class);
     is syntactic sugar for:
  bind(Bar.class).to(Key.get(BarImpl.class, New.class));

From limpbizkit on November 28, 2008 11:30:35

Plan:
We'll Introduce a special binding annotation called '@New'. It is an error to bind to @New by hand; ie. it's an
error to do this:
  bind(Foo.class).annotatedWith(New.class).to(...)
When an injection point asks for an @New Foo, we create a default binding for the constructor of Foo. Foo
must always be a concrete class with a Guice-invokable constructor (ie. @Inject or public no-args).

Complications:
What happens if Foo.class is annotated @Singleton? Do I get the same instance each time I inject @New Foo?
Or different ones?
Suppose I inject both Foo and @New Foo. If Foo.class is annotaed @Singleton, do I get the same instance?

SPI Considerations:
I'm tempted to make it so @New is 1:1 with constructor bindings. For example, given this code:
   bind(Bar.class).to(BarImpl.class);
Guice would create 3 bindings:
   Bar.class linked to BarImpl.class (explicit)
   BarImpl.class linked to @New BarImpl.class (default)
   @New BarImpl to its own constructor (built-in)

Syntactic Sugar:
We confound linked bindings and constructor bindings in the current Guice. It means you can't solve the
turkey bacon problem [ http://tinyurl.com/turkeybaconproblem ]. So I'd like to introduce some syntactic sugar
related to @New:
  bind(Bar.class).toConstructor(BarImpl.class);
     is syntactic sugar for:
  bind(Bar.class).to(Key.get(BarImpl.class, New.class));

@gissuebot

This comment has been minimized.

Show comment
Hide comment
@gissuebot

gissuebot Jul 7, 2014

From limpbizkit on December 24, 2008 20:30:47

Deferred to the next release so we can work out the scoping issues.

Labels: -Milestone-Release2.0

From limpbizkit on December 24, 2008 20:30:47

Deferred to the next release so we can work out the scoping issues.

Labels: -Milestone-Release2.0

@gissuebot

This comment has been minimized.

Show comment
Hide comment
@gissuebot

gissuebot Jul 7, 2014

From limpbizkit on June 21, 2009 11:21:49

We've implemented toConstructor() bindings:
  bind(Foo.class).toConstructor(Foo.class.getConstructor(Bar.class, Baz.class));

It's possible to easily implement @New as a simple built-in JIT binding on top of the toConstructor support.

From limpbizkit on June 21, 2009 11:21:49

We've implemented toConstructor() bindings:
  bind(Foo.class).toConstructor(Foo.class.getConstructor(Bar.class, Baz.class));

It's possible to easily implement @New as a simple built-in JIT binding on top of the toConstructor support.

@gissuebot

This comment has been minimized.

Show comment
Hide comment
@gissuebot

gissuebot Jul 7, 2014

From sberlin on May 23, 2010 05:26:03

Issue 485 has been merged into this issue.

From sberlin on May 23, 2010 05:26:03

Issue 485 has been merged into this issue.

@gissuebot

This comment has been minimized.

Show comment
Hide comment
@gissuebot

gissuebot Jul 7, 2014

From sberlin on May 23, 2010 07:21:19

toConstructor itself solves the TurkeyBacon problem as described @ http://tinyurl.com/turkeybaconproblem .  It would be solved by doing:

public class BritishModule extends AbstractModule {
  public void configure() {
    bind(Bacon.class).to(UncookedBacon.class);
    bind(Bacon.class).annotatedWith(Names.named("Turkey").to(TurkeyBacon.class);
   
bind(Bacon.class).annotatedWith(Names.named("Cooked")).toConstructor((Constructor)InjectionPoint.forConstructorOf(Bacon.class).getMember());
  }
}

.. a little bit unwieldy code-wise, but it works.

Is @New still needed?  It can be worked around pretty easily by:
 
bind(Bar.class).annotatedWith(named("new")).toConstructor((Constructor)InjectionPoint.forConstructorOf(BarImpl.class).getMember());
and later using it was @Inject Baz(@Named("new") Bar bar) { ... }

In other words, instead of toConstructor being syntactic sugar for @New, @New would
be syntactic sugar for toConstructor.

It'd be pretty easy to hack up, either way.

From sberlin on May 23, 2010 07:21:19

toConstructor itself solves the TurkeyBacon problem as described @ http://tinyurl.com/turkeybaconproblem .  It would be solved by doing:

public class BritishModule extends AbstractModule {
  public void configure() {
    bind(Bacon.class).to(UncookedBacon.class);
    bind(Bacon.class).annotatedWith(Names.named("Turkey").to(TurkeyBacon.class);
   
bind(Bacon.class).annotatedWith(Names.named("Cooked")).toConstructor((Constructor)InjectionPoint.forConstructorOf(Bacon.class).getMember());
  }
}

.. a little bit unwieldy code-wise, but it works.

Is @New still needed?  It can be worked around pretty easily by:
 
bind(Bar.class).annotatedWith(named("new")).toConstructor((Constructor)InjectionPoint.forConstructorOf(BarImpl.class).getMember());
and later using it was @Inject Baz(@Named("new") Bar bar) { ... }

In other words, instead of toConstructor being syntactic sugar for @New, @New would
be syntactic sugar for toConstructor.

It'd be pretty easy to hack up, either way.

@gissuebot

This comment has been minimized.

Show comment
Hide comment
@gissuebot

gissuebot Jul 7, 2014

From sberlin on May 23, 2010 07:32:01

FYI - I committed a test in r1166 that asserts that toConstructor solves the
turkeybacon problem.

From sberlin on May 23, 2010 07:32:01

FYI - I committed a test in r1166 that asserts that toConstructor solves the
turkeybacon problem.

@gissuebot

This comment has been minimized.

Show comment
Hide comment
@gissuebot

gissuebot Jul 7, 2014

From sberlin on May 23, 2010 08:18:54

Thinking about this some more... it looks like attempts to introduce @New would
introduce a lot confusion.  For example, if Bar is linked to BarImpl.class, what
would "@New Bar" return?  What if Bar was linked to Provider<Bar>, or @Provides Bar.
 Would @New just be disallowed on interfaces because of that confusion?  

I think we're safest adding an easy-to-use "find the right constuctor" method,
something like <T> Constructor<T> Constructors.forConstructorOf(Class<T> clazz), to
reduce the boilerplate from comment #8 of using InjectionPoint to find the right
constructor.  Then users can use it to create their own "new" bindings, annotated
with whatever they'd like.  That way, things like "@New Bar" would be defined,
because the user would have had to define it.

I'm for closing this as "will not fix" -- please chime in if you think otherwise!

From sberlin on May 23, 2010 08:18:54

Thinking about this some more... it looks like attempts to introduce @New would
introduce a lot confusion.  For example, if Bar is linked to BarImpl.class, what
would "@New Bar" return?  What if Bar was linked to Provider<Bar>, or @Provides Bar.
 Would @New just be disallowed on interfaces because of that confusion?  

I think we're safest adding an easy-to-use "find the right constuctor" method,
something like <T> Constructor<T> Constructors.forConstructorOf(Class<T> clazz), to
reduce the boilerplate from comment #8 of using InjectionPoint to find the right
constructor.  Then users can use it to create their own "new" bindings, annotated
with whatever they'd like.  That way, things like "@New Bar" would be defined,
because the user would have had to define it.

I'm for closing this as "will not fix" -- please chime in if you think otherwise!

@gissuebot

This comment has been minimized.

Show comment
Hide comment
@gissuebot

gissuebot Jul 7, 2014

From sberlin on October 24, 2010 17:15:54

Closing as fixed because toConstructor allows this with some configuration (bind your object with toConstructor and a custom @New annotation).

Status: Fixed

From sberlin on October 24, 2010 17:15:54

Closing as fixed because toConstructor allows this with some configuration (bind your object with toConstructor and a custom @New annotation).

Status: Fixed

@gissuebot gissuebot closed this Jul 7, 2014

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment