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 
30 import junit.framework.TestCase;
31 
32 import java.util.Collections;
33 import java.util.UUID;
34 import java.util.concurrent.Callable;
35 import java.util.concurrent.atomic.AtomicInteger;
36 import java.util.function.Predicate;
37 
38 /**
39  * Test bindings to lambdas, method references, etc.
40  *
41  * @author cgdecker@google.com (Colin Decker)
42  */
43 public 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 
testBinding_lambdaToInterface()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 
testProviderMethod_returningLambda()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 
testProviderMethod_containingLambda_throwingException()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 
testProvider_usingJdk8Features()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
StringProvider(UUID uuid)128     StringProvider(UUID uuid) {
129       this.uuid = uuid;
130     }
131 
132     @Override
get()133     public String get() {
134       return Collections.singleton(uuid).stream()
135           .map(UUID::toString)
136           .findFirst().get();
137     }
138   }
139 
testBinding_toProvider_lambda()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 
testBinding_toProvider_methodReference()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 
provideString()165   private String provideString() {
166     return "Hello";
167   }
168 }
169