Skip to content

Commit

Permalink
Serialize all URLs as String (#38)
Browse files Browse the repository at this point in the history
Serialize and deserialize all URLs as `String` instead of `java.net.URL`,
because of various problems with the Java URL API, including the
rejection of perfectly valid URLs.

Fixes #37.
  • Loading branch information
dbrgn authored May 4, 2024
1 parent 425c031 commit e7bc466
Show file tree
Hide file tree
Showing 9 changed files with 32 additions and 41 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ Possible log types:

### Unreleased

- [changed] Serialize and deserialize all URLs as `String` instead of
`java.net.URL`, because of various problems with the Java URL API, including
the rejection of perfectly valid URLs (#37)

### v0.5.0 (2023-09-02)

- [changed] Serialize and deserialize timestamp fields as `Instant` (#36)
Expand Down
3 changes: 1 addition & 2 deletions src/main/kotlin/io/spaceapi/types/Contact.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,11 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
@file:UseSerializers(URISerializer::class, URLSerializer::class)
@file:UseSerializers(URISerializer::class)

package io.spaceapi.types

import io.spaceapi.types.serializers.URISerializer
import io.spaceapi.types.serializers.URLSerializer
import kotlinx.serialization.Serializable
import kotlinx.serialization.UseSerializers
import java.net.URI
Expand Down
7 changes: 1 addition & 6 deletions src/main/kotlin/io/spaceapi/types/Feed.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,9 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
@file:UseSerializers(URLSerializer::class)

package io.spaceapi.types

import io.spaceapi.types.serializers.URLSerializer
import kotlinx.serialization.Serializable
import kotlinx.serialization.UseSerializers
import java.net.URL

@Serializable
data class Feeds(
Expand All @@ -42,5 +37,5 @@ data class Feed(
@JvmField
var type: String? = null,
@JvmField
var url: URL,
var url: String,
)
5 changes: 1 addition & 4 deletions src/main/kotlin/io/spaceapi/types/Link.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,8 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
@file:UseSerializers(URLSerializer::class)

package io.spaceapi.types

import io.spaceapi.types.serializers.URLSerializer
import kotlinx.serialization.Serializable
import kotlinx.serialization.UseSerializers
import java.net.URL
Expand All @@ -32,5 +29,5 @@ data class Link(
@JvmField
var description: String? = null,
@JvmField
var url: URL,
var url: String,
)
7 changes: 1 addition & 6 deletions src/main/kotlin/io/spaceapi/types/RadioShow.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,16 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
@file:UseSerializers(URLSerializer::class)

package io.spaceapi.types

import io.spaceapi.types.serializers.URLSerializer
import kotlinx.serialization.Serializable
import kotlinx.serialization.UseSerializers
import java.net.URL

@Serializable
data class RadioShow(
@JvmField
var name: String,
@JvmField
var url: URL,
var url: String,
@JvmField
var type: String,
@JvmField
Expand Down
8 changes: 3 additions & 5 deletions src/main/kotlin/io/spaceapi/types/State.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,13 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
@file:UseSerializers(URLSerializer::class, TimestampSerializer::class)
@file:UseSerializers(TimestampSerializer::class)

package io.spaceapi.types

import io.spaceapi.types.serializers.TimestampSerializer
import io.spaceapi.types.serializers.URLSerializer
import kotlinx.serialization.Serializable
import kotlinx.serialization.UseSerializers
import java.net.URL
import java.time.Instant

@Serializable
Expand All @@ -44,7 +42,7 @@ data class State(
@Serializable
data class Icon(
@JvmField
var open: URL,
var open: String,
@JvmField
var closed: URL,
var closed: String,
)
5 changes: 1 addition & 4 deletions src/main/kotlin/io/spaceapi/types/Status.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,8 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
@file:UseSerializers(URLSerializer::class)

package io.spaceapi.types

import io.spaceapi.types.serializers.URLSerializer
import kotlinx.serialization.Serializable
import kotlinx.serialization.UseSerializers
import java.net.URL
Expand All @@ -39,7 +36,7 @@ data class Status(
@JvmField
var logo: String,
@JvmField
var url: URL,
var url: String,
@JvmField
var location: Location,
@JvmField
Expand Down
12 changes: 3 additions & 9 deletions src/main/kotlin/io/spaceapi/types/serializers/Serializers.kt
Original file line number Diff line number Diff line change
Expand Up @@ -26,18 +26,12 @@ import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import java.net.URI
import java.net.URL
import java.time.Instant
import java.util.Date
import kotlin.math.round

@ExperimentalSerializationApi
object URLSerializer : KSerializer<URL> {
override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("URL", PrimitiveKind.STRING)
override fun serialize(encoder: Encoder, value: URL) = encoder.encodeString(value.toString())
override fun deserialize(decoder: Decoder): URL = URL(decoder.decodeString())
}

/**
* A serializer for URIs.
*/
@ExperimentalSerializationApi
object URISerializer : KSerializer<URI> {
override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("URI", PrimitiveKind.STRING)
Expand Down
22 changes: 17 additions & 5 deletions src/test/kotlin/io/spaceapi/ParserTestKotlin.kt
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
package io.spaceapi

import io.spaceapi.types.Contact
import io.spaceapi.types.MemberCount
import io.spaceapi.types.SpaceFed
import io.spaceapi.types.State
import io.spaceapi.types.*
import io.spaceapi.types.serializers.TimestampSerializer
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
Expand Down Expand Up @@ -131,7 +128,7 @@ class ParserTestKotlin {
assertEquals(setOf("14"), parsed.api_compatibility)
assertEquals("Coredump", parsed.space)
assertEquals("https://www.coredump.ch/wp-content/uploads/2016/11/logo.png", parsed.logo)
assertEquals(URL("https://www.coredump.ch/"), parsed.url)
assertEquals("https://www.coredump.ch/", parsed.url)
assertEquals(null, parsed.location.address)
assertEquals(47.2251f, parsed.location.lon)
assertEquals(8.8339f, parsed.location.lat)
Expand Down Expand Up @@ -298,4 +295,19 @@ class ParserTestKotlin {
val serialized = Json.encodeToString(TimestampSerializer, Instant.ofEpochSecond(1693685542))
assertEquals("1693685542", serialized)
}

/**
* Regression test for #37.
*/
@Test
fun parseFeedWithNonstandardUrl() {
val parsed: Feeds = Json.decodeFromString("""{
"calendar": {
"type": "ical",
"url": "webcal://example.com/remote.php/dav/public-calendars/asdf/?export"
}
}""")
assertEquals("ical", parsed.calendar?.type)
assertEquals("webcal://example.com/remote.php/dav/public-calendars/asdf/?export", parsed.calendar?.url)
}
}

0 comments on commit e7bc466

Please sign in to comment.