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 
17 package com.google.inject.jdk8;
18 
19 import com.google.inject.AbstractModule;
20 import com.google.inject.CreationException;
21 import com.google.inject.Guice;
22 import com.google.inject.Inject;
23 import com.google.inject.Injector;
24 import com.google.inject.Key;
25 import com.google.inject.Provider;
26 import com.google.inject.Provides;
27 import com.google.inject.ProvisionException;
28 import com.google.inject.TypeLiteral;
29 import java.util.Collections;
30 import java.util.UUID;
31 import java.util.concurrent.Callable;
32 import java.util.concurrent.atomic.AtomicInteger;
33 import java.util.function.Predicate;
34 import junit.framework.TestCase;
35 
36 /**
37  * Test bindings to lambdas, method references, etc.
38  *
39  * @author cgdecker@google.com (Colin Decker)
40  */
41 public class Java8LanguageFeatureBindingTest extends TestCase {
42 
43   // Some of these tests are kind of weird.
44   // See https://github.com/google/guice/issues/757 for more on why they exist.
45 
testBinding_lambdaToInterface()46   public void testBinding_lambdaToInterface() {
47     Injector injector =
48         Guice.createInjector(
49             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 
testProviderMethod_returningLambda()61   public void testProviderMethod_returningLambda() throws Exception {
62     Injector injector =
63         Guice.createInjector(
64             new AbstractModule() {
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 
testProviderMethod_containingLambda_throwingException()76   public void testProviderMethod_containingLambda_throwingException() throws Exception {
77     Injector injector =
78         Guice.createInjector(
79             new AbstractModule() {
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 
testProvider_usingJdk8Features()99   public void testProvider_usingJdk8Features() {
100     try {
101       Guice.createInjector(
102           new AbstractModule() {
103             @Override
104             protected void configure() {
105               bind(String.class).toProvider(StringProvider.class);
106             }
107           });
108 
109       fail();
110     } catch (CreationException expected) {
111     }
112 
113     UUID uuid = UUID.randomUUID();
114     Injector injector =
115         Guice.createInjector(
116             new AbstractModule() {
117               @Override
118               protected void configure() {
119                 bind(UUID.class).toInstance(uuid);
120                 bind(String.class).toProvider(StringProvider.class);
121               }
122             });
123 
124     assertEquals(uuid.toString(), injector.getInstance(String.class));
125   }
126 
127   private static final class StringProvider implements Provider<String> {
128     private final UUID uuid;
129 
130     @Inject
StringProvider(UUID uuid)131     StringProvider(UUID uuid) {
132       this.uuid = uuid;
133     }
134 
135     @Override
get()136     public String get() {
137       return Collections.singleton(uuid).stream().map(UUID::toString).findFirst().get();
138     }
139   }
140 
testBinding_toProvider_lambda()141   public void testBinding_toProvider_lambda() {
142     Injector injector =
143         Guice.createInjector(
144             new AbstractModule() {
145               @Override
146               protected void configure() {
147                 AtomicInteger i = new AtomicInteger();
148                 bind(String.class).toProvider(() -> "Hello" + i.incrementAndGet());
149               }
150             });
151 
152     assertEquals("Hello1", injector.getInstance(String.class));
153     assertEquals("Hello2", injector.getInstance(String.class));
154   }
155 
testBinding_toProvider_methodReference()156   public void testBinding_toProvider_methodReference() {
157     Injector injector =
158         Guice.createInjector(
159             new AbstractModule() {
160               @Override
161               protected void configure() {
162                 bind(String.class).toProvider(Java8LanguageFeatureBindingTest.this::provideString);
163               }
164             });
165 
166     Provider<String> provider = injector.getProvider(String.class);
167     assertEquals("Hello", provider.get());
168   }
169 
provideString()170   private String provideString() {
171     return "Hello";
172   }
173 }
174