166b415a2066cac9f36ed58070777de388f63a3a4crazyboblee/**
266b415a2066cac9f36ed58070777de388f63a3a4crazyboblee * Copyright (C) 2006 Google Inc.
366b415a2066cac9f36ed58070777de388f63a3a4crazyboblee *
466b415a2066cac9f36ed58070777de388f63a3a4crazyboblee * Licensed under the Apache License, Version 2.0 (the "License");
566b415a2066cac9f36ed58070777de388f63a3a4crazyboblee * you may not use this file except in compliance with the License.
666b415a2066cac9f36ed58070777de388f63a3a4crazyboblee * You may obtain a copy of the License at
766b415a2066cac9f36ed58070777de388f63a3a4crazyboblee *
866b415a2066cac9f36ed58070777de388f63a3a4crazyboblee * http://www.apache.org/licenses/LICENSE-2.0
966b415a2066cac9f36ed58070777de388f63a3a4crazyboblee *
1066b415a2066cac9f36ed58070777de388f63a3a4crazyboblee * Unless required by applicable law or agreed to in writing, software
1166b415a2066cac9f36ed58070777de388f63a3a4crazyboblee * distributed under the License is distributed on an "AS IS" BASIS,
1266b415a2066cac9f36ed58070777de388f63a3a4crazyboblee * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1366b415a2066cac9f36ed58070777de388f63a3a4crazyboblee * See the License for the specific language governing permissions and
1466b415a2066cac9f36ed58070777de388f63a3a4crazyboblee * limitations under the License.
1566b415a2066cac9f36ed58070777de388f63a3a4crazyboblee */
1666b415a2066cac9f36ed58070777de388f63a3a4crazyboblee
1766b415a2066cac9f36ed58070777de388f63a3a4crazybobleepackage com.google.inject;
1866b415a2066cac9f36ed58070777de388f63a3a4crazyboblee
19c0c12ea61414709600577bb547e1e77b4a405691kevinbimport static java.lang.annotation.RetentionPolicy.RUNTIME;
206a565c7216be86b23ae7390febd6c1f061a3981fkevinbimport static junit.framework.Assert.assertEquals;
216a565c7216be86b23ae7390febd6c1f061a3981fkevinbimport static junit.framework.Assert.assertSame;
22b7a02b02d81c830d148355c90bc309bcd66fb592sberlin
2366b415a2066cac9f36ed58070777de388f63a3a4crazybobleeimport org.springframework.beans.MutablePropertyValues;
2466b415a2066cac9f36ed58070777de388f63a3a4crazybobleeimport org.springframework.beans.factory.config.ConstructorArgumentValues;
2566b415a2066cac9f36ed58070777de388f63a3a4crazybobleeimport org.springframework.beans.factory.config.RuntimeBeanReference;
2666b415a2066cac9f36ed58070777de388f63a3a4crazybobleeimport org.springframework.beans.factory.support.DefaultListableBeanFactory;
2766b415a2066cac9f36ed58070777de388f63a3a4crazybobleeimport org.springframework.beans.factory.support.RootBeanDefinition;
2866b415a2066cac9f36ed58070777de388f63a3a4crazyboblee
29b7a02b02d81c830d148355c90bc309bcd66fb592sberlinimport java.lang.annotation.Retention;
30b7a02b02d81c830d148355c90bc309bcd66fb592sberlinimport java.text.DecimalFormat;
31b7a02b02d81c830d148355c90bc309bcd66fb592sberlinimport java.util.concurrent.Callable;
32b7a02b02d81c830d148355c90bc309bcd66fb592sberlin
3366b415a2066cac9f36ed58070777de388f63a3a4crazyboblee/**
34e9f0fa57c4b41b803faa42273bd8697f531a5fb8crazyboblee * A semi-useless microbenchmark. Spring and Guice constuct the same object
35e9f0fa57c4b41b803faa42273bd8697f531a5fb8crazyboblee * graph a bunch of times, and we see who can construct the most per second.
36e9f0fa57c4b41b803faa42273bd8697f531a5fb8crazyboblee * As of this writing Guice is more than 50X faster. Also useful for comparing
37e9f0fa57c4b41b803faa42273bd8697f531a5fb8crazyboblee * pure Java configuration options.
3866b415a2066cac9f36ed58070777de388f63a3a4crazyboblee *
3966b415a2066cac9f36ed58070777de388f63a3a4crazyboblee * @author crazybob@google.com (Bob Lee)
4066b415a2066cac9f36ed58070777de388f63a3a4crazyboblee */
41041e93387a67a7d15330592077b08577b2961a2ecrazybobleepublic class PerformanceComparison {
4266b415a2066cac9f36ed58070777de388f63a3a4crazyboblee
43e3adfd619abae820b90951f383ec7a271a62c0b0crazyboblee  public static void main(String[] args) throws Exception {
44e3adfd619abae820b90951f383ec7a271a62c0b0crazyboblee    // Once warm up. Takes lazy loading out of the equation and ensures we
45e3adfd619abae820b90951f383ec7a271a62c0b0crazyboblee    // created the graphs properly.
46e3adfd619abae820b90951f383ec7a271a62c0b0crazyboblee    validate(springFactory);
47e3adfd619abae820b90951f383ec7a271a62c0b0crazyboblee    validate(juiceFactory);
48e3adfd619abae820b90951f383ec7a271a62c0b0crazyboblee    validate(byHandFactory);
49e3adfd619abae820b90951f383ec7a271a62c0b0crazyboblee
50e3adfd619abae820b90951f383ec7a271a62c0b0crazyboblee    for (int i2 = 0; i2 < 10; i2++) {
51e3adfd619abae820b90951f383ec7a271a62c0b0crazyboblee      iterate(springFactory, "Spring:  ");
52e3adfd619abae820b90951f383ec7a271a62c0b0crazyboblee      iterate(juiceFactory,  "Guice:   ");
53e3adfd619abae820b90951f383ec7a271a62c0b0crazyboblee      iterate(byHandFactory, "By Hand: ");
54e3adfd619abae820b90951f383ec7a271a62c0b0crazyboblee
55e3adfd619abae820b90951f383ec7a271a62c0b0crazyboblee      System.err.println();
56e3adfd619abae820b90951f383ec7a271a62c0b0crazyboblee    }
573ea63ff1115a2a8bf1999fd763f699930efe701acrazyboblee
583ea63ff1115a2a8bf1999fd763f699930efe701acrazyboblee    System.err.println("Concurrent:");
593ea63ff1115a2a8bf1999fd763f699930efe701acrazyboblee
603ea63ff1115a2a8bf1999fd763f699930efe701acrazyboblee    for (int i2 = 0; i2 < 10; i2++) {
613ea63ff1115a2a8bf1999fd763f699930efe701acrazyboblee      concurrentlyIterate(springFactory, "Spring:  ");
623ea63ff1115a2a8bf1999fd763f699930efe701acrazyboblee      concurrentlyIterate(juiceFactory,  "Guice:   ");
633ea63ff1115a2a8bf1999fd763f699930efe701acrazyboblee      concurrentlyIterate(byHandFactory, "By Hand: ");
643ea63ff1115a2a8bf1999fd763f699930efe701acrazyboblee
653ea63ff1115a2a8bf1999fd763f699930efe701acrazyboblee      System.err.println();
663ea63ff1115a2a8bf1999fd763f699930efe701acrazyboblee    }
67e3adfd619abae820b90951f383ec7a271a62c0b0crazyboblee  }
68e3adfd619abae820b90951f383ec7a271a62c0b0crazyboblee
6966b415a2066cac9f36ed58070777de388f63a3a4crazyboblee  static final Callable<Foo> springFactory = new Callable<Foo>() {
7066b415a2066cac9f36ed58070777de388f63a3a4crazyboblee
7166b415a2066cac9f36ed58070777de388f63a3a4crazyboblee    final DefaultListableBeanFactory beanFactory;
7266b415a2066cac9f36ed58070777de388f63a3a4crazyboblee
7366b415a2066cac9f36ed58070777de388f63a3a4crazyboblee    {
7466b415a2066cac9f36ed58070777de388f63a3a4crazyboblee      beanFactory = new DefaultListableBeanFactory();
7566b415a2066cac9f36ed58070777de388f63a3a4crazyboblee
7666b415a2066cac9f36ed58070777de388f63a3a4crazyboblee      RootBeanDefinition tee = new RootBeanDefinition(TeeImpl.class, true);
7766b415a2066cac9f36ed58070777de388f63a3a4crazyboblee      tee.setLazyInit(true);
7866b415a2066cac9f36ed58070777de388f63a3a4crazyboblee      ConstructorArgumentValues teeValues = new ConstructorArgumentValues();
7966b415a2066cac9f36ed58070777de388f63a3a4crazyboblee      teeValues.addGenericArgumentValue("test");
8066b415a2066cac9f36ed58070777de388f63a3a4crazyboblee      tee.setConstructorArgumentValues(teeValues);
8166b415a2066cac9f36ed58070777de388f63a3a4crazyboblee
8266b415a2066cac9f36ed58070777de388f63a3a4crazyboblee      RootBeanDefinition bar = new RootBeanDefinition(BarImpl.class, false);
8366b415a2066cac9f36ed58070777de388f63a3a4crazyboblee      ConstructorArgumentValues barValues = new ConstructorArgumentValues();
8466b415a2066cac9f36ed58070777de388f63a3a4crazyboblee      barValues.addGenericArgumentValue(new RuntimeBeanReference("tee"));
8566b415a2066cac9f36ed58070777de388f63a3a4crazyboblee      barValues.addGenericArgumentValue(5);
8666b415a2066cac9f36ed58070777de388f63a3a4crazyboblee      bar.setConstructorArgumentValues(barValues);
8766b415a2066cac9f36ed58070777de388f63a3a4crazyboblee
8866b415a2066cac9f36ed58070777de388f63a3a4crazyboblee      RootBeanDefinition foo = new RootBeanDefinition(Foo.class, false);
8966b415a2066cac9f36ed58070777de388f63a3a4crazyboblee      MutablePropertyValues fooValues = new MutablePropertyValues();
9066b415a2066cac9f36ed58070777de388f63a3a4crazyboblee      fooValues.addPropertyValue("i", 5);
9166b415a2066cac9f36ed58070777de388f63a3a4crazyboblee      fooValues.addPropertyValue("bar", new RuntimeBeanReference("bar"));
9266b415a2066cac9f36ed58070777de388f63a3a4crazyboblee      fooValues.addPropertyValue("copy", new RuntimeBeanReference("bar"));
9366b415a2066cac9f36ed58070777de388f63a3a4crazyboblee      fooValues.addPropertyValue("s", "test");
9466b415a2066cac9f36ed58070777de388f63a3a4crazyboblee      foo.setPropertyValues(fooValues);
9566b415a2066cac9f36ed58070777de388f63a3a4crazyboblee
9666b415a2066cac9f36ed58070777de388f63a3a4crazyboblee      beanFactory.registerBeanDefinition("foo", foo);
9766b415a2066cac9f36ed58070777de388f63a3a4crazyboblee      beanFactory.registerBeanDefinition("bar", bar);
9866b415a2066cac9f36ed58070777de388f63a3a4crazyboblee      beanFactory.registerBeanDefinition("tee", tee);
9966b415a2066cac9f36ed58070777de388f63a3a4crazyboblee    }
10066b415a2066cac9f36ed58070777de388f63a3a4crazyboblee
10166b415a2066cac9f36ed58070777de388f63a3a4crazyboblee    public Foo call() throws Exception {
10266b415a2066cac9f36ed58070777de388f63a3a4crazyboblee      return (Foo) beanFactory.getBean("foo");
10366b415a2066cac9f36ed58070777de388f63a3a4crazyboblee    }
10466b415a2066cac9f36ed58070777de388f63a3a4crazyboblee  };
10566b415a2066cac9f36ed58070777de388f63a3a4crazyboblee
10666b415a2066cac9f36ed58070777de388f63a3a4crazyboblee  static final Callable<Foo> juiceFactory = new Callable<Foo>() {
107bd9544e08ba5d41995024e7e301faf465457e593crazyboblee    final Provider<Foo> fooProvider;
1087c5b2c4e5e3607c63c2785c8bc025706a158db80crazyboblee    {
109a2915a9855e2d110c708425ec44854587e419790kevinb      Injector injector;
1109bb62020927911172430dc3d94ee61796d519236crazyboblee      try {
111a2915a9855e2d110c708425ec44854587e419790kevinb        injector = Guice.createInjector(new AbstractModule() {
112db85d9c090a13457c47b91d018aad3aa8cecbb7ekevinb          protected void configure() {
113db85d9c090a13457c47b91d018aad3aa8cecbb7ekevinb            bind(Tee.class).to(TeeImpl.class);
114db85d9c090a13457c47b91d018aad3aa8cecbb7ekevinb            bind(Bar.class).to(BarImpl.class);
115db85d9c090a13457c47b91d018aad3aa8cecbb7ekevinb            bind(Foo.class);
1169e139521222140cba64ed77935d980d76644e4b0crazyboblee            bindConstant().annotatedWith(I.class).to(5);
1179e139521222140cba64ed77935d980d76644e4b0crazyboblee            bindConstant().annotatedWith(S.class).to("test");
118db85d9c090a13457c47b91d018aad3aa8cecbb7ekevinb          }
119db85d9c090a13457c47b91d018aad3aa8cecbb7ekevinb        });
1205746d5d7f2a97a9720ee33a7c7f9cc8e60e5cc71crazyboblee      } catch (CreationException e) {
1219bb62020927911172430dc3d94ee61796d519236crazyboblee        throw new RuntimeException(e);
1229bb62020927911172430dc3d94ee61796d519236crazyboblee      }
123a2915a9855e2d110c708425ec44854587e419790kevinb      fooProvider = injector.getProvider(Foo.class);
1247c5b2c4e5e3607c63c2785c8bc025706a158db80crazyboblee    }
12566b415a2066cac9f36ed58070777de388f63a3a4crazyboblee
12666b415a2066cac9f36ed58070777de388f63a3a4crazyboblee    public Foo call() throws Exception {
127bd9544e08ba5d41995024e7e301faf465457e593crazyboblee      return fooProvider.get();
12866b415a2066cac9f36ed58070777de388f63a3a4crazyboblee    }
12966b415a2066cac9f36ed58070777de388f63a3a4crazyboblee  };
13066b415a2066cac9f36ed58070777de388f63a3a4crazyboblee
1319e5fe5d549368dc52aa1d79f1f70ac0146a51542crazyboblee  static final Callable<Foo> byHandFactory = new Callable<Foo>() {
1329e5fe5d549368dc52aa1d79f1f70ac0146a51542crazyboblee    final Tee tee = new TeeImpl("test");
1339e5fe5d549368dc52aa1d79f1f70ac0146a51542crazyboblee    public Foo call() throws Exception {
1349e5fe5d549368dc52aa1d79f1f70ac0146a51542crazyboblee      Foo foo = new Foo();
1359e5fe5d549368dc52aa1d79f1f70ac0146a51542crazyboblee      foo.setI(5);
1369e5fe5d549368dc52aa1d79f1f70ac0146a51542crazyboblee      foo.setS("test");
1379e5fe5d549368dc52aa1d79f1f70ac0146a51542crazyboblee      Bar bar = new BarImpl(tee, 5);
1389e5fe5d549368dc52aa1d79f1f70ac0146a51542crazyboblee      Bar copy = new BarImpl(tee, 5);
1399e5fe5d549368dc52aa1d79f1f70ac0146a51542crazyboblee      foo.setBar(bar);
1409e5fe5d549368dc52aa1d79f1f70ac0146a51542crazyboblee      foo.setCopy(copy);
1419e5fe5d549368dc52aa1d79f1f70ac0146a51542crazyboblee      return foo;
1429e5fe5d549368dc52aa1d79f1f70ac0146a51542crazyboblee    }
1439e5fe5d549368dc52aa1d79f1f70ac0146a51542crazyboblee  };
1449e5fe5d549368dc52aa1d79f1f70ac0146a51542crazyboblee
14566b415a2066cac9f36ed58070777de388f63a3a4crazyboblee  static void validate(Callable<Foo> t) throws Exception {
14666b415a2066cac9f36ed58070777de388f63a3a4crazyboblee    Foo foo = t.call();
14766b415a2066cac9f36ed58070777de388f63a3a4crazyboblee    assertEquals(5, foo.i);
14866b415a2066cac9f36ed58070777de388f63a3a4crazyboblee    assertEquals("test", foo.s);
14966b415a2066cac9f36ed58070777de388f63a3a4crazyboblee    assertSame(foo.bar.getTee(), foo.copy.getTee());
15066b415a2066cac9f36ed58070777de388f63a3a4crazyboblee    assertEquals(5, foo.bar.getI());
15166b415a2066cac9f36ed58070777de388f63a3a4crazyboblee    assertEquals("test", foo.bar.getTee().getS());
15266b415a2066cac9f36ed58070777de388f63a3a4crazyboblee  }
15366b415a2066cac9f36ed58070777de388f63a3a4crazyboblee
1546a565c7216be86b23ae7390febd6c1f061a3981fkevinb  static final DecimalFormat format = new DecimalFormat();
15566b415a2066cac9f36ed58070777de388f63a3a4crazyboblee
1563ea63ff1115a2a8bf1999fd763f699930efe701acrazyboblee  static void iterate(Callable<Foo> callable, String label) {
157041e93387a67a7d15330592077b08577b2961a2ecrazyboblee    int count = 100000;
1583ea63ff1115a2a8bf1999fd763f699930efe701acrazyboblee
159041e93387a67a7d15330592077b08577b2961a2ecrazyboblee    long time = System.currentTimeMillis();
1603ea63ff1115a2a8bf1999fd763f699930efe701acrazyboblee
161041e93387a67a7d15330592077b08577b2961a2ecrazyboblee    for (int i = 0; i < count; i++) {
1623ea63ff1115a2a8bf1999fd763f699930efe701acrazyboblee      try {
1633ea63ff1115a2a8bf1999fd763f699930efe701acrazyboblee        callable.call();
1643ea63ff1115a2a8bf1999fd763f699930efe701acrazyboblee      }
1653ea63ff1115a2a8bf1999fd763f699930efe701acrazyboblee      catch (Exception e) {
1663ea63ff1115a2a8bf1999fd763f699930efe701acrazyboblee        throw new RuntimeException(e);
1673ea63ff1115a2a8bf1999fd763f699930efe701acrazyboblee      }
1683ea63ff1115a2a8bf1999fd763f699930efe701acrazyboblee    }
1693ea63ff1115a2a8bf1999fd763f699930efe701acrazyboblee
1703ea63ff1115a2a8bf1999fd763f699930efe701acrazyboblee    time = System.currentTimeMillis() - time;
1713ea63ff1115a2a8bf1999fd763f699930efe701acrazyboblee
1723ea63ff1115a2a8bf1999fd763f699930efe701acrazyboblee    System.err.println(label
1733ea63ff1115a2a8bf1999fd763f699930efe701acrazyboblee        + format.format(count * 1000 / time) + " creations/s");
1743ea63ff1115a2a8bf1999fd763f699930efe701acrazyboblee  }
1753ea63ff1115a2a8bf1999fd763f699930efe701acrazyboblee
1763ea63ff1115a2a8bf1999fd763f699930efe701acrazyboblee  static void concurrentlyIterate(final Callable<Foo> callable, String label) {
1773ea63ff1115a2a8bf1999fd763f699930efe701acrazyboblee    int threadCount = 10;
1783ea63ff1115a2a8bf1999fd763f699930efe701acrazyboblee    final int count = 10000;
1793ea63ff1115a2a8bf1999fd763f699930efe701acrazyboblee
1803ea63ff1115a2a8bf1999fd763f699930efe701acrazyboblee    Thread[] threads = new Thread[threadCount];
1813ea63ff1115a2a8bf1999fd763f699930efe701acrazyboblee
1823ea63ff1115a2a8bf1999fd763f699930efe701acrazyboblee    for (int i = 0; i < threadCount; i++) {
1833ea63ff1115a2a8bf1999fd763f699930efe701acrazyboblee      threads[i] = new Thread() {
1843ea63ff1115a2a8bf1999fd763f699930efe701acrazyboblee        public void run() {
1853ea63ff1115a2a8bf1999fd763f699930efe701acrazyboblee          for (int i = 0; i < count; i++) {
1863ea63ff1115a2a8bf1999fd763f699930efe701acrazyboblee            try {
1873ea63ff1115a2a8bf1999fd763f699930efe701acrazyboblee              validate(callable);
1883ea63ff1115a2a8bf1999fd763f699930efe701acrazyboblee            }
1893ea63ff1115a2a8bf1999fd763f699930efe701acrazyboblee            catch (Exception e) {
1903ea63ff1115a2a8bf1999fd763f699930efe701acrazyboblee              throw new RuntimeException(e);
1913ea63ff1115a2a8bf1999fd763f699930efe701acrazyboblee            }
1923ea63ff1115a2a8bf1999fd763f699930efe701acrazyboblee          }
1933ea63ff1115a2a8bf1999fd763f699930efe701acrazyboblee        }
1943ea63ff1115a2a8bf1999fd763f699930efe701acrazyboblee      };
1953ea63ff1115a2a8bf1999fd763f699930efe701acrazyboblee    }
1963ea63ff1115a2a8bf1999fd763f699930efe701acrazyboblee
1973ea63ff1115a2a8bf1999fd763f699930efe701acrazyboblee
1983ea63ff1115a2a8bf1999fd763f699930efe701acrazyboblee    long time = System.currentTimeMillis();
1993ea63ff1115a2a8bf1999fd763f699930efe701acrazyboblee
2003ea63ff1115a2a8bf1999fd763f699930efe701acrazyboblee    for (int i = 0; i < threadCount; i++) {
2013ea63ff1115a2a8bf1999fd763f699930efe701acrazyboblee      threads[i].start();
202041e93387a67a7d15330592077b08577b2961a2ecrazyboblee    }
2033ea63ff1115a2a8bf1999fd763f699930efe701acrazyboblee
2043ea63ff1115a2a8bf1999fd763f699930efe701acrazyboblee    for (int i = 0; i < threadCount; i++) {
2053ea63ff1115a2a8bf1999fd763f699930efe701acrazyboblee      try {
2063ea63ff1115a2a8bf1999fd763f699930efe701acrazyboblee        threads[i].join();
2073ea63ff1115a2a8bf1999fd763f699930efe701acrazyboblee      }
2083ea63ff1115a2a8bf1999fd763f699930efe701acrazyboblee      catch (InterruptedException e) {
2093ea63ff1115a2a8bf1999fd763f699930efe701acrazyboblee        throw new RuntimeException(e);
2103ea63ff1115a2a8bf1999fd763f699930efe701acrazyboblee      }
2113ea63ff1115a2a8bf1999fd763f699930efe701acrazyboblee    }
2123ea63ff1115a2a8bf1999fd763f699930efe701acrazyboblee
213041e93387a67a7d15330592077b08577b2961a2ecrazyboblee    time = System.currentTimeMillis() - time;
2143ea63ff1115a2a8bf1999fd763f699930efe701acrazyboblee
215e3adfd619abae820b90951f383ec7a271a62c0b0crazyboblee    System.err.println(label
216e3adfd619abae820b90951f383ec7a271a62c0b0crazyboblee        + format.format(count * 1000 / time) + " creations/s");
217041e93387a67a7d15330592077b08577b2961a2ecrazyboblee  }
218041e93387a67a7d15330592077b08577b2961a2ecrazyboblee
21966b415a2066cac9f36ed58070777de388f63a3a4crazyboblee  public static class Foo {
22066b415a2066cac9f36ed58070777de388f63a3a4crazyboblee
22166b415a2066cac9f36ed58070777de388f63a3a4crazyboblee    Bar bar;
22266b415a2066cac9f36ed58070777de388f63a3a4crazyboblee    Bar copy;
22366b415a2066cac9f36ed58070777de388f63a3a4crazyboblee    String s;
22466b415a2066cac9f36ed58070777de388f63a3a4crazyboblee    int i;
22566b415a2066cac9f36ed58070777de388f63a3a4crazyboblee
2264602a6fe08692b38cf36aa3cdb5c4e340e6929d7crazyboblee    @Inject
2271c4d3e37ba5aa517819f56e8544c4269b8ccadc3crazyboblee    public void setI(@I int i) {
22866b415a2066cac9f36ed58070777de388f63a3a4crazyboblee      this.i = i;
22966b415a2066cac9f36ed58070777de388f63a3a4crazyboblee    }
23066b415a2066cac9f36ed58070777de388f63a3a4crazyboblee
23166b415a2066cac9f36ed58070777de388f63a3a4crazyboblee    @Inject
23266b415a2066cac9f36ed58070777de388f63a3a4crazyboblee    public void setBar(Bar bar) {
23366b415a2066cac9f36ed58070777de388f63a3a4crazyboblee      this.bar = bar;
23466b415a2066cac9f36ed58070777de388f63a3a4crazyboblee    }
23566b415a2066cac9f36ed58070777de388f63a3a4crazyboblee
23666b415a2066cac9f36ed58070777de388f63a3a4crazyboblee    @Inject
23766b415a2066cac9f36ed58070777de388f63a3a4crazyboblee    public void setCopy(Bar copy) {
23866b415a2066cac9f36ed58070777de388f63a3a4crazyboblee      this.copy = copy;
23966b415a2066cac9f36ed58070777de388f63a3a4crazyboblee    }
24066b415a2066cac9f36ed58070777de388f63a3a4crazyboblee
2414602a6fe08692b38cf36aa3cdb5c4e340e6929d7crazyboblee    @Inject
2421c4d3e37ba5aa517819f56e8544c4269b8ccadc3crazyboblee    public void setS(@S String s) {
24366b415a2066cac9f36ed58070777de388f63a3a4crazyboblee      this.s = s;
24466b415a2066cac9f36ed58070777de388f63a3a4crazyboblee    }
24566b415a2066cac9f36ed58070777de388f63a3a4crazyboblee  }
24666b415a2066cac9f36ed58070777de388f63a3a4crazyboblee
24766b415a2066cac9f36ed58070777de388f63a3a4crazyboblee  interface Bar {
24866b415a2066cac9f36ed58070777de388f63a3a4crazyboblee
24966b415a2066cac9f36ed58070777de388f63a3a4crazyboblee    Tee getTee();
25066b415a2066cac9f36ed58070777de388f63a3a4crazyboblee    int getI();
25166b415a2066cac9f36ed58070777de388f63a3a4crazyboblee  }
25266b415a2066cac9f36ed58070777de388f63a3a4crazyboblee
25366b415a2066cac9f36ed58070777de388f63a3a4crazyboblee  public static class BarImpl implements Bar {
25466b415a2066cac9f36ed58070777de388f63a3a4crazyboblee
25566b415a2066cac9f36ed58070777de388f63a3a4crazyboblee    final int i;
25666b415a2066cac9f36ed58070777de388f63a3a4crazyboblee    final Tee tee;
25766b415a2066cac9f36ed58070777de388f63a3a4crazyboblee
25866b415a2066cac9f36ed58070777de388f63a3a4crazyboblee    @Inject
2591c4d3e37ba5aa517819f56e8544c4269b8ccadc3crazyboblee    public BarImpl(Tee tee, @I int i) {
26066b415a2066cac9f36ed58070777de388f63a3a4crazyboblee      this.tee = tee;
26166b415a2066cac9f36ed58070777de388f63a3a4crazyboblee      this.i = i;
26266b415a2066cac9f36ed58070777de388f63a3a4crazyboblee    }
26366b415a2066cac9f36ed58070777de388f63a3a4crazyboblee
26466b415a2066cac9f36ed58070777de388f63a3a4crazyboblee    public Tee getTee() {
26566b415a2066cac9f36ed58070777de388f63a3a4crazyboblee      return tee;
26666b415a2066cac9f36ed58070777de388f63a3a4crazyboblee    }
26766b415a2066cac9f36ed58070777de388f63a3a4crazyboblee
26866b415a2066cac9f36ed58070777de388f63a3a4crazyboblee    public int getI() {
26966b415a2066cac9f36ed58070777de388f63a3a4crazyboblee      return i;
27066b415a2066cac9f36ed58070777de388f63a3a4crazyboblee    }
27166b415a2066cac9f36ed58070777de388f63a3a4crazyboblee  }
27266b415a2066cac9f36ed58070777de388f63a3a4crazyboblee
27366b415a2066cac9f36ed58070777de388f63a3a4crazyboblee  interface Tee {
27466b415a2066cac9f36ed58070777de388f63a3a4crazyboblee
27566b415a2066cac9f36ed58070777de388f63a3a4crazyboblee    String getS();
27666b415a2066cac9f36ed58070777de388f63a3a4crazyboblee  }
27766b415a2066cac9f36ed58070777de388f63a3a4crazyboblee
278a2915a9855e2d110c708425ec44854587e419790kevinb  @Singleton
27966b415a2066cac9f36ed58070777de388f63a3a4crazyboblee  public static class TeeImpl implements Tee {
28066b415a2066cac9f36ed58070777de388f63a3a4crazyboblee
28166b415a2066cac9f36ed58070777de388f63a3a4crazyboblee    final String s;
28266b415a2066cac9f36ed58070777de388f63a3a4crazyboblee
28366b415a2066cac9f36ed58070777de388f63a3a4crazyboblee    @Inject
2841c4d3e37ba5aa517819f56e8544c4269b8ccadc3crazyboblee    public TeeImpl(@S String s) {
28566b415a2066cac9f36ed58070777de388f63a3a4crazyboblee      this.s = s;
28666b415a2066cac9f36ed58070777de388f63a3a4crazyboblee    }
28766b415a2066cac9f36ed58070777de388f63a3a4crazyboblee
28866b415a2066cac9f36ed58070777de388f63a3a4crazyboblee    public String getS() {
28966b415a2066cac9f36ed58070777de388f63a3a4crazyboblee      return s;
29066b415a2066cac9f36ed58070777de388f63a3a4crazyboblee    }
29166b415a2066cac9f36ed58070777de388f63a3a4crazyboblee  }
2921c4d3e37ba5aa517819f56e8544c4269b8ccadc3crazyboblee
2931c4d3e37ba5aa517819f56e8544c4269b8ccadc3crazyboblee  @Retention(RUNTIME)
294c0c12ea61414709600577bb547e1e77b4a405691kevinb  @BindingAnnotation @interface I {}
2951c4d3e37ba5aa517819f56e8544c4269b8ccadc3crazyboblee
2961c4d3e37ba5aa517819f56e8544c4269b8ccadc3crazyboblee  @Retention(RUNTIME)
297c0c12ea61414709600577bb547e1e77b4a405691kevinb  @BindingAnnotation @interface S {}
29866b415a2066cac9f36ed58070777de388f63a3a4crazyboblee}
299