From 358b8b458215ae4c2cac0bc68bc12a6ee338be00 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Sun, 9 May 2021 17:54:48 -0700 Subject: [PATCH] Improved exceptions. --- baseline.xml | 3 +- .../java/com/example/CryptoPriceSample.java | 3 +- .../net/thauvin/erik/crypto/CryptoPrice.kt | 47 +++++++++++-------- .../thauvin/erik/crypto/CryptoPriceTest.kt | 9 +++- 4 files changed, 40 insertions(+), 22 deletions(-) diff --git a/baseline.xml b/baseline.xml index 7566107..c4d9ac8 100644 --- a/baseline.xml +++ b/baseline.xml @@ -2,6 +2,7 @@ - ThrowsCount:CryptoPrice.kt$CryptoPrice.Companion$ @JvmStatic @JvmOverloads @Throws(CryptoException::class) fun apiCall(paths: List<String>, params: Map<String, String> = emptyMap()): String + ThrowsCount:CryptoPrice.kt$CryptoPrice.Companion$ @JvmStatic @JvmOverloads @Throws(CryptoException::class, IOException::class) fun apiCall(paths: List<String>, params: Map<String, String> = emptyMap()): String + ThrowsCount:CryptoPrice.kt$CryptoPrice.Companion$@JvmStatic @Throws(CryptoException::class) fun String.toPrice(): CryptoPrice diff --git a/examples/src/main/java/com/example/CryptoPriceSample.java b/examples/src/main/java/com/example/CryptoPriceSample.java index 68b897b..9ff5423 100644 --- a/examples/src/main/java/com/example/CryptoPriceSample.java +++ b/examples/src/main/java/com/example/CryptoPriceSample.java @@ -3,6 +3,7 @@ package com.example; import net.thauvin.erik.crypto.CryptoPrice; import net.thauvin.erik.crypto.CryptoException; +import java.io.IOException; import java.util.Collections; import java.util.List; import java.util.Map; @@ -35,7 +36,7 @@ public class CryptoPriceSample { final CryptoPrice gbpPrice = CryptoPrice.marketPrice("ETH", "GBP"); System.out.println("The current Ethereum price is " + gbpPrice.getAmount() + " in Pound sterling"); - } catch (CryptoException e) { + } catch (CryptoException | IOException e) { System.err.println(e.getMessage()); } } diff --git a/src/main/kotlin/net/thauvin/erik/crypto/CryptoPrice.kt b/src/main/kotlin/net/thauvin/erik/crypto/CryptoPrice.kt index 20af110..332851d 100644 --- a/src/main/kotlin/net/thauvin/erik/crypto/CryptoPrice.kt +++ b/src/main/kotlin/net/thauvin/erik/crypto/CryptoPrice.kt @@ -35,7 +35,9 @@ package net.thauvin.erik.crypto import okhttp3.HttpUrl.Companion.toHttpUrl import okhttp3.OkHttpClient import okhttp3.Request +import org.json.JSONException import org.json.JSONObject +import java.io.IOException import java.time.LocalDate /** @@ -49,15 +51,21 @@ open class CryptoPrice(val base: String, val currency: String, val amount: Doubl @JvmStatic @Throws(CryptoException::class) fun String.toPrice(): CryptoPrice { - val json = JSONObject(this) - if (json.has("data")) { - with(json.getJSONObject("data")) { - return CryptoPrice( - getString("base"), getString("currency"), getString("amount").toDouble() - ) + try { + val json = JSONObject(this) + if (json.has("data")) { + with(json.getJSONObject("data")) { + return CryptoPrice( + getString("base"), getString("currency"), getString("amount").toDouble() + ) + } + } else { + throw CryptoException(message = "Missing price data.") } - } else { - throw CryptoException(message = "Missing JSON data.") + } catch (e: NumberFormatException) { + throw CryptoException(message = "Could not convert price data to number.", cause = e) + } catch (e: JSONException) { + throw CryptoException(message = "Could not parse price data.", cause = e) } } @@ -66,10 +74,11 @@ open class CryptoPrice(val base: String, val currency: String, val amount: Doubl */ @JvmStatic @JvmOverloads - @Throws(CryptoException::class) + @Throws(CryptoException::class, IOException::class) fun apiCall(paths: List, params: Map = emptyMap()): String { val client = OkHttpClient() val url = COINBASE_API_URL.toHttpUrl().newBuilder() + paths.forEach { url.addPathSegment(it) } @@ -81,19 +90,19 @@ open class CryptoPrice(val base: String, val currency: String, val amount: Doubl val response = client.newCall(request).execute() val body = response.body?.string() if (body != null) { - val json = JSONObject(body) - if (!response.isSuccessful) { - if (json.has("errors")) { + try { + val json = JSONObject(body) + if (response.isSuccessful) { + return body + } else { val data = json.getJSONArray("errors") throw CryptoException(response.code, data.getJSONObject(0).getString("message")) - } else { - throw CryptoException(response.code, "Invalid API response.") } - } else { - return body + } catch (e: JSONException) { + throw CryptoException(response.code, "Could not parse data.", e) } } else { - throw CryptoException(response.code, "Empty API response.") + throw CryptoException(response.code, "Empty response.") } } @@ -104,11 +113,11 @@ open class CryptoPrice(val base: String, val currency: String, val amount: Doubl } /** - * Retrieves the current market price. + * Retrieve the current market price. */ @JvmStatic @JvmOverloads - @Throws(CryptoException::class) + @Throws(CryptoException::class, IOException::class) fun marketPrice(base: String, currency: String = "USD", date: LocalDate? = null): CryptoPrice { val params = if (date != null) mapOf("date" to "$date") else emptyMap() val body = apiCall(listOf("prices", "$base-$currency", "spot"), params) diff --git a/src/test/kotlin/net/thauvin/erik/crypto/CryptoPriceTest.kt b/src/test/kotlin/net/thauvin/erik/crypto/CryptoPriceTest.kt index b8f3a61..4df7fd0 100644 --- a/src/test/kotlin/net/thauvin/erik/crypto/CryptoPriceTest.kt +++ b/src/test/kotlin/net/thauvin/erik/crypto/CryptoPriceTest.kt @@ -74,9 +74,16 @@ class CryptoPriceTest { @Throws(CryptoException::class) fun testToPrice() { val d = 57515.69 - val price = "{\"data\":{\"base\":\"BTC\",\"currency\":\"USD\",\"amount\":\"$d\"}}".toPrice() + val json = "{\"data\":{\"base\":\"BTC\",\"currency\":\"USD\",\"amount\":\"$d\"}}" + val price = json.toPrice() assertEquals(price.base, "BTC", "base is BTC") assertEquals(price.currency, "USD", "currency is USD") assertEquals(price.amount, d, "amount is 57515.69") + + assertFailsWith( + message = "double convertion did not fail", + exceptionClass = CryptoException::class, + block = { json.replace("5", "a").toPrice() } + ) } }