Updated on 2026-08-14
This commit is contained in:
commit
5ee5b4f61b
563 changed files with 13917 additions and 4692 deletions
|
|
@ -16,6 +16,9 @@ enum class ApiEnvironment {
|
|||
@Json(name = "DEV_2")
|
||||
DEV_2,
|
||||
|
||||
@Json(name = "DEV_3")
|
||||
DEV_3,
|
||||
|
||||
@Json(name = "STAGE")
|
||||
STAGE,
|
||||
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ internal class Express(
|
|||
override val environmentConfigs: List<ApiEnvironmentConfig> = listOf(
|
||||
createDevEnvironment(),
|
||||
createDev2Environment(),
|
||||
createDev3Environment(),
|
||||
createStageEnvironment(),
|
||||
createMockedEnvironment(),
|
||||
createProdEnvironment(),
|
||||
|
|
@ -60,6 +61,12 @@ internal class Express(
|
|||
headers = createHeaders(isProd = false),
|
||||
)
|
||||
|
||||
private fun createDev3Environment(): ApiEnvironmentConfig = ApiEnvironmentConfig(
|
||||
environment = ApiEnvironment.DEV_3,
|
||||
baseUrl = "[REDACTED_ENV_URL]",
|
||||
headers = createHeaders(isProd = false),
|
||||
)
|
||||
|
||||
private fun createStageEnvironment(): ApiEnvironmentConfig = ApiEnvironmentConfig(
|
||||
environment = ApiEnvironment.STAGE,
|
||||
baseUrl = "[REDACTED_ENV_URL]",
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ internal class TangemPay(
|
|||
|
||||
private fun createProdEnvironment(): ApiEnvironmentConfig = ApiEnvironmentConfig(
|
||||
environment = ApiEnvironment.PROD,
|
||||
baseUrl = "https://api.paera.com/bff/",
|
||||
baseUrl = "https://api.us.paera.com/bff/",
|
||||
headers = createHeaders(),
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -73,6 +73,7 @@ internal class TangemTech(
|
|||
ApiEnvironment.MOCK,
|
||||
ApiEnvironment.DEV,
|
||||
ApiEnvironment.DEV_2,
|
||||
ApiEnvironment.DEV_3,
|
||||
-> environmentConfigStorage.getConfigSync().tangemApiKeyDev
|
||||
ApiEnvironment.STAGE -> environmentConfigStorage.getConfigSync().tangemApiKeyStage
|
||||
ApiEnvironment.PROD -> environmentConfigStorage.getConfigSync().tangemApiKey
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ data class CustomerMeResponse(
|
|||
@Json(name = "product_instance") val productInstance: ProductInstance?,
|
||||
@Json(name = "payment_account") val paymentAccount: PaymentAccount?,
|
||||
@Json(name = "kyc") val kyc: Kyc?,
|
||||
@Json(name = "depositAddress") val depositAddress: String?,
|
||||
@Json(name = "card") val card: Card?,
|
||||
@Json(name = "balance") val balance: Balance?,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -156,7 +156,7 @@ interface TangemTechApi {
|
|||
@Path("walletId") walletId: String,
|
||||
@Header("If-Match") eTag: String,
|
||||
@Body body: SaveWalletAccountsResponse,
|
||||
): ApiResponse<Unit>
|
||||
): ApiResponse<GetWalletAccountsResponse>
|
||||
|
||||
@GET("/v1/wallets/{walletId}/accounts/archived")
|
||||
suspend fun getWalletArchivedAccounts(
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import com.tangem.datasource.api.common.response.ApiResponse
|
|||
import com.tangem.datasource.api.tangemTech.models.YieldMarketsResponse
|
||||
import com.tangem.datasource.api.tangemTech.models.YieldModuleStatusResponse
|
||||
import com.tangem.datasource.api.tangemTech.models.YieldSupplyChangeTokenStatusBody
|
||||
import com.tangem.datasource.api.tangemTech.models.YieldTokenStatusResponse
|
||||
import com.tangem.datasource.api.tangemTech.models.YieldSupplyMarketTokenDto
|
||||
import com.tangem.datasource.api.tangemTech.models.YieldTokenChartResponse
|
||||
import retrofit2.http.Body
|
||||
import retrofit2.http.GET
|
||||
|
|
@ -15,13 +15,13 @@ import retrofit2.http.Query
|
|||
interface YieldSupplyApi {
|
||||
|
||||
@GET("api/v1/yield/markets")
|
||||
suspend fun getYieldMarkets(@Query("chainId") chainId: Int? = null): ApiResponse<YieldMarketsResponse>
|
||||
suspend fun getYieldMarkets(@Query("chainId") chainId: String? = null): ApiResponse<YieldMarketsResponse>
|
||||
|
||||
@GET("api/v1/yield/token/{chainId}/{tokenAddress}")
|
||||
suspend fun getYieldTokenStatus(
|
||||
@Path("chainId") chainId: Int,
|
||||
@Path("tokenAddress") tokenAddress: String,
|
||||
): ApiResponse<YieldTokenStatusResponse>
|
||||
): ApiResponse<YieldSupplyMarketTokenDto>
|
||||
|
||||
@GET("api/v1/yield/token/{chainId}/{tokenAddress}/chart")
|
||||
suspend fun getYieldTokenChart(
|
||||
|
|
|
|||
|
|
@ -2,21 +2,9 @@ package com.tangem.datasource.api.tangemTech.models
|
|||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
import java.math.BigDecimal
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class YieldMarketsResponse(
|
||||
@Json(name = "tokens") val marketDtos: List<MarketDto>,
|
||||
@Json(name = "tokens") val marketDtos: List<YieldSupplyMarketTokenDto>,
|
||||
@Json(name = "lastUpdatedAt") val lastUpdated: String,
|
||||
) {
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class MarketDto(
|
||||
@Json(name = "tokenAddress") val tokenAddress: String? = null,
|
||||
@Json(name = "tokenSymbol") val tokenSymbol: String? = null,
|
||||
@Json(name = "tokenName") val tokenName: String? = null,
|
||||
@Json(name = "apy") val apy: BigDecimal,
|
||||
@Json(name = "isActive") val isActive: Boolean,
|
||||
@Json(name = "chainId") val chainId: Int? = null,
|
||||
)
|
||||
}
|
||||
)
|
||||
|
|
@ -5,7 +5,7 @@ import com.squareup.moshi.JsonClass
|
|||
import java.math.BigDecimal
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class YieldTokenStatusResponse(
|
||||
data class YieldSupplyMarketTokenDto(
|
||||
@Json(name = "tokenAddress") val tokenAddress: String? = null,
|
||||
@Json(name = "tokenSymbol") val tokenSymbol: String? = null,
|
||||
@Json(name = "tokenName") val tokenName: String? = null,
|
||||
|
|
@ -2,8 +2,37 @@ package com.tangem.datasource.api.tangemTech.models.account
|
|||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
import com.tangem.datasource.utils.SerializeNulls
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class SaveWalletAccountsResponse(
|
||||
@Json(name = "accounts") val accounts: List<WalletAccountDTO>,
|
||||
)
|
||||
@Json(name = "accounts") val accounts: List<AccountDTO>,
|
||||
) {
|
||||
|
||||
@SerializeNulls
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class AccountDTO(
|
||||
@Json(name = "id") val id: String,
|
||||
@Json(name = "name") val name: String?,
|
||||
@Json(name = "derivation") val derivationIndex: Int,
|
||||
@Json(name = "icon") val icon: String,
|
||||
@Json(name = "iconColor") val iconColor: String,
|
||||
)
|
||||
|
||||
companion object {
|
||||
|
||||
operator fun invoke(accounts: List<WalletAccountDTO>): SaveWalletAccountsResponse {
|
||||
return SaveWalletAccountsResponse(
|
||||
accounts = accounts.map { accountDto ->
|
||||
AccountDTO(
|
||||
id = accountDto.id,
|
||||
name = accountDto.name,
|
||||
derivationIndex = accountDto.derivationIndex,
|
||||
icon = accountDto.icon,
|
||||
iconColor = accountDto.iconColor,
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -9,9 +9,8 @@ import com.tangem.common.json.MoshiJsonConverter
|
|||
import com.tangem.datasource.api.common.adapter.*
|
||||
import com.tangem.datasource.local.config.providers.models.ProviderModel
|
||||
import com.tangem.datasource.local.network.entity.NetworkStatusDM
|
||||
import com.tangem.datasource.utils.SerializeNullsFactory
|
||||
import com.tangem.domain.models.scan.serialization.*
|
||||
import com.tangem.domain.visa.model.VisaActivationRemoteState
|
||||
import com.tangem.domain.visa.model.VisaCardActivationStatus
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
|
|
@ -28,6 +27,7 @@ class MoshiModule {
|
|||
@NetworkMoshi
|
||||
fun provideNetworkMoshi(): Moshi {
|
||||
return Moshi.Builder()
|
||||
.add(SerializeNullsFactory)
|
||||
.add(
|
||||
PolymorphicJsonAdapterFactory.of(ProviderModel::class.java, "type")
|
||||
.withSubtype(ProviderModel.Public::class.java, "public")
|
||||
|
|
@ -38,8 +38,8 @@ class MoshiModule {
|
|||
.add(BigIntegerAdapter())
|
||||
.add(LocalDateAdapter())
|
||||
.add(DateTimeAdapter())
|
||||
.add(VisaActivationRemoteState.jsonAdapter)
|
||||
.add(VisaCardActivationStatus.jsonAdapter)
|
||||
// .add(VisaActivationRemoteState.jsonAdapter)
|
||||
// .add(VisaCardActivationStatus.jsonAdapter)
|
||||
.add(
|
||||
NamePolymorphicAdapterFactory.of(NetworkStatusDM::class.java)
|
||||
.withSubtype(NetworkStatusDM.Verified::class.java, "amounts")
|
||||
|
|
@ -84,8 +84,8 @@ class MoshiModule {
|
|||
val typedAdapters = MoshiJsonConverter.getTangemSdkTypedAdapters()
|
||||
|
||||
return Moshi.Builder().apply {
|
||||
add(VisaActivationRemoteState.jsonAdapter)
|
||||
add(VisaCardActivationStatus.jsonAdapter)
|
||||
// add(VisaActivationRemoteState.jsonAdapter)
|
||||
// add(VisaCardActivationStatus.jsonAdapter)
|
||||
adapters.forEach { this.add(it) }
|
||||
typedAdapters.forEach { add(it.key, it.value) }
|
||||
addLast(KotlinJsonAdapterFactory())
|
||||
|
|
|
|||
|
|
@ -4,11 +4,11 @@ import android.content.Context
|
|||
import androidx.datastore.core.DataStoreFactory
|
||||
import androidx.datastore.dataStoreFile
|
||||
import com.squareup.moshi.Moshi
|
||||
import com.tangem.datasource.api.tangemTech.models.YieldSupplyMarketTokenDto
|
||||
import com.tangem.datasource.local.yieldsupply.DefaultYieldMarketsStore
|
||||
import com.tangem.datasource.local.yieldsupply.YieldMarketsStore
|
||||
import com.tangem.datasource.utils.MoshiDataStoreSerializer
|
||||
import com.tangem.datasource.utils.listTypes
|
||||
import com.tangem.domain.yield.supply.models.YieldMarketToken
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
|
|
@ -34,7 +34,7 @@ object YieldSupplyModule {
|
|||
persistenceStore = DataStoreFactory.create(
|
||||
serializer = MoshiDataStoreSerializer(
|
||||
moshi = moshi,
|
||||
types = listTypes<YieldMarketToken>(),
|
||||
types = listTypes<YieldSupplyMarketTokenDto>(),
|
||||
defaultValue = emptyList(),
|
||||
),
|
||||
produceFile = { context.dataStoreFile(fileName = "yield_markets_cache") },
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import java.math.BigDecimal
|
|||
/**
|
||||
* Network status for storage in the local cache. Supports two types - the [Verified] and [NoAccount].
|
||||
*
|
||||
* @see [com.tangem.domain.tokens.model.NetworkStatus]
|
||||
* @see [com.tangem.domain.models.network.NetworkStatus]
|
||||
*/
|
||||
@JsonClass(generateAdapter = true, generator = PolymorphicAdapterType.NAME_POLYMORPHIC_ADAPTER)
|
||||
sealed interface NetworkStatusDM {
|
||||
|
|
@ -41,8 +41,8 @@ sealed interface NetworkStatusDM {
|
|||
@Json(name = "derivation_path") override val derivationPath: DerivationPath,
|
||||
@Json(name = "selected_address") override val selectedAddress: String,
|
||||
@Json(name = "available_addresses") override val availableAddresses: Set<Address>,
|
||||
@Json(name = "amounts") val amounts: Map<String, BigDecimal>,
|
||||
@Json(name = "yield_supply_statuses") val yieldSupplyStatuses: Map<String, YieldSupplyStatus?> = emptyMap(),
|
||||
@Json(name = "amounts") val amounts: List<CurrencyAmount>,
|
||||
@Json(name = "yield_supply_statuses") val yieldSupplyStatuses: List<YieldSupplyStatus>,
|
||||
) : NetworkStatusDM
|
||||
|
||||
/**
|
||||
|
|
@ -107,10 +107,44 @@ sealed interface NetworkStatusDM {
|
|||
}
|
||||
}
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class CurrencyAmount(
|
||||
@Json(name = "id") val id: CurrencyId,
|
||||
@Json(name = "amount") val amount: BigDecimal,
|
||||
)
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class YieldSupplyStatus(
|
||||
@Json(name = "id") val id: CurrencyId,
|
||||
@Json(name = "is_active") val isActive: Boolean,
|
||||
@Json(name = "is_initialized") val isInitialized: Boolean,
|
||||
@Json(name = "is_allowed_to_spend") val isAllowedToSpend: Boolean,
|
||||
)
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class CurrencyId(
|
||||
@Json(name = "value") val value: String,
|
||||
) {
|
||||
|
||||
companion object Companion {
|
||||
|
||||
const val CONTRACT_ADDRESS_DELIMITER = '\u2693' // ⚓
|
||||
|
||||
fun createCoinId(coinId: String): CurrencyId {
|
||||
return CurrencyId(value = coinId)
|
||||
}
|
||||
|
||||
fun createTokenId(rawTokenId: String?, contractAddress: String): CurrencyId {
|
||||
return CurrencyId(
|
||||
value = buildString {
|
||||
if (rawTokenId != null) {
|
||||
append(rawTokenId)
|
||||
}
|
||||
append(CONTRACT_ADDRESS_DELIMITER)
|
||||
append(contractAddress)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -12,5 +12,7 @@ interface TangemPayStorage {
|
|||
|
||||
suspend fun getOrderId(customerWalletAddress: String): String?
|
||||
|
||||
suspend fun clear(customerWalletAddress: String)
|
||||
suspend fun clearOrderId(customerWalletAddress: String)
|
||||
|
||||
suspend fun clearAll(customerWalletAddress: String)
|
||||
}
|
||||
|
|
@ -1,21 +1,21 @@
|
|||
package com.tangem.datasource.local.yieldsupply
|
||||
|
||||
import androidx.datastore.core.DataStore
|
||||
import com.tangem.domain.yield.supply.models.YieldMarketToken
|
||||
import com.tangem.datasource.api.tangemTech.models.YieldSupplyMarketTokenDto
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.firstOrNull
|
||||
|
||||
internal class DefaultYieldMarketsStore(
|
||||
private val persistenceStore: DataStore<List<YieldMarketToken>>,
|
||||
private val persistenceStore: DataStore<List<YieldSupplyMarketTokenDto>>,
|
||||
) : YieldMarketsStore {
|
||||
|
||||
override fun get(): Flow<List<YieldMarketToken>> = persistenceStore.data
|
||||
override fun get(): Flow<List<YieldSupplyMarketTokenDto>> = persistenceStore.data
|
||||
|
||||
override suspend fun getSyncOrNull(): List<YieldMarketToken>? {
|
||||
override suspend fun getSyncOrNull(): List<YieldSupplyMarketTokenDto>? {
|
||||
return persistenceStore.data.firstOrNull()
|
||||
}
|
||||
|
||||
override suspend fun store(items: List<YieldMarketToken>) {
|
||||
override suspend fun store(items: List<YieldSupplyMarketTokenDto>) {
|
||||
persistenceStore.updateData { _ -> items }
|
||||
}
|
||||
}
|
||||
|
|
@ -1,13 +1,13 @@
|
|||
package com.tangem.datasource.local.yieldsupply
|
||||
|
||||
import com.tangem.domain.yield.supply.models.YieldMarketToken
|
||||
import com.tangem.datasource.api.tangemTech.models.YieldSupplyMarketTokenDto
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
interface YieldMarketsStore {
|
||||
|
||||
fun get(): Flow<List<YieldMarketToken>>
|
||||
fun get(): Flow<List<YieldSupplyMarketTokenDto>>
|
||||
|
||||
suspend fun getSyncOrNull(): List<YieldMarketToken>?
|
||||
suspend fun getSyncOrNull(): List<YieldSupplyMarketTokenDto>?
|
||||
|
||||
suspend fun store(items: List<YieldMarketToken>)
|
||||
suspend fun store(items: List<YieldSupplyMarketTokenDto>)
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
package com.tangem.datasource.utils
|
||||
|
||||
@Target(AnnotationTarget.CLASS)
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
annotation class SerializeNulls
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
package com.tangem.datasource.utils
|
||||
|
||||
import com.squareup.moshi.JsonAdapter
|
||||
import com.squareup.moshi.Moshi
|
||||
import com.squareup.moshi.Types
|
||||
import java.lang.reflect.Type
|
||||
|
||||
/**
|
||||
* Factory to serialize nulls in Moshi if the class is annotated with [SerializeNulls].
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
internal object SerializeNullsFactory : JsonAdapter.Factory {
|
||||
|
||||
override fun create(type: Type, annotations: MutableSet<out Annotation>, moshi: Moshi): JsonAdapter<*>? {
|
||||
val rawType = Types.getRawType(type)
|
||||
if (!rawType.isAnnotationPresent(SerializeNulls::class.java)) {
|
||||
return null
|
||||
}
|
||||
|
||||
val nextAdapter: JsonAdapter<Any> = moshi.nextAdapter(this, type, annotations)
|
||||
|
||||
return nextAdapter.serializeNulls()
|
||||
}
|
||||
}
|
||||
|
|
@ -64,9 +64,15 @@ class NetworkStatusDMSerializationTest {
|
|||
NetworkStatusDM.Address("0x123456", NetworkStatusDM.Address.Type.Primary),
|
||||
NetworkStatusDM.Address("0xabcdef", NetworkStatusDM.Address.Type.Secondary),
|
||||
),
|
||||
amounts = mapOf("ETH" to BigDecimal("1.2345")),
|
||||
yieldSupplyStatuses = mapOf(
|
||||
"ETH" to NetworkStatusDM.YieldSupplyStatus(
|
||||
amounts = listOf(
|
||||
NetworkStatusDM.CurrencyAmount(
|
||||
id = NetworkStatusDM.CurrencyId.createCoinId("ethereum"),
|
||||
amount = BigDecimal("1.2345"),
|
||||
),
|
||||
),
|
||||
yieldSupplyStatuses = listOf(
|
||||
NetworkStatusDM.YieldSupplyStatus(
|
||||
id = NetworkStatusDM.CurrencyId.createCoinId("ethereum"),
|
||||
isActive = false,
|
||||
isInitialized = false,
|
||||
isAllowedToSpend = false,
|
||||
|
|
@ -91,9 +97,15 @@ class NetworkStatusDMSerializationTest {
|
|||
NetworkStatusDM.Address("0x123456", NetworkStatusDM.Address.Type.Primary),
|
||||
NetworkStatusDM.Address("0xabcdef", NetworkStatusDM.Address.Type.Secondary),
|
||||
),
|
||||
amounts = mapOf("ETH" to BigDecimal("1.2345")),
|
||||
yieldSupplyStatuses = mapOf(
|
||||
"ETH" to NetworkStatusDM.YieldSupplyStatus(
|
||||
amounts = listOf(
|
||||
NetworkStatusDM.CurrencyAmount(
|
||||
id = NetworkStatusDM.CurrencyId.createCoinId("ethereum"),
|
||||
amount = BigDecimal("1.2345"),
|
||||
),
|
||||
),
|
||||
yieldSupplyStatuses = listOf(
|
||||
NetworkStatusDM.YieldSupplyStatus(
|
||||
id = NetworkStatusDM.CurrencyId.createCoinId("ethereum"),
|
||||
isActive = false,
|
||||
isInitialized = false,
|
||||
isAllowedToSpend = false,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,51 @@
|
|||
package com.tangem.datasource.utils
|
||||
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import com.squareup.moshi.JsonClass
|
||||
import com.squareup.moshi.Moshi
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.TestInstance
|
||||
|
||||
// --- DTO ---
|
||||
@SerializeNulls
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class UserWithNulls(val id: String?, val name: String?)
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class UserWithoutNulls(val id: String?, val name: String?)
|
||||
|
||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||
class SerializeNullsFactoryTest {
|
||||
|
||||
private val moshi = Moshi.Builder()
|
||||
.add(SerializeNullsFactory)
|
||||
.build()
|
||||
|
||||
@Test
|
||||
fun `should serialize nulls for annotated class`() {
|
||||
val adapter = moshi.adapter(UserWithNulls::class.java)
|
||||
|
||||
val json = adapter.toJson(UserWithNulls(id = null, name = "John"))
|
||||
|
||||
assertThat(json).isEqualTo("""{"id":null,"name":"John"}""")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should skip nulls for non-annotated class`() {
|
||||
val adapter = moshi.adapter(UserWithoutNulls::class.java)
|
||||
|
||||
val json = adapter.toJson(UserWithoutNulls(id = null, name = "John"))
|
||||
|
||||
assertThat(json).isEqualTo("""{"name":"John"}""")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should deserialize annotated class correctly`() {
|
||||
val adapter = moshi.adapter(UserWithNulls::class.java)
|
||||
|
||||
val json = """{"id":null,"name":"Jane"}"""
|
||||
val result = adapter.fromJson(json)
|
||||
|
||||
assertThat(result).isEqualTo(UserWithNulls(id = null, name = "Jane"))
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue