/* * 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.installduplicate; import com.google.gwt.core.client.GWT; import com.google.gwt.inject.client.GinModule; 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.inject.client.binder.GinBinder; import com.google.gwt.junit.client.GWTTestCase; import com.google.inject.name.Named; import com.google.inject.name.Names; /** * Tests that modules that compare equal are actually installed once only. * <p> * This is done by installing a bunch of modules twice, using different * scenarios: * <ul> * <li>Referenced twice in a {@literal @}{@link GinModules} annotation * <li>Referenced once in a {@literal @}{@link GinModules} annotation and then * {@link GinBinder#install(GinModule) installed}. * <li>{@link GinBinder#install(GinModule) Installed} twice using the very same * instance. * <li>{@link GinBinder#install(GinModule) Installed} twice using two instances * that compare equal. * </ul> * <p> * The {@link Ginjector}s explicitly declare the dependencies on what the * modules install, to make sure they're all actually installed. * <p> * The test fails when compilation fails, because of double-bound keys that * would result from {@link #configure(GinBinder) configuring} the modules * twice. GIN should actually {@link #configure(GinBinder) configure} modules * once per scenario only, because the modules compare equal. */ public class InstallDuplicateTest extends GWTTestCase { public void testDuplicateModuleThroughGinModulesAnnotation() { GWT.create(TestGinjector.class); } @Override public String getModuleName() { return "com.google.gwt.inject.InjectTest"; } @GinModules( { ReferencedTwiceFromGinModulesAnnotation.class, TestModule.class, InstalledFromDistinctModules.A.class, InstalledFromDistinctModules.B.class}) public interface TestGinjector extends BaseTestGinjector { @Named("InstalledFromDistinctModules") Foo installedFromDistinctModules(); @Named("SameInstanceInstalledTwice") Foo sameInstanceInstalledTwice(); @Named("TwoInstancesInstalledOnBinder") Foo twoInstancesInstalledOnBinder(); } @GinModules( { ReferencedTwiceFromGinModulesAnnotation.class, ReferencedFromAnnotationAndInstalledOnBinder.class}) public interface BaseTestGinjector extends Ginjector { @Named("ReferencedTwiceFromGinModulesAnnotation") Foo referencedTwiceFromGinModulesAnnotation(); @Named("ReferencedFromAnnotationAndInstalledOnBinder") Foo referencedFromAnnotationAndInstalledOnBinder(); } static class TestModule implements GinModule { public void configure(GinBinder binder) { binder.install(new ReferencedFromAnnotationAndInstalledOnBinder()); SameInstanceInstalledTwice module = new SameInstanceInstalledTwice(); binder.install(module); binder.install(new TwoInstancesInstalledOnBinder()); binder.install(module); binder.install(new TwoInstancesInstalledOnBinder()); binder.install(new PrivateModuleInstalledTwiceOnBinder()); binder.install(new PrivateModuleInstalledTwiceOnBinder()); } } /** * This class is injected using different binding annotations, one for each * scenario. */ static class Foo { } /** * Two instances are referenced from {@literal @}{@link GinModules} on the * {@link Ginjector}. * <p> * This class doesn't implement equals and hashCode because it is expected * that module classes referenced from GinModules are instantiated once only. */ static class ReferencedTwiceFromGinModulesAnnotation implements GinModule { public void configure(GinBinder binder) { binder.bind(Foo.class).annotatedWith( Names.named("ReferencedTwiceFromGinModulesAnnotation")).to(Foo.class); } } /** * One instance is referenced from {@literal @}{@link GinModules} on the * {@link Ginjector}, another is installed on the {@link GinBinder}. */ static class ReferencedFromAnnotationAndInstalledOnBinder implements GinModule { public void configure(GinBinder binder) { binder.bind(Foo.class).annotatedWith( Names.named("ReferencedFromAnnotationAndInstalledOnBinder")).to(Foo.class); } @Override public boolean equals(Object obj) { return obj instanceof ReferencedFromAnnotationAndInstalledOnBinder; } @Override public int hashCode() { return 31; } } /** * Does not implement equals/hashCode but the same instance is installed * twice. */ static class SameInstanceInstalledTwice implements GinModule { public void configure(GinBinder binder) { binder.bind(Foo.class).annotatedWith(Names.named("SameInstanceInstalledTwice")).to(Foo.class); } } /** * All instances are equal to each another. */ static class TwoInstancesInstalledOnBinder implements GinModule { public void configure(GinBinder binder) { binder.bind(Foo.class).annotatedWith( Names.named("TwoInstancesInstalledOnBinder")).to(Foo.class); } @Override public boolean equals(Object obj) { return obj instanceof TwoInstancesInstalledOnBinder; } @Override public int hashCode() { return 42; } } static class PrivateModuleInstalledTwiceOnBinder extends PrivateGinModule { @Override protected void configure() { bind(Foo.class).annotatedWith(Names.named("BoundInPrivateModule")) .to(Foo.class); expose(Foo.class).annotatedWith(Names.named("BoundInPrivateModule")); } @Override public boolean equals(Object obj) { return obj instanceof PrivateModuleInstalledTwiceOnBinder; } @Override public int hashCode() { return 42; } } static class InstalledFromDistinctModules implements GinModule { public void configure(GinBinder binder) { binder.bind(Foo.class).annotatedWith( Names.named("InstalledFromDistinctModules")).to(Foo.class); } @Override public boolean equals(Object obj) { return obj instanceof InstalledFromDistinctModules; } @Override public int hashCode() { return 42; } static class A implements GinModule { public void configure(GinBinder binder) { binder.install(new InstalledFromDistinctModules()); } } static class B implements GinModule { public void configure(GinBinder binder) { binder.install(new InstalledFromDistinctModules()); } } } }