diff --git a/README.md b/README.md
index 3394f29..586d5a9 100644
--- a/README.md
+++ b/README.md
@@ -25,7 +25,7 @@ using it is as simple as adding a single line to Gradle.
##### Gradle
```kotlin
-implementation("org.audux.bgg:bggclient:0.6.0")
+implementation("org.audux.bgg:bggclient:0.8.0")
```
##### Maven
@@ -35,7 +35,7 @@ implementation("org.audux.bgg:bggclient:0.6.0")
org.audux.bggbggclient
- 0.6.0
+ 0.8.0
```
diff --git a/build.gradle.kts b/build.gradle.kts
index 1fafe7d..9a65890 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -7,6 +7,7 @@ plugins {
`maven-publish`
signing
alias(libs.plugins.com.gradleup.nmcp)
+ alias(libs.plugins.kotlin.serialization)
alias(libs.plugins.ktfmt.gradle)
alias(libs.plugins.org.jetbrains.dokka)
alias(libs.plugins.org.jetbrains.kotlin.jvm)
@@ -22,7 +23,7 @@ publishing {
create("mavenJava") {
groupId = "org.audux.bgg"
artifactId = "bggclient"
- version = "0.6.0"
+ version = "0.8.0"
pom {
name = "Unofficial JVM BGG client"
@@ -100,6 +101,7 @@ dependencies {
// Testing dependencies.
testApi(libs.ktor.client.mock)
+ testImplementation(libs.kotlin.serialization.json)
testImplementation(libs.junit5.jupiter)
testImplementation(libs.junit5.params)
testImplementation(libs.truth)
diff --git a/examples/android/app/build.gradle.kts b/examples/android/app/build.gradle.kts
index 6063c74..c6ebce2 100644
--- a/examples/android/app/build.gradle.kts
+++ b/examples/android/app/build.gradle.kts
@@ -68,7 +68,7 @@ dependencies {
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.7.0")
implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.7.0")
implementation("io.coil-kt:coil-compose:2.5.0")
- implementation("org.audux.bgg:bggclient:0.6.0")
+ implementation("org.audux.bgg:bggclient:0.8.0")
testImplementation("junit:junit:4.13.2")
diff --git a/examples/java/build.gradle.kts b/examples/java/build.gradle.kts
index 3404827..738f184 100644
--- a/examples/java/build.gradle.kts
+++ b/examples/java/build.gradle.kts
@@ -12,7 +12,7 @@ repositories {
}
dependencies {
- implementation("org.audux.bgg:bggclient:0.6.0")
+ implementation("org.audux.bgg:bggclient:0.8.0")
testImplementation(platform("org.junit:junit-bom:5.9.1"))
testImplementation("org.junit.jupiter:junit-jupiter")
diff --git a/examples/paginate/build.gradle.kts b/examples/paginate/build.gradle.kts
index d4da7d5..8bbdba7 100644
--- a/examples/paginate/build.gradle.kts
+++ b/examples/paginate/build.gradle.kts
@@ -20,7 +20,7 @@ application {
}
dependencies {
- implementation("org.audux.bgg:bggclient:0.6.0")
+ implementation("org.audux.bgg:bggclient:0.8.0")
testImplementation("org.jetbrains.kotlin:kotlin-test")
}
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 43e5152..e5b9942 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -9,7 +9,7 @@ ktor = "2.3.8"
org-jetbrains-dokka = "1.9.10"
org-jetbrains-kotlin-jvm = "1.9.22"
org-jetbrains-kotlin-jdk8 = "1.8.0"
-serialization = "1.6.3"
+serialization = "1.5.0"
slf4j = "2.0.12"
truth = "1.4.1"
@@ -24,6 +24,7 @@ junit5-params = { module = "org.junit.jupiter:junit-jupiter-params", version.ref
kermit = { module = "co.touchlab:kermit", version.ref = "kermit" }
kotlin-coroutines-jdk8 = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-jdk8", version.ref = "org-jetbrains-kotlin-jdk8" }
kotlin-serialization = { module = "org.jetbrains.kotlinx:kotlinx-serialization-core", version.ref = "serialization" }
+kotlin-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json-jvm", version.ref = "serialization" }
ktor-core = { module = "io.ktor:ktor-client-core", version.ref = "ktor" }
ktor-client = { module = "io.ktor:ktor-client-cio", version.ref = "ktor" }
ktor-client-mock = { module = "io.ktor:ktor-client-mock", version.ref = "ktor" }
@@ -35,4 +36,5 @@ org-jetbrains-kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "org
ktfmt-gradle = { id = "com.ncorti.ktfmt.gradle", version.ref = "ktfmt-gradle" }
com-gradleup-nmcp = { id = "com.gradleup.nmcp", version.ref = "com-gradleup-nmcp" }
org-jetbrains-dokka = { id = "org.jetbrains.dokka", version.ref = "org-jetbrains-dokka" }
+kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "org-jetbrains-kotlin-jvm" }
diff --git a/src/main/kotlin/org/audux/bgg/common/Types.kt b/src/main/kotlin/org/audux/bgg/common/Types.kt
index f844402..06415ff 100644
--- a/src/main/kotlin/org/audux/bgg/common/Types.kt
+++ b/src/main/kotlin/org/audux/bgg/common/Types.kt
@@ -16,6 +16,7 @@ package org.audux.bgg.common
import com.fasterxml.jackson.databind.annotation.JsonDeserialize
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty
+import kotlinx.serialization.Serializable
import org.audux.bgg.response.WrappedDoubleDeserializer
import org.audux.bgg.response.WrappedIntDeserializer
@@ -23,6 +24,7 @@ import org.audux.bgg.response.WrappedIntDeserializer
* The different kind/type of things the API may return such as a board game or expansion etc.
* [See docs for more info](https://boardgamegeek.com/wiki/page/BGG_XML_API2#Thing_Items).
*/
+@Serializable
enum class ThingType(val param: String) {
UNKNOWN(""), // Used whenever the type is empty or not recognized.
BOARD_GAME("boardgame"),
@@ -47,6 +49,7 @@ enum class ThingType(val param: String) {
*
* Note: About half of these types actually do _not_ return any list.
*/
+@Serializable
enum class HotListType(val param: String) {
UNKNOWN(""), // Used whenever the type is empty or not recognized.
BOARD_GAME("boardgame"),
@@ -60,6 +63,7 @@ enum class HotListType(val param: String) {
}
/** Different sub types returned in the [org.audux.bgg.request.plays] request/ response */
+@Serializable
enum class SubType(val param: String) {
UNKNOWN(""), // Used whenever the type is empty or not recognized.
BOARD_GAME("boardgame"),
@@ -81,6 +85,7 @@ enum class SubType(val param: String) {
* The different kind/type of families the API may return such as a board game or rpgs.
* [See docs for more info](https://boardgamegeek.com/wiki/page/BGG_XML_API2#Family_Items).
*/
+@Serializable
enum class FamilyType(val param: String) {
UNKNOWN(""), // Used whenever the type is empty or not recognized.
RPG("rpg"),
@@ -96,6 +101,7 @@ enum class FamilyType(val param: String) {
* Used to map the id in the forumlist request to either a family ot thing.
* [See docs for more info](https://boardgamegeek.com/wiki/page/BGG_XML_API2#Forum_Lists).
*/
+@Serializable
enum class ForumListType(val param: String) {
UNKNOWN(""), // Used whenever the type is empty or not recognized.
THING("thing"),
@@ -107,6 +113,7 @@ enum class ForumListType(val param: String) {
}
/** Used to show what type of thing it is when played, either a thing or a family(?) */
+@Serializable
enum class PlayThingType(val param: String) {
UNKNOWN(""), // Used whenever the type is empty or not recognized.
THING("thing"),
@@ -121,6 +128,7 @@ enum class PlayThingType(val param: String) {
* Used to either include or exclude certain items in a request, see
* [org.audux.bgg.request.collection] and [org.audux.bgg.request.user].
*/
+@Serializable
enum class Inclusion {
INCLUDE,
EXCLUDE;
@@ -129,6 +137,7 @@ enum class Inclusion {
}
/** Different domains used for the users' hot- and top-10. */
+@Serializable
enum class Domain(val param: String, val address: String) {
BOARD_GAME_GEEK("boardgame", "https://boardgamegeek.com"),
RPG_GEEK("rpg", "https://rpggeek.com"),
@@ -136,6 +145,7 @@ enum class Domain(val param: String, val address: String) {
}
/** Encapsulates the name of a Thing either primary or alternate name. */
+@Serializable
data class Name(
/** The actual name. */
@JacksonXmlProperty(isAttribute = true) val value: String,
@@ -151,6 +161,7 @@ data class Name(
)
/** Wrapper for [Ratings]. */
+@Serializable
data class Statistics(
/** Unused attribute? */
@JacksonXmlProperty(isAttribute = true) val page: Int?,
@@ -163,6 +174,7 @@ data class Statistics(
* Contains rating aggregated and other statistics like average rating, standard deviation, number
* of comments.
*/
+@Serializable
data class Ratings(
/** A user rating if available. */
@JacksonXmlProperty(isAttribute = true) val value: String? = null,
@@ -211,6 +223,7 @@ data class Ratings(
)
/** Represents a rank in a single ranking (Consisting of type & name). */
+@Serializable
data class Rank(
/** Unique of the ranking type - ID and type+name should always be a coupled. */
@JacksonXmlProperty(isAttribute = true) val id: Int,
@@ -248,6 +261,7 @@ data class Rank(
*
* And so on.
*/
+@Serializable
data class Link(
/**
* The id for the link, most of these cannot be retrieved via the API although a 'family'-API
diff --git a/src/main/kotlin/org/audux/bgg/response/Collection.kt b/src/main/kotlin/org/audux/bgg/response/Collection.kt
index aa460e7..1613e38 100644
--- a/src/main/kotlin/org/audux/bgg/response/Collection.kt
+++ b/src/main/kotlin/org/audux/bgg/response/Collection.kt
@@ -19,6 +19,7 @@ import com.fasterxml.jackson.annotation.JsonRootName
import com.fasterxml.jackson.databind.annotation.JsonDeserialize
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty
import java.time.LocalDateTime
+import kotlinx.serialization.Serializable
import org.audux.bgg.common.Ratings
import org.audux.bgg.common.ThingType
@@ -26,6 +27,7 @@ import org.audux.bgg.common.ThingType
* Response wrapper for the user's Collection. These contain lists of items like board games wrapped
* in [CollectionItem].
*/
+@Serializable
@JsonRootName("items")
data class Collection(
/** Terms of use of the BGG API. */
@@ -43,6 +45,7 @@ data class Collection(
/** An item in the collection e.g. a board game, rpg etc. */
@JsonIgnoreProperties("objecttype")
+@Serializable
data class CollectionItem(
@JacksonXmlProperty(isAttribute = true, localName = "collid") val collectionId: Int,
@JacksonXmlProperty(isAttribute = true) val objectId: Int,
@@ -84,6 +87,7 @@ data class CollectionItem(
)
/** The status of collection item e.g. whether the user owns it, wants it etc. */
+@Serializable
data class Status(
/** Whether item is currently owned. */
@JsonDeserialize(using = NumberToBooleanDeserializer::class)
@@ -131,10 +135,12 @@ data class Status(
/** Whether item is currently owned. */
@JacksonXmlProperty(isAttribute = true)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ @Serializable(with = LocalDateTimeSerializer::class)
val lastModified: LocalDateTime? = null,
)
/** Statistics for a collection item. */
+@Serializable
data class CollectionStatistics(
/** Minimum number of players. */
@JacksonXmlProperty(localName = "minplayers") val minimumPlayers: Int?,
diff --git a/src/main/kotlin/org/audux/bgg/response/Family.kt b/src/main/kotlin/org/audux/bgg/response/Family.kt
index b9891ae..5695c6b 100644
--- a/src/main/kotlin/org/audux/bgg/response/Family.kt
+++ b/src/main/kotlin/org/audux/bgg/response/Family.kt
@@ -16,12 +16,14 @@ package org.audux.bgg.response
import com.fasterxml.jackson.annotation.JsonRootName
import com.fasterxml.jackson.databind.annotation.JsonDeserialize
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty
+import kotlinx.serialization.Serializable
import org.audux.bgg.common.FamilyType
import org.audux.bgg.common.Link
import org.audux.bgg.common.Name
/** Response wrapper for Family items, e.g. games having a related theme or gameplay. */
@JsonRootName("items")
+@Serializable
data class Family(
/** Terms of use of the BGG API. */
@JacksonXmlProperty(isAttribute = true) val termsOfUse: String,
@@ -31,6 +33,7 @@ data class Family(
)
/** The actual Family item e.g. a `boardgamefamily`, rpg etc. */
+@Serializable
data class FamilyItem(
/** Unique ID that can be used to look up more information using the thing endpoint. */
@JacksonXmlProperty(isAttribute = true) val id: Int,
diff --git a/src/main/kotlin/org/audux/bgg/response/Forum.kt b/src/main/kotlin/org/audux/bgg/response/Forum.kt
index 8a2406d..d036ea3 100644
--- a/src/main/kotlin/org/audux/bgg/response/Forum.kt
+++ b/src/main/kotlin/org/audux/bgg/response/Forum.kt
@@ -19,12 +19,14 @@ import com.fasterxml.jackson.databind.annotation.JsonDeserialize
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty
import java.time.LocalDateTime
+import kotlinx.serialization.Serializable
/**
* Encapsulates a forum containing a list of thread summaries - these can be retrieve using in
* [org.audux.bgg.request.thread] endpoint.
*/
@JsonRootName("forum")
+@Serializable
data class Forum(
/** Terms of use of the BGG API. */
@JacksonXmlProperty(isAttribute = true) val termsOfUse: String,
@@ -51,6 +53,7 @@ data class Forum(
/** The date and time a post was last made. */
@JsonFormat(pattern = "E, dd MMM yyyy HH:mm:ss Z")
@JacksonXmlProperty(isAttribute = true)
+ @Serializable(with = LocalDateTimeSerializer::class)
val lastPostDate: LocalDateTime?,
/** The list of threads in this forum. */
@@ -60,6 +63,7 @@ data class Forum(
/**
* Summary of a thread in the forum, contains some stats and aggregated data but no articles/posts.
*/
+@Serializable
data class ThreadSummary(
/** Unique ID that can be used to look up more information using the thread endpoint. */
@JacksonXmlProperty(isAttribute = true) val id: Int,
@@ -80,10 +84,12 @@ data class ThreadSummary(
/** The date and time this thread was created. */
@JsonFormat(pattern = "E, dd MMM yyyy HH:mm:ss Z")
@JacksonXmlProperty(isAttribute = true)
+ @Serializable(with = LocalDateTimeSerializer::class)
val postDate: LocalDateTime?,
/** The date and time a post was last made in this thread. */
@JsonFormat(pattern = "E, dd MMM yyyy HH:mm:ss Z")
@JacksonXmlProperty(isAttribute = true)
+ @Serializable(with = LocalDateTimeSerializer::class)
val lastPostDate: LocalDateTime?,
)
diff --git a/src/main/kotlin/org/audux/bgg/response/ForumList.kt b/src/main/kotlin/org/audux/bgg/response/ForumList.kt
index 45e362e..60dd21c 100644
--- a/src/main/kotlin/org/audux/bgg/response/ForumList.kt
+++ b/src/main/kotlin/org/audux/bgg/response/ForumList.kt
@@ -18,10 +18,12 @@ import com.fasterxml.jackson.annotation.JsonRootName
import com.fasterxml.jackson.databind.annotation.JsonDeserialize
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty
import java.time.LocalDateTime
+import kotlinx.serialization.Serializable
import org.audux.bgg.common.ForumListType
/** Response wrapper for a list of forums for the given id/thing pair. */
@JsonRootName("forums")
+@Serializable
data class ForumList(
/** Terms of use of the BGG API. */
@JacksonXmlProperty(isAttribute = true) val termsOfUse: String,
@@ -42,6 +44,7 @@ data class ForumList(
* Encapsulates the summary of a forum - these can be retrieve using the
* [org.audux.bgg.request.forum] endpoint.
*/
+@Serializable
data class ForumSummary(
/** Unique ID that can be used to look up more information using the forum endpoint. */
@JacksonXmlProperty(isAttribute = true) val id: Int,
@@ -73,5 +76,6 @@ data class ForumSummary(
/** The date and time a post was last made. */
@JsonFormat(pattern = "E, dd MMM yyyy HH:mm:ss Z")
@JacksonXmlProperty(isAttribute = true)
+ @Serializable(with = LocalDateTimeSerializer::class)
val lastPostDate: LocalDateTime?,
)
diff --git a/src/main/kotlin/org/audux/bgg/response/GeekList.kt b/src/main/kotlin/org/audux/bgg/response/GeekList.kt
index 6a27bc6..37f4274 100644
--- a/src/main/kotlin/org/audux/bgg/response/GeekList.kt
+++ b/src/main/kotlin/org/audux/bgg/response/GeekList.kt
@@ -17,15 +17,18 @@ import com.fasterxml.jackson.annotation.JsonFormat
import com.fasterxml.jackson.annotation.JsonIgnoreProperties
import com.fasterxml.jackson.annotation.JsonProperty
import com.fasterxml.jackson.annotation.JsonRootName
+import com.fasterxml.jackson.annotation.JsonSetter
import com.fasterxml.jackson.databind.annotation.JsonDeserialize
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlText
import java.time.LocalDateTime
+import kotlinx.serialization.Serializable
import org.audux.bgg.common.Constants
/** Encapsulates a geek list including its items and optionally its comments. */
@JsonRootName("geeklist")
@JsonIgnoreProperties("postdate_timestamp", "editdate_timestamp")
+@Serializable
data class GeekList(
/** Terms of use of the BGG API. */
@JacksonXmlProperty(isAttribute = true) val termsOfUse: String,
@@ -34,10 +37,14 @@ data class GeekList(
@JacksonXmlProperty(isAttribute = true) val id: Int,
/** The date and time the geek list was posted/published. */
- @JsonFormat(pattern = Constants.DAY_FIRST_DATE_TIME_FORMAT) val postDate: LocalDateTime,
+ @JsonFormat(pattern = Constants.DAY_FIRST_DATE_TIME_FORMAT)
+ @Serializable(with = LocalDateTimeSerializer::class)
+ val postDate: LocalDateTime,
/** The date and time the geek list was last edited - the same as [postDate] if not edited. */
- @JsonFormat(pattern = Constants.DAY_FIRST_DATE_TIME_FORMAT) val editDate: LocalDateTime,
+ @JsonFormat(pattern = Constants.DAY_FIRST_DATE_TIME_FORMAT)
+ @Serializable(with = LocalDateTimeSerializer::class)
+ val editDate: LocalDateTime,
/** The number of thumbs up/likes the geek list received. */
val thumbs: Int,
@@ -66,6 +73,7 @@ data class GeekList(
}
/** A single comment on either a Geek list or a Geek list item. */
+@Serializable
data class GeekListComment(
/** The username of the user that left the comment. */
@JacksonXmlProperty(isAttribute = true) val username: String,
@@ -73,16 +81,19 @@ data class GeekListComment(
/** The date the comment was originally posted. */
@JacksonXmlProperty(isAttribute = true)
@JsonFormat(pattern = Constants.DAY_FIRST_DATE_TIME_FORMAT)
+ @Serializable(with = LocalDateTimeSerializer::class)
val date: LocalDateTime,
/** The date the comment was originally posted. */
@JacksonXmlProperty(isAttribute = true)
@JsonFormat(pattern = Constants.DAY_FIRST_DATE_TIME_FORMAT)
+ @Serializable(with = LocalDateTimeSerializer::class)
val postDate: LocalDateTime,
/** The date the comment was last edited - the same as [postDate] if not edited. */
@JacksonXmlProperty(isAttribute = true)
@JsonFormat(pattern = Constants.DAY_FIRST_DATE_TIME_FORMAT)
+ @Serializable(with = LocalDateTimeSerializer::class)
val editDate: LocalDateTime,
/** The number of thumbs up/likes on this item. */
@@ -97,6 +108,7 @@ data class GeekListComment(
}
/** An item in the geek list e.g. a board game including a description/[body] */
+@Serializable
data class GeekListItem(
/** The ID of the geek list item - NOT the id of the object. */
@JacksonXmlProperty(isAttribute = true) val id: Int,
@@ -124,11 +136,13 @@ data class GeekListItem(
/** The original date this item was added/posted to the list. */
@JacksonXmlProperty(isAttribute = true)
@JsonFormat(pattern = Constants.DAY_FIRST_DATE_TIME_FORMAT)
+ @Serializable(with = LocalDateTimeSerializer::class)
val postDate: LocalDateTime,
/** The date this item was last edited/changed. */
@JacksonXmlProperty(isAttribute = true)
@JsonFormat(pattern = Constants.DAY_FIRST_DATE_TIME_FORMAT)
+ @Serializable(with = LocalDateTimeSerializer::class)
val editDate: LocalDateTime,
/** The number of thumbs up/likes this item has received. */
@@ -140,11 +154,12 @@ data class GeekListItem(
*/
@JacksonXmlProperty(isAttribute = true) val imageId: Int? = null,
@JsonDeserialize(using = TrimmedStringDeserializer::class) val body: String,
-) {
+
/** The list of comments of this list. */
- @JsonProperty("comment")
- var comments: List = mutableListOf()
- set(value) {
- field = field + value
- }
+ var comments: List = mutableListOf(),
+) {
+ @JsonSetter("comment")
+ fun internalSetComment(value: List) {
+ comments = comments + value
+ }
}
diff --git a/src/main/kotlin/org/audux/bgg/response/Guild.kt b/src/main/kotlin/org/audux/bgg/response/Guild.kt
index 0522119..e223c72 100644
--- a/src/main/kotlin/org/audux/bgg/response/Guild.kt
+++ b/src/main/kotlin/org/audux/bgg/response/Guild.kt
@@ -18,10 +18,12 @@ import com.fasterxml.jackson.annotation.JsonProperty
import com.fasterxml.jackson.annotation.JsonRootName
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty
import java.time.LocalDateTime
+import kotlinx.serialization.Serializable
import org.audux.bgg.common.Constants
/** Response wrapper for Guilds to be returned. */
@JsonRootName("guild")
+@Serializable
data class Guild(
/** Terms of use of the BGG API. */
@JacksonXmlProperty(isAttribute = true) val termsOfUse: String,
@@ -35,6 +37,7 @@ data class Guild(
/** The date and time the guild was created. */
@JsonFormat(pattern = Constants.DAY_FIRST_DATE_TIME_FORMAT)
@JacksonXmlProperty(isAttribute = true, localName = "created")
+ @Serializable(with = LocalDateTimeSerializer::class)
val createdAt: LocalDateTime?,
/** The category of the Guild e.g. an interest group, regional group etc. */
@@ -57,6 +60,7 @@ data class Guild(
)
/** The physical location of the guild. */
+@Serializable
data class Location(
/** First address line. */
@JsonProperty("addr1") val addressLine1: String,
@@ -78,6 +82,7 @@ data class Location(
)
/** Represents a (partial) list of members of the guild. */
+@Serializable
data class GuildMembers(
/** The total number of guild members. */
@JacksonXmlProperty(isAttribute = true) val count: Int,
@@ -97,6 +102,7 @@ data class GuildMembers(
* A GuildMember entry, consisting of simply a username (can be used to retrieve more user info) and
* a join date and time.
*/
+@Serializable
data class GuildMember(
/** The username of the guild member. */
@JacksonXmlProperty(isAttribute = true) val name: String,
@@ -104,5 +110,6 @@ data class GuildMember(
/** When the user joined the guild. */
@JsonFormat(pattern = Constants.DAY_FIRST_DATE_TIME_FORMAT)
@JacksonXmlProperty(isAttribute = true, localName = "date")
+ @Serializable(with = LocalDateTimeSerializer::class)
val joinDate: LocalDateTime,
)
diff --git a/src/main/kotlin/org/audux/bgg/response/HotList.kt b/src/main/kotlin/org/audux/bgg/response/HotList.kt
index db7f6f2..e123cd2 100644
--- a/src/main/kotlin/org/audux/bgg/response/HotList.kt
+++ b/src/main/kotlin/org/audux/bgg/response/HotList.kt
@@ -16,9 +16,11 @@ package org.audux.bgg.response
import com.fasterxml.jackson.annotation.JsonRootName
import com.fasterxml.jackson.databind.annotation.JsonDeserialize
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty
+import kotlinx.serialization.Serializable
/** Response wrapper for Hot lists to be returned. */
@JsonRootName("items")
+@Serializable
data class HotList(
/** Terms of use of the BGG API. */
@JacksonXmlProperty(isAttribute = true) val termsOfUse: String,
@@ -28,6 +30,7 @@ data class HotList(
)
/** Encapsulates a ranked item in the hot list. */
+@Serializable
data class HotListItem(
/** Unique ID that can be used to look up more information using the thing endpoint. */
@JacksonXmlProperty(isAttribute = true) val id: Int,
diff --git a/src/main/kotlin/org/audux/bgg/response/TypeDeserializers.kt b/src/main/kotlin/org/audux/bgg/response/JsonDeserializers.kt
similarity index 100%
rename from src/main/kotlin/org/audux/bgg/response/TypeDeserializers.kt
rename to src/main/kotlin/org/audux/bgg/response/JsonDeserializers.kt
diff --git a/src/main/kotlin/org/audux/bgg/response/KSerializers.kt b/src/main/kotlin/org/audux/bgg/response/KSerializers.kt
new file mode 100644
index 0000000..1c3740f
--- /dev/null
+++ b/src/main/kotlin/org/audux/bgg/response/KSerializers.kt
@@ -0,0 +1,80 @@
+package org.audux.bgg.response
+
+import java.net.URI
+import java.time.LocalDate
+import java.time.LocalDateTime
+import kotlinx.serialization.InternalSerializationApi
+import kotlinx.serialization.KSerializer
+import kotlinx.serialization.SealedClassSerializer
+import kotlinx.serialization.descriptors.PrimitiveKind
+import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
+import kotlinx.serialization.descriptors.SerialDescriptor
+import kotlinx.serialization.encoding.Decoder
+import kotlinx.serialization.encoding.Encoder
+
+/** [KSerializer] for a [LocalDate]. */
+internal class LocalDateSerializer : KSerializer {
+ override val descriptor: SerialDescriptor =
+ PrimitiveSerialDescriptor("LocalDate", PrimitiveKind.STRING)
+
+ override fun serialize(encoder: Encoder, value: LocalDate) {
+ encoder.encodeString(value.toString())
+ }
+
+ override fun deserialize(decoder: Decoder): LocalDate = LocalDate.parse(decoder.decodeString())
+}
+
+/** [KSerializer] for a [LocalDateTime]. */
+internal class LocalDateTimeSerializer : KSerializer {
+ override val descriptor: SerialDescriptor =
+ PrimitiveSerialDescriptor("LocalDateTime", PrimitiveKind.STRING)
+
+ override fun serialize(encoder: Encoder, value: LocalDateTime) {
+ encoder.encodeString(value.toString())
+ }
+
+ override fun deserialize(decoder: Decoder): LocalDateTime =
+ LocalDateTime.parse(decoder.decodeString())
+}
+
+/** [KSerializer] for a [URI]. */
+internal class URISerializer : KSerializer {
+ override val descriptor: SerialDescriptor =
+ PrimitiveSerialDescriptor("URI", PrimitiveKind.STRING)
+
+ override fun serialize(encoder: Encoder, value: URI) {
+ encoder.encodeString(value.toString())
+ }
+
+ override fun deserialize(decoder: Decoder): URI = URI.create(decoder.decodeString())
+}
+
+/** [KSerializer] for [Poll] and all sub-classes. */
+@OptIn(InternalSerializationApi::class)
+internal class PollSerializer : KSerializer {
+ private val serializer =
+ SealedClassSerializer(
+ "Poll",
+ Poll::class,
+ arrayOf(
+ LanguageDependencePoll::class,
+ PlayerAgePoll::class,
+ NumberOfPlayersPoll::class
+ ),
+ arrayOf(
+ LanguageDependencePoll.serializer(),
+ PlayerAgePoll.serializer(),
+ NumberOfPlayersPoll.serializer(),
+ ),
+ )
+
+ override val descriptor: SerialDescriptor = serializer.descriptor
+
+ override fun deserialize(decoder: Decoder): Poll {
+ return serializer.deserialize(decoder)
+ }
+
+ override fun serialize(encoder: Encoder, value: Poll) {
+ serializer.serialize(encoder, value)
+ }
+}
diff --git a/src/main/kotlin/org/audux/bgg/response/Plays.kt b/src/main/kotlin/org/audux/bgg/response/Plays.kt
index a78f33f..65c69e4 100644
--- a/src/main/kotlin/org/audux/bgg/response/Plays.kt
+++ b/src/main/kotlin/org/audux/bgg/response/Plays.kt
@@ -18,10 +18,12 @@ import com.fasterxml.jackson.databind.annotation.JsonDeserialize
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty
import java.time.LocalDate
+import kotlinx.serialization.Serializable
import org.audux.bgg.common.PlayThingType
/** Response wrapper for plays by the user to be returned. */
@JsonRootName("plays")
+@Serializable
data class Plays(
/** Terms of use of the BGG API. */
@JacksonXmlProperty(isAttribute = true) val termsOfUse: String,
@@ -46,12 +48,15 @@ data class Plays(
* Represents a single(or batched as specified by `quantity`) play, including the 'thing'/game and
* its players.
*/
+@Serializable
data class Play(
/** Unique ID of the play - not used */
@JacksonXmlProperty(isAttribute = true) val id: Int,
/** The date the play took place. */
- @JacksonXmlProperty(isAttribute = true) val date: LocalDate,
+ @JacksonXmlProperty(isAttribute = true)
+ @Serializable(with = LocalDateSerializer::class)
+ val date: LocalDate,
/** The number of plays, of the same game with the same players. */
@JacksonXmlProperty(isAttribute = true) val quantity: Int,
@@ -86,6 +91,7 @@ data class Play(
)
/** Represents the item/thing that was played e.g. a board game. */
+@Serializable
data class PlayItem(
/** The name of the item. */
@JacksonXmlProperty(isAttribute = true) val name: String,
@@ -107,6 +113,7 @@ data class PlayItem(
)
/** A SubType of a thing e.g. board game. */
+@Serializable
data class SubType(
@JsonDeserialize(using = WrappedSubTypeDeserializer::class)
val subtype: org.audux.bgg.common.SubType
@@ -116,6 +123,7 @@ data class SubType(
* Represents a person in the play i.e. their username, id, what color they played, how they did
* etc.
*/
+@Serializable
data class Player(
/** Optional username of the player. */
@JacksonXmlProperty(isAttribute = true) val username: String?,
diff --git a/src/main/kotlin/org/audux/bgg/response/Search.kt b/src/main/kotlin/org/audux/bgg/response/Search.kt
index c081fd8..68f2652 100644
--- a/src/main/kotlin/org/audux/bgg/response/Search.kt
+++ b/src/main/kotlin/org/audux/bgg/response/Search.kt
@@ -16,11 +16,13 @@ package org.audux.bgg.response
import com.fasterxml.jackson.annotation.JsonRootName
import com.fasterxml.jackson.databind.annotation.JsonDeserialize
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty
+import kotlinx.serialization.Serializable
import org.audux.bgg.common.Name
import org.audux.bgg.common.ThingType
/** Response wrapper for the search results/items to be returned. */
@JsonRootName("items")
+@Serializable
data class SearchResults(
/** Terms of use of the BGG API. */
@JacksonXmlProperty(isAttribute = true) val termsOfUse: String,
@@ -33,6 +35,7 @@ data class SearchResults(
)
/** Encapsulates a single search result. */
+@Serializable
data class SearchResult(
/** Primary or alternative name. */
val name: Name,
diff --git a/src/main/kotlin/org/audux/bgg/response/Sitemap.kt b/src/main/kotlin/org/audux/bgg/response/Sitemap.kt
index 57d480b..c07107e 100644
--- a/src/main/kotlin/org/audux/bgg/response/Sitemap.kt
+++ b/src/main/kotlin/org/audux/bgg/response/Sitemap.kt
@@ -19,10 +19,12 @@ import com.fasterxml.jackson.annotation.JsonRootName
import com.fasterxml.jackson.databind.annotation.JsonDeserialize
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty
import java.time.LocalDate
+import kotlinx.serialization.Serializable
/** Represents a single Sitemap containing a set of URLs. */
@JsonRootName("urlset")
@JsonIgnoreProperties("schemaLocation")
+@Serializable
data class Sitemap(
/** List of the URLs in this Sitemap. */
@JacksonXmlProperty(localName = "url") val sitemaps: List
@@ -32,6 +34,7 @@ data class Sitemap(
* Single URL/Location contained in the Sitemap; could, for example, represent a single Board game
* page.
*/
+@Serializable
data class SitemapUrl(
/** The actual URL/Web address */
@JsonProperty("loc")
@@ -45,5 +48,7 @@ data class SitemapUrl(
val priority: Double?,
/** The date the page was last modified. */
- @JsonProperty("lastmod") val lastModified: LocalDate?,
+ @JsonProperty("lastmod")
+ @Serializable(with = LocalDateSerializer::class)
+ val lastModified: LocalDate?,
)
diff --git a/src/main/kotlin/org/audux/bgg/response/SitemapIndex.kt b/src/main/kotlin/org/audux/bgg/response/SitemapIndex.kt
index 636ddad..3ca6037 100644
--- a/src/main/kotlin/org/audux/bgg/response/SitemapIndex.kt
+++ b/src/main/kotlin/org/audux/bgg/response/SitemapIndex.kt
@@ -18,6 +18,7 @@ import com.fasterxml.jackson.annotation.JsonProperty
import com.fasterxml.jackson.annotation.JsonRootName
import com.fasterxml.jackson.databind.annotation.JsonDeserialize
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty
+import kotlinx.serialization.Serializable
import org.audux.bgg.common.SitemapLocationType
/**
@@ -26,12 +27,14 @@ import org.audux.bgg.common.SitemapLocationType
*/
@JsonRootName("sitemapindex")
@JsonIgnoreProperties("schemaLocation")
+@Serializable
data class SitemapIndex(
/** List of sitemap locations. */
@JacksonXmlProperty(localName = "sitemap") val sitemaps: List
)
/** A URL/Location of a single sitemap/sitemap page. */
+@Serializable
data class SitemapLocation(
/** The URL/Web address of the sitemap. */
@JsonProperty("loc")
diff --git a/src/main/kotlin/org/audux/bgg/response/Things.kt b/src/main/kotlin/org/audux/bgg/response/Things.kt
index 438d7be..45f5a19 100644
--- a/src/main/kotlin/org/audux/bgg/response/Things.kt
+++ b/src/main/kotlin/org/audux/bgg/response/Things.kt
@@ -17,6 +17,7 @@ import com.fasterxml.jackson.annotation.JsonFormat
import com.fasterxml.jackson.annotation.JsonIgnore
import com.fasterxml.jackson.annotation.JsonProperty
import com.fasterxml.jackson.annotation.JsonRootName
+import com.fasterxml.jackson.annotation.JsonSetter
import com.fasterxml.jackson.annotation.JsonSubTypes
import com.fasterxml.jackson.annotation.JsonTypeInfo
import com.fasterxml.jackson.databind.annotation.JsonDeserialize
@@ -25,12 +26,14 @@ import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty
import java.net.URI
import java.time.LocalDate
import java.time.LocalDateTime
+import kotlinx.serialization.Serializable
import org.audux.bgg.common.Link
import org.audux.bgg.common.Name
import org.audux.bgg.common.Statistics
import org.audux.bgg.common.ThingType
/** Response wrapper for the things to be returned. */
+@Serializable
@JsonRootName("items")
data class Things(
/** Terms of use of the BGG API. */
@@ -52,6 +55,7 @@ data class Things(
*
* @see org.audux.bgg.request.things
*/
+@Serializable
data class Thing(
/** Unique BGG identifier. */
val id: Int,
@@ -83,7 +87,9 @@ data class Thing(
@JsonDeserialize(using = WrappedStringDeserializer::class) val datePublished: String?,
/** The year it was released in e.g. `2019`. (For video games) */
- @JsonDeserialize(using = WrappedLocalDateDeserializer::class) val releaseDate: LocalDate?,
+ @JsonDeserialize(using = WrappedLocalDateDeserializer::class)
+ @Serializable(with = LocalDateSerializer::class)
+ val releaseDate: LocalDate?,
/** Minimum number of players required. */
@JsonDeserialize(using = WrappedIntDeserializer::class) val minPlayers: Int?,
@@ -138,88 +144,40 @@ data class Thing(
@JsonDeserialize(using = WrappedIntDeserializer::class) val issueIndex: Int?,
/** Primary name. */
- @JsonIgnore var name: String = ""
-) {
+ @JsonIgnore var name: String = "",
+
/** Contains a list of polls such as the [PlayerAgePoll]. */
- @JsonProperty("poll")
- var polls: List = listOf()
- set(value) {
- field = field + value
- }
+ var polls: List = listOf(),
/**
* Depending on the [type] this list may contain different links e.g. for boardgames links such
* as: `boardgamecategory`, `boardgamefamily`, `boardgamemechanic` etc. may be included. For
* `rpgitem` similar but different links are returned e.g. `rpgitemcategory` etc.
*/
- @JacksonXmlProperty(localName = "link")
- var links: List = listOf()
- set(value) {
- field = field + value
- }
+ var links: List = listOf(),
/** Names of the thing, consisting of a primary and optionally alternatives. */
- @JsonProperty("name")
- var names: List = listOf()
- set(value) {
- field = field + value
- field.forEach { if (it.type == "primary") name = it.value }
- }
-
- fun copy(
- id: Int = this.id,
- type: ThingType = this.type,
- thumbnail: String? = this.thumbnail,
- image: String? = this.image,
- description: String? = this.description,
- yearPublished: Int? = this.yearPublished,
- datePublished: String? = this.datePublished,
- releaseDate: LocalDate? = this.releaseDate,
- minPlayers: Int? = this.minPlayers,
- maxPlayers: Double? = this.maxPlayers,
- playingTimeInMinutes: Int? = this.playingTimeInMinutes,
- minPlayingTimeInMinutes: Int? = this.minPlayingTimeInMinutes,
- maxPlayingTimeInMinutes: Int? = this.maxPlayingTimeInMinutes,
- minAge: Int? = this.minAge,
- videos: List