Add a Maven module for JDK8-specific tests to open-source Guice.
-------------
Created by MOE: http://code.google.com/p/moe-java
MOE_MIGRATED_REVID=78097782
diff --git a/jdk8-tests/pom.xml b/jdk8-tests/pom.xml
new file mode 100644
index 0000000..a5877fe
--- /dev/null
+++ b/jdk8-tests/pom.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+Copyright (c) 2014 Google, Inc. All rights reserved.
+
+This program is licensed to you under the Apache License Version 2.0,
+and you may not use this file except in compliance with the Apache License Version 2.0.
+You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0.
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the Apache License Version 2.0 is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <parent>
+    <artifactId>guice-parent</artifactId>
+    <groupId>com.google.inject</groupId>
+    <version>4.0-SNAPSHOT</version>
+  </parent>
+  <modelVersion>4.0.0</modelVersion>
+
+  <artifactId>jdk8-tests</artifactId>
+
+  <name>Google Guice - JDK8 Tests</name>
+
+  <dependencies>
+    <dependency>
+      <groupId>com.google.inject</groupId>
+      <artifactId>guice</artifactId>
+      <version>${parent.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>cglib</groupId>
+      <artifactId>cglib</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>com.google.guava</groupId>
+      <artifactId>guava-testlib</artifactId>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <artifactId>maven-compiler-plugin</artifactId>
+        <configuration>
+          <source>8</source>
+          <target>8</target>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+
+</project>
diff --git a/jdk8-tests/test/com/google/inject/jdk8/DefaultMethodInterceptionTest.java b/jdk8-tests/test/com/google/inject/jdk8/DefaultMethodInterceptionTest.java
new file mode 100644
index 0000000..29e0681
--- /dev/null
+++ b/jdk8-tests/test/com/google/inject/jdk8/DefaultMethodInterceptionTest.java
@@ -0,0 +1,223 @@
+/**
+ * Copyright (C) 2014 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.inject.jdk8;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import com.google.inject.AbstractModule;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import com.google.inject.matcher.Matchers;
+
+import junit.framework.TestCase;
+
+import org.aopalliance.intercept.MethodInterceptor;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * Tests for interception of default methods.
+ *
+ * @author cgdecker@google.com (Colin Decker)
+ */
+public class DefaultMethodInterceptionTest extends TestCase {
+
+  private static final AtomicInteger callCount = new AtomicInteger(0);
+  private static final AtomicInteger interceptedCallCount = new AtomicInteger(0);
+
+  // the interceptor's a lambda too
+  private final MethodInterceptor interceptor = invocation -> {
+    interceptedCallCount.incrementAndGet();
+    return invocation.proceed();
+  };
+
+  @Override
+  protected void setUp() throws Exception {
+    callCount.set(0);
+    interceptedCallCount.set(0);
+  }
+
+  @Retention(RUNTIME)
+  @Target({METHOD, TYPE})
+  public @interface InterceptMe {}
+
+  /** Interface with a default method annotated to be intercepted. */
+  public interface Foo {
+    @InterceptMe
+    default String defaultMethod() {
+      callCount.incrementAndGet();
+      return "Foo";
+    }
+  }
+
+  /** Foo implementation that does not override the default method. */
+  public static class NonOverridingFoo implements Foo {
+    public String methodCallingDefault() {
+      return "NonOverriding-" + defaultMethod();
+    }
+  }
+
+  public void testInterceptedDefaultMethod() {
+    Injector injector = Guice.createInjector(new AbstractModule() {
+      @Override
+      protected void configure() {
+        bindInterceptor(Matchers.any(), Matchers.annotatedWith(InterceptMe.class),
+            interceptor);
+        bind(Foo.class).to(NonOverridingFoo.class);
+      }
+    });
+
+    Foo foo = injector.getInstance(Foo.class);
+    assertEquals("Foo", foo.defaultMethod());
+    assertEquals(1, callCount.get());
+    assertEquals(1, interceptedCallCount.get());
+  }
+
+  public void testInterceptedDefaultMethod_calledByAnotherMethod() {
+    Injector injector = Guice.createInjector(new AbstractModule() {
+      @Override
+      protected void configure() {
+        bindInterceptor(Matchers.any(), Matchers.annotatedWith(InterceptMe.class),
+            interceptor);
+      }
+    });
+
+    NonOverridingFoo foo = injector.getInstance(NonOverridingFoo.class);
+    assertEquals("NonOverriding-Foo", foo.methodCallingDefault());
+    assertEquals(1, callCount.get());
+    assertEquals(1, interceptedCallCount.get());
+  }
+
+  /** A base class defining a method with the same signature as Foo's default method. */
+  public static class BaseClass {
+    // the definition of this method on the class will win over the default method
+    public String defaultMethod() {
+      callCount.incrementAndGet();
+      return "BaseClass";
+    }
+  }
+
+  /** Foo implementation that should use superclass method rather than default method. */
+  public static class InheritingFoo extends BaseClass implements Foo {
+  }
+
+  public void testInterceptedDefaultMethod_whenParentClassDefinesNonInterceptedMethod() {
+    Injector injector = Guice.createInjector(new AbstractModule() {
+      @Override
+      protected void configure() {
+        bindInterceptor(Matchers.any(), Matchers.annotatedWith(InterceptMe.class),
+            interceptor);
+        bind(Foo.class).to(InheritingFoo.class);
+      }
+    });
+
+    // the concrete implementation that wins is not annotated
+    Foo foo = injector.getInstance(Foo.class);
+    assertEquals("BaseClass", foo.defaultMethod());
+    assertEquals(1, callCount.get());
+    assertEquals(0, interceptedCallCount.get());
+  }
+
+  /**
+   * A base class defining an intercepted method with the same signature as Foo's default method.
+   */
+  public static class BaseClass2 {
+    // the definition of this method on the class will win over the default method
+    @InterceptMe
+    public String defaultMethod() {
+      callCount.incrementAndGet();
+      return "BaseClass2";
+    }
+  }
+
+  /**
+   * Foo implementation that should use intercepted superclass method rather than default method.
+   */
+  public static class InheritingFoo2 extends BaseClass2 implements Foo {
+  }
+
+  public void testInterceptedDefaultMethod_whenParentClassDefinesInterceptedMethod() {
+    Injector injector = Guice.createInjector(new AbstractModule() {
+      @Override
+      protected void configure() {
+        bindInterceptor(Matchers.any(), Matchers.annotatedWith(InterceptMe.class),
+            interceptor);
+        bind(Foo.class).to(InheritingFoo2.class);
+      }
+    });
+
+    // the concrete implementation that wins is not annotated
+    Foo foo = injector.getInstance(Foo.class);
+    assertEquals("BaseClass2", foo.defaultMethod());
+    assertEquals(1, callCount.get());
+    assertEquals(1, interceptedCallCount.get());
+  }
+
+  public interface Baz {
+    default String doSomething() {
+      return "Baz";
+    }
+
+    String doSomethingElse();
+  }
+
+  public static class BazImpl implements Baz {
+
+    @Override
+    public String doSomethingElse() {
+      return "BazImpl";
+    }
+  }
+
+  public void testInterception_ofAllMethodsOnType() {
+    Injector injector = Guice.createInjector(new AbstractModule() {
+      @Override
+      protected void configure() {
+        bindInterceptor(Matchers.subclassesOf(Baz.class), Matchers.any(), interceptor);
+        bind(Baz.class).to(BazImpl.class);
+      }
+    });
+
+    Baz baz = injector.getInstance(Baz.class);
+
+    assertEquals("Baz", baz.doSomething());
+    assertEquals("BazImpl", baz.doSomethingElse());
+
+    assertEquals(2, interceptedCallCount.get());
+  }
+
+  public void testInterception_ofAllMethodsOnType_interceptsInheritedDefaultMethod() {
+    Injector injector = Guice.createInjector(new AbstractModule() {
+      @Override
+      protected void configure() {
+        bindInterceptor(Matchers.subclassesOf(BazImpl.class), Matchers.any(), interceptor);
+        bind(Baz.class).to(BazImpl.class);
+      }
+    });
+
+    Baz baz = injector.getInstance(Baz.class);
+
+    assertEquals("Baz", baz.doSomething());
+    assertEquals("BazImpl", baz.doSomethingElse());
+
+    assertEquals(2, interceptedCallCount.get());
+  }
+}
diff --git a/jdk8-tests/test/com/google/inject/jdk8/Java8LanguageFeatureBindingTest.java b/jdk8-tests/test/com/google/inject/jdk8/Java8LanguageFeatureBindingTest.java
new file mode 100644
index 0000000..9c57cd3
--- /dev/null
+++ b/jdk8-tests/test/com/google/inject/jdk8/Java8LanguageFeatureBindingTest.java
@@ -0,0 +1,165 @@
+/**
+ * Copyright (C) 2014 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.inject.jdk8;
+
+import com.google.inject.AbstractModule;
+import com.google.inject.CreationException;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import com.google.inject.Key;
+import com.google.inject.Provider;
+import com.google.inject.Provides;
+import com.google.inject.ProvisionException;
+import com.google.inject.TypeLiteral;
+
+import junit.framework.TestCase;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Predicate;
+
+/**
+ * Test bindings to lambdas, method references, etc.
+ *
+ * @author cgdecker@google.com (Colin Decker)
+ */
+public class Java8LanguageFeatureBindingTest extends TestCase {
+  
+  // Some of these tests are kind of weird.
+  // See https://github.com/google/guice/issues/757 for more on why they exist.
+
+  public void testBinding_lambdaToInterface() {
+    Injector injector = Guice.createInjector(new AbstractModule() {
+      @Override
+      protected void configure() {
+        bind(new TypeLiteral<Predicate<Object>>() {}).toInstance(o -> o != null);
+      }
+    });
+
+    Predicate<Object> predicate = injector.getInstance(new Key<Predicate<Object>>() {});
+    assertTrue(predicate.test(new Object()));
+    assertFalse(predicate.test(null));
+  }
+
+  public void testProviderMethod_returningLambda() throws Exception {
+    Injector injector = Guice.createInjector(new AbstractModule() {
+      @Override
+      protected void configure() {}
+
+      @Provides
+      public Callable<String> provideCallable() {
+        return () -> "foo";
+      }
+    });
+
+    Callable<String> callable = injector.getInstance(new Key<Callable<String>>() {});
+    assertEquals("foo", callable.call());
+  }
+
+  public void testProviderMethod_containingLambda_throwingException() throws Exception {
+    Injector injector = Guice.createInjector(new AbstractModule() {
+      @Override
+      protected void configure() {}
+
+      @Provides
+      public Callable<String> provideCallable() {
+        if (Boolean.parseBoolean("false")) { // avoid dead code warnings
+          return () -> "foo";
+        } else {
+          throw new RuntimeException("foo");
+        }
+      }
+    });
+
+    try {
+      injector.getInstance(new Key<Callable<String>>() {});
+    } catch (ProvisionException expected) {
+      assertTrue(expected.getCause() instanceof RuntimeException);
+      assertEquals("foo", expected.getCause().getMessage());
+    }
+  }
+
+  public void testProvider_usingJdk8Features() {
+    try {
+      Guice.createInjector(new AbstractModule() {
+        @Override
+        protected void configure() {
+          bind(String.class).toProvider(StringProvider.class);
+        }
+      });
+
+      fail();
+    } catch (CreationException expected) {
+    }
+
+    UUID uuid = UUID.randomUUID();
+    Injector injector = Guice.createInjector(new AbstractModule() {
+      @Override
+      protected void configure() {
+        bind(UUID.class).toInstance(uuid);
+        bind(String.class).toProvider(StringProvider.class);
+      }
+    });
+
+    assertEquals(uuid.toString(), injector.getInstance(String.class));
+  }
+
+  private static final class StringProvider implements Provider<String> {
+    private final UUID uuid;
+
+    @Inject
+    StringProvider(UUID uuid) {
+      this.uuid = uuid;
+    }
+
+    @Override
+    public String get() {
+      return Collections.singleton(uuid).stream()
+          .map(UUID::toString)
+          .findFirst().get();
+    }
+  }
+
+  public void testBinding_toProvider_lambda() {
+    Injector injector = Guice.createInjector(new AbstractModule() {
+      @Override
+      protected void configure() {
+        AtomicInteger i = new AtomicInteger();
+        bind(String.class).toProvider(() -> "Hello" + i.incrementAndGet());
+      }
+    });
+
+    assertEquals("Hello1", injector.getInstance(String.class));
+    assertEquals("Hello2", injector.getInstance(String.class));
+  }
+
+  public void testBinding_toProvider_methodReference() {
+    Injector injector = Guice.createInjector(new AbstractModule() {
+      @Override
+      protected void configure() {
+        bind(String.class).toProvider(Java8LanguageFeatureBindingTest.this::provideString);
+      }
+    });
+
+    Provider<String> provider = injector.getProvider(String.class);
+    assertEquals("Hello", provider.get());
+  }
+
+  private String provideString() {
+    return "Hello";
+  }
+}
diff --git a/pom.xml b/pom.xml
index cc93bc7..7ded5d8 100644
--- a/pom.xml
+++ b/pom.xml
@@ -99,6 +99,7 @@
   <modules>
     <module>core</module>
     <module>extensions</module>
+    <!-- jdk8-tests module activated only when running under JDK8, below -->
   </modules>
 
   <prerequisites>
@@ -431,12 +432,17 @@
 
   <profiles>
     <profile>
-      <id>doclint-java8-disable</id>
+      <id>java8</id>
       <activation>
         <jdk>[1.8,)</jdk>
       </activation>
+      <modules>
+        <!-- Activate jdk8-tests module only under JDK 8 -->
+        <module>jdk8-tests</module>
+      </modules>
       <build>
         <plugins>
+          <!-- Disable doclint under JDK 8 -->
           <plugin>
             <groupId>org.apache.maven.plugins</groupId>
             <artifactId>maven-javadoc-plugin</artifactId>