Improved exceptions.
This commit is contained in:
parent
4209cb83c5
commit
358b8b4582
4 changed files with 40 additions and 22 deletions
|
@ -2,6 +2,7 @@
|
||||||
<SmellBaseline>
|
<SmellBaseline>
|
||||||
<ManuallySuppressedIssues/>
|
<ManuallySuppressedIssues/>
|
||||||
<CurrentIssues>
|
<CurrentIssues>
|
||||||
<ID>ThrowsCount:CryptoPrice.kt$CryptoPrice.Companion$ @JvmStatic @JvmOverloads @Throws(CryptoException::class) fun apiCall(paths: List<String>, params: Map<String, String> = emptyMap()): String</ID>
|
<ID>ThrowsCount:CryptoPrice.kt$CryptoPrice.Companion$ @JvmStatic @JvmOverloads @Throws(CryptoException::class, IOException::class) fun apiCall(paths: List<String>, params: Map<String, String> = emptyMap()): String</ID>
|
||||||
|
<ID>ThrowsCount:CryptoPrice.kt$CryptoPrice.Companion$@JvmStatic @Throws(CryptoException::class) fun String.toPrice(): CryptoPrice</ID>
|
||||||
</CurrentIssues>
|
</CurrentIssues>
|
||||||
</SmellBaseline>
|
</SmellBaseline>
|
||||||
|
|
|
@ -3,6 +3,7 @@ package com.example;
|
||||||
import net.thauvin.erik.crypto.CryptoPrice;
|
import net.thauvin.erik.crypto.CryptoPrice;
|
||||||
import net.thauvin.erik.crypto.CryptoException;
|
import net.thauvin.erik.crypto.CryptoException;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -35,7 +36,7 @@ public class CryptoPriceSample {
|
||||||
final CryptoPrice gbpPrice = CryptoPrice.marketPrice("ETH", "GBP");
|
final CryptoPrice gbpPrice = CryptoPrice.marketPrice("ETH", "GBP");
|
||||||
System.out.println("The current Ethereum price is " + gbpPrice.getAmount() + " in Pound sterling");
|
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());
|
System.err.println(e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,9 @@ package net.thauvin.erik.crypto
|
||||||
import okhttp3.HttpUrl.Companion.toHttpUrl
|
import okhttp3.HttpUrl.Companion.toHttpUrl
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
import okhttp3.Request
|
import okhttp3.Request
|
||||||
|
import org.json.JSONException
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
|
import java.io.IOException
|
||||||
import java.time.LocalDate
|
import java.time.LocalDate
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -49,6 +51,7 @@ open class CryptoPrice(val base: String, val currency: String, val amount: Doubl
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
@Throws(CryptoException::class)
|
@Throws(CryptoException::class)
|
||||||
fun String.toPrice(): CryptoPrice {
|
fun String.toPrice(): CryptoPrice {
|
||||||
|
try {
|
||||||
val json = JSONObject(this)
|
val json = JSONObject(this)
|
||||||
if (json.has("data")) {
|
if (json.has("data")) {
|
||||||
with(json.getJSONObject("data")) {
|
with(json.getJSONObject("data")) {
|
||||||
|
@ -57,7 +60,12 @@ open class CryptoPrice(val base: String, val currency: String, val amount: Doubl
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
throw CryptoException(message = "Missing JSON data.")
|
throw CryptoException(message = "Missing price 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
|
@JvmStatic
|
||||||
@JvmOverloads
|
@JvmOverloads
|
||||||
@Throws(CryptoException::class)
|
@Throws(CryptoException::class, IOException::class)
|
||||||
fun apiCall(paths: List<String>, params: Map<String, String> = emptyMap()): String {
|
fun apiCall(paths: List<String>, params: Map<String, String> = emptyMap()): String {
|
||||||
val client = OkHttpClient()
|
val client = OkHttpClient()
|
||||||
val url = COINBASE_API_URL.toHttpUrl().newBuilder()
|
val url = COINBASE_API_URL.toHttpUrl().newBuilder()
|
||||||
|
|
||||||
paths.forEach {
|
paths.forEach {
|
||||||
url.addPathSegment(it)
|
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 response = client.newCall(request).execute()
|
||||||
val body = response.body?.string()
|
val body = response.body?.string()
|
||||||
if (body != null) {
|
if (body != null) {
|
||||||
|
try {
|
||||||
val json = JSONObject(body)
|
val json = JSONObject(body)
|
||||||
if (!response.isSuccessful) {
|
if (response.isSuccessful) {
|
||||||
if (json.has("errors")) {
|
return body
|
||||||
|
} else {
|
||||||
val data = json.getJSONArray("errors")
|
val data = json.getJSONArray("errors")
|
||||||
throw CryptoException(response.code, data.getJSONObject(0).getString("message"))
|
throw CryptoException(response.code, data.getJSONObject(0).getString("message"))
|
||||||
} else {
|
}
|
||||||
throw CryptoException(response.code, "Invalid API response.")
|
} catch (e: JSONException) {
|
||||||
|
throw CryptoException(response.code, "Could not parse data.", e)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return body
|
throw CryptoException(response.code, "Empty response.")
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw CryptoException(response.code, "Empty API 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
|
@JvmStatic
|
||||||
@JvmOverloads
|
@JvmOverloads
|
||||||
@Throws(CryptoException::class)
|
@Throws(CryptoException::class, IOException::class)
|
||||||
fun marketPrice(base: String, currency: String = "USD", date: LocalDate? = null): CryptoPrice {
|
fun marketPrice(base: String, currency: String = "USD", date: LocalDate? = null): CryptoPrice {
|
||||||
val params = if (date != null) mapOf("date" to "$date") else emptyMap()
|
val params = if (date != null) mapOf("date" to "$date") else emptyMap()
|
||||||
val body = apiCall(listOf("prices", "$base-$currency", "spot"), params)
|
val body = apiCall(listOf("prices", "$base-$currency", "spot"), params)
|
||||||
|
|
|
@ -74,9 +74,16 @@ class CryptoPriceTest {
|
||||||
@Throws(CryptoException::class)
|
@Throws(CryptoException::class)
|
||||||
fun testToPrice() {
|
fun testToPrice() {
|
||||||
val d = 57515.69
|
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.base, "BTC", "base is BTC")
|
||||||
assertEquals(price.currency, "USD", "currency is USD")
|
assertEquals(price.currency, "USD", "currency is USD")
|
||||||
assertEquals(price.amount, d, "amount is 57515.69")
|
assertEquals(price.amount, d, "amount is 57515.69")
|
||||||
|
|
||||||
|
assertFailsWith(
|
||||||
|
message = "double convertion did not fail",
|
||||||
|
exceptionClass = CryptoException::class,
|
||||||
|
block = { json.replace("5", "a").toPrice() }
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue