square / moshi

A modern JSON library for Kotlin and Java.
https://square.github.io/moshi/1.x/
Apache License 2.0
9.61k stars 750 forks source link

@JsonQualifier Can't I turn an Object field into a JSON string? #1596

Open XiaoyuZhann opened 1 year ago

XiaoyuZhann commented 1 year ago

Let's look directly at the example:

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

class ObjectToJsonAdapter {

    @ToJson
    fun toJson(@ObjectToJson data: Any): String {
        return JSON.toJSONString(data)
    }

    @FromJson
    @ObjectToJson
    fun fromJson(data: Any): Any {
        return data
    }

}
@Parcelize
data class OperateGroup(
    var id: String? = null,
    var name: String? = null,
    var illustrate: String? = null,
    var level: String? = null,
    var pack: String? = null,
    @ObjectToJson var payload: GroupPayload = GroupPayload(),

    var ownerLabel: String? = null
) : Parcelable

@Parcelize
data class GroupPayload(
    var lat_lon: String = ""
) : Parcelable
private val retrofit = Retrofit.Builder()
        .baseUrl(baseUrl)
        .client(okHttpClient)
        .addConverterFactory(
            MoshiConverterFactory.create(
                Moshi.Builder()
                    .add(KotlinJsonAdapterFactory())
                    .add(ObjectToJsonAdapter())
                    .build()
            )
        ).build()

An error message is reported:

E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.sproutapp, PID: 5121
    java.lang.IllegalArgumentException: Unable to create converter for com.example.sproutapp.entity.Result<com.example.sproutapp.api.members.BaseStatisticData>
        for method OperateGroupAPI.baseStatistic
        at retrofit2.Utils.methodError(Utils.java:54)
        at retrofit2.HttpServiceMethod.createResponseConverter(HttpServiceMethod.java:126)
        at retrofit2.HttpServiceMethod.parseAnnotations(HttpServiceMethod.java:85)
        at retrofit2.ServiceMethod.parseAnnotations(ServiceMethod.java:39)
        at retrofit2.Retrofit.loadServiceMethod(Retrofit.java:202)
        at retrofit2.Retrofit$1.invoke(Retrofit.java:160)
        at java.lang.reflect.Proxy.invoke(Proxy.java:1006)
        at $Proxy7.baseStatistic(Unknown Source)
        at com.example.sproutapp.store.FixedResources.update(FixedResources.kt:45)
        at com.example.sproutapp.SproutAppState$loginNavigate$1.invokeSuspend(SproutAppState.kt:130)
        at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
        at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
        at androidx.compose.ui.platform.AndroidUiDispatcher.performTrampolineDispatch(AndroidUiDispatcher.android.kt:81)
        at androidx.compose.ui.platform.AndroidUiDispatcher.access$performTrampolineDispatch(AndroidUiDispatcher.android.kt:41)
        at androidx.compose.ui.platform.AndroidUiDispatcher$dispatchCallback$1.run(AndroidUiDispatcher.android.kt:57)
        at android.os.Handler.handleCallback(Handler.java:938)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loopOnce(Looper.java:210)
        at android.os.Looper.loop(Looper.java:299)
        at android.app.ActivityThread.main(ActivityThread.java:8293)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:556)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1045)
        Suppressed: kotlinx.coroutines.DiagnosticCoroutineContextException: [androidx.compose.ui.platform.MotionDurationScaleImpl@aa9c863, androidx.compose.runtime.BroadcastFrameClock@4eaac60, StandaloneCoroutine{Cancelling}@ab0d519, AndroidUiDispatcher@88e89de]
    Caused by: java.lang.IllegalArgumentException: No JsonAdapter for class com.example.sproutapp.api.members.GroupPayload annotated [@com.example.sproutapp.model.ObjectToJson()]
    for class com.example.sproutapp.api.members.GroupPayload payload
    for class com.example.sproutapp.api.members.OperateGroup
    for java.util.List<com.example.sproutapp.api.members.OperateGroup> groupList
    for class com.example.sproutapp.api.members.BaseStatisticData data
    for com.example.sproutapp.entity.Result<com.example.sproutapp.api.members.BaseStatisticData>
        at com.squareup.moshi.Moshi$LookupChain.exceptionWithLookupStack(Moshi.java:389)
        at com.squareup.moshi.Moshi.adapter(Moshi.java:158)
        at com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory.create(KotlinJsonAdapter.kt:292)
        at com.squareup.moshi.Moshi.adapter(Moshi.java:146)
        at com.squareup.moshi.Moshi.adapter(Moshi.java:106)
        at com.squareup.moshi.Moshi.adapter(Moshi.java:75)
        at com.squareup.moshi.CollectionJsonAdapter.newArrayListAdapter(CollectionJsonAdapter.java:54)
        at com.squareup.moshi.CollectionJsonAdapter$1.create(CollectionJsonAdapter.java:38)
        at com.squareup.moshi.Moshi.adapter(Moshi.java:146)
        at com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory.create(KotlinJsonAdapter.kt:292)
        at com.squareup.moshi.Moshi.adapter(Moshi.java:146)
        at com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory.create(KotlinJsonAdapter.kt:292)
        at com.squareup.moshi.Moshi.adapter(Moshi.java:146)
        at com.squareup.moshi.Moshi.adapter(Moshi.java:106)
        at retrofit2.converter.moshi.MoshiConverterFactory.responseBodyConverter(MoshiConverterFactory.java:89)
        at retrofit2.Retrofit.nextResponseBodyConverter(Retrofit.java:362)
        at retrofit2.Retrofit.responseBodyConverter(Retrofit.java:345)
        at retrofit2.HttpServiceMethod.createResponseConverter(HttpServiceMethod.java:124)
            ... 21 more
E/AndroidRuntime: Caused by: java.lang.IllegalArgumentException: No JsonAdapter for class com.example.sproutapp.api.members.GroupPayload annotated [@com.example.sproutapp.model.ObjectToJson()]
        at com.squareup.moshi.Moshi.adapter(Moshi.java:156)
            ... 37 more
NightlyNexus commented 2 months ago

It looks like the primary problem is you registered an adapter for the @ObjectToJson Any qualified type, but you want it to apply to all types with that qualifier. You'll want to implement a JsonAdapter.Factory. StackOverflow might be the best place for these usage questions.