diff --git a/CHANGELOG.md b/CHANGELOG.md index db7f24d9cb..0578f57b60 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ # Changelog +## 1.2.1 +* Fix gson serialization error of the Refunds object. [#626](https://github.com/stellar/java-stellar-anchor-sdk/issues/626) + ## 1.2.0 * Add Stellar observer retries with exponential back-off timer [#607](https://github.com/stellar/java-stellar-anchor-sdk/pull/607) * Add health check endpoint to the Stellar observer [#602](https://github.com/stellar/java-stellar-anchor-sdk/pull/602) diff --git a/build.gradle.kts b/build.gradle.kts index b8b8e926a2..82f10f304e 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -118,7 +118,7 @@ subprojects { allprojects { group = "org.stellar.anchor-sdk" - version = "1.2.0" + version = "1.2.1" tasks.jar { manifest { diff --git a/core/src/test/kotlin/org/stellar/anchor/sep10/Sep10ServiceTest.kt b/core/src/test/kotlin/org/stellar/anchor/sep10/Sep10ServiceTest.kt index 18c69462b1..ad1f560005 100644 --- a/core/src/test/kotlin/org/stellar/anchor/sep10/Sep10ServiceTest.kt +++ b/core/src/test/kotlin/org/stellar/anchor/sep10/Sep10ServiceTest.kt @@ -5,8 +5,12 @@ import io.mockk.* import io.mockk.impl.annotations.MockK import java.io.IOException import java.security.SecureRandom +import java.security.cert.X509Certificate import java.util.concurrent.TimeUnit import java.util.stream.Stream +import javax.net.ssl.SSLContext +import javax.net.ssl.TrustManager +import javax.net.ssl.X509TrustManager import okhttp3.OkHttpClient import okhttp3.Request import okhttp3.mockwebserver.MockResponse @@ -80,12 +84,8 @@ internal class Sep10ServiceTest { private lateinit var sep10Service: Sep10Service private val clientKeyPair = KeyPair.random() private val clientDomainKeyPair = KeyPair.random() - private val httpClient: OkHttpClient = - OkHttpClient.Builder() - .connectTimeout(10, TimeUnit.MINUTES) - .readTimeout(10, TimeUnit.MINUTES) - .writeTimeout(10, TimeUnit.MINUTES) - .build() + + private lateinit var httpClient: OkHttpClient @BeforeEach fun setUp() { @@ -108,6 +108,8 @@ internal class Sep10ServiceTest { this.jwtService = spyk(JwtService(appConfig)) this.sep10Service = Sep10Service(appConfig, sep10Config, horizon, jwtService) + + this.httpClient = `create httpClient that trust all certificates`() } @AfterEach @@ -116,6 +118,30 @@ internal class Sep10ServiceTest { unmockkAll() } + fun `create httpClient that trust all certificates`(): OkHttpClient { + val trustAllCerts = + arrayOf( + object : X509TrustManager { + override fun checkClientTrusted(chain: Array?, authType: String?) {} + + override fun checkServerTrusted(chain: Array?, authType: String?) {} + + override fun getAcceptedIssuers() = arrayOf() + } + ) + + // Install the all-trusting trust manager + val sslContext = SSLContext.getInstance("SSL") + sslContext.init(null, trustAllCerts, SecureRandom()) + return OkHttpClient.Builder() + .connectTimeout(10, TimeUnit.MINUTES) + .readTimeout(10, TimeUnit.MINUTES) + .writeTimeout(10, TimeUnit.MINUTES) + .sslSocketFactory(sslContext.socketFactory, trustAllCerts[0] as X509TrustManager) + .hostnameVerifier { _, _ -> true } + .build() + } + @Test fun `test the challenge with existent account, multisig, and client domain`() { // 1 ------ Create Test Transaction diff --git a/core/src/test/kotlin/org/stellar/anchor/sep31/Sep31TransactionTest.kt b/core/src/test/kotlin/org/stellar/anchor/sep31/Sep31TransactionTest.kt index c157ce416b..b88fd2639a 100644 --- a/core/src/test/kotlin/org/stellar/anchor/sep31/Sep31TransactionTest.kt +++ b/core/src/test/kotlin/org/stellar/anchor/sep31/Sep31TransactionTest.kt @@ -136,7 +136,7 @@ class Sep31TransactionTest { } @Test - fun test_toPlatformApiGetTransactionResponse() { + fun `test PlatformApiGetTransactionResponse correctness`() { val wantRefunds: Refund = Refund.builder() .amountRefunded(Amount("90.0000", fiatUSD)) @@ -196,7 +196,7 @@ class Sep31TransactionTest { } @Test - fun test_toSep31GetTransactionResponse() { + fun `test Sep31GetTransactionResponse correctness`() { val refunds = Sep31GetTransactionResponse.Refunds.builder() .amountRefunded("90.0000") diff --git a/platform/src/main/java/org/stellar/anchor/platform/data/JdbcSep31RefundPayment.java b/platform/src/main/java/org/stellar/anchor/platform/data/JdbcSep31RefundPayment.java index 3adf81dbee..18d7f4b57f 100644 --- a/platform/src/main/java/org/stellar/anchor/platform/data/JdbcSep31RefundPayment.java +++ b/platform/src/main/java/org/stellar/anchor/platform/data/JdbcSep31RefundPayment.java @@ -3,11 +3,9 @@ import lombok.Data; import org.stellar.anchor.sep31.RefundPayment; -public class JdbcSep31RefundPayment { - @Data - public static class JdbcRefundPayment implements RefundPayment { - String Id; - String amount; - String fee; - } +@Data +public class JdbcSep31RefundPayment implements RefundPayment { + String id; + String amount; + String fee; } diff --git a/platform/src/main/java/org/stellar/anchor/platform/data/JdbcSep31Refunds.java b/platform/src/main/java/org/stellar/anchor/platform/data/JdbcSep31Refunds.java index 08ddbf58d5..5a8f372882 100644 --- a/platform/src/main/java/org/stellar/anchor/platform/data/JdbcSep31Refunds.java +++ b/platform/src/main/java/org/stellar/anchor/platform/data/JdbcSep31Refunds.java @@ -1,6 +1,7 @@ package org.stellar.anchor.platform.data; import com.google.gson.annotations.SerializedName; +import java.util.ArrayList; import java.util.List; import lombok.Data; import org.stellar.anchor.sep31.RefundPayment; @@ -15,5 +16,28 @@ public class JdbcSep31Refunds implements Refunds { String amountFee; @SerializedName("payments") - List refundPayments; + List refundPayments; + + @Override + public List getRefundPayments() { + if (refundPayments == null) return null; + // getPayments() is made for Gson serialization. + List payments = new ArrayList<>(refundPayments.size()); + for (JdbcSep31RefundPayment refundPayment : refundPayments) { + payments.add(refundPayment); + } + return payments; + } + + @Override + public void setRefundPayments(List refundPayments) { + this.refundPayments = new ArrayList<>(refundPayments.size()); + for (RefundPayment rp : refundPayments) { + if (rp instanceof JdbcSep31RefundPayment) + this.refundPayments.add((JdbcSep31RefundPayment) rp); + else + throw new ClassCastException( + String.format("Error casting %s to JdbcSep31RefundPayment", rp.getClass())); + } + } } diff --git a/platform/src/main/java/org/stellar/anchor/platform/data/JdbcSep31Transaction.java b/platform/src/main/java/org/stellar/anchor/platform/data/JdbcSep31Transaction.java index 45b4163177..dfb14ec191 100644 --- a/platform/src/main/java/org/stellar/anchor/platform/data/JdbcSep31Transaction.java +++ b/platform/src/main/java/org/stellar/anchor/platform/data/JdbcSep31Transaction.java @@ -143,7 +143,7 @@ public String getRefundsJson() { public void setRefundsJson(String refundsJson) { if (refundsJson != null) { - this.refunds = gson.fromJson(refundsJson, Refunds.class); + this.refunds = gson.fromJson(refundsJson, JdbcSep31Refunds.class); } } diff --git a/platform/src/main/java/org/stellar/anchor/platform/data/JdbcSep31TransactionStore.java b/platform/src/main/java/org/stellar/anchor/platform/data/JdbcSep31TransactionStore.java index 72d97b932b..a483266ebe 100644 --- a/platform/src/main/java/org/stellar/anchor/platform/data/JdbcSep31TransactionStore.java +++ b/platform/src/main/java/org/stellar/anchor/platform/data/JdbcSep31TransactionStore.java @@ -31,7 +31,7 @@ public Refunds newRefunds() { @Override public RefundPayment newRefundPayment() { - return new JdbcSep31RefundPayment.JdbcRefundPayment(); + return new JdbcSep31RefundPayment(); } @Override diff --git a/platform/src/test/kotlin/org/stellar/anchor/platform/data/JdbcSep31TransactionTest.kt b/platform/src/test/kotlin/org/stellar/anchor/platform/data/JdbcSep31TransactionTest.kt new file mode 100644 index 0000000000..1e64bfada7 --- /dev/null +++ b/platform/src/test/kotlin/org/stellar/anchor/platform/data/JdbcSep31TransactionTest.kt @@ -0,0 +1,61 @@ +package org.stellar.anchor.platform.data + +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Assertions.assertNull +import org.junit.jupiter.api.Test +import org.skyscreamer.jsonassert.JSONAssert + +class JdbcSep31TransactionTest { + private val refundsJsonNoRefundPayment = + """ + { + "amount_refunded": "10", + "amount_fee": "5", + "refundPayments": null + } + """.trimIndent() + + private val refundsJsonWithRefundPayment = + """ + { + "amount_refunded": "10", + "amount_fee": "5", + "payments": [ + { + "id": "1", + "amount": "5", + "fee": "1" + }, + { + "id": "2", + "amount": "5", + "fee": "4" + } + ] + } + """.trimIndent() + + @Test + fun `test JdbcSep31Transaction refunds Json conversion`() { + val txn = JdbcSep31Transaction() + txn.refundsJson = refundsJsonNoRefundPayment + // strict is set to false because refundPayments is omitted in txn.refundsJson when it is set to + // null. + JSONAssert.assertEquals(txn.refundsJson, refundsJsonNoRefundPayment, false) + assertEquals("10", txn.refunds.amountRefunded) + assertEquals("5", txn.refunds.amountFee) + assertNull(txn.refunds.refundPayments) + + txn.refundsJson = refundsJsonWithRefundPayment + JSONAssert.assertEquals(txn.refundsJson, refundsJsonWithRefundPayment, true) + assertEquals("10", txn.refunds.amountRefunded) + assertEquals("5", txn.refunds.amountFee) + assertEquals(2, txn.refunds.refundPayments.size) + assertEquals("1", txn.refunds.refundPayments[0].id) + assertEquals("5", txn.refunds.refundPayments[0].amount) + assertEquals("1", txn.refunds.refundPayments[0].fee) + assertEquals("2", txn.refunds.refundPayments[1].id) + assertEquals("5", txn.refunds.refundPayments[1].amount) + assertEquals("4", txn.refunds.refundPayments[1].fee) + } +} diff --git a/platform/src/test/kotlin/org/stellar/anchor/platform/service/TransactionServiceTest.kt b/platform/src/test/kotlin/org/stellar/anchor/platform/service/TransactionServiceTest.kt index 437d4ee1af..ce716dfed0 100644 --- a/platform/src/test/kotlin/org/stellar/anchor/platform/service/TransactionServiceTest.kt +++ b/platform/src/test/kotlin/org/stellar/anchor/platform/service/TransactionServiceTest.kt @@ -3,8 +3,11 @@ package org.stellar.anchor.platform.service import io.mockk.* import io.mockk.impl.annotations.MockK import java.time.Instant -import org.junit.jupiter.api.* +import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.Assertions.* +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertThrows import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.EnumSource import org.stellar.anchor.api.exception.AnchorException @@ -19,7 +22,7 @@ import org.stellar.anchor.api.shared.RefundPayment import org.stellar.anchor.asset.AssetService import org.stellar.anchor.asset.ResourceJsonAssetService import org.stellar.anchor.event.models.TransactionEvent -import org.stellar.anchor.platform.data.JdbcSep31RefundPayment.JdbcRefundPayment +import org.stellar.anchor.platform.data.JdbcSep31RefundPayment import org.stellar.anchor.platform.data.JdbcSep31Refunds import org.stellar.anchor.platform.data.JdbcSep31Transaction import org.stellar.anchor.sep31.* @@ -78,7 +81,7 @@ class TransactionServiceTest { // Mock the store every { sep31TransactionStore.newTransaction() } returns JdbcSep31Transaction() every { sep31TransactionStore.newRefunds() } returns JdbcSep31Refunds() - every { sep31TransactionStore.newRefundPayment() } answers { JdbcRefundPayment() } + every { sep31TransactionStore.newRefundPayment() } answers { JdbcSep31RefundPayment() } // mock time val mockStartedAt = Instant.now().minusSeconds(180)