From cc407b04eca41be1a3a18e1210aeaa26d380ef4a Mon Sep 17 00:00:00 2001 From: Gian <47775302+gpunto@users.noreply.github.com> Date: Wed, 8 Jul 2026 11:19:00 +0200 Subject: [PATCH] Migrate sendEvent to generated SendEventRequest with custom-flattening EventRequest adapter --- .../chat/android/client/api2/MoshiChatApi.kt | 10 +++-- .../client/api2/endpoint/ChannelApi.kt | 2 +- .../android/client/parser2/MoshiChatParser.kt | 2 + .../parser2/adapters/EventRequestAdapter.kt | 43 ++++++++++++++++++ .../android/network/models/EventRequest.kt | 42 +++++++++++++++++ .../models}/SendEventRequest.kt | 20 +++++++-- .../android/client/api2/MoshiChatApiTest.kt | 5 ++- .../client/parser2/EventRequestAdapterTest.kt | 45 +++++++++++++++++++ 8 files changed, 158 insertions(+), 11 deletions(-) create mode 100644 stream-chat-android-client/src/main/java/io/getstream/chat/android/client/parser2/adapters/EventRequestAdapter.kt create mode 100644 stream-chat-android-client/src/main/java/io/getstream/chat/android/network/models/EventRequest.kt rename stream-chat-android-client/src/main/java/io/getstream/chat/android/{client/api2/model/requests => network/models}/SendEventRequest.kt (64%) create mode 100644 stream-chat-android-client/src/test/java/io/getstream/chat/android/client/parser2/EventRequestAdapterTest.kt diff --git a/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api2/MoshiChatApi.kt b/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api2/MoshiChatApi.kt index e08718aa097..ffb411991a2 100644 --- a/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api2/MoshiChatApi.kt +++ b/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api2/MoshiChatApi.kt @@ -61,7 +61,6 @@ import io.getstream.chat.android.client.api2.model.requests.QueryBannedUsersRequ import io.getstream.chat.android.client.api2.model.requests.QueryDraftMessagesRequest import io.getstream.chat.android.client.api2.model.requests.RejectInviteRequest import io.getstream.chat.android.client.api2.model.requests.RemoveMembersRequest -import io.getstream.chat.android.client.api2.model.requests.SendEventRequest import io.getstream.chat.android.client.api2.model.requests.SendMessageRequest import io.getstream.chat.android.client.api2.model.requests.SyncHistoryRequest import io.getstream.chat.android.client.api2.model.requests.TruncateChannelRequest @@ -143,6 +142,7 @@ import io.getstream.chat.android.network.models.CreateReminderRequest import io.getstream.chat.android.network.models.CreateUserGroupRequest import io.getstream.chat.android.network.models.CreateUserGroupResponse import io.getstream.chat.android.network.models.DeliveredMessagePayload +import io.getstream.chat.android.network.models.EventRequest import io.getstream.chat.android.network.models.GetUserGroupResponse import io.getstream.chat.android.network.models.HideChannelRequest import io.getstream.chat.android.network.models.ListUserGroupsResponse @@ -161,6 +161,7 @@ import io.getstream.chat.android.network.models.QueryRemindersRequest import io.getstream.chat.android.network.models.RemoveUserGroupMembersRequest import io.getstream.chat.android.network.models.RemoveUserGroupMembersResponse import io.getstream.chat.android.network.models.SearchUserGroupsResponse +import io.getstream.chat.android.network.models.SendEventRequest import io.getstream.chat.android.network.models.SendReactionRequest import io.getstream.chat.android.network.models.SortParamRequest import io.getstream.chat.android.network.models.UnblockUsersRequest @@ -1670,13 +1671,14 @@ constructor( channelId: String, extraData: Map, ): Call = with(eventMapping) { - val map = mutableMapOf("type" to eventType) - map.putAll(extraData) + val custom = extraData.entries.associate { (key, value) -> key.toString() to value } return channelApi.sendEvent( channelType = channelType, channelId = channelId, - request = SendEventRequest(map), + request = SendEventRequest( + event = EventRequest(type = eventType, custom = custom), + ), ).map { response -> response.event.toDomain() } diff --git a/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api2/endpoint/ChannelApi.kt b/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api2/endpoint/ChannelApi.kt index 076f8be551c..23e1658c067 100644 --- a/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api2/endpoint/ChannelApi.kt +++ b/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api2/endpoint/ChannelApi.kt @@ -26,7 +26,6 @@ import io.getstream.chat.android.client.api2.model.requests.PinnedMessagesReques import io.getstream.chat.android.client.api2.model.requests.QueryChannelRequest import io.getstream.chat.android.client.api2.model.requests.RejectInviteRequest import io.getstream.chat.android.client.api2.model.requests.RemoveMembersRequest -import io.getstream.chat.android.client.api2.model.requests.SendEventRequest import io.getstream.chat.android.client.api2.model.requests.TruncateChannelRequest import io.getstream.chat.android.client.api2.model.requests.UpdateChannelRequest import io.getstream.chat.android.client.api2.model.requests.UpdateMemberPartialResponse @@ -43,6 +42,7 @@ import io.getstream.chat.android.network.models.MarkReadRequest import io.getstream.chat.android.network.models.MarkUnreadRequest import io.getstream.chat.android.network.models.QueryChannelsRequest import io.getstream.chat.android.network.models.Response +import io.getstream.chat.android.network.models.SendEventRequest import io.getstream.chat.android.network.models.UpdateChannelPartialRequest import io.getstream.chat.android.network.models.UpdateMemberPartialRequest import retrofit2.http.Body diff --git a/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/parser2/MoshiChatParser.kt b/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/parser2/MoshiChatParser.kt index e61d44862e5..f037b5cb971 100644 --- a/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/parser2/MoshiChatParser.kt +++ b/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/parser2/MoshiChatParser.kt @@ -44,6 +44,7 @@ import io.getstream.chat.android.client.parser2.adapters.DownstreamThreadDtoAdap import io.getstream.chat.android.client.parser2.adapters.DownstreamThreadInfoDtoAdapter import io.getstream.chat.android.client.parser2.adapters.DownstreamUserDtoAdapter import io.getstream.chat.android.client.parser2.adapters.EventAdapterFactory +import io.getstream.chat.android.client.parser2.adapters.EventRequestAdapter import io.getstream.chat.android.client.parser2.adapters.ExactDateAdapter import io.getstream.chat.android.client.parser2.adapters.PollOptionInputAdapter import io.getstream.chat.android.client.parser2.adapters.PollOptionRequestAdapter @@ -97,6 +98,7 @@ internal class MoshiChatParser( .add(UpdatePollOptionRequestAdapter) .add(PollOptionInputAdapter) .add(PollOptionRequestAdapter) + .add(EventRequestAdapter) .add( CreatePollRequest.VotingVisibility::class.java, CreatePollRequest.VotingVisibility.VotingVisibilityAdapter(), diff --git a/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/parser2/adapters/EventRequestAdapter.kt b/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/parser2/adapters/EventRequestAdapter.kt new file mode 100644 index 00000000000..d5a1084439f --- /dev/null +++ b/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/parser2/adapters/EventRequestAdapter.kt @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2014-2026 Stream.io Inc. All rights reserved. + * + * Licensed under the Stream License; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://github.com/GetStream/stream-chat-android/blob/main/LICENSE + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.getstream.chat.android.client.parser2.adapters + +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 +import io.getstream.chat.android.network.models.EventRequest + +internal object EventRequestAdapter : + CustomObjectDtoAdapter( + kClass = EventRequest::class, + extraDataPropertyName = "custom", + ) { + + @FromJson + @Suppress("UNUSED_PARAMETER") + fun fromJson(jsonReader: JsonReader): EventRequest = error("Can't parse this from Json") + + @ToJson + fun toJson( + jsonWriter: JsonWriter, + event: EventRequest?, + mapAdapter: JsonAdapter>, + eventAdapter: JsonAdapter, + ) = serializeWithExtraData(jsonWriter, event, mapAdapter, eventAdapter) +} diff --git a/stream-chat-android-client/src/main/java/io/getstream/chat/android/network/models/EventRequest.kt b/stream-chat-android-client/src/main/java/io/getstream/chat/android/network/models/EventRequest.kt new file mode 100644 index 00000000000..c46e3297409 --- /dev/null +++ b/stream-chat-android-client/src/main/java/io/getstream/chat/android/network/models/EventRequest.kt @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2014-2026 Stream.io Inc. All rights reserved. + * + * Licensed under the Stream License; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://github.com/GetStream/stream-chat-android/blob/main/LICENSE + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@file:Suppress( + "ArrayInDataClass", + "EnumEntryName", + "RemoveRedundantQualifierName", + "UnusedImport", +) + +package io.getstream.chat.android.network.models + +import com.squareup.moshi.Json + +/** + * + */ + +@com.squareup.moshi.JsonClass(generateAdapter = true) +internal data class EventRequest( + @Json(name = "type") + internal val type: String, + + @Json(name = "parent_id") + internal val parentId: String? = null, + + @Json(name = "custom") + internal val custom: Map? = emptyMap(), +) diff --git a/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api2/model/requests/SendEventRequest.kt b/stream-chat-android-client/src/main/java/io/getstream/chat/android/network/models/SendEventRequest.kt similarity index 64% rename from stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api2/model/requests/SendEventRequest.kt rename to stream-chat-android-client/src/main/java/io/getstream/chat/android/network/models/SendEventRequest.kt index 45d9e46f548..a4398744b96 100644 --- a/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api2/model/requests/SendEventRequest.kt +++ b/stream-chat-android-client/src/main/java/io/getstream/chat/android/network/models/SendEventRequest.kt @@ -14,11 +14,23 @@ * limitations under the License. */ -package io.getstream.chat.android.client.api2.model.requests +@file:Suppress( + "ArrayInDataClass", + "EnumEntryName", + "RemoveRedundantQualifierName", + "UnusedImport", +) + +package io.getstream.chat.android.network.models + +import com.squareup.moshi.Json -import com.squareup.moshi.JsonClass +/** + * + */ -@JsonClass(generateAdapter = true) +@com.squareup.moshi.JsonClass(generateAdapter = true) internal data class SendEventRequest( - val event: Map, + @Json(name = "event") + internal val event: io.getstream.chat.android.network.models.EventRequest, ) diff --git a/stream-chat-android-client/src/test/java/io/getstream/chat/android/client/api2/MoshiChatApiTest.kt b/stream-chat-android-client/src/test/java/io/getstream/chat/android/client/api2/MoshiChatApiTest.kt index 8c290fb3e84..a838d6f0654 100644 --- a/stream-chat-android-client/src/test/java/io/getstream/chat/android/client/api2/MoshiChatApiTest.kt +++ b/stream-chat-android-client/src/test/java/io/getstream/chat/android/client/api2/MoshiChatApiTest.kt @@ -53,7 +53,6 @@ import io.getstream.chat.android.client.api2.model.requests.MuteUserRequest import io.getstream.chat.android.client.api2.model.requests.PinnedMessagesRequest import io.getstream.chat.android.client.api2.model.requests.QueryBannedUsersRequest import io.getstream.chat.android.client.api2.model.requests.RejectInviteRequest -import io.getstream.chat.android.client.api2.model.requests.SendEventRequest import io.getstream.chat.android.client.api2.model.requests.UpdateLiveLocationRequest import io.getstream.chat.android.client.api2.model.requests.UpdateMemberPartialResponse import io.getstream.chat.android.client.api2.model.requests.UpsertPushPreferencesRequest @@ -142,6 +141,7 @@ import io.getstream.chat.android.network.models.CreateReminderRequest import io.getstream.chat.android.network.models.CreateUserGroupRequest import io.getstream.chat.android.network.models.CreateUserGroupResponse import io.getstream.chat.android.network.models.DeliveredMessagePayload +import io.getstream.chat.android.network.models.EventRequest import io.getstream.chat.android.network.models.GetApplicationResponse import io.getstream.chat.android.network.models.GetUserGroupResponse import io.getstream.chat.android.network.models.GroupedChannelsGroupRequest @@ -166,6 +166,7 @@ import io.getstream.chat.android.network.models.RemoveUserGroupMembersResponse import io.getstream.chat.android.network.models.Response import io.getstream.chat.android.network.models.SearchRolesResponse import io.getstream.chat.android.network.models.SearchUserGroupsResponse +import io.getstream.chat.android.network.models.SendEventRequest import io.getstream.chat.android.network.models.SortParamRequest import io.getstream.chat.android.network.models.UnblockUsersRequest import io.getstream.chat.android.network.models.UnblockUsersResponse @@ -2355,7 +2356,7 @@ internal class MoshiChatApiTest { val result = sut.sendEvent(eventType, channelType, channelId, extraData).await() // then val expectedRequest = SendEventRequest( - event = extraData + mapOf("type" to eventType), + event = EventRequest(type = eventType, custom = emptyMap()), ) result `should be instance of` expected verify(api, times(1)).sendEvent(channelType, channelId, expectedRequest) diff --git a/stream-chat-android-client/src/test/java/io/getstream/chat/android/client/parser2/EventRequestAdapterTest.kt b/stream-chat-android-client/src/test/java/io/getstream/chat/android/client/parser2/EventRequestAdapterTest.kt new file mode 100644 index 00000000000..6e58e5661e8 --- /dev/null +++ b/stream-chat-android-client/src/test/java/io/getstream/chat/android/client/parser2/EventRequestAdapterTest.kt @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2014-2026 Stream.io Inc. All rights reserved. + * + * Licensed under the Stream License; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://github.com/GetStream/stream-chat-android/blob/main/LICENSE + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.getstream.chat.android.client.parser2 + +import io.getstream.chat.android.network.models.EventRequest +import org.junit.jupiter.api.Assertions +import org.junit.jupiter.api.Test + +internal class EventRequestAdapterTest { + private val parser = ParserFactory.createMoshiChatParser() + + @Test + fun `Serialize EventRequest with custom fields flattened to root`() { + val request = EventRequest( + type = "typing.start", + custom = mapOf("customKey" to "customValue"), + ) + val json = parser.toJson(request) + Assertions.assertEquals( + """{"type":"typing.start","customKey":"customValue"}""", + json, + ) + } + + @Test + fun `Serialize EventRequest without custom fields`() { + val request = EventRequest(type = "typing.start", custom = emptyMap()) + val json = parser.toJson(request) + Assertions.assertEquals("""{"type":"typing.start"}""", json) + } +}