From 28fbf0859c63b2a30555b3295fe738c263c0db6b Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Fri, 10 Jul 2015 21:45:41 -0400 Subject: lazy: Fix LazyBinder de-duplication. --- .../java/com/tavianator/sangria/lazy/LazyTest.java | 204 ++++++++++----------- 1 file changed, 94 insertions(+), 110 deletions(-) (limited to 'sangria-lazy/src/test') diff --git a/sangria-lazy/src/test/java/com/tavianator/sangria/lazy/LazyTest.java b/sangria-lazy/src/test/java/com/tavianator/sangria/lazy/LazyTest.java index 8bea02d..ee6200a 100644 --- a/sangria-lazy/src/test/java/com/tavianator/sangria/lazy/LazyTest.java +++ b/sangria-lazy/src/test/java/com/tavianator/sangria/lazy/LazyTest.java @@ -22,6 +22,7 @@ import java.lang.annotation.RetentionPolicy; import java.util.*; import javax.inject.Inject; import javax.inject.Qualifier; +import javax.inject.Singleton; import com.google.inject.AbstractModule; import com.google.inject.Binding; @@ -30,6 +31,8 @@ import com.google.inject.Guice; import com.google.inject.Injector; import com.google.inject.Key; import com.google.inject.Module; +import com.google.inject.ProvidedBy; +import com.google.inject.Provider; import com.google.inject.spi.DefaultBindingTargetVisitor; import com.google.inject.spi.Element; import com.google.inject.spi.Elements; @@ -43,7 +46,7 @@ import static org.junit.Assert.*; * Tests for {@link Lazy} injection. * * @author Tavian Barnes (tavianator@tavianator.com) - * @version 1.2 + * @version 1.3 * @since 1.2 */ public class LazyTest { @@ -52,157 +55,139 @@ public class LazyTest { private @interface Simple { } + @ProvidedBy(CountingProvider.class) private interface Abstract { } - private static class Concrete implements Abstract { - static final ThreadLocal INSTANCES = new ThreadLocal() { - @Override - protected Integer initialValue() { - return 0; - } - }; + @Singleton + private static class CountingProvider implements Provider { + int count = 0; @Inject - Concrete() { - INSTANCES.set(INSTANCES.get() + 1); + CountingProvider() { + } + + @Override + public Abstract get() { + ++count; + return new Abstract() { }; } } - private static class HasConcrete { - final Lazy lazy; + private static class HasLazy { + final Lazy lazy; @Inject - HasConcrete(Lazy lazy) { + HasLazy(Lazy lazy) { this.lazy = lazy; } } - private static class HasQualifiedAbstract { - @Inject @Simple Lazy lazy; + private static class HasSimpleLazy extends HasLazy { + @Inject + HasSimpleLazy(@Simple Lazy lazy) { + super(lazy); + } } - @Test - public void testJustInTime() { - testHasConcrete(Guice.createInjector()); - } + private void test(Injector injector, Class type) { + CountingProvider provider = injector.getInstance(CountingProvider.class); + HasLazy hasLazy = injector.getInstance(type); + assertThat(provider.count, equalTo(0)); - @Test - public void testExplicitBindings() { - testHasConcrete(Guice.createInjector(new AbstractModule() { - @Override - protected void configure() { - binder().requireExplicitBindings(); + Abstract a = hasLazy.lazy.get(); + assertThat(provider.count, equalTo(1)); - bind(HasConcrete.class); + assertThat(hasLazy.lazy.get(), sameInstance(a)); + assertThat(provider.count, equalTo(1)); - bind(Concrete.class); - LazyBinder.create(binder()) - .bind(Concrete.class); - } - })); - } + hasLazy = injector.getInstance(type); + assertThat(provider.count, equalTo(1)); - @Test - public void testBestPractices() { - Module module = new AbstractModule() { - @Override - protected void configure() { - bind(HasConcrete.class); + a = hasLazy.lazy.get(); + assertThat(provider.count, equalTo(2)); - bind(Concrete.class); - LazyBinder.create(binder()) - .bind(Concrete.class); - } - }; - assertThat(module, is(atomic())); - assertThat(module, followsBestPractices()); + assertThat(hasLazy.lazy.get(), sameInstance(a)); + assertThat(provider.count, equalTo(2)); } - private void testHasConcrete(Injector injector) { - int before = Concrete.INSTANCES.get(); - - HasConcrete hasConcrete = injector.getInstance(HasConcrete.class); - assertThat(Concrete.INSTANCES.get(), equalTo(before)); - - Concrete instance = hasConcrete.lazy.get(); - assertThat(Concrete.INSTANCES.get(), equalTo(before + 1)); + @Test + public void testJustInTime() { + test(Guice.createInjector(), HasLazy.class); + } - Concrete instance2 = hasConcrete.lazy.get(); - assertThat(instance2, sameInstance(instance)); - assertThat(Concrete.INSTANCES.get(), equalTo(before + 1)); + private static final Module EXPLICIT_MODULE = new AbstractModule() { + @Override + protected void configure() { + bind(Abstract.class) + .toProvider(CountingProvider.class); - HasConcrete hasConcrete2 = injector.getInstance(HasConcrete.class); - assertThat(Concrete.INSTANCES.get(), equalTo(before + 1)); + LazyBinder.create(binder()) + .bind(Abstract.class); - Concrete instance3 = hasConcrete2.lazy.get(); - assertThat(instance3, not(sameInstance(instance))); - assertThat(Concrete.INSTANCES.get(), equalTo(before + 2)); - } + bind(HasLazy.class); + } + }; @Test - public void testBindSeparately() { - testQualifiedAbstract(Guice.createInjector(new AbstractModule() { - @Override - protected void configure() { - bind(Abstract.class) - .annotatedWith(Simple.class) - .to(Concrete.class); - - LazyBinder.create(binder()) - .bind(Abstract.class) - .annotatedWith(Simple.class); - } - })); + public void testExplicitBindings() { + test(Guice.createInjector(EXPLICIT_MODULE), HasLazy.class); } - @Test - public void testBindTogether() { - testQualifiedAbstract(Guice.createInjector(new AbstractModule() { - @Override - protected void configure() { - LazyBinder.create(binder()) - .bind(Abstract.class) - .annotatedWith(Simple.class) - .to(Concrete.class); - } - })); - } + private static final Module BIND_SEPARATELY_MODULE = new AbstractModule() { + @Override + protected void configure() { + bind(Abstract.class) + .annotatedWith(Simple.class) + .toProvider(CountingProvider.class); - private void testQualifiedAbstract(Injector injector) { - int before = Concrete.INSTANCES.get(); + LazyBinder.create(binder()) + .bind(Abstract.class) + .annotatedWith(Simple.class); - HasQualifiedAbstract hasQualifiedAbstract = injector.getInstance(HasQualifiedAbstract.class); - assertThat(Concrete.INSTANCES.get(), equalTo(before)); + bind(HasSimpleLazy.class); + } + }; - Abstract instance = hasQualifiedAbstract.lazy.get(); - assertThat(Concrete.INSTANCES.get(), equalTo(before + 1)); + @Test + public void testBindSeparately() { + test(Guice.createInjector(BIND_SEPARATELY_MODULE), HasSimpleLazy.class); + } - Abstract instance2 = hasQualifiedAbstract.lazy.get(); - assertThat(instance2, sameInstance(instance2)); - assertThat(Concrete.INSTANCES.get(), equalTo(before + 1)); + private static final Module BIND_TOGETHER_MODULE = new AbstractModule() { + @Override + protected void configure() { + LazyBinder.create(binder()) + .bind(Abstract.class) + .annotatedWith(Simple.class) + .toProvider(CountingProvider.class); - HasQualifiedAbstract hasQualifiedAbstract2 = injector.getInstance(HasQualifiedAbstract.class); - assertThat(Concrete.INSTANCES.get(), equalTo(before + 1)); + bind(HasSimpleLazy.class); + } + }; - Abstract instance3 = hasQualifiedAbstract2.lazy.get(); - assertThat(instance3, not(sameInstance(instance))); - assertThat(Concrete.INSTANCES.get(), equalTo(before + 2)); + @Test + public void testBindTogether() { + test(Guice.createInjector(BIND_TOGETHER_MODULE), HasSimpleLazy.class); } - @Test(expected = CreationException.class) - public void testMissingBinding() { - Guice.createInjector(new AbstractModule() { + @Test + public void testBestPractices() { + Module module = new AbstractModule() { @Override protected void configure() { - LazyBinder.create(binder()) - .bind(Abstract.class); + install(EXPLICIT_MODULE); + install(BIND_SEPARATELY_MODULE); + install(BIND_TOGETHER_MODULE); } - }); + }; + + assertThat(module, is(atomic())); + assertThat(module, followsBestPractices()); } @Test(expected = CreationException.class) - public void testMissingQualifiedBinding() { + public void testMissingBinding() { Guice.createInjector(new AbstractModule() { @Override protected void configure() { @@ -239,7 +224,7 @@ public class LazyTest { LazyBinder.create(binder()) .bind(Abstract.class) .annotatedWith(Simple.class) - .to(Concrete.class); + .toProvider(CountingProvider.class); } }; @@ -258,6 +243,5 @@ public class LazyTest { Injector injector = Guice.createInjector(Elements.getModule(elements)); assertThat(visit(injector.getBinding(new Key>(Simple.class) { })), is(true)); assertThat(visit(injector.getBinding(new Key(Simple.class) { })), is(false)); - assertThat(visit(injector.getBinding(new Key() { })), is(false)); } } -- cgit v1.2.3 From 8c7d863828e0bf4b9045075ff3ccd386993dfbb5 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Fri, 10 Jul 2015 22:01:30 -0400 Subject: lazy: Fix Lazy when a provider returns null. --- .../java/com/tavianator/sangria/lazy/Lazy.java | 11 +++++---- .../java/com/tavianator/sangria/lazy/LazyTest.java | 27 +++++++++++++++++++++- 2 files changed, 33 insertions(+), 5 deletions(-) (limited to 'sangria-lazy/src/test') diff --git a/sangria-lazy/src/main/java/com/tavianator/sangria/lazy/Lazy.java b/sangria-lazy/src/main/java/com/tavianator/sangria/lazy/Lazy.java index adf531c..ee42a2f 100644 --- a/sangria-lazy/src/main/java/com/tavianator/sangria/lazy/Lazy.java +++ b/sangria-lazy/src/main/java/com/tavianator/sangria/lazy/Lazy.java @@ -56,8 +56,10 @@ import javax.inject.Provider; * @since 1.2 */ public final class Lazy { + private static final Object SENTINEL = new Object(); + private final Provider provider; - private volatile T instance = null; + private volatile Object instance = SENTINEL; @Inject Lazy(Provider provider) { @@ -67,15 +69,16 @@ public final class Lazy { /** * @return A lazily-produced value of type {@code T}. */ + @SuppressWarnings("unchecked") public T get() { // Double-checked locking - if (instance == null) { + if (instance == SENTINEL) { synchronized (this) { - if (instance == null) { + if (instance == SENTINEL) { instance = provider.get(); } } } - return instance; + return (T) instance; } } diff --git a/sangria-lazy/src/test/java/com/tavianator/sangria/lazy/LazyTest.java b/sangria-lazy/src/test/java/com/tavianator/sangria/lazy/LazyTest.java index ee6200a..a451a96 100644 --- a/sangria-lazy/src/test/java/com/tavianator/sangria/lazy/LazyTest.java +++ b/sangria-lazy/src/test/java/com/tavianator/sangria/lazy/LazyTest.java @@ -36,6 +36,7 @@ import com.google.inject.Provider; import com.google.inject.spi.DefaultBindingTargetVisitor; import com.google.inject.spi.Element; import com.google.inject.spi.Elements; +import com.google.inject.util.Providers; import org.junit.Test; import static com.tavianator.sangria.test.SangriaMatchers.*; @@ -62,15 +63,26 @@ public class LazyTest { @Singleton private static class CountingProvider implements Provider { int count = 0; + private final Provider impl; @Inject CountingProvider() { + this.impl = new Provider() { + @Override + public Abstract get() { + return new Abstract() { }; + } + }; + } + + CountingProvider(Abstract instance) { + this.impl = Providers.of(instance); } @Override public Abstract get() { ++count; - return new Abstract() { }; + return impl.get(); } } @@ -186,6 +198,19 @@ public class LazyTest { assertThat(module, followsBestPractices()); } + @Test + public void testNull() { + Module module = new AbstractModule() { + @Override + protected void configure() { + bind(CountingProvider.class) + .toInstance(new CountingProvider(null)); + } + }; + + test(Guice.createInjector(module), HasLazy.class); + } + @Test(expected = CreationException.class) public void testMissingBinding() { Guice.createInjector(new AbstractModule() { -- cgit v1.2.3