[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[taler-taler-android] branch master updated (d3955c2 -> 0e28f81)
From: |
gnunet |
Subject: |
[taler-taler-android] branch master updated (d3955c2 -> 0e28f81) |
Date: |
Mon, 24 Aug 2020 22:29:43 +0200 |
This is an automated email from the git hooks/post-receive script.
torsten-grote pushed a change to branch master
in repository taler-android.
from d3955c2 Add README files to top-level and update the project ones
new 35bc917 Upgrade to Kotlin 1.4
new 39dcd04 Get rid of Jackson and only use multi-platform serialization
new 0e28f81 [wallet] upgrade to latest wallet-core version
The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
Summary of changes:
.idea/compiler.xml | 4 +
build.gradle | 4 +-
cashier/build.gradle | 7 +-
merchant-lib/build.gradle | 2 -
.../main/java/net/taler/merchantlib/MerchantApi.kt | 12 +-
.../src/main/java/net/taler/merchantlib/Orders.kt | 34 +---
.../main/java/net/taler/merchantlib/Response.kt | 5 +-
.../java/net/taler/merchantlib/MockHttpClient.kt | 5 +-
.../net/taler/merchantpos/config/ConfigManager.kt | 2 +-
multiplatform | 2 +-
taler-kotlin-android/build.gradle | 4 +-
.../main/java/net/taler/common/ContractTerms.kt | 18 +--
.../java/net/taler/lib/android/Serialization.kt | 11 +-
.../main/java/net/taler/lib/common/AmountMixin.kt | 51 ------
.../java/net/taler/lib/common/TimestampMixin.kt | 39 -----
.../java/net/taler/common/ContractTermsTest.kt | 24 +--
wallet/build.gradle | 13 +-
wallet/proguard-rules.pro | 33 ----
.../main/java/net/taler/wallet/MainViewModel.kt | 17 +-
.../net/taler/wallet/backend/WalletBackendApi.kt | 43 ++---
.../net/taler/wallet/backend/WalletResponse.kt | 30 +---
.../net/taler/wallet/payment/PaymentManager.kt | 25 +--
.../net/taler/wallet/payment/PaymentResponses.kt | 47 +++---
.../taler/wallet/payment/PromptPaymentFragment.kt | 4 +-
.../wallet/transactions/TransactionAdapter.kt | 2 +-
.../transactions/TransactionDetailFragment.kt | 2 +-
.../wallet/transactions/TransactionManager.kt | 9 +-
.../net/taler/wallet/transactions/Transactions.kt | 180 +++++++++++----------
.../net/taler/wallet/backend/WalletResponseTest.kt | 27 +---
29 files changed, 207 insertions(+), 449 deletions(-)
copy wallet/src/main/java/net/taler/wallet/balances/BalanceResponse.kt =>
taler-kotlin-android/src/main/java/net/taler/lib/android/Serialization.kt (81%)
delete mode 100644
taler-kotlin-android/src/main/java/net/taler/lib/common/AmountMixin.kt
delete mode 100644
taler-kotlin-android/src/main/java/net/taler/lib/common/TimestampMixin.kt
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
index 2b48706..9389bf3 100644
--- a/.idea/compiler.xml
+++ b/.idea/compiler.xml
@@ -12,6 +12,10 @@
<entry name="!?*.clj" />
</wildcardResourcePatterns>
<bytecodeTargetLevel>
+ <module name="common_commonMain" target="1.6" />
+ <module name="common_commonTest" target="1.6" />
+ <module name="common_jvmMain" target="1.6" />
+ <module name="common_jvmTest" target="1.6" />
<module name="taler-kotlin-common_jvmMain" target="1.6" />
<module name="taler-kotlin-common_jvmTest" target="1.6" />
</bytecodeTargetLevel>
diff --git a/build.gradle b/build.gradle
index 442d232..7c9e378 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,6 +1,6 @@
buildscript {
- ext.kotlin_version = '1.3.72'
- ext.ktor_version = "1.3.2"
+ ext.kotlin_version = '1.4.0'
+ ext.ktor_version = "1.4.0"
ext.nav_version = "2.3.0"
ext.lifecycle_version = "2.2.0"
// check https://android-rebuilds.beuc.net/ for availability of free build
tools
diff --git a/cashier/build.gradle b/cashier/build.gradle
index 341562d..916758b 100644
--- a/cashier/build.gradle
+++ b/cashier/build.gradle
@@ -59,13 +59,14 @@ android {
dependencies {
implementation project(":taler-kotlin-android")
- implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
- implementation 'androidx.security:security-crypto:1.0.0-rc02'
- implementation 'com.google.android.material:material:1.1.0'
+ implementation 'androidx.constraintlayout:constraintlayout:2.0.0'
+ implementation 'androidx.security:security-crypto:1.0.0-rc03'
+ implementation 'com.google.android.material:material:1.2.0'
implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
implementation "androidx.navigation:navigation-ui-ktx:$nav_version"
+ // https://github.com/square/okhttp/releases
implementation "com.squareup.okhttp3:okhttp:3.12.12"
testImplementation 'junit:junit:4.13'
diff --git a/merchant-lib/build.gradle b/merchant-lib/build.gradle
index 5082253..9b349ea 100644
--- a/merchant-lib/build.gradle
+++ b/merchant-lib/build.gradle
@@ -47,8 +47,6 @@ android {
dependencies {
api project(":taler-kotlin-android")
- implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
-
api "io.ktor:ktor-client:$ktor_version"
api "io.ktor:ktor-client-okhttp:$ktor_version"
api "io.ktor:ktor-client-serialization-jvm:$ktor_version"
diff --git a/merchant-lib/src/main/java/net/taler/merchantlib/MerchantApi.kt
b/merchant-lib/src/main/java/net/taler/merchantlib/MerchantApi.kt
index a4ca397..a467c41 100644
--- a/merchant-lib/src/main/java/net/taler/merchantlib/MerchantApi.kt
+++ b/merchant-lib/src/main/java/net/taler/merchantlib/MerchantApi.kt
@@ -31,7 +31,6 @@ import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import kotlinx.serialization.json.Json
-import kotlinx.serialization.json.JsonConfiguration
import net.taler.merchantlib.Response.Companion.response
class MerchantApi(
@@ -116,10 +115,9 @@ fun getDefaultHttpClient(): HttpClient =
HttpClient(OkHttp) {
}
fun getSerializer() = KotlinxSerializer(
- Json(
- JsonConfiguration(
- encodeDefaults = false,
- ignoreUnknownKeys = true
- )
- )
+ Json {
+ encodeDefaults = false
+ ignoreUnknownKeys = true
+ classDiscriminator = "order_status"
+ }
)
diff --git a/merchant-lib/src/main/java/net/taler/merchantlib/Orders.kt
b/merchant-lib/src/main/java/net/taler/merchantlib/Orders.kt
index 0a405ad..9242df3 100644
--- a/merchant-lib/src/main/java/net/taler/merchantlib/Orders.kt
+++ b/merchant-lib/src/main/java/net/taler/merchantlib/Orders.kt
@@ -16,15 +16,10 @@
package net.taler.merchantlib
-import kotlinx.serialization.Decoder
-import kotlinx.serialization.Encoder
-import kotlinx.serialization.KSerializer
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
-import kotlinx.serialization.Serializer
-import kotlinx.serialization.json.JsonInput
-import kotlinx.serialization.json.JsonObject
import net.taler.common.ContractTerms
+import net.taler.lib.android.CustomClassDiscriminator
import net.taler.lib.common.Duration
@Serializable
@@ -42,32 +37,12 @@ data class PostOrderResponse(
)
@Serializable
-sealed class CheckPaymentResponse {
+sealed class CheckPaymentResponse: CustomClassDiscriminator {
+ override val discriminator: String = "order_status"
abstract val paid: Boolean
- @Serializer(forClass = CheckPaymentResponse::class)
- companion object : KSerializer<CheckPaymentResponse> {
- override fun deserialize(decoder: Decoder): CheckPaymentResponse {
- val input = decoder as JsonInput
- val tree = input.decodeJson() as JsonObject
- val orderStatus = tree.getPrimitive("order_status").content
-// return if (orderStatus == "paid")
decoder.json.fromJson(Paid.serializer(), tree)
-// else decoder.json.fromJson(Unpaid.serializer(), tree)
- // manual parsing due to
https://github.com/Kotlin/kotlinx.serialization/issues/576
- return if (orderStatus == "paid") Paid(
- refunded = tree.getPrimitive("refunded").boolean
- ) else Unpaid(
- talerPayUri = tree.getPrimitive("taler_pay_uri").content
- )
- }
-
- override fun serialize(encoder: Encoder, value: CheckPaymentResponse)
= when (value) {
- is Unpaid -> Unpaid.serializer().serialize(encoder, value)
- is Paid -> Paid.serializer().serialize(encoder, value)
- }
- }
-
@Serializable
+ @SerialName("unpaid")
data class Unpaid(
override val paid: Boolean = false,
@SerialName("taler_pay_uri")
@@ -77,6 +52,7 @@ sealed class CheckPaymentResponse {
) : CheckPaymentResponse()
@Serializable
+ @SerialName("paid")
data class Paid(
override val paid: Boolean = true,
val refunded: Boolean
diff --git a/merchant-lib/src/main/java/net/taler/merchantlib/Response.kt
b/merchant-lib/src/main/java/net/taler/merchantlib/Response.kt
index fb48b46..1b63900 100644
--- a/merchant-lib/src/main/java/net/taler/merchantlib/Response.kt
+++ b/merchant-lib/src/main/java/net/taler/merchantlib/Response.kt
@@ -70,11 +70,12 @@ class Response<out T> private constructor(
}
private suspend fun getExceptionString(e: ResponseException): String {
+ val response = e.response ?: return e.toString()
return try {
- val error: Error = e.response.receive()
+ val error: Error = response.receive()
"Error ${error.code}: ${error.hint}"
} catch (ex: Exception) {
- "Status code: ${e.response.status.value}"
+ "Status code: ${response.status.value}"
}
}
diff --git a/merchant-lib/src/test/java/net/taler/merchantlib/MockHttpClient.kt
b/merchant-lib/src/test/java/net/taler/merchantlib/MockHttpClient.kt
index 993be15..c8e6f22 100644
--- a/merchant-lib/src/test/java/net/taler/merchantlib/MockHttpClient.kt
+++ b/merchant-lib/src/test/java/net/taler/merchantlib/MockHttpClient.kt
@@ -32,6 +32,7 @@ import io.ktor.http.content.TextContent
import io.ktor.http.fullPath
import io.ktor.http.headersOf
import io.ktor.http.hostWithPort
+import kotlinx.serialization.json.Json.Default.parseToJsonElement
import org.junit.Assert.assertEquals
object MockHttpClient {
@@ -75,8 +76,8 @@ object MockHttpClient {
private val Url.fullUrl: String get() =
"${protocol.name}://$hostWithPortIfRequired$fullPath"
private fun assertJsonEquals(json1: String, json2: String) {
- val parsed1 = kotlinx.serialization.json.Json.parseJson(json1)
- val parsed2 = kotlinx.serialization.json.Json.parseJson(json2)
+ val parsed1 = parseToJsonElement(json1)
+ val parsed2 = parseToJsonElement(json2)
assertEquals(parsed1, parsed2)
}
diff --git
a/merchant-terminal/src/main/java/net/taler/merchantpos/config/ConfigManager.kt
b/merchant-terminal/src/main/java/net/taler/merchantpos/config/ConfigManager.kt
index 23abe7d..d7c446f 100644
---
a/merchant-terminal/src/main/java/net/taler/merchantpos/config/ConfigManager.kt
+++
b/merchant-terminal/src/main/java/net/taler/merchantpos/config/ConfigManager.kt
@@ -115,7 +115,7 @@ class ConfigManager(
Log.e(TAG, "Error retrieving merchant config", e)
val msg = if (e is ClientRequestException) {
context.getString(
- if (e.response.status == Unauthorized)
R.string.config_auth_error
+ if (e.response?.status == Unauthorized)
R.string.config_auth_error
else R.string.config_error_network
)
} else {
diff --git a/multiplatform b/multiplatform
index dade047..6f698f4 160000
--- a/multiplatform
+++ b/multiplatform
@@ -1 +1 @@
-Subproject commit dade0470c7e378c72ac2f2fd2a623416dadbff10
+Subproject commit 6f698f4d0ef580a898d3b03e9e8954af4f194037
diff --git a/taler-kotlin-android/build.gradle
b/taler-kotlin-android/build.gradle
index ca4df8a..6d992a0 100644
--- a/taler-kotlin-android/build.gradle
+++ b/taler-kotlin-android/build.gradle
@@ -52,7 +52,6 @@ android {
dependencies {
api project(":multiplatform:common")
- implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'androidx.core:core-ktx:1.3.1'
@@ -67,8 +66,7 @@ dependencies {
implementation 'com.google.zxing:core:3.4.0' // needs minSdkVersion 24+
// JSON parsing and serialization
- api "org.jetbrains.kotlinx:kotlinx-serialization-runtime:0.20.0"
- implementation "com.fasterxml.jackson.module:jackson-module-kotlin:2.10.2"
+ api "org.jetbrains.kotlinx:kotlinx-serialization-core:1.0.0-RC"
lintPublish 'com.github.thirdegg:lint-rules:0.0.4-alpha'
diff --git
a/taler-kotlin-android/src/main/java/net/taler/common/ContractTerms.kt
b/taler-kotlin-android/src/main/java/net/taler/common/ContractTerms.kt
index 8bf77e8..2c50fa9 100644
--- a/taler-kotlin-android/src/main/java/net/taler/common/ContractTerms.kt
+++ b/taler-kotlin-android/src/main/java/net/taler/common/ContractTerms.kt
@@ -17,10 +17,6 @@
package net.taler.common
import androidx.annotation.RequiresApi
-import com.fasterxml.jackson.annotation.JsonIgnore
-import com.fasterxml.jackson.annotation.JsonInclude
-import com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL
-import com.fasterxml.jackson.annotation.JsonProperty
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import net.taler.common.TalerUtils.getLocalizedString
@@ -31,36 +27,24 @@ import net.taler.lib.common.Timestamp
data class ContractTerms(
val summary: String,
@SerialName("summary_i18n")
- @get:JsonProperty("summary_i18n")
val summaryI18n: Map<String, String>? = null,
val amount: Amount,
@SerialName("fulfillment_url")
- @get:JsonProperty("fulfillment_url")
val fulfillmentUrl: String,
val products: List<ContractProduct>,
@SerialName("wire_transfer_deadline")
- @get:JsonProperty("wire_transfer_deadline")
val wireTransferDeadline: Timestamp? = null,
@SerialName("refund_deadline")
- @get:JsonProperty("refund_deadline")
val refundDeadline: Timestamp? = null
)
-@JsonInclude(NON_NULL)
abstract class Product {
- @get:JsonProperty("product_id")
abstract val productId: String?
abstract val description: String
-
- @get:JsonProperty("description_i18n")
abstract val descriptionI18n: Map<String, String>?
abstract val price: Amount
-
- @get:JsonProperty("delivery_location")
abstract val location: String?
abstract val image: String?
-
- @get:JsonIgnore
val localizedDescription: String
@RequiresApi(26)
get() = getLocalizedString(descriptionI18n, description)
@@ -79,12 +63,12 @@ data class ContractProduct(
override val image: String? = null,
val quantity: Int
) : Product() {
- @get:JsonIgnore
val totalPrice: Amount by lazy {
price * quantity
}
}
+@Serializable
data class ContractMerchant(
val name: String
)
diff --git a/wallet/src/main/java/net/taler/wallet/balances/BalanceResponse.kt
b/taler-kotlin-android/src/main/java/net/taler/lib/android/Serialization.kt
similarity index 81%
copy from wallet/src/main/java/net/taler/wallet/balances/BalanceResponse.kt
copy to
taler-kotlin-android/src/main/java/net/taler/lib/android/Serialization.kt
index d1a111f..7eb4480 100644
--- a/wallet/src/main/java/net/taler/wallet/balances/BalanceResponse.kt
+++ b/taler-kotlin-android/src/main/java/net/taler/lib/android/Serialization.kt
@@ -14,11 +14,8 @@
* GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
-package net.taler.wallet.balances
+package net.taler.lib.android
-import kotlinx.serialization.Serializable
-
-@Serializable
-data class BalanceResponse(
- val balances: List<BalanceItem>
-)
+interface CustomClassDiscriminator {
+ val discriminator: String
+}
diff --git
a/taler-kotlin-android/src/main/java/net/taler/lib/common/AmountMixin.kt
b/taler-kotlin-android/src/main/java/net/taler/lib/common/AmountMixin.kt
deleted file mode 100644
index 59285b6..0000000
--- a/taler-kotlin-android/src/main/java/net/taler/lib/common/AmountMixin.kt
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * This file is part of GNU Taler
- * (C) 2020 Taler Systems S.A.
- *
- * GNU Taler is free software; you can redistribute it and/or modify it under
the
- * terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 3, or (at your option) any later version.
- *
- * GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR
- * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-package net.taler.lib.common
-
-import com.fasterxml.jackson.core.JsonGenerator
-import com.fasterxml.jackson.core.JsonParser
-import com.fasterxml.jackson.databind.DeserializationContext
-import com.fasterxml.jackson.databind.JsonMappingException
-import com.fasterxml.jackson.databind.SerializerProvider
-import com.fasterxml.jackson.databind.annotation.JsonDeserialize
-import com.fasterxml.jackson.databind.annotation.JsonSerialize
-import com.fasterxml.jackson.databind.deser.std.StdDeserializer
-import com.fasterxml.jackson.databind.ser.std.StdSerializer
-
-/**
- * Used to support Jackson serialization along with KotlinX.
- */
-@JsonSerialize(using = AmountSerializer::class)
-@JsonDeserialize(using = AmountDeserializer::class)
-abstract class AmountMixin
-
-class AmountSerializer : StdSerializer<Amount>(Amount::class.java) {
- override fun serialize(value: Amount, gen: JsonGenerator, provider:
SerializerProvider) {
- gen.writeString(value.toJSONString())
- }
-}
-
-class AmountDeserializer : StdDeserializer<Amount>(Amount::class.java) {
- override fun deserialize(p: JsonParser, ctxt: DeserializationContext):
Amount {
- val node = p.codec.readValue(p, String::class.java)
- try {
- return Amount.fromJSONString(node)
- } catch (e: AmountParserException) {
- throw JsonMappingException(p, "Error parsing Amount", e)
- }
- }
-}
diff --git
a/taler-kotlin-android/src/main/java/net/taler/lib/common/TimestampMixin.kt
b/taler-kotlin-android/src/main/java/net/taler/lib/common/TimestampMixin.kt
deleted file mode 100644
index 40c03f6..0000000
--- a/taler-kotlin-android/src/main/java/net/taler/lib/common/TimestampMixin.kt
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * This file is part of GNU Taler
- * (C) 2020 Taler Systems S.A.
- *
- * GNU Taler is free software; you can redistribute it and/or modify it under
the
- * terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 3, or (at your option) any later version.
- *
- * GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR
- * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-package net.taler.lib.common
-
-import com.fasterxml.jackson.annotation.JsonProperty
-import com.fasterxml.jackson.core.JsonParser
-import com.fasterxml.jackson.databind.DeserializationContext
-import com.fasterxml.jackson.databind.annotation.JsonDeserialize
-import com.fasterxml.jackson.databind.deser.std.StdDeserializer
-
-/**
- * Used to support Jackson serialization along with KotlinX.
- */
-abstract class TimestampMixin(
- @get:JsonDeserialize(using = NeverDeserializer::class)
- @get:JsonProperty("t_ms")
- val ms: Long
-)
-
-class NeverDeserializer : StdDeserializer<Long>(Long::class.java) {
- override fun deserialize(p: JsonParser, ctxt: DeserializationContext):
Long {
- return if (p.text == "never") -1
- else p.longValue
- }
-}
diff --git
a/taler-kotlin-android/src/test/java/net/taler/common/ContractTermsTest.kt
b/taler-kotlin-android/src/test/java/net/taler/common/ContractTermsTest.kt
index 62e8922..3a2cdb4 100644
--- a/taler-kotlin-android/src/test/java/net/taler/common/ContractTermsTest.kt
+++ b/taler-kotlin-android/src/test/java/net/taler/common/ContractTermsTest.kt
@@ -16,29 +16,21 @@
package net.taler.common
-import com.fasterxml.jackson.databind.DeserializationFeature
-import com.fasterxml.jackson.databind.ObjectMapper
-import com.fasterxml.jackson.module.kotlin.KotlinModule
-import com.fasterxml.jackson.module.kotlin.readValue
-import net.taler.lib.common.Amount
-import net.taler.lib.common.AmountMixin
+import kotlinx.serialization.decodeFromString
+import kotlinx.serialization.json.Json
import net.taler.lib.common.Timestamp
-import net.taler.lib.common.Timestamp.Companion.NEVER
-import net.taler.lib.common.TimestampMixin
import org.junit.Assert.assertEquals
import org.junit.Test
class ContractTermsTest {
- private val mapper = ObjectMapper()
- .registerModule(KotlinModule())
- .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
- .addMixIn(Amount::class.java, AmountMixin::class.java)
- .addMixIn(Timestamp::class.java, TimestampMixin::class.java)
+ private val json = Json {
+ ignoreUnknownKeys = true
+ }
@Test
fun test() {
- val json = """
+ val jsonStr = """
{
"amount":"TESTKUDOS:0.5",
"extra":{
@@ -73,9 +65,9 @@ class ContractTermsTest {
"nonce":"FK8ZKJRV6VX6YFAG4CDSC6W0DWD084Q09DP81ANF30GRFQYM2KPG"
}
""".trimIndent()
- val contractTerms: ContractTerms = mapper.readValue(json)
+ val contractTerms: ContractTerms = json.decodeFromString(jsonStr)
assertEquals("Essay: 1. The Free Software Definition",
contractTerms.summary)
- assertEquals(Timestamp(NEVER), contractTerms.refundDeadline)
+ assertEquals(Timestamp.never(), contractTerms.refundDeadline)
}
}
diff --git a/wallet/build.gradle b/wallet/build.gradle
index 87019f8..70b9648 100644
--- a/wallet/build.gradle
+++ b/wallet/build.gradle
@@ -20,11 +20,11 @@ plugins {
id "com.android.application"
id "kotlin-android"
id "kotlin-android-extensions"
- id 'kotlinx-serialization'
+ id "kotlinx-serialization"
id "de.undercouch.download"
}
-def walletCoreVersion = "v0.7.1-dev.21"
+def walletCoreVersion = "v0.7.1-dev.22"
static def versionCodeEpoch() {
return (new Date().getTime() / 1000).toInteger()
@@ -48,7 +48,7 @@ android {
minSdkVersion 24
targetSdkVersion 29
versionCode 6
- versionName "0.7.1.dev.21"
+ versionName "0.7.1.dev.22"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
buildConfigField "String", "WALLET_CORE_VERSION",
"\"$walletCoreVersion\""
}
@@ -102,9 +102,11 @@ dependencies {
implementation project(":anastasis-ui")
implementation 'net.taler:akono:0.1'
+ implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
+
implementation 'androidx.preference:preference:1.1.1'
implementation 'com.google.android.material:material:1.2.0'
- implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
+ implementation 'androidx.constraintlayout:constraintlayout:2.0.0'
// Lists and Selection
implementation "androidx.recyclerview:recyclerview:1.1.0"
@@ -129,9 +131,6 @@ dependencies {
implementation "io.noties.markwon:ext-tables:$markwon_version"
implementation "io.noties.markwon:recycler:$markwon_version"
- // JSON parsing and serialization
- implementation 'com.fasterxml.jackson.module:jackson-module-kotlin:2.10.2'
-
testImplementation 'junit:junit:4.13'
testImplementation 'org.json:json:20200518'
androidTestImplementation 'androidx.test:runner:1.2.0'
diff --git a/wallet/proguard-rules.pro b/wallet/proguard-rules.pro
index 147334d..27f3799 100644
--- a/wallet/proguard-rules.pro
+++ b/wallet/proguard-rules.pro
@@ -23,36 +23,3 @@
-keep class akono.AkonoJni {*;}
-keep class net.taler.wallet.** {*;}
-
-# Jackson
--keep @com.fasterxml.jackson.annotation.JsonIgnoreProperties class * { *; }
--keep @com.fasterxml.jackson.annotation.JsonCreator class * { *; }
--keep @com.fasterxml.jackson.annotation.JsonValue class * { *; }
--keep class com.fasterxml.** { *; }
--keep class org.codehaus.** { *; }
--keepnames class com.fasterxml.jackson.** { *; }
--keepclassmembers public final enum
com.fasterxml.jackson.annotation.JsonAutoDetect$Visibility {
- public static final
com.fasterxml.jackson.annotation.JsonAutoDetect$Visibility *;
-}
-
--keep class * extends com.fasterxml.** { *; }
--keep class * implements com.fasterxml.** { *; }
-
--keep class * {
- @com.fasterxml.** *;
-}
-
-# KotlinX serialization
--keep @kotlinx.serialization.Serializable class * { *; }
-
-# Kotlin reflection
--dontwarn kotlin.reflect.**
--keep class kotlin.** { *; }
--keep class org.jetbrains.annotations.** { *; }
-
-
-# General
--keepattributes
SourceFile,LineNumberTable,*Annotation*,EnclosingMethod,Signature,Exceptions,InnerClasses
--dontobfuscate
--dontoptimize
--dontshrink
\ No newline at end of file
diff --git a/wallet/src/main/java/net/taler/wallet/MainViewModel.kt
b/wallet/src/main/java/net/taler/wallet/MainViewModel.kt
index 3fc49a9..9e49f54 100644
--- a/wallet/src/main/java/net/taler/wallet/MainViewModel.kt
+++ b/wallet/src/main/java/net/taler/wallet/MainViewModel.kt
@@ -24,18 +24,11 @@ import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.distinctUntilChanged
import androidx.lifecycle.viewModelScope
-import
com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES
-import com.fasterxml.jackson.databind.ObjectMapper
-import com.fasterxml.jackson.module.kotlin.KotlinModule
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import net.taler.common.Event
import net.taler.common.assertUiThread
import net.taler.common.toEvent
-import net.taler.lib.common.Amount
-import net.taler.lib.common.AmountMixin
-import net.taler.lib.common.Timestamp
-import net.taler.lib.common.TimestampMixin
import net.taler.wallet.backend.WalletBackendApi
import net.taler.wallet.balances.BalanceItem
import net.taler.wallet.balances.BalanceResponse
@@ -70,12 +63,6 @@ class MainViewModel(val app: Application) :
AndroidViewModel(app) {
var merchantVersion: String? = null
private set
- private val mapper = ObjectMapper()
- .registerModule(KotlinModule())
- .configure(FAIL_ON_UNKNOWN_PROPERTIES, false)
- .addMixIn(Amount::class.java, AmountMixin::class.java)
- .addMixIn(Timestamp::class.java, TimestampMixin::class.java)
-
private val api = WalletBackendApi(app) { payload ->
if (payload.optString("operation") == "init") {
val result = payload.getJSONObject("result")
@@ -99,9 +86,9 @@ class MainViewModel(val app: Application) :
AndroidViewModel(app) {
}
val withdrawManager = WithdrawManager(api, viewModelScope)
- val paymentManager = PaymentManager(api, viewModelScope, mapper)
+ val paymentManager = PaymentManager(api, viewModelScope)
val pendingOperationsManager: PendingOperationsManager =
PendingOperationsManager(api)
- val transactionManager: TransactionManager = TransactionManager(api,
viewModelScope, mapper)
+ val transactionManager: TransactionManager = TransactionManager(api,
viewModelScope)
val refundManager = RefundManager(api, viewModelScope)
val exchangeManager: ExchangeManager = ExchangeManager(api, viewModelScope)
diff --git a/wallet/src/main/java/net/taler/wallet/backend/WalletBackendApi.kt
b/wallet/src/main/java/net/taler/wallet/backend/WalletBackendApi.kt
index 5ca2255..c6261bf 100644
--- a/wallet/src/main/java/net/taler/wallet/backend/WalletBackendApi.kt
+++ b/wallet/src/main/java/net/taler/wallet/backend/WalletBackendApi.kt
@@ -26,13 +26,11 @@ import android.os.IBinder
import android.os.Message
import android.os.Messenger
import android.util.Log
-import com.fasterxml.jackson.databind.ObjectMapper
-import com.fasterxml.jackson.module.kotlin.readValue
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import kotlinx.serialization.KSerializer
import kotlinx.serialization.json.Json
-import kotlinx.serialization.json.JsonConfiguration
+import net.taler.lib.android.CustomClassDiscriminator
import net.taler.wallet.backend.WalletBackendService.Companion.MSG_COMMAND
import net.taler.wallet.backend.WalletBackendService.Companion.MSG_NOTIFY
import net.taler.wallet.backend.WalletBackendService.Companion.MSG_REPLY
@@ -44,14 +42,12 @@ import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.atomic.AtomicInteger
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine
+import kotlin.reflect.full.companionObjectInstance
class WalletBackendApi(
private val app: Application,
private val notificationHandler: ((payload: JSONObject) -> Unit)
) {
- private val json = Json(
- JsonConfiguration.Stable.copy(ignoreUnknownKeys = true)
- )
private var walletBackendMessenger: Messenger? = null
private val queuedMessages = LinkedList<Message>()
private val handlers = ConcurrentHashMap<Int, (isError: Boolean, message:
JSONObject) -> Unit>()
@@ -148,38 +144,25 @@ class WalletBackendApi(
}
}
- suspend fun <T> request(
+ suspend inline fun <reified T> request(
operation: String,
serializer: KSerializer<T>? = null,
- args: (JSONObject.() -> JSONObject)? = null
+ noinline args: (JSONObject.() -> JSONObject)? = null
): WalletResponse<T> = withContext(Dispatchers.Default) {
- suspendCoroutine<WalletResponse<T>> { cont ->
- sendRequest(operation, args?.invoke(JSONObject())) { isError,
message ->
- val response = if (isError) {
- val error = json.parse(WalletErrorInfo.serializer(),
message.toString())
- WalletResponse.Error<T>(error)
- } else {
- @Suppress("UNCHECKED_CAST") // if serializer is null, T
must be Unit
- val t: T = serializer?.let { json.parse(serializer,
message.toString()) } ?: Unit as T
- WalletResponse.Success(t)
+ suspendCoroutine { cont ->
+ val json = Json {
+ ignoreUnknownKeys = true
+ (T::class.companionObjectInstance as?
CustomClassDiscriminator)?.let {
+ classDiscriminator = it.discriminator
}
- cont.resume(response)
}
- }
- }
-
- suspend inline fun <reified T> request(
- operation: String,
- mapper: ObjectMapper,
- noinline args: (JSONObject.() -> JSONObject)? = null
- ): WalletResponse<T> = withContext(Dispatchers.Default) {
- suspendCoroutine<WalletResponse<T>> { cont ->
sendRequest(operation, args?.invoke(JSONObject())) { isError,
message ->
val response = if (isError) {
- val error: WalletErrorInfo =
mapper.readValue(message.toString())
- WalletResponse.Error<T>(error)
+ val error =
json.decodeFromString(WalletErrorInfo.serializer(), message.toString())
+ WalletResponse.Error(error)
} else {
- val t: T = mapper.readValue(message.toString())
+ @Suppress("UNCHECKED_CAST") // if serializer is null, T
must be Unit
+ val t: T = serializer?.let {
json.decodeFromString(serializer, message.toString()) } ?: Unit as T
WalletResponse.Success(t)
}
cont.resume(response)
diff --git a/wallet/src/main/java/net/taler/wallet/backend/WalletResponse.kt
b/wallet/src/main/java/net/taler/wallet/backend/WalletResponse.kt
index ab3d42e..4b39ff8 100644
--- a/wallet/src/main/java/net/taler/wallet/backend/WalletResponse.kt
+++ b/wallet/src/main/java/net/taler/wallet/backend/WalletResponse.kt
@@ -16,23 +16,17 @@
package net.taler.wallet.backend
-import com.fasterxml.jackson.core.JsonParser
-import com.fasterxml.jackson.databind.DeserializationContext
-import com.fasterxml.jackson.databind.JsonNode
-import com.fasterxml.jackson.databind.annotation.JsonDeserialize
-import com.fasterxml.jackson.databind.deser.std.StdDeserializer
-import kotlinx.serialization.Decoder
-import kotlinx.serialization.Encoder
import kotlinx.serialization.KSerializer
-import kotlinx.serialization.PrimitiveDescriptor
-import kotlinx.serialization.PrimitiveKind.STRING
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
-import kotlinx.serialization.json.JsonInput
+import kotlinx.serialization.descriptors.PrimitiveKind.STRING
+import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
+import kotlinx.serialization.encoding.Decoder
+import kotlinx.serialization.encoding.Encoder
+import kotlinx.serialization.json.JsonDecoder
import kotlinx.serialization.json.JsonObject
import org.json.JSONObject
-
@Serializable
sealed class WalletResponse<T> {
@Serializable
@@ -73,7 +67,6 @@ data class WalletErrorInfo(
// Error details, type depends on talerErrorCode
@Serializable(JSONObjectDeserializer::class)
- @JsonDeserialize(using = JsonObjectDeserializer::class)
val details: JSONObject?
) {
val userFacingMsg: String
@@ -96,11 +89,11 @@ data class WalletErrorInfo(
class JSONObjectDeserializer : KSerializer<JSONObject> {
- override val descriptor = PrimitiveDescriptor("JSONObjectDeserializer",
STRING)
+ override val descriptor =
PrimitiveSerialDescriptor("JSONObjectDeserializer", STRING)
override fun deserialize(decoder: Decoder): JSONObject {
- val input = decoder as JsonInput
- val tree = input.decodeJson() as JsonObject
+ val input = decoder as JsonDecoder
+ val tree = input.decodeJsonElement() as JsonObject
return JSONObject(tree.toString())
}
@@ -108,10 +101,3 @@ class JSONObjectDeserializer : KSerializer<JSONObject> {
error("not supported")
}
}
-
-class JsonObjectDeserializer :
StdDeserializer<JSONObject>(JSONObject::class.java) {
- override fun deserialize(p: JsonParser, ctxt: DeserializationContext):
JSONObject {
- val node: JsonNode = p.codec.readTree(p)
- return JSONObject(node.toString())
- }
-}
diff --git a/wallet/src/main/java/net/taler/wallet/payment/PaymentManager.kt
b/wallet/src/main/java/net/taler/wallet/payment/PaymentManager.kt
index 4924752..befcd83 100644
--- a/wallet/src/main/java/net/taler/wallet/payment/PaymentManager.kt
+++ b/wallet/src/main/java/net/taler/wallet/payment/PaymentManager.kt
@@ -20,12 +20,10 @@ import android.util.Log
import androidx.annotation.UiThread
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
-import com.fasterxml.jackson.databind.ObjectMapper
-import com.fasterxml.jackson.module.kotlin.readValue
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
-import net.taler.lib.common.Amount
import net.taler.common.ContractTerms
+import net.taler.lib.common.Amount
import net.taler.wallet.TAG
import net.taler.wallet.backend.WalletBackendApi
import net.taler.wallet.backend.WalletErrorInfo
@@ -34,8 +32,6 @@ import net.taler.wallet.payment.PayStatus.InsufficientBalance
import net.taler.wallet.payment.PreparePayResponse.AlreadyConfirmedResponse
import net.taler.wallet.payment.PreparePayResponse.InsufficientBalanceResponse
import net.taler.wallet.payment.PreparePayResponse.PaymentPossibleResponse
-import org.json.JSONObject
-import java.net.MalformedURLException
val REGEX_PRODUCT_IMAGE =
Regex("^data:image/(jpeg|png);base64,([A-Za-z0-9+/=]+)$")
@@ -63,7 +59,6 @@ sealed class PayStatus {
class PaymentManager(
private val api: WalletBackendApi,
private val scope: CoroutineScope,
- private val mapper: ObjectMapper
) {
private val mPayStatus = MutableLiveData<PayStatus>(PayStatus.None)
@@ -76,7 +71,7 @@ class PaymentManager(
fun preparePay(url: String) = scope.launch {
mPayStatus.value = PayStatus.Loading
mDetailsShown.value = false
- api.request<PreparePayResponse>("preparePay", mapper) {
+ api.request("preparePay", PreparePayResponse.serializer()) {
put("talerPayUri", url)
}.onError {
handleError("preparePay", it)
@@ -93,20 +88,6 @@ class PaymentManager(
}
}
- // TODO validate product images (or leave to wallet-core?)
- private fun getContractTerms(json: JSONObject): ContractTerms {
- val terms: ContractTerms =
mapper.readValue(json.getString("contractTermsRaw"))
- // validate product images
- terms.products.forEach { product ->
- product.image?.let { image ->
- if (REGEX_PRODUCT_IMAGE.matchEntire(image) == null) {
- throw MalformedURLException("Invalid image data URL for
${product.description}")
- }
- }
- }
- return terms
- }
-
fun confirmPay(proposalId: String, currency: String) = scope.launch {
api.request("confirmPay", ConfirmPayResult.serializer()) {
put("proposalId", proposalId)
@@ -128,7 +109,7 @@ class PaymentManager(
internal fun abortProposal(proposalId: String) = scope.launch {
Log.i(TAG, "aborting proposal")
- api.request<String>("abortProposal", mapper) {
+ api.request<Unit>("abortProposal") {
put("proposalId", proposalId)
}.onError {
Log.e(TAG, "received error response to abortProposal")
diff --git a/wallet/src/main/java/net/taler/wallet/payment/PaymentResponses.kt
b/wallet/src/main/java/net/taler/wallet/payment/PaymentResponses.kt
index c490654..2e99806 100644
--- a/wallet/src/main/java/net/taler/wallet/payment/PaymentResponses.kt
+++ b/wallet/src/main/java/net/taler/wallet/payment/PaymentResponses.kt
@@ -16,61 +16,62 @@
package net.taler.wallet.payment
-import com.fasterxml.jackson.annotation.JsonTypeInfo
-import com.fasterxml.jackson.annotation.JsonTypeInfo.Id.NAME
-import com.fasterxml.jackson.annotation.JsonTypeName
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import net.taler.common.ContractTerms
+import net.taler.lib.android.CustomClassDiscriminator
import net.taler.lib.common.Amount
import net.taler.wallet.transactions.TransactionError
-@JsonTypeInfo(use = NAME, property = "status")
-sealed class PreparePayResponse(open val proposalId: String) {
- @JsonTypeName("payment-possible")
+@Serializable
+sealed class PreparePayResponse {
+ companion object : CustomClassDiscriminator {
+ override val discriminator: String = "status"
+ }
+
+ @Serializable
+ @SerialName("payment-possible")
data class PaymentPossibleResponse(
- override val proposalId: String,
+ val proposalId: String,
val amountRaw: Amount,
val amountEffective: Amount,
- val contractTerms: ContractTerms
- ) : PreparePayResponse(proposalId) {
+ val contractTerms: ContractTerms,
+ ) : PreparePayResponse() {
fun toPayStatusPrepared() = PayStatus.Prepared(
contractTerms = contractTerms,
proposalId = proposalId,
amountRaw = amountRaw,
- amountEffective = amountEffective
+ amountEffective = amountEffective,
)
}
- @JsonTypeName("insufficient-balance")
+ @Serializable
+ @SerialName("insufficient-balance")
data class InsufficientBalanceResponse(
- override val proposalId: String,
+ val proposalId: String,
val amountRaw: Amount,
- val contractTerms: ContractTerms
- ) : PreparePayResponse(proposalId)
+ val contractTerms: ContractTerms,
+ ) : PreparePayResponse()
- @JsonTypeName("already-confirmed")
+ @Serializable
+ @SerialName("already-confirmed")
data class AlreadyConfirmedResponse(
- override val proposalId: String,
+ val proposalId: String,
/**
* Did the payment succeed?
*/
val paid: Boolean,
val amountRaw: Amount,
val amountEffective: Amount,
-
- /**
- * Redirect URL for the fulfillment page, only given if paid==true.
- */
- val nextUrl: String?
- ) : PreparePayResponse(proposalId)
+ val contractTerms: ContractTerms,
+ ) : PreparePayResponse()
}
@Serializable
sealed class ConfirmPayResult {
@Serializable
@SerialName("done")
- data class Done(val nextUrl: String) : ConfirmPayResult()
+ data class Done(val contractTerms: ContractTerms) : ConfirmPayResult()
@Serializable
@SerialName("pending")
diff --git
a/wallet/src/main/java/net/taler/wallet/payment/PromptPaymentFragment.kt
b/wallet/src/main/java/net/taler/wallet/payment/PromptPaymentFragment.kt
index 3d00900..99a6ec8 100644
--- a/wallet/src/main/java/net/taler/wallet/payment/PromptPaymentFragment.kt
+++ b/wallet/src/main/java/net/taler/wallet/payment/PromptPaymentFragment.kt
@@ -58,7 +58,7 @@ class PromptPaymentFragment : Fragment(),
ProductImageClickListener {
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
- paymentManager.payStatus.observe(viewLifecycleOwner,
this::onPaymentStatusChanged)
+ paymentManager.payStatus.observe(viewLifecycleOwner,
::onPaymentStatusChanged)
paymentManager.detailsShown.observe(viewLifecycleOwner, Observer {
shown ->
beginDelayedTransition(view as ViewGroup)
val res = if (shown) R.string.payment_hide_details else
R.string.payment_show_details
@@ -91,7 +91,7 @@ class PromptPaymentFragment : Fragment(),
ProductImageClickListener {
}
}
- private fun onPaymentStatusChanged(payStatus: PayStatus) {
+ private fun onPaymentStatusChanged(payStatus: PayStatus?) {
when (payStatus) {
is PayStatus.Prepared -> {
showLoading(false)
diff --git
a/wallet/src/main/java/net/taler/wallet/transactions/TransactionAdapter.kt
b/wallet/src/main/java/net/taler/wallet/transactions/TransactionAdapter.kt
index f494b05..9dc2d23 100644
--- a/wallet/src/main/java/net/taler/wallet/transactions/TransactionAdapter.kt
+++ b/wallet/src/main/java/net/taler/wallet/transactions/TransactionAdapter.kt
@@ -104,7 +104,7 @@ internal class TransactionAdapter(
private fun bindExtraInfo(transaction: Transaction) {
if (transaction.error != null) {
extraInfoView.text =
- context.getString(R.string.payment_error,
transaction.error.text)
+ context.getString(R.string.payment_error,
transaction.error!!.text)
extraInfoView.setTextColor(red)
extraInfoView.visibility = VISIBLE
} else if (transaction is TransactionWithdrawal &&
!transaction.confirmed) {
diff --git
a/wallet/src/main/java/net/taler/wallet/transactions/TransactionDetailFragment.kt
b/wallet/src/main/java/net/taler/wallet/transactions/TransactionDetailFragment.kt
index f5a4fc9..1103207 100644
---
a/wallet/src/main/java/net/taler/wallet/transactions/TransactionDetailFragment.kt
+++
b/wallet/src/main/java/net/taler/wallet/transactions/TransactionDetailFragment.kt
@@ -145,7 +145,7 @@ class TransactionDetailFragment : Fragment() {
orderAmountView.text = raw.toString()
feeView.text = getString(R.string.amount_negative, fee.toString())
orderSummaryView.text = info.summary
- if (info.fulfillmentUrl.startsWith("http")) {
+ if (info.fulfillmentUrl?.startsWith("http") == true) {
val i = Intent().apply {
data = Uri.parse(info.fulfillmentUrl)
}
diff --git
a/wallet/src/main/java/net/taler/wallet/transactions/TransactionManager.kt
b/wallet/src/main/java/net/taler/wallet/transactions/TransactionManager.kt
index e9b1b71..6b5a79b 100644
--- a/wallet/src/main/java/net/taler/wallet/transactions/TransactionManager.kt
+++ b/wallet/src/main/java/net/taler/wallet/transactions/TransactionManager.kt
@@ -20,11 +20,11 @@ import androidx.annotation.UiThread
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.switchMap
-import com.fasterxml.jackson.databind.ObjectMapper
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import net.taler.wallet.backend.WalletBackendApi
import java.util.HashMap
+import java.util.LinkedList
sealed class TransactionsResult {
class Error(val msg: String) : TransactionsResult()
@@ -33,8 +33,7 @@ sealed class TransactionsResult {
class TransactionManager(
private val api: WalletBackendApi,
- private val scope: CoroutineScope,
- private val mapper: ObjectMapper
+ private val scope: CoroutineScope
) {
private val mProgress = MutableLiveData<Boolean>()
@@ -64,14 +63,14 @@ class TransactionManager(
}
if (liveData.value == null) mProgress.value = true
- api.request<Transactions>("getTransactions", mapper) {
+ api.request("getTransactions", Transactions.serializer()) {
if (searchQuery != null) put("search", searchQuery)
put("currency", currency)
}.onError {
liveData.postValue(TransactionsResult.Error(it.userFacingMsg))
mProgress.postValue(false)
}.onSuccess { result ->
- val transactions = result.transactions
+ val transactions = LinkedList(result.transactions)
// TODO remove when fixed in wallet-core
val comparator = compareBy<Transaction>(
{ it.pending },
diff --git a/wallet/src/main/java/net/taler/wallet/transactions/Transactions.kt
b/wallet/src/main/java/net/taler/wallet/transactions/Transactions.kt
index 1ed6788..3210093 100644
--- a/wallet/src/main/java/net/taler/wallet/transactions/Transactions.kt
+++ b/wallet/src/main/java/net/taler/wallet/transactions/Transactions.kt
@@ -20,42 +20,30 @@ import android.content.Context
import androidx.annotation.DrawableRes
import androidx.annotation.LayoutRes
import androidx.annotation.StringRes
-import com.fasterxml.jackson.annotation.JsonProperty
-import com.fasterxml.jackson.annotation.JsonSubTypes
-import com.fasterxml.jackson.annotation.JsonSubTypes.Type
-import com.fasterxml.jackson.annotation.JsonTypeInfo
-import com.fasterxml.jackson.annotation.JsonTypeInfo.As.PROPERTY
-import com.fasterxml.jackson.annotation.JsonTypeInfo.Id.NAME
-import com.fasterxml.jackson.annotation.JsonTypeName
+import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
-import net.taler.lib.common.Amount
+import kotlinx.serialization.Transient
import net.taler.common.ContractMerchant
import net.taler.common.ContractProduct
+import net.taler.lib.common.Amount
import net.taler.lib.common.Timestamp
import net.taler.wallet.R
import net.taler.wallet.cleanExchange
import net.taler.wallet.transactions.WithdrawalDetails.ManualTransfer
import net.taler.wallet.transactions.WithdrawalDetails.TalerBankIntegrationApi
-import java.util.LinkedList
-data class Transactions(val transactions: LinkedList<Transaction>)
+@Serializable
+data class Transactions(val transactions: List<Transaction>)
+
+@Serializable
+sealed class Transaction {
+ abstract val transactionId: String
+ abstract val timestamp: Timestamp
+ abstract val pending: Boolean
+ abstract val error: TransactionError?
+ abstract val amountRaw: Amount
+ abstract val amountEffective: Amount
-@JsonTypeInfo(use = NAME, include = PROPERTY, property = "type")
-@JsonSubTypes(
- Type(value = TransactionWithdrawal::class, name = "withdrawal"),
- Type(value = TransactionPayment::class, name = "payment"),
- Type(value = TransactionRefund::class, name = "refund"),
- Type(value = TransactionTip::class, name = "tip"),
- Type(value = TransactionRefresh::class, name = "refresh")
-)
-abstract class Transaction(
- val transactionId: String,
- val timestamp: Timestamp,
- val pending: Boolean,
- val error: TransactionError? = null,
- val amountRaw: Amount,
- val amountEffective: Amount
-) {
@get:DrawableRes
abstract val icon: Int
@@ -79,24 +67,27 @@ sealed class AmountType {
@Serializable
data class TransactionError(
private val ec: Int,
- private val hint: String?
+ private val hint: String? = null,
) {
val text get() = if (hint == null) "$ec" else "$ec $hint"
}
-@JsonTypeName("withdrawal")
+@Serializable
+@SerialName("withdrawal")
class TransactionWithdrawal(
- transactionId: String,
- timestamp: Timestamp,
- pending: Boolean,
+ override val transactionId: String,
+ override val timestamp: Timestamp,
+ override val pending: Boolean,
val exchangeBaseUrl: String,
val withdrawalDetails: WithdrawalDetails,
- error: TransactionError? = null,
- amountRaw: Amount,
- amountEffective: Amount
-) : Transaction(transactionId, timestamp, pending, error, amountRaw,
amountEffective) {
+ override val error: TransactionError? = null,
+ override val amountRaw: Amount,
+ override val amountEffective: Amount
+) : Transaction() {
override val icon = R.drawable.transaction_withdrawal
override val detailPageLayout = R.layout.fragment_transaction_withdrawal
+
+ @Transient
override val amountType = AmountType.Positive
override fun getTitle(context: Context) = cleanExchange(exchangeBaseUrl)
override val generalTitleRes = R.string.withdraw_title
@@ -107,13 +98,10 @@ class TransactionWithdrawal(
)
}
-@JsonTypeInfo(use = NAME, include = PROPERTY, property = "type")
-@JsonSubTypes(
- Type(value = TalerBankIntegrationApi::class, name =
"taler-bank-integration-api"),
- Type(value = ManualTransfer::class, name = "manual-transfer")
-)
+@Serializable
sealed class WithdrawalDetails {
- @JsonTypeName("manual-transfer")
+ @Serializable
+ @SerialName("manual-transfer")
class ManualTransfer(
/**
* Payto URIs that the exchange supports.
@@ -123,7 +111,8 @@ sealed class WithdrawalDetails {
val exchangePaytoUris: List<String>
) : WithdrawalDetails()
- @JsonTypeName("taler-bank-integration-api")
+ @Serializable
+ @SerialName("taler-bank-integration-api")
class TalerBankIntegrationApi(
/**
* Set to true if the bank has confirmed the withdrawal, false if not.
@@ -136,71 +125,88 @@ sealed class WithdrawalDetails {
/**
* If the withdrawal is unconfirmed, this can include a URL for
user-initiated confirmation.
*/
- val bankConfirmationUrl: String?
+ val bankConfirmationUrl: String? = null,
) : WithdrawalDetails()
}
-@JsonTypeName("payment")
+@Serializable
+@SerialName("payment")
class TransactionPayment(
- transactionId: String,
- timestamp: Timestamp,
- pending: Boolean,
+ override val transactionId: String,
+ override val timestamp: Timestamp,
+ override val pending: Boolean,
val info: TransactionInfo,
val status: PaymentStatus,
- error: TransactionError? = null,
- amountRaw: Amount,
- amountEffective: Amount
-) : Transaction(transactionId, timestamp, pending, error, amountRaw,
amountEffective) {
+ override val error: TransactionError? = null,
+ override val amountRaw: Amount,
+ override val amountEffective: Amount
+) : Transaction() {
override val icon = R.drawable.ic_cash_usd_outline
override val detailPageLayout = R.layout.fragment_transaction_payment
+
+ @Transient
override val amountType = AmountType.Negative
override fun getTitle(context: Context) = info.merchant.name
override val generalTitleRes = R.string.payment_title
}
+@Serializable
class TransactionInfo(
val orderId: String,
val merchant: ContractMerchant,
val summary: String,
- @get:JsonProperty("summary_i18n")
- val summaryI18n: Map<String, String>?,
+ @SerialName("summary_i18n")
+ val summaryI18n: Map<String, String>? = null,
val products: List<ContractProduct>,
- val fulfillmentUrl: String
+ val fulfillmentUrl: String? = null,
+ /**
+ * Message shown to the user after the payment is complete.
+ * TODO actually show this
+ */
+ val fulfillmentMessage: String? = null,
+ /**
+ * Map from IETF BCP 47 language tags to localized fulfillment messages
+ */
+ val fulfillmentMessage_i18n: Map<String, String>? = null,
)
+@Serializable
enum class PaymentStatus {
- @JsonProperty("aborted")
+ @SerialName("aborted")
Aborted,
- @JsonProperty("failed")
+ @SerialName("failed")
Failed,
- @JsonProperty("paid")
+ @SerialName("paid")
Paid,
- @JsonProperty("accepted")
+ @SerialName("accepted")
Accepted
}
-@JsonTypeName("refund")
+@Serializable
+@SerialName("refund")
class TransactionRefund(
- transactionId: String,
- timestamp: Timestamp,
- pending: Boolean,
+ override val transactionId: String,
+ override val timestamp: Timestamp,
+ override val pending: Boolean,
val refundedTransactionId: String,
val info: TransactionInfo,
/**
* Part of the refund that couldn't be applied because the refund
permissions were expired
*/
val amountInvalid: Amount? = null,
- error: TransactionError? = null,
- @JsonProperty("amountEffective") // TODO remove when fixed in wallet-core
- amountRaw: Amount,
- @JsonProperty("amountRaw") // TODO remove when fixed in wallet-core
- amountEffective: Amount
-) : Transaction(transactionId, timestamp, pending, error, amountRaw,
amountEffective) {
+ override val error: TransactionError? = null,
+ @SerialName("amountEffective") // TODO remove when fixed in wallet-core
+ override val amountRaw: Amount,
+ @SerialName("amountRaw") // TODO remove when fixed in wallet-core
+ override val amountEffective: Amount
+) : Transaction() {
override val icon = R.drawable.transaction_refund
override val detailPageLayout = R.layout.fragment_transaction_payment
+
+ @Transient
override val amountType = AmountType.Positive
override fun getTitle(context: Context): String {
return context.getString(R.string.transaction_refund_from,
info.merchant.name)
@@ -209,20 +215,23 @@ class TransactionRefund(
override val generalTitleRes = R.string.refund_title
}
-@JsonTypeName("tip")
+@Serializable
+@SerialName("tip")
class TransactionTip(
- transactionId: String,
- timestamp: Timestamp,
- pending: Boolean,
+ override val transactionId: String,
+ override val timestamp: Timestamp,
+ override val pending: Boolean,
// TODO status: TipStatus,
val exchangeBaseUrl: String,
val merchant: ContractMerchant,
- error: TransactionError? = null,
- amountRaw: Amount,
- amountEffective: Amount
-) : Transaction(transactionId, timestamp, pending, error, amountRaw,
amountEffective) {
+ override val error: TransactionError? = null,
+ override val amountRaw: Amount,
+ override val amountEffective: Amount
+) : Transaction() {
override val icon = R.drawable.transaction_tip_accepted // TODO different
when declined
override val detailPageLayout = R.layout.fragment_transaction_payment
+
+ @Transient
override val amountType = AmountType.Positive
override fun getTitle(context: Context): String {
return context.getString(R.string.transaction_tip_from, merchant.name)
@@ -231,18 +240,21 @@ class TransactionTip(
override val generalTitleRes = R.string.tip_title
}
-@JsonTypeName("refresh")
+@Serializable
+@SerialName("refresh")
class TransactionRefresh(
- transactionId: String,
- timestamp: Timestamp,
- pending: Boolean,
+ override val transactionId: String,
+ override val timestamp: Timestamp,
+ override val pending: Boolean,
val exchangeBaseUrl: String,
- error: TransactionError? = null,
- amountRaw: Amount,
- amountEffective: Amount
-) : Transaction(transactionId, timestamp, pending, error, amountRaw,
amountEffective) {
+ override val error: TransactionError? = null,
+ override val amountRaw: Amount,
+ override val amountEffective: Amount
+) : Transaction() {
override val icon = R.drawable.transaction_refresh
override val detailPageLayout = R.layout.fragment_transaction_withdrawal
+
+ @Transient
override val amountType = AmountType.Negative
override fun getTitle(context: Context): String {
return context.getString(R.string.transaction_refresh)
diff --git
a/wallet/src/test/java/net/taler/wallet/backend/WalletResponseTest.kt
b/wallet/src/test/java/net/taler/wallet/backend/WalletResponseTest.kt
index d8f28c5..4872149 100644
--- a/wallet/src/test/java/net/taler/wallet/backend/WalletResponseTest.kt
+++ b/wallet/src/test/java/net/taler/wallet/backend/WalletResponseTest.kt
@@ -16,36 +16,21 @@
package net.taler.wallet.backend
-import com.fasterxml.jackson.databind.DeserializationFeature
-import com.fasterxml.jackson.databind.ObjectMapper
-import com.fasterxml.jackson.module.kotlin.KotlinModule
-import com.fasterxml.jackson.module.kotlin.readValue
import kotlinx.serialization.json.Json
-import kotlinx.serialization.json.JsonConfiguration
-import net.taler.lib.common.Amount
-import net.taler.lib.common.AmountMixin
-import net.taler.lib.common.Timestamp
-import net.taler.lib.common.TimestampMixin
import net.taler.wallet.balances.BalanceResponse
import org.junit.Assert.assertEquals
import org.junit.Test
class WalletResponseTest {
- private val json = Json(
- JsonConfiguration.Stable.copy(ignoreUnknownKeys = true)
- )
-
- private val mapper = ObjectMapper()
- .registerModule(KotlinModule())
- .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
- .addMixIn(Amount::class.java, AmountMixin::class.java)
- .addMixIn(Timestamp::class.java, TimestampMixin::class.java)
+ private val json = Json {
+ ignoreUnknownKeys = true
+ }
@Test
fun testBalanceResponse() {
val serializer =
WalletResponse.Success.serializer(BalanceResponse.serializer())
- val response = json.parse(
+ val response = json.decodeFromString(
serializer, """
{
"type": "response",
@@ -82,9 +67,7 @@ class WalletResponseTest {
"message":"unexpected exception: Error: BUG: invariant
violation (purchase status)"
}
""".trimIndent()
- val info = json.parse(WalletErrorInfo.serializer(), infoJson)
- val infoJackson: WalletErrorInfo = mapper.readValue(infoJson)
+ val info = json.decodeFromString(WalletErrorInfo.serializer(),
infoJson)
println(info.userFacingMsg)
- assertEquals(info.userFacingMsg, infoJackson.userFacingMsg)
}
}
--
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.
- [taler-taler-android] branch master updated (d3955c2 -> 0e28f81),
gnunet <=