As the title says, I'm having some issue on a project since we updated to Java 11 and to AGP 7+. The issue only happens in release and when we make a retrofit call using okhttp3.MultipartBody :
2022-01-18 00:56:23.043 27908-27908/com.test.okhttpissue E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.test.okhttpissue, PID: 27908
java.lang.TypeNotPresentException: Type okhttp3.MultipartBody$Part not present
at libcore.reflect.ParameterizedTypeImpl.getRawType(ParameterizedTypeImpl.java:67)
at libcore.reflect.ParameterizedTypeImpl.getResolvedType(ParameterizedTypeImpl.java:76)
at libcore.reflect.GenericArrayTypeImpl.getGenericComponentType(GenericArrayTypeImpl.java:32)
at j2.y.j(:362)
at j2.s$a.j(:812)
at j2.s$a.g(:626)
at j2.s$a.f(:325)
at j2.s$a.b(:206)
at j2.s.b(:67)
at j2.v.b(:26)
at j2.u.c(:202)
at j2.u$a.invoke(:160)
at java.lang.reflect.Proxy.invoke(Proxy.java:1006)
at $Proxy2.a(Unknown Source)
at f1.a.a(:41)
at com.test.okhttpissue.MainActivity.G(:30)
at com.test.okhttpissue.MainActivity.F(Unknown Source:0)
at f1.b.onClick(Unknown Source:0)
at android.view.View.performClick(View.java:7259)
at android.view.View.performClickInternal(View.java:7236)
at android.view.View.access$3600(View.java:801)
at android.view.View$PerformClick.run(View.java:27896)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7397)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:935)
Caused by: java.lang.ClassNotFoundException: okhttp3.MultipartBody$Part
at java.lang.Class.classForName(Native Method)
at java.lang.Class.forName(Class.java:454)
at libcore.reflect.ParameterizedTypeImpl.getRawType(ParameterizedTypeImpl.java:65)
at libcore.reflect.ParameterizedTypeImpl.getResolvedType(ParameterizedTypeImpl.java:76)
at libcore.reflect.GenericArrayTypeImpl.getGenericComponentType(GenericArrayTypeImpl.java:32)
at j2.y.j(:362)
at j2.s$a.j(:812)
at j2.s$a.g(:626)
at j2.s$a.f(:325)
at j2.s$a.b(:206)
at j2.s.b(:67)
at j2.v.b(:26)
at j2.u.c(:202)
at j2.u$a.invoke(:160)
at java.lang.reflect.Proxy.invoke(Proxy.java:1006)
at $Proxy2.a(Unknown Source)
at f1.a.a(:41)
at com.test.okhttpissue.MainActivity.G(:30)
at com.test.okhttpissue.MainActivity.F(Unknown Source:0)
at f1.b.onClick(Unknown Source:0)
at android.view.View.performClick(View.java:7259)
at android.view.View.performClickInternal(View.java:7236)
at android.view.View.access$3600(View.java:801)
at android.view.View$PerformClick.run(View.java:27896)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7397)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:935)
Caused by: java.lang.ClassNotFoundException: Didn't find class "okhttp3.MultipartBody$Part" on path: DexPathList[[zip file "/data/app/com.test.okhttpissue-pBclZ8Dcl_TuV_j7iAp7oA==/base.apk"],nativeLibraryDirectories=[/data/app/com.test.okhttpissue-pBclZ8Dcl_TuV_j7iAp7oA==/lib/arm64, /system/lib64, /system/product/lib64]]
at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:196)
at java.lang.ClassLoader.loadClass(ClassLoader.java:379)
at java.lang.ClassLoader.loadClass(ClassLoader.java:312)
at java.lang.Class.classForName(Native Method)
at java.lang.Class.forName(Class.java:454)
at libcore.reflect.ParameterizedTypeImpl.getRawType(ParameterizedTypeImpl.java:65)
at libcore.reflect.ParameterizedTypeImpl.getResolvedType(ParameterizedTypeImpl.java:76)
at libcore.reflect.GenericArrayTypeImpl.getGenericComponentType(GenericArrayTypeImpl.java:32)
at j2.y.j(:362)
at j2.s$a.j(:812)
at j2.s$a.g(:626)
at j2.s$a.f(:325)
at j2.s$a.b(:206)
at j2.s.b(:67)
at j2.v.b(:26)
at j2.u.c(:202)
at j2.u$a.invoke(:160)
at java.lang.reflect.Proxy.invoke(Proxy.java:1006)
at $Proxy2.a(Unknown Source)
at f1.a.a(:41)
at com.test.okhttpissue.MainActivity.G(:30)
at com.test.okhttpissue.MainActivity.F(Unknown Source:0)
at f1.b.onClick(Unknown Source:0)
at android.view.View.performClick(View.java:7259)
at android.view.View.performClickInternal(View.java:7236)
at android.view.View.access$3600(View.java:801)
at android.view.View$PerformClick.run(View.java:27896)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7397)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:935)
2022-01-18 00:56:23.074 27908-27908/com.test.okhttpissue I/Process: Sending signal. PID: 27908 SIG: 9
The problem does not occur on AGP 4.2.2 / Java 1.8.
I was able to reproduce it in a basic sample app with the following configuration :
plugins {
id 'com.android.application'
id 'kotlin-android'
}
android {
compileSdkVersion 30
defaultConfig {
applicationId "com.test.okhttpissue"
minSdk 24
targetSdk 29
versionCode 1
versionName "1.0"
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
signingConfig signingConfigs.debug
debuggable true
minifyEnabled true
shrinkResources true
zipAlignEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_11
targetCompatibility JavaVersion.VERSION_11
}
kotlinOptions {
jvmTarget = JavaVersion.VERSION_11.toString()
}
buildFeatures {
viewBinding true
}
}
dependencies {
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'com.google.android.material:material:1.0.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation "io.reactivex.rxjava3:rxjava:3.1.3"
implementation 'io.reactivex.rxjava3:rxandroid:3.0.0'
implementation "com.squareup.retrofit2:adapter-rxjava3:2.9.0"
implementation "com.squareup.retrofit2:retrofit:2.9.0"
implementation "com.squareup.retrofit2:converter-gson:2.9.0"
}
And the following snippet :
class IssueDemo {
val testApi: TestApi by lazy {
Retrofit.Builder()
.baseUrl("https://google.com")
.client(OkHttpClient().newBuilder().build())
.addCallAdapterFactory(RxJava3CallAdapterFactory.createWithScheduler(Schedulers.io()))
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(TestApi::class.java)
}
interface TestApi {
@Multipart
@POST("test/files")
fun uploadMultipleFiles(@Part files: Array<MultipartBody.Part?>): Single<String>
}
fun execute() {
val file = File("")
val requestFile: RequestBody =
RequestBody.create(MediaType.parse("multipart/form-data"), file)
val test = MultipartBody.Part.createFormData("nameFormData", file.name, requestFile)
testApi.uploadMultipleFiles(arrayOf(test))
}
}
I tried many things but so far the only thing that seems to fix it is to add a proguard rule -keep class okhttp3.MultipartBody but it doesn't feel right. With AGP 4.2.2 it was already using R8 and the proguard rules bundled with the library so why would we suddendly need another specific rule just for one class of this library?
Edit: It seems that switching from Array<MultipartBody.Part?> to List<MultipartBody.Part?>, without touching any proguard rule, solves the issue. Does someone understand what could be happening?