1/**
2 * Copyright (C) 2014 Google Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.google.inject.jdk8;
18
19import com.google.inject.AbstractModule;
20import com.google.inject.CreationException;
21import com.google.inject.Guice;
22import com.google.inject.Inject;
23import com.google.inject.Injector;
24import com.google.inject.Key;
25import com.google.inject.Provider;
26import com.google.inject.Provides;
27import com.google.inject.ProvisionException;
28import com.google.inject.TypeLiteral;
29
30import junit.framework.TestCase;
31
32import java.util.Collections;
33import java.util.UUID;
34import java.util.concurrent.Callable;
35import java.util.concurrent.atomic.AtomicInteger;
36import java.util.function.Predicate;
37
38/**
39 * Test bindings to lambdas, method references, etc.
40 *
41 * @author cgdecker@google.com (Colin Decker)
42 */
43public class Java8LanguageFeatureBindingTest extends TestCase {
44
45  // Some of these tests are kind of weird.
46  // See https://github.com/google/guice/issues/757 for more on why they exist.
47
48  public void testBinding_lambdaToInterface() {
49    Injector injector = Guice.createInjector(new AbstractModule() {
50      @Override
51      protected void configure() {
52        bind(new TypeLiteral<Predicate<Object>>() {}).toInstance(o -> o != null);
53      }
54    });
55
56    Predicate<Object> predicate = injector.getInstance(new Key<Predicate<Object>>() {});
57    assertTrue(predicate.test(new Object()));
58    assertFalse(predicate.test(null));
59  }
60
61  public void testProviderMethod_returningLambda() throws Exception {
62    Injector injector = Guice.createInjector(new AbstractModule() {
63      @Override
64      protected void configure() {}
65
66      @Provides
67      public Callable<String> provideCallable() {
68        return () -> "foo";
69      }
70    });
71
72    Callable<String> callable = injector.getInstance(new Key<Callable<String>>() {});
73    assertEquals("foo", callable.call());
74  }
75
76  public void testProviderMethod_containingLambda_throwingException() throws Exception {
77    Injector injector = Guice.createInjector(new AbstractModule() {
78      @Override
79      protected void configure() {}
80
81      @Provides
82      public Callable<String> provideCallable() {
83        if (Boolean.parseBoolean("false")) { // avoid dead code warnings
84          return () -> "foo";
85        } else {
86          throw new RuntimeException("foo");
87        }
88      }
89    });
90
91    try {
92      injector.getInstance(new Key<Callable<String>>() {});
93    } catch (ProvisionException expected) {
94      assertTrue(expected.getCause() instanceof RuntimeException);
95      assertEquals("foo", expected.getCause().getMessage());
96    }
97  }
98
99  public void testProvider_usingJdk8Features() {
100    try {
101      Guice.createInjector(new AbstractModule() {
102        @Override
103        protected void configure() {
104          bind(String.class).toProvider(StringProvider.class);
105        }
106      });
107
108      fail();
109    } catch (CreationException expected) {
110    }
111
112    UUID uuid = UUID.randomUUID();
113    Injector injector = Guice.createInjector(new AbstractModule() {
114      @Override
115      protected void configure() {
116        bind(UUID.class).toInstance(uuid);
117        bind(String.class).toProvider(StringProvider.class);
118      }
119    });
120
121    assertEquals(uuid.toString(), injector.getInstance(String.class));
122  }
123
124  private static final class StringProvider implements Provider<String> {
125    private final UUID uuid;
126
127    @Inject
128    StringProvider(UUID uuid) {
129      this.uuid = uuid;
130    }
131
132    @Override
133    public String get() {
134      return Collections.singleton(uuid).stream()
135          .map(UUID::toString)
136          .findFirst().get();
137    }
138  }
139
140  public void testBinding_toProvider_lambda() {
141    Injector injector = Guice.createInjector(new AbstractModule() {
142      @Override
143      protected void configure() {
144        AtomicInteger i = new AtomicInteger();
145        bind(String.class).toProvider(() -> "Hello" + i.incrementAndGet());
146      }
147    });
148
149    assertEquals("Hello1", injector.getInstance(String.class));
150    assertEquals("Hello2", injector.getInstance(String.class));
151  }
152
153  public void testBinding_toProvider_methodReference() {
154    Injector injector = Guice.createInjector(new AbstractModule() {
155      @Override
156      protected void configure() {
157        bind(String.class).toProvider(Java8LanguageFeatureBindingTest.this::provideString);
158      }
159    });
160
161    Provider<String> provider = injector.getProvider(String.class);
162    assertEquals("Hello", provider.get());
163  }
164
165  private String provideString() {
166    return "Hello";
167  }
168}
169