Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unexpected signature after migrating to KSP #1720

Open
FilippoVigani opened this issue Aug 9, 2023 · 5 comments
Open

Unexpected signature after migrating to KSP #1720

FilippoVigani opened this issue Aug 9, 2023 · 5 comments

Comments

@FilippoVigani
Copy link

FilippoVigani commented Aug 9, 2023

I have a runtime crash that happens after migrating to KSP (and upgrading from 1.13.0 to 1.14.0) and it only happens in the release build (R8 enabled). I'm also using moshi kotlin codegen.

java.lang.RuntimeException: Unable to create application com.truescreen.android.TrueScreenApplication: java.lang.IllegalArgumentException: Unexpected signature for public final java.util.List com.truescreen.core.repositories.truelink.configuration.FormInputsAdapter.fromJson(jk.w,jk.s).
@FromJson method signatures may have one of the following structures:
	<any access modifier> R fromJson(JsonReader jsonReader) throws <any>;
	<any access modifier> R fromJson(JsonReader jsonReader, JsonAdapter<any> delegate, <any more delegates>) throws <any>;
	<any access modifier> R fromJson(T value) throws <any>;

	at android.app.ActivityThread.handleBindApplication(ActivityThread.java:6810)
	at android.app.ActivityThread.-$$Nest$mhandleBindApplication(Unknown Source:0)
	at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2132)
	at android.os.Handler.dispatchMessage(Handler.java:106)
	at android.os.Looper.loopOnce(Looper.java:201)
	at android.os.Looper.loop(Looper.java:288)
	at android.app.ActivityThread.main(ActivityThread.java:7918)
	at java.lang.reflect.Method.invoke(Native Method)
	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:936)
Caused by: java.lang.IllegalArgumentException: Unexpected signature for public final java.util.List com.truescreen.core.repositories.truelink.configuration.FormInputsAdapter.fromJson(jk.w,jk.s).
@FromJson method signatures may have one of the following structures:
	<any access modifier> R fromJson(JsonReader jsonReader) throws <any>;
	<any access modifier> R fromJson(JsonReader jsonReader, JsonAdapter<any> delegate, <any more delegates>) throws <any>;
	<any access modifier> R fromJson(T value) throws <any>;

	at jk.h0.a(Unknown Source:513)
	at ml.l0.get(Unknown Source:634)
	at cs.a.get(Unknown Source:13)
	at ml.l0.get(Unknown Source:939)
	at cs.a.get(Unknown Source:13)
	at ml.l0.get(Unknown Source:993)
	at cs.a.get(Unknown Source:13)
	at ml.r0.onCreate(Unknown Source:30)
	at com.truescreen.android.TrueScreenApplication.onCreate(Unknown Source:2)
	at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1277)
	at android.app.ActivityThread.handleBindApplication(ActivityThread.java:6805)

These are my adapters:


import com.squareup.moshi.*
import org.json.JSONObject


@JsonClass(generateAdapter = true)
data class TrueLinkFormAcquisitionGroup(
    @Json(name = "id") val id: String,
    @Json(name = "title") val title: String,
    @Json(name = "description") val description: String?,
    @Json(name = "properties") @FormInputs val inputs: List<TrueLinkFormInput>,
    @Json(name = "order") val order: List<String>,
    @Json(name = "required") val required: List<String>?,
) {
    @Json(ignore = true)
    val sortedInputs = inputs.sortedBy { order.indexOf(it.id) }
}

@Retention(AnnotationRetention.RUNTIME)
@JsonQualifier
annotation class FormInputs

class FormInputsAdapter {
    @ToJson
    fun toJson(
        jsonWriter: JsonWriter,
        @FormInputs formInputs: @JvmSuppressWildcards List<TrueLinkFormInput>,
        formInputAdapter: JsonAdapter<TrueLinkFormInput>,
    ) {
        with(jsonWriter) {
            beginObject()
            formInputs.forEach {
                name(it.id)
                formInputAdapter.toJson(jsonWriter, it)
            }
            endObject()
        }
    }

    @FromJson
    @FormInputs
    fun fromJson(
        reader: JsonReader,
        formInputAdapter: JsonAdapter<TrueLinkFormInput>,
    ): List<TrueLinkFormInput> {
        val jsonText = reader.nextSource().readString(Charsets.UTF_8)
        val jsonObject = JSONObject(jsonText)
        val inputs = jsonObject.keys().asSequence().mapNotNull { key ->
            val formInput = jsonObject.getJSONObject(key)
            formInput.put("id", key)
            formInputAdapter.fromJson(formInput.toString())
        }.toList()
        return inputs
    }
}

I also tried removing @JvmSuppressWildcards, thinking that maybe it's no longer needed for ksp, but the issue still occurs.

@ZacSweers
Copy link
Collaborator

without a repro sample this isn't super actionable, looks like you're using proguard or R8 and unsure what configs you have there to protect them

@EStepiuk
Copy link

Hi @FilippoVigani! Did you manage to solve this somehow? I have the same issue...

@FilippoVigani
Copy link
Author

Hi @FilippoVigani! Did you manage to solve this somehow? I have the same issue...

Unfortunately no, the easier route for me was to switch to kotlinx serialization which in my case was already used elsewhere in the project

@EStepiuk
Copy link

I've fixed the issue with this proguard rule:

-keepnames class com.squareup.moshi.JsonAdapter

Seems that needs to be added to moshi.pro

@haluzpav
Copy link

I had the same problem on KSP 1.9.22-1.0.16 and Moshi 1.14.0. Fixed by #1720 (comment), thanks for that!

Here's the problematic adapter

import android.icu.util.Currency
import androidx.annotation.Keep
import com.squareup.moshi.FromJson
import com.squareup.moshi.JsonAdapter
import com.squareup.moshi.JsonReader
import com.squareup.moshi.JsonWriter
import com.squareup.moshi.ToJson

class CurrencyAdapter {
    @Keep
    data class CurrencyProxy(
        val shortName: String,
    )

    @FromJson
    fun fromJson(
        jsonReader: JsonReader,
        delegate: JsonAdapter<CurrencyProxy>,
    ): Currency = Currency.getInstance(delegate.fromJson(jsonReader)!!.shortName)

    @ToJson
    fun toJson(
        jsonWriter: JsonWriter,
        value: Currency,
        delegate: JsonAdapter<CurrencyProxy>,
    ) {
        delegate.toJson(jsonWriter, CurrencyProxy(value.currencyCode))
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants