square/dagger — pull request #169 by cgruber (2013-02-24 01:26:32+00:00)
Title: Fix singleton behaviour when forced to link on graph.plus();

Credit to Andy Dennie who reported this issue here:

https://plus.google.com/u/0/104032734670594482848/posts/L7222eSyEjo

The text of this is:

I've got a library that builds its own object graph, including an entry point for an @Singleton-annotated class (e.g. MySingleton). After creating that object graph, I can call get(MySingleton.class) on it successfully. However, if instead of calling get() on that graph, I use plus() to expand it with another module, and then call get(MySingleton.class) on that extended object graph, I get an AssertionError thrown from Linker.requestBinding, here:

Binding binding = null;
for (Linker linker = this; linker != null; linker = linker.base) {
binding = linker.bindings.get(key);
if (binding != null) {
if (linker != this && !binding.isLinked()) throw new AssertionError();
break;
}
}

In this case, it's the second time through the loop, such that linker == this.base, and the problem is that binding.isLinked is false.

Looking through the code, it seemed that the original graph should have had all its bindings linked during plus, since it calls linkEverything. So I stepped through that, down into linkAll, and then into linkRequested. As that method works its way through the toLink list, when it gets to the DeferredBinding for MySingleton, it creates a JIT binding (a ReflectiveAtInjectBinding) for it. It adds that binding to the toLink linked list, then wraps it with a SingletonBinding and adds that to the bindings map. Subsequently, as it it continues through the toLink list, linkRequested eventually comes to the ReflectiveAtInjectBinding it added earlier, and calls attach and setLinked on it. But the SingletonBinding that wraps it, which is sitting in the bindings map, doesn't have setLinked called on it, so even though it wraps a linked binding, it fails the isLinked test I ran into above, which causes the AssertionError.

Andy was right. This PR adds a repro/regression test and fixes singleton.