From 26d51a2d7bae1a6d924ccd413d592033ee50b1bf Mon Sep 17 00:00:00 2001 From: Ian Clarke Date: Sun, 8 Jul 2018 19:03:46 -0500 Subject: [PATCH] bump version --- build.gradle | 2 +- .../kotlin/io/kweb/shoebox/OrderedViewSet.kt | 4 +- .../io/kweb/shoebox/stores/DirectoryStore.kt | 8 ++-- src/main/kotlin/io/kweb/shoebox/utils.kt | 46 +++++++++++++++++-- 4 files changed, 52 insertions(+), 8 deletions(-) diff --git a/build.gradle b/build.gradle index dc20a9a..f9a4975 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,5 @@ group 'io.kweb' -version '0.2.17' +version '0.2.18' buildscript { ext.kotlin_version = '1.2.50' diff --git a/src/main/kotlin/io/kweb/shoebox/OrderedViewSet.kt b/src/main/kotlin/io/kweb/shoebox/OrderedViewSet.kt index 2ea41ca..4c4d8e0 100644 --- a/src/main/kotlin/io/kweb/shoebox/OrderedViewSet.kt +++ b/src/main/kotlin/io/kweb/shoebox/OrderedViewSet.kt @@ -44,7 +44,9 @@ class OrderedViewSet(val view : View, val viewKey : String, val comp removeListeners.values.forEach { it(binarySearchResult.index, keyValue) } orderedList.removeAt(binarySearchResult.index) } - is Between -> throw RuntimeException("remove listener called for unknown value") + is Between -> { + throw RuntimeException("$keyValue not found in orderedList $orderedList") + } } } else { // On very rare occasions the View callback doesn't supply the value that was removed, in this case diff --git a/src/main/kotlin/io/kweb/shoebox/stores/DirectoryStore.kt b/src/main/kotlin/io/kweb/shoebox/stores/DirectoryStore.kt index 73e20b8..68646e2 100644 --- a/src/main/kotlin/io/kweb/shoebox/stores/DirectoryStore.kt +++ b/src/main/kotlin/io/kweb/shoebox/stores/DirectoryStore.kt @@ -3,14 +3,14 @@ package io.kweb.shoebox.stores import com.fatboyindustrial.gsonjavatime.Converters import com.google.common.cache.* import com.google.gson.GsonBuilder +import com.google.gson.reflect.TypeToken import io.kweb.shoebox.* import java.nio.file.* import java.nio.file.attribute.FileTime +import java.time.Duration import java.util.concurrent.TimeUnit import kotlin.reflect.KClass - - /** * Created by ian on 3/22/17. */ @@ -22,7 +22,9 @@ class DirectoryStore(val directory : Path, private val kc : KClass) const private val LOCK_FILENAME = "shoebox.lock" const private val LOCK_TOUCH_TIME_MS = 2000.toLong() const private val LOCK_STALE_TIME = LOCK_TOUCH_TIME_MS * 2 - private val gson = Converters.registerAll(GsonBuilder()).create() + private val gson = Converters.registerAll(GsonBuilder()).let { + it.registerTypeAdapter(object : TypeToken() {}.type, DurationConverter()) + }.create() } internal val cache: LoadingCache = CacheBuilder.newBuilder().build( diff --git a/src/main/kotlin/io/kweb/shoebox/utils.kt b/src/main/kotlin/io/kweb/shoebox/utils.kt index f5bf7d0..e92bebb 100644 --- a/src/main/kotlin/io/kweb/shoebox/utils.kt +++ b/src/main/kotlin/io/kweb/shoebox/utils.kt @@ -1,9 +1,11 @@ package io.kweb.shoebox +import com.google.gson.* import io.kweb.shoebox.BinarySearchResult.* -import java.nio.file.Files -import java.nio.file.OpenOption -import java.nio.file.Path +import java.lang.reflect.Type +import java.nio.file.* +import java.time.* +import java.time.format.DateTimeFormatter import java.util.* import java.util.concurrent.Executors import java.util.concurrent.atomic.AtomicLong @@ -81,4 +83,42 @@ private fun toBinarySearchResult(result: Int): BinarySearchResult { val insertionPoint = -result - 1 Between(insertionPoint - 1, insertionPoint) } +} + + +/** + * GSON serialiser/deserialiser for converting [Instant] objects. + */ +class DurationConverter : JsonSerializer, JsonDeserializer { + + override fun serialize(src: Duration, typeOfSrc: Type, context: JsonSerializationContext): JsonElement { + return JsonPrimitive(src.toMillis()) + } + + /** + * Gson invokes this call-back method during deserialization when it encounters a field of the + * specified type. + * + * + * + * In the implementation of this call-back method, you should consider invoking + * [JsonDeserializationContext.deserialize] method to create objects + * for any non-trivial field of the returned object. However, you should never invoke it on the + * the same type passing `json` since that will cause an infinite loop (Gson will call your + * call-back method again). + * + * @param json The Json data being deserialized + * @param typeOfT The type of the Object to deserialize to + * @return a deserialized object of the specified type typeOfT which is a subclass of `T` + * @throws JsonParseException if json is not in the expected format of `typeOfT` + */ + @Throws(JsonParseException::class) + override fun deserialize(json: JsonElement, typeOfT: Type, context: JsonDeserializationContext): Duration { + return Duration.ofNanos(json.asLong) + } + + companion object { + /** Formatter. */ + private val FORMATTER = DateTimeFormatter.ISO_INSTANT + } } \ No newline at end of file