diff --git a/build.gradle b/build.gradle index f78d171d54..acccdbaa2e 100644 --- a/build.gradle +++ b/build.gradle @@ -90,7 +90,7 @@ subprojects { googleJavaFormat(libs.googleJavaFormat.get().version) .formatJavadoc(false) removeUnusedImports() - target 'src/*/java/**/*.java' + target 'src/*/java*/**/*.java' } kotlin { ktlint(libs.ktlint.get().version) diff --git a/retrofit/build.gradle b/retrofit/build.gradle index b1c6b0de06..c58957cba1 100644 --- a/retrofit/build.gradle +++ b/retrofit/build.gradle @@ -2,6 +2,35 @@ apply plugin: 'java-library' apply plugin: 'org.jetbrains.kotlin.jvm' apply plugin: 'com.vanniktech.maven.publish' +def addMultiReleaseSourceSet(int version) { + def sourceSet = sourceSets.create("java$version") + sourceSet.java.srcDir("src/main/java$version") + + // Propagate dependencies to be visible to this version's source set. + configurations.getByName("java${version}Implementation").extendsFrom(configurations.getByName('implementation')) + configurations.getByName("java${version}Api").extendsFrom(configurations.getByName('api')) + configurations.getByName("java${version}CompileOnly").extendsFrom(configurations.getByName('compileOnly')) + + // Allow types in the main source set to be visible to this version's source set. + dependencies.add("java${version}Implementation", sourceSets.getByName("main").output) + + tasks.named("compileJava${version}Java", JavaCompile) { + javaCompiler = javaToolchains.compilerFor { + languageVersion = JavaLanguageVersion.of(version) + vendor = JvmVendorSpec.AZUL + } + } + + tasks.named('jar', Jar) { + from(sourceSet.output) { + into("META-INF/versions/$version") + } + } +} + +addMultiReleaseSourceSet(14) +addMultiReleaseSourceSet(16) + dependencies { api libs.okhttp @@ -11,37 +40,11 @@ dependencies { compileOnly libs.animalSnifferAnnotations compileOnly libs.findBugsAnnotations - - testImplementation projects.retrofit.testHelpers - testImplementation libs.junit - testImplementation libs.truth - testImplementation libs.guava - testImplementation libs.mockwebserver } jar { manifest { - attributes 'Automatic-Module-Name': 'retrofit2' - } -} - -// Create a test task for each supported JDK. -(8..21).each { majorVersion -> - def jdkTest = tasks.register("testJdk$majorVersion", Test) { - javaLauncher = javaToolchains.launcherFor { - languageVersion = JavaLanguageVersion.of(majorVersion) - vendor = JvmVendorSpec.AZUL - } - - description = "Runs the test suite on JDK $majorVersion" - group = LifecycleBasePlugin.VERIFICATION_GROUP - - // Copy inputs from normal Test task. - def testTask = tasks.getByName("test") - classpath = testTask.classpath - testClassesDirs = testTask.testClassesDirs - } - tasks.named("check").configure { - dependsOn(jdkTest) + attributes 'Automatic-Module-Name': 'retrofit2' + attributes 'Multi-Release': 'true' } } diff --git a/retrofit/java-test/README.md b/retrofit/java-test/README.md new file mode 100644 index 0000000000..eced926fcf --- /dev/null +++ b/retrofit/java-test/README.md @@ -0,0 +1,6 @@ +# Retrofit Java Tests + +These are in a separate module for two reasons: + +- It ensures optional dependencies (Kotlin stuff) are completely absent. +- It uses the multi-release jar on the classpath rather than only the classes folder. diff --git a/retrofit/java-test/build.gradle b/retrofit/java-test/build.gradle new file mode 100644 index 0000000000..e4928f1a02 --- /dev/null +++ b/retrofit/java-test/build.gradle @@ -0,0 +1,34 @@ +apply plugin: 'java-library' + +dependencies { + testImplementation projects.retrofit + testImplementation projects.retrofit.testHelpers + testImplementation libs.junit + testImplementation libs.truth + testImplementation libs.guava + testImplementation libs.mockwebserver +} + +// Create a test task for each supported JDK. +(8..21).each { majorVersion -> + def jdkTest = tasks.register("testJdk$majorVersion", Test) { + javaLauncher = javaToolchains.launcherFor { + languageVersion = JavaLanguageVersion.of(majorVersion) + vendor = JvmVendorSpec.AZUL + } + + description = "Runs the test suite on JDK $majorVersion" + group = LifecycleBasePlugin.VERIFICATION_GROUP + + // Copy inputs from normal Test task. + def testTask = tasks.getByName("test") + classpath = testTask.classpath + testClassesDirs = testTask.testClassesDirs + } + tasks.named("check").configure { + dependsOn(jdkTest) + } +} + +// We don't need the built-in task which uses Gradle's JVM given the above variants. +tasks.getByName('test').enabled = false diff --git a/retrofit/src/test/java/retrofit2/AnnotationArraySubject.java b/retrofit/java-test/src/test/java/retrofit2/AnnotationArraySubject.java similarity index 100% rename from retrofit/src/test/java/retrofit2/AnnotationArraySubject.java rename to retrofit/java-test/src/test/java/retrofit2/AnnotationArraySubject.java diff --git a/retrofit/src/test/java/retrofit2/CallAdapterTest.java b/retrofit/java-test/src/test/java/retrofit2/CallAdapterTest.java similarity index 100% rename from retrofit/src/test/java/retrofit2/CallAdapterTest.java rename to retrofit/java-test/src/test/java/retrofit2/CallAdapterTest.java diff --git a/retrofit/src/test/java/retrofit2/CallTest.java b/retrofit/java-test/src/test/java/retrofit2/CallTest.java similarity index 100% rename from retrofit/src/test/java/retrofit2/CallTest.java rename to retrofit/java-test/src/test/java/retrofit2/CallTest.java diff --git a/retrofit/src/test/java/retrofit2/CompletableFutureCallAdapterFactoryTest.java b/retrofit/java-test/src/test/java/retrofit2/CompletableFutureCallAdapterFactoryTest.java similarity index 100% rename from retrofit/src/test/java/retrofit2/CompletableFutureCallAdapterFactoryTest.java rename to retrofit/java-test/src/test/java/retrofit2/CompletableFutureCallAdapterFactoryTest.java diff --git a/retrofit/src/test/java/retrofit2/CompletableFutureTest.java b/retrofit/java-test/src/test/java/retrofit2/CompletableFutureTest.java similarity index 100% rename from retrofit/src/test/java/retrofit2/CompletableFutureTest.java rename to retrofit/java-test/src/test/java/retrofit2/CompletableFutureTest.java diff --git a/retrofit/src/test/java/retrofit2/DefaultCallAdapterFactoryTest.java b/retrofit/java-test/src/test/java/retrofit2/DefaultCallAdapterFactoryTest.java similarity index 100% rename from retrofit/src/test/java/retrofit2/DefaultCallAdapterFactoryTest.java rename to retrofit/java-test/src/test/java/retrofit2/DefaultCallAdapterFactoryTest.java diff --git a/retrofit/src/test/java/retrofit2/DefaultMethodsTest.java b/retrofit/java-test/src/test/java/retrofit2/DefaultMethodsTest.java similarity index 100% rename from retrofit/src/test/java/retrofit2/DefaultMethodsTest.java rename to retrofit/java-test/src/test/java/retrofit2/DefaultMethodsTest.java diff --git a/retrofit/src/test/java/retrofit2/HttpExceptionTest.java b/retrofit/java-test/src/test/java/retrofit2/HttpExceptionTest.java similarity index 100% rename from retrofit/src/test/java/retrofit2/HttpExceptionTest.java rename to retrofit/java-test/src/test/java/retrofit2/HttpExceptionTest.java diff --git a/retrofit/src/test/java/retrofit2/InvocationTest.java b/retrofit/java-test/src/test/java/retrofit2/InvocationTest.java similarity index 100% rename from retrofit/src/test/java/retrofit2/InvocationTest.java rename to retrofit/java-test/src/test/java/retrofit2/InvocationTest.java diff --git a/retrofit/src/test/java/retrofit2/Java8DefaultStaticMethodsInValidationTest.java b/retrofit/java-test/src/test/java/retrofit2/Java8DefaultStaticMethodsInValidationTest.java similarity index 100% rename from retrofit/src/test/java/retrofit2/Java8DefaultStaticMethodsInValidationTest.java rename to retrofit/java-test/src/test/java/retrofit2/Java8DefaultStaticMethodsInValidationTest.java diff --git a/retrofit/src/test/java/retrofit2/NonFatalError.java b/retrofit/java-test/src/test/java/retrofit2/NonFatalError.java similarity index 100% rename from retrofit/src/test/java/retrofit2/NonFatalError.java rename to retrofit/java-test/src/test/java/retrofit2/NonFatalError.java diff --git a/retrofit/src/test/java/retrofit2/OptionalConverterFactoryTest.java b/retrofit/java-test/src/test/java/retrofit2/OptionalConverterFactoryTest.java similarity index 100% rename from retrofit/src/test/java/retrofit2/OptionalConverterFactoryTest.java rename to retrofit/java-test/src/test/java/retrofit2/OptionalConverterFactoryTest.java diff --git a/retrofit/src/test/java/retrofit2/RequestFactoryBuilderTest.java b/retrofit/java-test/src/test/java/retrofit2/RequestFactoryBuilderTest.java similarity index 100% rename from retrofit/src/test/java/retrofit2/RequestFactoryBuilderTest.java rename to retrofit/java-test/src/test/java/retrofit2/RequestFactoryBuilderTest.java diff --git a/retrofit/src/test/java/retrofit2/RequestFactoryTest.java b/retrofit/java-test/src/test/java/retrofit2/RequestFactoryTest.java similarity index 100% rename from retrofit/src/test/java/retrofit2/RequestFactoryTest.java rename to retrofit/java-test/src/test/java/retrofit2/RequestFactoryTest.java diff --git a/retrofit/src/test/java/retrofit2/ResponseTest.java b/retrofit/java-test/src/test/java/retrofit2/ResponseTest.java similarity index 100% rename from retrofit/src/test/java/retrofit2/ResponseTest.java rename to retrofit/java-test/src/test/java/retrofit2/ResponseTest.java diff --git a/retrofit/src/test/java/retrofit2/RetrofitTest.java b/retrofit/java-test/src/test/java/retrofit2/RetrofitTest.java similarity index 100% rename from retrofit/src/test/java/retrofit2/RetrofitTest.java rename to retrofit/java-test/src/test/java/retrofit2/RetrofitTest.java diff --git a/retrofit/kotlin-test/build.gradle b/retrofit/kotlin-test/build.gradle index bc6e133e48..6c25cb1e95 100644 --- a/retrofit/kotlin-test/build.gradle +++ b/retrofit/kotlin-test/build.gradle @@ -6,6 +6,5 @@ dependencies { testImplementation libs.junit testImplementation libs.truth testImplementation libs.mockwebserver - testImplementation libs.kotlin.stdLib testImplementation libs.kotlinCoroutines } diff --git a/retrofit/robovm-test/src/main/java/retrofit2/RoboVmPlatformTest.java b/retrofit/robovm-test/src/main/java/retrofit2/RoboVmPlatformTest.java index 6e312e8269..1b09bd48d6 100644 --- a/retrofit/robovm-test/src/main/java/retrofit2/RoboVmPlatformTest.java +++ b/retrofit/robovm-test/src/main/java/retrofit2/RoboVmPlatformTest.java @@ -17,8 +17,12 @@ public final class RoboVmPlatformTest { public static void main(String[] args) { - Platform platform = Platform.get(); - if (platform.createDefaultCallAdapterFactories(null).size() > 1) { + Retrofit retrofit = new Retrofit.Builder() + .baseUrl("https://example.com") + .callFactory(c -> { throw new AssertionError(); }) + .build(); + + if (retrofit.callAdapterFactories().size() > 1) { // Everyone gets the callback executor adapter. If RoboVM was correctly detected it will NOT // get the Java 8-supporting CompletableFuture call adapter factory. System.exit(1); diff --git a/retrofit/src/main/java/retrofit2/AndroidMainExecutor.java b/retrofit/src/main/java/retrofit2/AndroidMainExecutor.java new file mode 100644 index 0000000000..c7c7448562 --- /dev/null +++ b/retrofit/src/main/java/retrofit2/AndroidMainExecutor.java @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2013 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 android.os.Handler; +import android.os.Looper; +import java.util.concurrent.Executor; + +final class AndroidMainExecutor implements Executor { + private final Handler handler = new Handler(Looper.getMainLooper()); + + @Override + public void execute(Runnable r) { + handler.post(r); + } +} diff --git a/retrofit/src/main/java/retrofit2/BuiltInFactories.java b/retrofit/src/main/java/retrofit2/BuiltInFactories.java new file mode 100644 index 0000000000..752dfd83bb --- /dev/null +++ b/retrofit/src/main/java/retrofit2/BuiltInFactories.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2024 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 static java.util.Arrays.asList; +import static java.util.Collections.emptyList; +import static java.util.Collections.singletonList; + +import android.annotation.TargetApi; +import java.util.List; +import java.util.concurrent.Executor; +import javax.annotation.Nullable; + +class BuiltInFactories { + List extends CallAdapter.Factory> createDefaultCallAdapterFactories( + @Nullable Executor callbackExecutor) { + return singletonList(new DefaultCallAdapterFactory(callbackExecutor)); + } + + List extends Converter.Factory> createDefaultConverterFactories() { + return emptyList(); + } + + @TargetApi(24) + static final class Java8 extends BuiltInFactories { + @Override + List extends CallAdapter.Factory> createDefaultCallAdapterFactories( + @Nullable Executor callbackExecutor) { + return asList( + new CompletableFutureCallAdapterFactory(), + new DefaultCallAdapterFactory(callbackExecutor)); + } + + @Override + List extends Converter.Factory> createDefaultConverterFactories() { + return singletonList(new OptionalConverterFactory()); + } + } +} diff --git a/retrofit/src/main/java/retrofit2/DefaultMethodSupport.java b/retrofit/src/main/java/retrofit2/DefaultMethodSupport.java new file mode 100644 index 0000000000..5aa09ac122 --- /dev/null +++ b/retrofit/src/main/java/retrofit2/DefaultMethodSupport.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2024 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 android.annotation.TargetApi; +import android.os.Build; +import java.lang.reflect.Method; +import javax.annotation.Nullable; + +class DefaultMethodSupport { + boolean isDefaultMethod(Method method) { + return false; + } + + @Nullable + Object invokeDefaultMethod( + Method method, Class> declaringClass, Object proxy, @Nullable Object[] args) + throws Throwable { + throw new AssertionError(); + } + + /** + * Android does not support MR jars, so this extends the baseline JVM support which targets + * Java 8 APIs. Default methods and the reflection API to detect them were added to API 24 + * as part of the initial Java 8 set. MethodHandle, our means of invoking the default method + * through the proxy, was not added until API 26. + */ + @TargetApi(24) + static final class Android24 extends DefaultMethodSupportJvm { + @Override + Object invokeDefaultMethod( + Method method, Class> declaringClass, Object proxy, @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, proxy, args); + } + } +} diff --git a/retrofit/src/main/java/retrofit2/DefaultMethodSupportJvm.java b/retrofit/src/main/java/retrofit2/DefaultMethodSupportJvm.java new file mode 100644 index 0000000000..ed696977c3 --- /dev/null +++ b/retrofit/src/main/java/retrofit2/DefaultMethodSupportJvm.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2024 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.lang.invoke.MethodHandles.Lookup; +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import org.jetbrains.annotations.Nullable; + +/** + * From Java 8 to Java 13, the only way to invoke a default method on a proxied interface is by + * reflectively creating a trusted {@link Lookup} to invoke a method handle. + *
+ * Note: This class has multi-release jar variants for newer versions of Java.
+ */
+class DefaultMethodSupportJvm extends DefaultMethodSupport {
+ private @Nullable Constructor https://bugs.openjdk.java.net/browse/JDK-8209005
- */
- @IgnoreJRERequirement // Only used on JVM and Java 14.
- @SuppressWarnings("NewApi") // Not used for Android.
- private static final class Java14 extends Platform {
- static boolean isSupported() {
- try {
- Object version = Runtime.class.getMethod("version").invoke(null);
- Integer feature = (Integer) version.getClass().getMethod("feature").invoke(version);
- return feature >= 14;
- } catch (InvocationTargetException | IllegalAccessException | NoSuchMethodException ignored) {
- return false;
- }
- }
-
- @Nullable
- @Override
- Executor defaultCallbackExecutor() {
- return null;
- }
-
- @Override
- List extends CallAdapter.Factory> createDefaultCallAdapterFactories(
- @Nullable Executor callbackExecutor) {
- return asList(
- new CompletableFutureCallAdapterFactory(),
- new DefaultCallAdapterFactory(callbackExecutor));
- }
-
- @Override
- List extends Converter.Factory> createDefaultConverterFactories() {
- return singletonList(new OptionalConverterFactory());
- }
-
- @Override
- public boolean isDefaultMethod(Method method) {
- return method.isDefault();
- }
-
- @Nullable
- @Override
- public Object invokeDefaultMethod(
- Method method, Class> declaringClass, Object proxy, Object... args) throws Throwable {
- return MethodHandles.lookup()
- .unreflectSpecial(method, declaringClass)
- .bindTo(proxy)
- .invokeWithArguments(args);
- }
- }
-
- /**
- * Java 16 has a supported public API for invoking default methods on a proxy. We invoke it
- * reflectively because we cannot compile against the API directly.
- */
- @IgnoreJRERequirement // Only used on JVM and Java 16.
- @SuppressWarnings("NewApi") // Not used for Android.
- private static final class Java16 extends Platform {
- static boolean isSupported() {
- try {
- Object version = Runtime.class.getMethod("version").invoke(null);
- Integer feature = (Integer) version.getClass().getMethod("feature").invoke(version);
- return feature >= 16;
- } catch (InvocationTargetException | IllegalAccessException | NoSuchMethodException ignored) {
- return false;
- }
- }
-
- private @Nullable Method invokeDefaultMethod;
-
- @Nullable
- @Override
- Executor defaultCallbackExecutor() {
- return null;
- }
-
- @Override
- List extends CallAdapter.Factory> createDefaultCallAdapterFactories(
- @Nullable Executor callbackExecutor) {
- return asList(
- new CompletableFutureCallAdapterFactory(),
- new DefaultCallAdapterFactory(callbackExecutor));
- }
-
- @Override
- List extends Converter.Factory> createDefaultConverterFactories() {
- return singletonList(new OptionalConverterFactory());
- }
-
- @Override
- public boolean isDefaultMethod(Method method) {
- return method.isDefault();
- }
-
- @SuppressWarnings("JavaReflectionMemberAccess") // Only available on Java 16, as we expect.
- @Nullable
- @Override
- public Object invokeDefaultMethod(
- Method method, Class> declaringClass, Object proxy, Object... args) throws Throwable {
- Method invokeDefaultMethod = this.invokeDefaultMethod;
- if (invokeDefaultMethod == null) {
- invokeDefaultMethod =
- InvocationHandler.class.getMethod(
- "invokeDefault", Object.class, Method.class, Object[].class);
- this.invokeDefaultMethod = invokeDefaultMethod;
- }
- return invokeDefaultMethod.invoke(null, proxy, method, args);
+ callbackExecutor = null;
+ defaultMethodSupport = new DefaultMethodSupportJvm();
+ builtInFactories = new BuiltInFactories.Java8();
+ break;
}
}
- private static final class MainThreadExecutor implements Executor {
- static final Executor INSTANCE = new MainThreadExecutor();
-
- private final Handler handler = new Handler(Looper.getMainLooper());
-
- @Override
- public void execute(Runnable r) {
- handler.post(r);
- }
- }
+ private Platform() {}
}
diff --git a/retrofit/src/main/java/retrofit2/Retrofit.java b/retrofit/src/main/java/retrofit2/Retrofit.java
index e6dd8690ce..f855534a79 100644
--- a/retrofit/src/main/java/retrofit2/Retrofit.java
+++ b/retrofit/src/main/java/retrofit2/Retrofit.java
@@ -171,9 +171,9 @@ public
+ * https://bugs.openjdk.java.net/browse/JDK-8209005
+ */
+class DefaultMethodSupportJvm extends DefaultMethodSupport {
+ @Override
+ boolean isDefaultMethod(Method method) {
+ return method.isDefault();
+ }
+
+ @Override
+ @Nullable
+ Object invokeDefaultMethod(
+ Method method, Class> declaringClass, Object proxy, @Nullable Object[] args)
+ throws Throwable {
+ return MethodHandles.lookup()
+ .unreflectSpecial(method, declaringClass)
+ .bindTo(proxy)
+ .invokeWithArguments(args);
+ }
+}
diff --git a/retrofit/src/main/java16/retrofit2/DefaultMethodSupportJvm.java b/retrofit/src/main/java16/retrofit2/DefaultMethodSupportJvm.java
new file mode 100644
index 0000000000..09614af5b1
--- /dev/null
+++ b/retrofit/src/main/java16/retrofit2/DefaultMethodSupportJvm.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2024 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.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import javax.annotation.Nullable;
+
+/** Java 16 finally has a public API for invoking default methods on a proxy. */
+class DefaultMethodSupportJvm extends DefaultMethodSupport {
+ @Override
+ boolean isDefaultMethod(Method method) {
+ return method.isDefault();
+ }
+
+ @Override
+ @Nullable
+ Object invokeDefaultMethod(
+ Method method, Class> declaringClass, Object proxy, @Nullable Object[] args)
+ throws Throwable {
+ return InvocationHandler.invokeDefault(proxy, method, args);
+ }
+}
diff --git a/settings.gradle b/settings.gradle
index 282ecc9a4a..a5a6b25685 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -6,7 +6,9 @@ rootProject.name = 'retrofit-root'
include ':retrofit'
include ':retrofit-bom'
+
include ':retrofit:android-test'
+include ':retrofit:java-test'
include ':retrofit:kotlin-test'
include ':retrofit:robovm-test'
include ':retrofit:test-helpers'