Repository: square/retrofit
Issue: Didn't find class "java.lang.invoke.MethodHandles$Lookup"

//retrofit
 ```
   implementation 'com.squareup.retrofit2:converter-moshi:2.8.0'
   implementation 'com.squareup.retrofit2:retrofit:2.8.0'
   implementation 'com.squareup.retrofit2:adapter-rxjava2:2.8.0'
   implementation 'com.squareup.retrofit2:converter-gson:2.8.0'
```

It doesn't work with either moshi either gson converters.

Gradle configured with

```
compileOptions {
        sourceCompatibility = 1.8
        targetCompatibility = 1.8
    }

kotlinOptions {
        jvmTarget = "1.8"
    }
```

Also tried

```
compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
```

What's the error?

>  Caused by: java.lang.ClassNotFoundException: Didn't find class "java.lang.invoke.MethodHandles$Lookup" 

It happens only on:
Android 7.0
Android 7.1.1
Android 7.1.2


Where does it print the stack trace?

https://github.com/square/retrofit/blob/master/retrofit/src/main/java/retrofit2/Platform.java 
Line 62, 115, 44, 34, 37, 430



Issue comments:
Also worth mentioning that, the clean build didn't help, deleting the build folder inside my files didn't help.

Tested from Android 5.0 till 11, had to double-check and confirm that it breaks on Android 7.X and 7.X.X releases
The same error with Retrofit 2.8.0 on Android 7:
```
Caused by java.lang.NoClassDefFoundError: Failed resolution of: Ljava/lang/invoke/MethodHandles$Lookup;
       at retrofit2.Platform.<init> + 62(Platform.java:62)
       at retrofit2.Platform$Android.<init> + 115(Platform.java:115)
       at retrofit2.Platform.findPlatform + 44(Platform.java:44)
       at retrofit2.Platform.<clinit> + 34(Platform.java:34)
       at retrofit2.Platform.get + 37(Platform.java:37)
       at retrofit2.Retrofit$Builder.<init> + 430(Retrofit.java:430)
       at com.drakeet.purewriter.Retrofits.<clinit> + 45(Retrofits.java:45)
       at com.drakeet.purewriter.PureWriter$onCreate$1.run + 104(PureWriter.java:104)
       at io.reactivex.internal.operators.completable.CompletableFromAction.subscribeActual + 35(CompletableFromAction.java:35)
       at io.reactivex.Completable.subscribe + 2309(Completable.java:2309)
       at io.reactivex.internal.operators.completable.CompletableSubscribeOn$SubscribeOnObserver.run + 64(CompletableSubscribeOn.java:64)
       at io.reactivex.Scheduler$DisposeTask.run + 578(Scheduler.java:578)
       at io.reactivex.internal.schedulers.ScheduledRunnable.run + 66(ScheduledRunnable.java:66)
       at io.reactivex.internal.schedulers.ScheduledRunnable.call + 57(ScheduledRunnable.java:57)
       at java.util.concurrent.FutureTask.run + 237(FutureTask.java:237)
       at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run + 272(ScheduledThreadPoolExecutor.java:272)
       at java.util.concurrent.ThreadPoolExecutor.runWorker + 1133(ThreadPoolExecutor.java:1133)
       at java.util.concurrent.ThreadPoolExecutor$Worker.run + 607(ThreadPoolExecutor.java:607)
       at java.lang.Thread.run + 761(Thread.java:761)
```

![image](https://user-images.githubusercontent.com/5214214/77420609-51884b80-6e05-11ea-9ed6-b120b97dd798.png)

@JakeWharton @swankjesse 
I see the same on Android 7.1.1:
```
Fatal Exception: java.lang.NoClassDefFoundError: Failed resolution of: Ljava/lang/invoke/MethodHandles$Lookup;
       at retrofit2.Platform.<init>(Platform.java)
       at retrofit2.Platform$Android.<init>(Platform.java)
       at retrofit2.Platform.findPlatform(Platform.java)
       at retrofit2.Platform.<clinit>(Platform.java)
       at retrofit2.Platform.get(Platform.java)
       at retrofit2.Retrofit$Builder.<init>(Retrofit.java)
       at com.twitter.sdk.android.core.internal.oauth.OAuthService.<init>(OAuthService.java)
       at com.twitter.sdk.android.core.internal.oauth.OAuth2Service.<init>(OAuth2Service.java)
       at com.twitter.sdk.android.core.TwitterCore.createGuestSessionProvider(TwitterCore.java)
       at com.twitter.sdk.android.core.TwitterCore.getGuestSessionProvider(TwitterCore.java)
       at com.twitter.sdk.android.core.TwitterCore.addApiClient(TwitterCore.java)
       at com.twitter.sdk.android.core.TwitterCore.lambda$getInstance$0(TwitterCore.java)
       at com.twitter.sdk.android.core.-$$Lambda$TwitterCore$ltCfCYbT02qdRyGLE4y1z_Jg9Os.run(-.java)
       at java.util.concurrent.ThreadPoolExecutor.runWorker + 1133(ThreadPoolExecutor.java:1133)
       at java.util.concurrent.ThreadPoolExecutor$Worker.run + 607(ThreadPoolExecutor.java:607)
       at java.lang.Thread.run + 761(Thread.java:761)
```
What is the fix for this? I've upgraded to Retrofit 2.9.0 and im still getting this crash for Android 7.X ... Using Java 1.8 and gradle plugin 3.6.1
> What is the fix for this? I've upgraded to Retrofit 2.9.0 and im still getting this crash for Android 7.X ... Using Java 1.8 and gradle plugin 3.6.1

Did you update your retrofit adapters too?
> > What is the fix for this? I've upgraded to Retrofit 2.9.0 and im still getting this crash for Android 7.X ... Using Java 1.8 and gradle plugin 3.6.1
> 
> Did you update your retrofit adapters too?

I did.
> > > What is the fix for this? I've upgraded to Retrofit 2.9.0 and im still getting this crash for Android 7.X ... Using Java 1.8 and gradle plugin 3.6.1
> > 
> > 
> > Did you update your retrofit adapters too?
> 
> I did.

I just tested it on Android 7.1.1

```
def retrofit = "2.9.0"
   implementation "com.squareup.retrofit2:converter-moshi:$retrofit"
    implementation "com.squareup.retrofit2:retrofit:$retrofit"
    implementation "com.squareup.retrofit2:adapter-rxjava3:$retrofit"
    implementation "com.squareup.retrofit2:converter-gson:$retrofit"
    implementation 'com.squareup.okhttp3:logging-interceptor:4.7.2'
```

I didn't get any crash not with gson or rxjava3 adapter or moshi in this case

Try to clean your project and re-build?
Invalidate caches and restart?

Pull request review comments:
25?

Patch that resolved the issue:
diff --git a/retrofit/src/main/java/retrofit2/Platform.java b/retrofit/src/main/java/retrofit2/Platform.java
index 3da9a4d97c..edd944ad11 100644
--- a/retrofit/src/main/java/retrofit2/Platform.java
+++ b/retrofit/src/main/java/retrofit2/Platform.java
@@ -61,6 +61,9 @@ private static Platform findPlatform() {
         // that ignores the visibility of the declaringClass.
         lookupConstructor = Lookup.class.getDeclaredConstructor(Class.class, int.class);
         lookupConstructor.setAccessible(true);
+      } catch (NoClassDefFoundError ignored) {
+        // Android API 24 or 25 where Lookup doesn't exist. Calling default methods on non-public
+        // interfaces will fail, but there's nothing we can do about it.
       } catch (NoSuchMethodException ignored) {
         // Assume JDK 14+ which contains a fix that allows a regular lookup to succeed.
         // See https://bugs.openjdk.java.net/browse/JDK-8209005.
@@ -119,7 +122,16 @@ static final class Android extends Platform {
       return new MainThreadExecutor();
     }
 
-    static class MainThreadExecutor implements Executor {
+    @Nullable @Override Object invokeDefaultMethod(Method method, Class<?> declaringClass,
+        Object object, @Nullable Object... args) throws Throwable {
+      if (Build.VERSION.SDK_INT < 26) {
+        throw new UnsupportedOperationException(
+            "Calling default methods on API 24 and 25 is not supported");
+      }
+      return super.invokeDefaultMethod(method, declaringClass, object, args);
+    }
+
+    static final class MainThreadExecutor implements Executor {
       private final Handler handler = new Handler(Looper.getMainLooper());
 
       @Override public void execute(Runnable r) {


Test patch:
diff --git a/retrofit/src/test/java/retrofit2/DefaultMethodsAndroidTest.java b/retrofit/src/test/java/retrofit2/DefaultMethodsAndroidTest.java
new file mode 100644
index 0000000000..8a8357b170
--- /dev/null
+++ b/retrofit/src/test/java/retrofit2/DefaultMethodsAndroidTest.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2016 Square, 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 retrofit2;
+
+import java.io.IOException;
+import okhttp3.mockwebserver.MockResponse;
+import okhttp3.mockwebserver.MockWebServer;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
+import retrofit2.helpers.ToStringConverterFactory;
+import retrofit2.http.GET;
+import retrofit2.http.Query;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.Assert.fail;
+import static org.robolectric.annotation.Config.NEWEST_SDK;
+import static org.robolectric.annotation.Config.NONE;
+
+@RunWith(RobolectricTestRunner.class)
+@Config(sdk = NEWEST_SDK, manifest = NONE)
+public final class DefaultMethodsAndroidTest {
+  @Rule public final MockWebServer server = new MockWebServer();
+
+  interface Example {
+    @GET("/") Call<String> user(@Query("name") String name);
+
+    default Call<String> user() {
+      return user("hey");
+    }
+  }
+
+  @Config(sdk = 24)
+  @Test public void failsOnApi24() {
+    Retrofit retrofit = new Retrofit.Builder()
+        .baseUrl(server.url("/"))
+        .addConverterFactory(new ToStringConverterFactory())
+        .build();
+    Example example = retrofit.create(Example.class);
+
+    try {
+      example.user();
+      fail();
+    } catch (UnsupportedOperationException e) {
+      assertThat(e).hasMessage("Calling default methods on API 24 and 25 is not supported");
+    }
+  }
+
+  @Config(sdk = 25)
+  @Test public void failsOnApi25() {
+    Retrofit retrofit = new Retrofit.Builder()
+        .baseUrl(server.url("/"))
+        .addConverterFactory(new ToStringConverterFactory())
+        .build();
+    Example example = retrofit.create(Example.class);
+
+    try {
+      example.user();
+      fail();
+    } catch (UnsupportedOperationException e) {
+      assertThat(e).hasMessage("Calling default methods on API 24 and 25 is not supported");
+    }
+  }
+
+  /**
+   * Notably, this does not test that it works correctly on API 26+. Merely that the special casing
+   * of API 24/25 does not trigger.
+   */
+  @Test public void doesNotFailOnApi26() throws IOException {
+    server.enqueue(new MockResponse().setBody("Hi"));
+    server.enqueue(new MockResponse().setBody("Hi"));
+
+    Retrofit retrofit = new Retrofit.Builder()
+        .baseUrl(server.url("/"))
+        .addConverterFactory(new ToStringConverterFactory())
+        .build();
+    Example example = retrofit.create(Example.class);
+
+    Response<String> response = example.user().execute();
+    assertThat(response.body()).isEqualTo("Hi");
+    Response<String> response2 = example.user("Hi").execute();
+    assertThat(response2.body()).isEqualTo("Hi");
+  }
+}
diff --git a/retrofit/src/test/java/retrofit2/Java8DefaultMethodsTest.java b/retrofit/src/test/java/retrofit2/DefaultMethodsTest.java
similarity index 97%
rename from retrofit/src/test/java/retrofit2/Java8DefaultMethodsTest.java
rename to retrofit/src/test/java/retrofit2/DefaultMethodsTest.java
index fe101cae4b..fe01db903e 100644
--- a/retrofit/src/test/java/retrofit2/Java8DefaultMethodsTest.java
+++ b/retrofit/src/test/java/retrofit2/DefaultMethodsTest.java
@@ -26,7 +26,7 @@
 
 import static org.assertj.core.api.Assertions.assertThat;
 
-public final class Java8DefaultMethodsTest {
+public final class DefaultMethodsTest {
   @Rule public final MockWebServer server = new MockWebServer();
 
   interface Example {