Fixed
Status Update
Comments
ke...@gmail.com <ke...@gmail.com> #2
Logcat
```
2019-12-19 16:40:58.764 31333-31333/? E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.myapplication, PID: 31333
java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:503)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
Caused by: java.lang.reflect.InvocationTargetException
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
Caused by: java.lang.NoSuchMethodException: parameter type is null
at java.lang.Class.getConstructor0(Class.java:2322)
at java.lang.Class.getDeclaredConstructor(Class.java:2166)
at com.example.myapplication.UserJsonAdapter.a(:1)
at b.b.a.y.a.a(Unknown Source:15)
at com.example.myapplication.MainActivity.a(:7)
at com.example.myapplication.MainActivity$b.onClick(Unknown Source:2)
at android.view.View.performClick(View.java:6597)
at android.view.View.performClickInternal(View.java:6574)
at android.view.View.access$3100(View.java:778)
at android.view.View$PerformClick.run(View.java:25885)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6718)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
```
```
2019-12-19 16:40:58.764 31333-31333/? E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.myapplication, PID: 31333
java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:503)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
Caused by: java.lang.reflect.InvocationTargetException
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
Caused by: java.lang.NoSuchMethodException: parameter type is null
at java.lang.Class.getConstructor0(Class.java:2322)
at java.lang.Class.getDeclaredConstructor(Class.java:2166)
at com.example.myapplication.UserJsonAdapter.a(:1)
at b.b.a.y.a.a(Unknown Source:15)
at com.example.myapplication.MainActivity.a(:7)
at com.example.myapplication.MainActivity$b.onClick(Unknown Source:2)
at android.view.View.performClick(View.java:6597)
at android.view.View.performClickInternal(View.java:6574)
at android.view.View.access$3100(View.java:778)
at android.view.View$PerformClick.run(View.java:25885)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6718)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
```
mk...@google.com <mk...@google.com>
mk...@google.com <mk...@google.com> #3
Thank you for posting an issue regarding R8. This problem arises from us removing Kotlin.Metadata. The generated UserJsonAdapter will try and get the declared synthetic constructor, by the following code:
val localConstructor: Constructor<User> = this.constructorRef ?:
User::class.java.getDeclaredConstructor(Int::class.javaPrimitiveType, String::class.java,
String::class.java, Int::class.javaPrimitiveType, Util.DEFAULT_CONSTRUCTOR_MARKER).also {
this.constructorRef = it }
Here it relies on Util.DEFAULT_CONSTRUCTOR_MARKER being set to class Lkotlin/jvm/internal/DefaultConstructorMarker; and not null.
The static initializer in com.squareup.moshi.internal.Util looks like this:
static {
Class<? extends Annotation> metadata = null;
Class<?> defaultConstructorMarker = null;
try {
metadata = (Class<? extends Annotation>) Class.forName("kotlin.Metadata");
defaultConstructorMarker = Class.forName("kotlin.jvm.internal.DefaultConstructorMarker");
} catch (ClassNotFoundException ignored) {
}
METADATA = metadata;
DEFAULT_CONSTRUCTOR_MARKER = defaultConstructorMarker;
}
That is, because kotlin.Metadata do not exist, the ClassNotFoundExpection is thrown and the defaultConstructorMarker is never set. This seems to be an oversight in Moshi. If Moshi needs both of them defined, it should not ignore the exception. An easy fix is to add
-keep class Kotlin.Metadata { }
to ensure the ClassNotFoundException is not thrown.
It looks to me like no app will work if defaultConstructorMarker is not set, so I think the catch handler should rethrow if it could not find "kotlin.jvm.internal.DefaultConstructorMarker".
One could argue that we should keep classes given to Class.ForName, but the Kotlin.Metadata is an interface so I will investigate this a bit more before passing judgement.
val localConstructor: Constructor<User> = this.constructorRef ?:
User::class.java.getDeclaredConstructor(Int::class.javaPrimitiveType, String::class.java,
String::class.java, Int::class.javaPrimitiveType, Util.DEFAULT_CONSTRUCTOR_MARKER).also {
this.constructorRef = it }
Here it relies on Util.DEFAULT_CONSTRUCTOR_MARKER being set to class Lkotlin/jvm/internal/DefaultConstructorMarker; and not null.
The static initializer in com.squareup.moshi.internal.Util looks like this:
static {
Class<? extends Annotation> metadata = null;
Class<?> defaultConstructorMarker = null;
try {
metadata = (Class<? extends Annotation>) Class.forName("kotlin.Metadata");
defaultConstructorMarker = Class.forName("kotlin.jvm.internal.DefaultConstructorMarker");
} catch (ClassNotFoundException ignored) {
}
METADATA = metadata;
DEFAULT_CONSTRUCTOR_MARKER = defaultConstructorMarker;
}
That is, because kotlin.Metadata do not exist, the ClassNotFoundExpection is thrown and the defaultConstructorMarker is never set. This seems to be an oversight in Moshi. If Moshi needs both of them defined, it should not ignore the exception. An easy fix is to add
-keep class Kotlin.Metadata { }
to ensure the ClassNotFoundException is not thrown.
It looks to me like no app will work if defaultConstructorMarker is not set, so I think the catch handler should rethrow if it could not find "kotlin.jvm.internal.DefaultConstructorMarker".
One could argue that we should keep classes given to Class.ForName, but the Kotlin.Metadata is an interface so I will investigate this a bit more before passing judgement.
ap...@google.com <ap...@google.com> #4
Project: r8
Branch: master
commit 1124e34a226f9394dd23d79303331aeba2591983
Author: Morten Krogh-Jespersen <mkroghj@google.com>
Date: Mon Dec 23 11:20:17 2019
Interfaces in Clazz.forName should be marked as live
Before this CL we only trace classes as input to Clazz.forName and not
interfaces. This CL changes this to also mark interfaces as live.
Bug: 146534384
Change-Id: I42c5d190e47c840b8d540da473a89dd1df344384
M src/main/java/com/android/tools/r8/shaking/Enqueuer.java
A src/test/java/com/android/tools/r8/ir/optimize/reflection/ForNameInterfaceTest.java
https://r8-review.googlesource.com/47041
Branch: master
commit 1124e34a226f9394dd23d79303331aeba2591983
Author: Morten Krogh-Jespersen <mkroghj@google.com>
Date: Mon Dec 23 11:20:17 2019
Interfaces in Clazz.forName should be marked as live
Before this CL we only trace classes as input to Clazz.forName and not
interfaces. This CL changes this to also mark interfaces as live.
Bug: 146534384
Change-Id: I42c5d190e47c840b8d540da473a89dd1df344384
M src/main/java/com/android/tools/r8/shaking/Enqueuer.java
A src/test/java/com/android/tools/r8/ir/optimize/reflection/ForNameInterfaceTest.java
sg...@google.com <sg...@google.com>
[Deleted User] <[Deleted User]> #6
I got this issue after upgrading to Android Studio 3.6.0 stable. Definitely not fixed when using moshi codegen 1.9.2.
sg...@google.com <sg...@google.com> #7
This fix was never merged to the 1.6 branch, which is why the issue is present in Android Studio 3.6.0.
ap...@google.com <ap...@google.com> #8
Project: r8
Branch: 1.6
commit 1136126fe282213c460bfe0180ce48df76f59b1e
Author: Søren Gjesse <sgjesse@google.com>
Date: Thu Feb 27 12:29:35 2020
Version 1.6.75
Cherry-pick: Interfaces in Clazz.forName should be marked as live
CL:https://r8-review.googlesource.com/c/r8/+/47041
Merge conflicts where resolved.
Bug: 146534384
Change-Id: I1b3e4f4c852db1f935a987e17d1af8ae100e8dea
M src/main/java/com/android/tools/r8/Version.java
M src/main/java/com/android/tools/r8/shaking/Enqueuer.java
A src/test/java/com/android/tools/r8/ir/optimize/reflection/ForNameInterfaceTest.java
https://r8-review.googlesource.com/49240
Branch: 1.6
commit 1136126fe282213c460bfe0180ce48df76f59b1e
Author: Søren Gjesse <sgjesse@google.com>
Date: Thu Feb 27 12:29:35 2020
Version 1.6.75
Cherry-pick: Interfaces in Clazz.forName should be marked as live
CL:
Merge conflicts where resolved.
Bug: 146534384
Change-Id: I1b3e4f4c852db1f935a987e17d1af8ae100e8dea
M src/main/java/com/android/tools/r8/Version.java
M src/main/java/com/android/tools/r8/shaking/Enqueuer.java
A src/test/java/com/android/tools/r8/ir/optimize/reflection/ForNameInterfaceTest.java
do...@revelo.com <do...@revelo.com> #9
How will this fix be released for us, should we expect it on Android Gradle Plugin 3.6.1?
do...@revelo.com <do...@revelo.com> #10
Hi Søren Gjesse or any other google employee. How can we get this fix?
ze...@google.com <ze...@google.com> #11
Sorry for keeping you hanging. The fix will be in the 3.6.2 point release. Until then you can enable it directly by amending your top-level build.gradle file with:
buildscript {
repositories {
maven {
url 'https://storage.googleapis.com/r8-releases/raw '
}
}
dependencies {
classpath 'com.android.tools:r8:1.6.75' // Must be before the Gradle Plugin for Android.
classpath 'com.android.tools.build:gradle:X.Y.Z' // Your current AGP version.
}
}
buildscript {
repositories {
maven {
url '
}
}
dependencies {
classpath 'com.android.tools:r8:1.6.75' // Must be before the Gradle Plugin for Android.
classpath 'com.android.tools.build:gradle:X.Y.Z' // Your current AGP version.
}
}
sp...@gmail.com <sp...@gmail.com> #12
New Android Studio 3.6.2 is out with the fix!
Description
If use moshi data class with default value, it will have error in app with R8.
```
@JsonClass(generateAdapter = true)
data class User(
@Json(name = "id") val id: Int,
@Json(name = "name") val name: String,
@Json(name = "profile") val profile: String? = null // use default value
)
```
```
val moshi = Moshi.Builder().build()
val user = moshi.adapter(User::class.java).fromJson(json)
```
If use AGP3.5.3 or remove default value, it's working.
I will attach sample project which reproduce. Could you please check it.