question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

@Inject Injector does not work with child injectors

See original GitHub issue

The testcase below works, if the injector is created by:

Guice.createInjector(new ChildModule());

it fails if the injector is created by:

Guice.createInjector().createChildInjector(new ChildModule());

The error is:

com.google.inject.ConfigurationException: Guice configuration errors:

  1. Unable to create binding for guice.GuiceTest$IOne. It was already configured on one or more child injectors or private modules bound at guice.GuiceTest$ChildModule.configure(GuiceTest.java:39) If it was in a PrivateModule, did you forget to expose the binding? while locating guice.GuiceTest$IOne
package guice;

import static org.junit.Assert.assertNotNull;

import org.junit.Test;

import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.Provider;

public class GuiceTest {

  public interface IOne {
  }

  public static class One implements IOne {
  }

  public interface ITwo {
    IOne getOne();
  }

  public static class Two implements ITwo {
    @Inject Provider<Injector> provider;

    @Override
    public IOne getOne() {
      return provider.get().getInstance(IOne.class);
    }
  }

  public static class ChildModule extends AbstractModule {

    @Override
    protected void configure() {
      bind(IOne.class).to(One.class);
      bind(ITwo.class).to(Two.class);
    }

  }

  @Test
  public void thisTestWorks() {
    Injector injector = Guice.createInjector(new ChildModule());
    ITwo two = injector.getInstance(ITwo.class);
    assertNotNull(two.getOne());

  }

  @Test
  public void thisTestFails() {
    Injector injector = Guice.createInjector().createChildInjector(new ChildModule());
    ITwo two = injector.getInstance(ITwo.class);
    assertNotNull(two.getOne());
  }
}

Issue Analytics

  • State:open
  • Created 8 years ago
  • Reactions:6
  • Comments:18 (6 by maintainers)

github_iconTop GitHub Comments

8reactions
404-commented, Jan 22, 2018

This may be a problem with the way injectors are injected into things from child injectors. Looks like it’s always giving you the parent injector.

@sameb, that does, indeed, seem to be the bug - instances obtained through child injectors are handed the parent injector in some (but not all) cases:

package com.example.guice;

import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.Provides;
import com.google.inject.name.Named;

import static com.google.inject.name.Names.named;

public class GuiceBug {
    interface IntContainer {
        int value();
    }

    static final class HashCodeContainer implements IntContainer {
        final int value;

        @Inject
        HashCodeContainer(final Injector injector) {
            this.value = injector.hashCode();
        }

        @Override
        public int value() {
            return value;
        }
    }

    static final class Foo {
        final int number;

        @Inject
        Foo(final Injector injector) {
            this.number = injector.hashCode();
        }
    }

    static final class M extends AbstractModule {
        @Override
        protected void configure() {
            //#1 gets the parent injector, bugged:
            bind(IntContainer.class).annotatedWith(named("1")).to(HashCodeContainer.class);

            //#2 gets the parent injector, bugged:
            bind(HashCodeContainer.class).annotatedWith(named("2")).to(HashCodeContainer.class);

            //#3 gets the child injector, which is correct...
            bind(Foo.class);
        }

        //#4 gets the child injector, which is correct...
        @Provides @Named("4") IntContainer provide(final Injector injector) {
            return new HashCodeContainer(injector);
        }
    }

    public static void main(String[] args) {
        final Injector parent = Guice.createInjector();
        final Injector child  = parent.createChildInjector(new M());

        final IntContainer four = child.getInstance(Key.get(IntContainer.class, named("1")));
        check(four.value() == child.hashCode(), "1");
        final HashCodeContainer five = child.getInstance(Key.get(HashCodeContainer.class, named("2")));
        check(five.value() == child.hashCode(), "2");
        final Foo foo = child.getInstance(Foo.class);
        check(foo.number == child.hashCode(), "3");
        final IntContainer six = child.getInstance(Key.get(IntContainer.class, named("4")));
        check(six.value() == child.hashCode(), "4");
    }

    static void check(final boolean pass, final String n) {
        if (pass) {
            System.out.printf("Scenario #%s: PASSED%n", n);
        } else {
            System.err.printf("Scenario #%s: FAILED%n", n);
        }
    }
}

Any chance this bug will get addressed?

4reactions
JLLeitschuhcommented, Mar 6, 2019

So, the weird workaround that someone at my company seems to have figured out is that if you inject an injector along with something exclusively from the parent injector scope, the right injector gets injected.

Read more comments on GitHub >

github_iconTop Results From Across the Web

@Inject Injector is injecting root injector rather than child injector
The easy answer is to simply bind the child injector using a provider. Dhanji.
Read more >
Do child injectors in Guice ever get created automatically?
I've found references to child injectors inside the Guice documentation, but other than them being used explicitly I can't find any ...
Read more >
Injector (Google Guice 5.0.1 API)
Builds the graphs of objects that make up your application. The injector tracks the dependencies for each type and uses bindings to inject...
Read more >
Hierarchical injectors - Angular
With hierarchical dependency injection, you can isolate sections of the application and give them their own private dependencies not shared with the rest...
Read more >
Child Injectors - WireBox : Dependency Injection & AOP For ...
Child Injector Methods ... Here are some of the new methods to assist with child injectors: hasChildInjector( name ) - Verify if a...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found