/*
* Copyright 2011 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.gwt.inject.client.privatepinned;
import com.google.gwt.core.client.GWT;
import com.google.gwt.inject.client.GinModules;
import com.google.gwt.inject.client.Ginjector;
import com.google.gwt.inject.client.PrivateGinModule;
import com.google.gwt.junit.client.GWTTestCase;
import com.google.inject.Inject;
import com.google.inject.Singleton;
/**
* Verify that pinning and exposing work together.
*
* <p>Sets up an implicit, unconstrained binding (the Implementation classes)
* that depends on a pinned, private binding. The unconstrained binding has to
* move into the private module; we had errors in the past because it would
* "escape" the module and drag the pinned binding with it.
*/
public class PrivatePinnedTest extends GWTTestCase {
public void testBindingsStayInSubModulesA() throws Exception {
// Both Module1 and Module2 are installed in the Ginjector
verifyBindingsStayInSubModules((TestInterface) GWT.create(TestGinjectorA.class));
}
public void testBindingsStayInSubModulesB() throws Exception {
// Both Module1 is installed in the ginjector, and Module2 is installed
// through an extra layer of indirection. Verifies that the pins work.
verifyBindingsStayInSubModules((TestInterface) GWT.create(TestGinjectorB.class));
}
public void testNoDoubleBindingFromInheritedImplicitBinding() {
// Verifies that if the parent pins a singleton that it also implicitly
// requires, and a child implicitly requires it, the singleton is
// instantiated in the parent and doesn't cause a double binding error.
GWT.create(TestGinjectorC.class);
}
private void verifyBindingsStayInSubModules(TestInterface ginjector) throws Exception {
Interface1 interface1 = ginjector.getInterface1();
Interface2 interface2 = ginjector.getInterface2();
SubImplementation subImplementation1 = interface1.getSubImplementation();
SubImplementation subImplementation2 = interface2.getSubImplementation();
assertNotNull(subImplementation1);
assertNotNull(subImplementation2);
Interface1 otherInterface1 = ginjector.getInterface1();
Interface2 otherInterface2 = ginjector.getInterface2();
assertNotSame(interface1, otherInterface1);
assertNotSame(interface2, otherInterface2);
SubImplementation otherSubImplementation1 = otherInterface1.getSubImplementation();
SubImplementation otherSubImplementation2 = otherInterface2.getSubImplementation();
assertSame(subImplementation1, otherSubImplementation1);
assertSame(subImplementation2, otherSubImplementation2);
assertNotSame(subImplementation1, subImplementation2);
}
interface TestInterface {
Interface1 getInterface1();
Interface2 getInterface2();
}
@GinModules({Module1.class, Module2a.class})
interface TestGinjectorA extends Ginjector, TestInterface {}
@GinModules({Module1.class, TopModule.class})
interface TestGinjectorB extends Ginjector, TestInterface {}
@GinModules({TopModuleCheckForDoubleBinding.class})
interface TestGinjectorC extends Ginjector, TestInterface {}
static class TopModule extends PrivateGinModule {
@Override
protected void configure() {
bind(SubImplementation.class).in(Singleton.class);
install(new Module2b());
expose(Interface2.class);
}
}
// Verifies that nothing bad happens if the parent requires the same key that
// it promises to bind.
static class TopModuleCheckForDoubleBinding extends PrivateGinModule {
@Override
protected void configure() {
bind(Interface1.class).to(Implementation1.class);
bind(Implementation1.class);
// This is the pinned binding that the child will require. The parent
// requires it because Implementation1 is pinned here (see above), while
// the child requires it because Implementation2 is pinned there (see
// below).
bind(SubImplementation.class);
install(new Module2b());
expose(Interface1.class);
expose(Interface2.class);
}
}
static class Module1 extends PrivateGinModule {
@Override
protected void configure() {
bind(Interface1.class).to(Implementation1.class);
expose(Interface1.class);
bind(SubImplementation.class).in(Singleton.class);
}
}
static class Module2a extends PrivateGinModule {
@Override
protected void configure() {
bind(Interface2.class).to(Implementation2.class);
expose(Interface2.class);
bind(SubImplementation.class).in(Singleton.class);
}
}
static class Module2b extends PrivateGinModule {
@Override
protected void configure() {
bind(Interface2.class).to(Implementation2.class);
// If we don't pin this here, it floats out of the module, so we don't
// need a local binding for Subimplementation.
bind(Implementation2.class);
expose(Interface2.class);
}
}
interface Interface1 {
SubImplementation getSubImplementation();
}
interface Interface2 {
SubImplementation getSubImplementation();
}
static class Implementation1 implements Interface1 {
private final SubImplementation subImplementation;
@Inject
public Implementation1(SubImplementation subImplementation) {
this.subImplementation = subImplementation;
}
@Override
public SubImplementation getSubImplementation() {
return subImplementation;
}
}
static class Implementation2 implements Interface2 {
private final SubImplementation subImplementation;
@Inject
public Implementation2(SubImplementation subImplementation) {
this.subImplementation = subImplementation;
}
@Override
public SubImplementation getSubImplementation() {
return subImplementation;
}
}
static class SubImplementation {
}
public String getModuleName() {
return "com.google.gwt.inject.InjectTest";
}
}