1

I can't seem to figure out this issue...

I've tried all sorts of methods to keep required classes and searched for long time to find the solution....

When I apply pro guard, app crashes with this error.

I'm using retrofit 2.9.0 and moshi 1.13.0 with moshi-kotlin 1.13.0

Caused by: java.lang.ClassNotFoundException: Didn't find class ApiResponseJsonAdapter

ApiResponse is model with Generic type

@Keep
@JsonClass(generateAdapter = true)
data class ApiResponse<T>(
    @Json(name = "detail")
    val message: String,
    @Json(name = "result")
    val result: T
)

Please I need help. Thanks in advance.

Update This is my pro guard

-keepattributes SourceFile,LineNumberTable

# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

-keep class com.example.base.ApiResponse { *; }
-keepclassmembers class com.example.base.ApiResponse.** {
  <init>(...);
  <fields>;
}
-keep class com.example.data.entity.server.** { *; }
-keepclassmembers class com.example.data.entity.server.** {
  <init>(...);
  <fields>;
}

-keep class com.squareup.moshi.kotlin.reflect.** { *; }
-keepclasseswithmembers class * {
    @com.squareup.moshi.* <methods>;
}

-keep @com.squareup.moshi.JsonQualifier interface *

-keepclassmembers @com.squareup.moshi.JsonClass class * extends java.lang.Enum {
    <fields>;
}

-keepnames @com.squareup.moshi.JsonClass class *

-keepclasseswithmembers class **.*JsonAdapter extends com.squareup.moshi.JsonAdapter {
    <init>(...);
    <fields>;
}

# JSR 305 annotations are for embedding nullability information.
-dontwarn javax.annotation.**

-keepclasseswithmembers class * {
    @com.squareup.moshi.* <methods>;
}

-keep @com.squareup.moshi.JsonQualifier @interface *

# Enum field names are used by the integrated EnumJsonAdapter.
# values() is synthesized by the Kotlin compiler and is used by EnumJsonAdapter indirectly
# Annotate enums with @JsonClass(generateAdapter = false) to use them with Moshi.
-keepclassmembers @com.squareup.moshi.JsonClass class * extends java.lang.Enum {
    <fields>;
    **[] values();
}

# Keep helper method to avoid R8 optimisation that would keep all Kotlin Metadata when unwanted
-keepclassmembers class com.squareup.moshi.internal.Util {
    private static java.lang.String getKotlinMetadataClassName();
}

-keepclassmembers class * {
    @com.squareup.moshi.FromJson <methods>;
    @com.squareup.moshi.ToJson <methods>;
}

# Understand the @Keep support annotation.
-keep class androidx.annotation.Keep

-keep @androidx.annotation.Keep class * {*;}

-keepclasseswithmembers class * {
    @androidx.annotation.Keep <methods>;
}

-keepclasseswithmembers class * {
    @androidx.annotation.Keep <fields>;
}

-keepclasseswithmembers class * {
    @androidx.annotation.Keep <init>(...);
}

-keep,allowobfuscation,allowshrinking class kotlin.coroutines.Continuation

-optimizationpasses 5
-dontusemixedcaseclassnames
-dontskipnonpubliclibraryclasses
-dontskipnonpubliclibraryclassmembers
-dontpreverify
-verbose
-dump class_files.txt
-printseeds seeds.txt
-printusage unused.txt
-printmapping mapping.txt
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*


-allowaccessmodification
-keepattributes *Annotation*
-renamesourcefileattribute SourceFile
-keepattributes SourceFile,LineNumberTable
-repackageclasses ''

-keep public class * extends androidx.appcompat.app.AppCompatActivity
-keep public class * extends android.app.Application
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keep public class * extends android.app.backup.BackupAgentHelper
-keep public class * extends android.preference.Preference

# Explicitly preserve all serialization members. The Serializable interface
# is only a marker interface, so it wouldn't save them.
-keepclassmembers class * implements java.io.Serializable {
    static final long serialVersionUID;
    private static final java.io.ObjectStreamField[] serialPersistentFields;
    private void writeObject(java.io.ObjectOutputStream);
    private void readObject(java.io.ObjectInputStream);
    java.lang.Object writeReplace();
    java.lang.Object readResolve();
}


# Preserve all native method names and the names of their classes.
-keepclasseswithmembernames class * {
    native <methods>;
}


-keepclasseswithmembernames class * {
    public <init>(android.content.Context, android.util.AttributeSet);
}


-keepclasseswithmembernames class * {
    public <init>(android.content.Context, android.util.AttributeSet, int);
}


# Preserve static fields of inner classes of R classes that might be accessed
# through introspection.
-keepclassmembers class **.R$* {
  public static <fields>;
}


# Preserve the special static methods that are required in all enumeration classes.
-keepclassmembers enum * {
    public static **[] values();
    public static ** valueOf(java.lang.String);
}

#-keep public class * {
#    public protected *;
#}

-keep class * implements android.os.Parcelable {
  public static final android.os.Parcelable$Creator *;
}

-keepattributes Signature

-keepclassmembers class fqcn.of.javascript.interface.for.webview {
   public *;
}

-keepattributes *Annotation*

-dontwarn com.airbnb.lottie.**
-keep class com.airbnb.lottie.** {*;}

# Retrofit does reflection on generic parameters. InnerClasses is required to use Signature and
# EnclosingMethod is required to use InnerClasses.
-keepattributes Signature, InnerClasses, EnclosingMethod

# Retrofit does reflection on method and parameter annotations.
-keepattributes RuntimeVisibleAnnotations, RuntimeVisibleParameterAnnotations

# Keep annotation default values (e.g., retrofit2.http.Field.encoded).
-keepattributes AnnotationDefault

# Retain service method parameters when optimizing.
-keepclassmembers,allowshrinking,allowobfuscation interface * {
    @retrofit2.http.* <methods>;
}

# Ignore annotation used for build tooling.
-dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement

# Ignore JSR 305 annotations for embedding nullability information.
-dontwarn javax.annotation.**

# Guarded by a NoClassDefFoundError try/catch and only used when on the classpath.
-dontwarn kotlin.Unit

# Top-level functions that can only be used by Kotlin.
-dontwarn retrofit2.KotlinExtensions

# With R8 full mode, it sees no subtypes of Retrofit interfaces since they are created with a Proxy
# and replaces all potential values with null. Explicitly keeping the interfaces prevents this.
-if interface * { @retrofit2.http.* <methods>; }
-keep,allowobfuscation interface <1>

# Keep generic signature of Call, Response (R8 full mode strips signatures from non-kept items).
-keep,allowobfuscation,allowshrinking interface retrofit2.Call
-keep,allowobfuscation,allowshrinking class retrofit2.Response

# With R8 full mode generic signatures are stripped for classes that are not
# kept. Suspend functions are wrapped in continuations where the type argument
# is used.
-keep,allowobfuscation,allowshrinking class kotlin.coroutines.Continuation

-dontwarn com.google.auto.service.AutoService
-dontwarn javax.lang.model.SourceVersion
-dontwarn javax.lang.model.element.AnnotationMirror
-dontwarn javax.lang.model.element.Element
-dontwarn javax.lang.model.element.ElementKind
-dontwarn javax.lang.model.element.ElementVisitor
-dontwarn javax.lang.model.element.ExecutableElement
-dontwarn javax.lang.model.element.Modifier
-dontwarn javax.lang.model.element.Name
-dontwarn javax.lang.model.element.TypeElement
-dontwarn javax.lang.model.element.TypeParameterElement
-dontwarn javax.lang.model.element.VariableElement
-dontwarn javax.lang.model.type.ArrayType
-dontwarn javax.lang.model.type.DeclaredType
-dontwarn javax.lang.model.type.ExecutableType
-dontwarn javax.lang.model.type.TypeKind
-dontwarn javax.lang.model.type.TypeMirror
-dontwarn javax.lang.model.type.TypeVariable
-dontwarn javax.lang.model.type.TypeVisitor
-dontwarn javax.lang.model.util.AbstractTypeVisitor8
-dontwarn javax.lang.model.util.ElementFilter
-dontwarn javax.lang.model.util.Elements
-dontwarn javax.lang.model.util.SimpleElementVisitor8
-dontwarn javax.lang.model.util.SimpleTypeVisitor8
-dontwarn javax.lang.model.util.Types
-dontwarn org.bouncycastle.jsse.BCSSLParameters
-dontwarn org.bouncycastle.jsse.BCSSLSocket
-dontwarn org.bouncycastle.jsse.provider.BouncyCastleJsseProvider
-dontwarn org.conscrypt.Conscrypt$Version
-dontwarn org.conscrypt.Conscrypt
-dontwarn org.conscrypt.ConscryptHostnameVerifier
-dontwarn org.openjsse.javax.net.ssl.SSLParameters
-dontwarn org.openjsse.javax.net.ssl.SSLSocket
-dontwarn org.openjsse.net.ssl.OpenJSSE
-dontwarn java.util.concurrent.Flow*

Error Stacktrace

java.lang.IllegalArgumentException: Unable to create converter for com.example.base.ApiResponse<com.example.data.entity.server.Info>
    for method a5.b
    at an2.n(SourceFile:54)
    at ii0.e(SourceFile:126)
    at ii0.f(SourceFile:85)
    at cz1.b(SourceFile:39)
    at tt1.c(SourceFile:202)
    at tt1$a.invoke(SourceFile:160)
    at java.lang.reflect.Proxy.invoke(Proxy.java:1006)
    at $Proxy3.b(Unknown Source)
    at k4.b(SourceFile:46)
    at z4.b(SourceFile:72)
    at jf0.a(SourceFile:6)
    at com.example.presentation.ViewModel.m(SourceFile:27)
    at p4.C1(SourceFile:70)
    at td.G0(SourceFile:33)
    at androidx.fragment.app.Fragment.f1(SourceFile:3019)
    at androidx.fragment.app.h.f(SourceFile:551)
    at androidx.fragment.app.h.m(SourceFile:261)
    at androidx.fragment.app.FragmentManager.Z(SourceFile:1840)
    at androidx.fragment.app.FragmentManager.X0(SourceFile:1758)
    at androidx.fragment.app.FragmentManager.W(SourceFile:1701)
    at androidx.fragment.app.FragmentManager$d.run(SourceFile:488)
    at android.os.Handler.handleCallback(Handler.java:938)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:223)
    at android.app.ActivityThread.main(ActivityThread.java:7664)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
 Caused by: java.lang.RuntimeException: Failed to find the generated JsonAdapter class for com.example.base.ApiResponse<com.example.data.entity.server.Info>
    at com.squareup.moshi.internal.a.d(SourceFile:590)
    at com.squareup.moshi.StandardJsonAdapters$b.create(SourceFile:61)
    at com.squareup.moshi.g.f(SourceFile:146)
    at com.squareup.moshi.g.e(SourceFile:106)
    at a81.d(SourceFile:89)
    at tt1.f(SourceFile:362)
    at tt1.h(SourceFile:345)
    at ii0.e(SourceFile:124)
    at ii0.f(SourceFile:85) 
    at cz1.b(SourceFile:39) 
    at tt1.c(SourceFile:202) 
    at tt1$a.invoke(SourceFile:160) 
    at java.lang.reflect.Proxy.invoke(Proxy.java:1006) 
    at $Proxy3.b(Unknown Source) 
    at k4.b(SourceFile:46) 
    at z4.b(SourceFile:72) 
    at jf0.a(SourceFile:6) 
    at com.example.presentation.ViewModel.m(SourceFile:27) 
    at p4.C1(SourceFile:70) 
    at td.G0(SourceFile:33) 
    at androidx.fragment.app.Fragment.f1(SourceFile:3019) 
    at androidx.fragment.app.h.f(SourceFile:551) 
    at androidx.fragment.app.h.m(SourceFile:261) 
    at androidx.fragment.app.FragmentManager.Z(SourceFile:1840) 
    at androidx.fragment.app.FragmentManager.X0(SourceFile:1758) 
    at androidx.fragment.app.FragmentManager.W(SourceFile:1701) 
    at androidx.fragment.app.FragmentManager$d.run(SourceFile:488) 
    at android.os.Handler.handleCallback(Handler.java:938) 
    at android.os.Handler.dispatchMessage(Handler.java:99) 
    at android.os.Looper.loop(Looper.java:223) 
    at android.app.ActivityThread.main(ActivityThread.java:7664) 
    at java.lang.reflect.Method.invoke(Native Method) 
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947) 
 Caused by: java.lang.ClassNotFoundException: com.example.base.ApiResponseJsonAdapter
    at java.lang.Class.classForName(Native Method)
    at java.lang.Class.forName(Class.java:454)
    at com.squareup.moshi.internal.a.d(SourceFile:564)
    at com.squareup.moshi.StandardJsonAdapters$b.create(SourceFile:61) 
    at com.squareup.moshi.g.f(SourceFile:146) 
    at com.squareup.moshi.g.e(SourceFile:106) 
    at a81.d(SourceFile:89) 
    at tt1.f(SourceFile:362) 
    at tt1.h(SourceFile:345) 
    at ii0.e(SourceFile:124) 
    at ii0.f(SourceFile:85) 
    at cz1.b(SourceFile:39) 
    at tt1.c(SourceFile:202) 
    at tt1$a.invoke(SourceFile:160) 
    at java.lang.reflect.Proxy.invoke(Proxy.java:1006) 
    at $Proxy3.b(Unknown Source) 
    at k4.b(SourceFile:46) 
    at z4.b(SourceFile:72) 
    at jf0.a(SourceFile:6) 
    at com.example.presentation.ViewModel.m(SourceFile:27) 
    at p4.C1(SourceFile:70) 
    at td.G0(SourceFile:33) 
    at androidx.fragment.app.Fragment.f1(SourceFile:3019) 
    at androidx.fragment.app.h.f(SourceFile:551) 
    at androidx.fragment.app.h.m(SourceFile:261) 
    at androidx.fragment.app.FragmentManager.Z(SourceFile:1840) 
    at androidx.fragment.app.FragmentManager.X0(SourceFile:1758) 
    at androidx.fragment.app.FragmentManager.W(SourceFile:1701) 
    at androidx.fragment.app.FragmentManager$d.run(SourceFile:488) 
    at android.os.Handler.handleCallback(Handler.java:938) 
    at android.os.Handler.dispatchMessage(Handler.java:99) 
    at android.os.Looper.loop(Looper.java:223) 
    at android.app.ActivityThread.main(ActivityThread.java:7664) 
    at java.lang.reflect.Method.invoke(Native Method) 
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947) 
 Caused by: java.lang.ClassNotFoundException: Didn't find class "com.example.base.ApiResponseJsonAdapter" on path:
Jae
  • 163
  • 3
  • 14

2 Answers2

0

I've resolved the issues. I realized that Kotlin-codegen artifact from Moshi wasn't generating so I ran gradle build from terminal and found that for Moshi it was required to use Java 16 but I was using default Android Java. After switching everything worked like charm with miscellaneous fixes like

including below statement to gradle properties.

android.jetifier.ignorelist=moshi-1.13.0

Jae
  • 163
  • 3
  • 14
  • How did you figure out it needs Java 16? What in the terminal prompted to come to that conclusion? Where did you switch to Java 16? – Waqas Aug 22 '22 at 23:18
0

This is what Moshi Docs tells about Reflection:

The reflection adapter uses Kotlin’s reflection library to convert your Kotlin classes to and from JSON. Enable it by adding the KotlinJsonAdapterFactory to your Moshi.Builder:

val moshi = Moshi.Builder()
    .addLast(KotlinJsonAdapterFactory())
    .build()

With this in mind, you should have Core Moshi JSON Library and Moshi's Kotlin support and converter factory in your gradle.

implementation "com.squareup.moshi:moshi:1.12.0"
implementation "com.squareup.moshi:moshi-kotlin:1.12.0"
implementation 'com.squareup.retrofit2:converter-moshi:2.9.0'

If you are using DI, you can do something like this when building the Retrofit object:

@Provides
    @Singleton
    fun provideNeowsAPI(): NeowsAPI {
  //add the JsonAdapter factory to use when build the Moshi object
    val moshi = Moshi.Builder().addLast(KotlinJsonAdapterFactory()).build()
        return Retrofit.Builder()
                .baseUrl(NeowsAPI.BASE_URL)
                . addConverterFactory(ScalarsConverterFactory.create())
                .addConverterFactory(MoshiConverterFactory.create(moshi))
                .build()
                .create(NeowsAPI::class.java)
    }

If you are not using DI you can build the Moshi Object and then add it to Retrofit Builder.

//Build Moshi Object
private val moshi =
    Moshi.Builder()
        .addLast(KotlinJsonAdapterFactory())
        .build()

//Build Retrofit Object
val retrofit =
    Retrofit.Builder()
        .addConverterFactory(ScalarsConverterFactory.create()) // for parsing JSON String
        .addConverterFactory(MoshiConverterFactory.create(moshi)) //for parsing KotlinObjects i.e.
        // picture of the day
        .baseUrl(BASE_URL)
        .build()
Tonnie
  • 4,865
  • 3
  • 34
  • 50