diff --git a/vitrivr-engine-server/src/main/kotlin/org/vitrivr/engine/server/api/rest/KotlinxJsonMapper.kt b/vitrivr-engine-server/src/main/kotlin/org/vitrivr/engine/server/api/rest/KotlinxJsonMapper.kt index 387718a7..c1cf09cc 100644 --- a/vitrivr-engine-server/src/main/kotlin/org/vitrivr/engine/server/api/rest/KotlinxJsonMapper.kt +++ b/vitrivr-engine-server/src/main/kotlin/org/vitrivr/engine/server/api/rest/KotlinxJsonMapper.kt @@ -1,55 +1,53 @@ -import io.javalin.json.JsonMapper -import kotlinx.serialization.* -import kotlinx.serialization.json.Json -import kotlinx.serialization.modules.SerializersModule -import kotlinx.serialization.serializer -import kotlin.reflect.KType -import java.lang.reflect.ParameterizedType -import java.lang.reflect.Type -import kotlin.reflect.KTypeProjection -import kotlin.reflect.full.createType + import io.javalin.json.JsonMapper + import kotlinx.serialization.* + import kotlinx.serialization.json.Json + import kotlinx.serialization.serializer + import kotlin.reflect.KType + import java.lang.reflect.ParameterizedType + import java.lang.reflect.Type + import kotlin.reflect.KTypeProjection + import kotlin.reflect.full.createType -object KotlinxJsonMapper : JsonMapper { + object KotlinxJsonMapper : JsonMapper { - private val json = Json { - serializersModule = SerializersModule { } - isLenient = true - ignoreUnknownKeys = true - } + private val json = Json { + isLenient = true + ignoreUnknownKeys = true + } - override fun fromJsonString(jsonString: String, targetType: Type): T { - return try { - val kType : KType = targetType.toKType() - val serializer = json.serializersModule.serializer(kType) - json.decodeFromString(serializer, jsonString) as T - } catch (e: SerializationException) { - throw Exception("Error while deserializing JSON: ${e.message}") - } catch (e: IllegalStateException) { - throw Exception("Error state: ${e.message}") + override fun fromJsonString(jsonString: String, targetType: Type): T { + return try { + val kType : KType = targetType.toKType() + val serializer = json.serializersModule.serializer(kType) + json.decodeFromString(serializer, jsonString) as T + } catch (e: SerializationException) { + throw Exception("Error while deserializing JSON: ${e.message}") + } catch (e: IllegalStateException) { + throw Exception("Error state: ${e.message}") + } } - } - override fun toJsonString(obj: Any, type: Type): String { - return try { - val kType = type.toKType() - val serializer = json.serializersModule.serializer(kType) - json.encodeToString(serializer, obj) - } catch (e: SerializationException) { - throw Exception("Error while serializing JSON: ${e.message}") - } catch (e: IllegalStateException) { - throw Exception("Error state: ${e.message}") + override fun toJsonString(obj: Any, type: Type): String { + return try { + val kType : KType = type.toKType() + val serializer = json.serializersModule.serializer(kType) + json.encodeToString(serializer, obj) + } catch (e: SerializationException) { + throw Exception("Error while serializing JSON: ${e.message}") + } catch (e: IllegalStateException) { + throw Exception("Error state: ${e.message}") + } } - } - private fun Type.toKType(): KType { - return when (this) { - is ParameterizedType -> { - val rawType = (this.rawType as Class<*>).kotlin - val args = this.actualTypeArguments.map { it.toKType() } - rawType.createType(args.map { KTypeProjection.invariant(it) }) + private fun Type.toKType(): KType { + return when (this) { + is ParameterizedType -> { + val rawType = (this.rawType as Class<*>).kotlin + val args = this.actualTypeArguments.map { it.toKType() } + rawType.createType(args.map { KTypeProjection.invariant(it) }) + } + is Class<*> -> this.kotlin.createType() + else -> throw IllegalArgumentException("Unsupported Type: $this") } - is Class<*> -> this.kotlin.createType() - else -> throw IllegalArgumentException("Unsupported Type: $this") } } -} diff --git a/vitrivr-engine-server/src/main/kotlin/org/vitrivr/engine/server/api/rest/handlers/Schema.kt b/vitrivr-engine-server/src/main/kotlin/org/vitrivr/engine/server/api/rest/handlers/Schema.kt index d6989e7e..e4378ced 100644 --- a/vitrivr-engine-server/src/main/kotlin/org/vitrivr/engine/server/api/rest/handlers/Schema.kt +++ b/vitrivr-engine-server/src/main/kotlin/org/vitrivr/engine/server/api/rest/handlers/Schema.kt @@ -2,9 +2,14 @@ package org.vitrivr.engine.server.api.rest.handlers import io.javalin.http.Context import io.javalin.openapi.* +import kotlinx.serialization.Serializable import org.vitrivr.engine.core.model.metamodel.SchemaManager import org.vitrivr.engine.server.api.rest.model.ErrorStatus + +@Serializable +data class SchemaList(val schemas: List) + @OpenApi( path = "/api/schema/list", summary = "Lists the names of all available schemas.", @@ -12,10 +17,10 @@ import org.vitrivr.engine.server.api.rest.model.ErrorStatus tags = ["Schema Management"], pathParams = [], responses = [ - OpenApiResponse("200", [OpenApiContent(Array::class)]), + OpenApiResponse("200", [OpenApiContent(SchemaList::class)]), OpenApiResponse("400", [OpenApiContent(ErrorStatus::class)]) ] ) fun listSchemas(ctx: Context, manager: SchemaManager) { - ctx.json(manager.listSchemas().map { it.name }) + ctx.json(SchemaList(manager.listSchemas().map { it.name })) } \ No newline at end of file diff --git a/vitrivr-engine-server/src/test/kotlin/org/vitrivr/engine/server/api/rest/KotlinxJsonMapperTest.kt b/vitrivr-engine-server/src/test/kotlin/org/vitrivr/engine/server/api/rest/KotlinxJsonMapperTest.kt new file mode 100644 index 00000000..6351a394 --- /dev/null +++ b/vitrivr-engine-server/src/test/kotlin/org/vitrivr/engine/server/api/rest/KotlinxJsonMapperTest.kt @@ -0,0 +1,117 @@ +import io.javalin.json.JsonMapper +import kotlinx.serialization.* +import kotlinx.serialization.json.Json +import kotlinx.serialization.serializer +import org.junit.jupiter.api.Assertions.* +import org.junit.jupiter.api.Test +import org.vitrivr.engine.core.config.pipeline.execution.ExecutionStatus +import org.vitrivr.engine.core.model.relationship.Relationship +import org.vitrivr.engine.core.model.retrievable.RetrievableId +import org.vitrivr.engine.core.model.retrievable.Retrieved +import org.vitrivr.engine.query.model.api.result.QueryResult +import org.vitrivr.engine.server.api.rest.handlers.SchemaList +import org.vitrivr.engine.server.api.rest.model.ErrorStatus +import org.vitrivr.engine.server.api.rest.model.IngestStatus +import java.lang.reflect.Type +import java.util.* + +class KotlinxJsonMapperTest { + + private val jsonMapper: JsonMapper = KotlinxJsonMapper + private val schemaList = SchemaList(listOf("schema1", "schema2")) + private val queryResult : QueryResult + private val ingestStatus = IngestStatus(UUID.randomUUID().toString(), ExecutionStatus.RUNNING, System.currentTimeMillis()) + private val errorStatus = ErrorStatus("Error") + + private val schemaListStr = """{"schemas":["schema1","schema2"]}""" + private val ingestStatusStr = """{"jobId":"${ingestStatus.jobId}","executionStatus":"RUNNING","timestamp":${ingestStatus.timestamp}}""" + private val errorStatusStr = """{"message":"Error"}""" + + init { + val retrieveds = listOf(Retrieved(UUID.randomUUID(), "SOURCE:IMAGE", false), + Retrieved(UUID.randomUUID(), "SOURCE:IMAGE", false)) + + retrieveds[0].addRelationship(Relationship.ByRef(retrieveds[0], "partOf", retrieveds[1], false)) + + queryResult = QueryResult(retrieveds) + + } + + @Test + fun testFromJsonString_validSchemaList() { + val result: SchemaList = jsonMapper.fromJsonString(schemaListStr, SchemaList::class.java) + assertNotNull(result) + assertEquals(2, result.schemas.size) + assertTrue(result.schemas.contains("schema1")) + assertTrue(result.schemas.contains("schema2")) + } + + @Test + fun testToJsonString_validSchemaList() { + val jsonString = jsonMapper.toJsonString(schemaList, SchemaList::class.java) + assert(jsonString == schemaListStr) + } + + @Test + fun testFromJsonString_validIngestStatus() { + val result: IngestStatus = jsonMapper.fromJsonString(ingestStatusStr, IngestStatus::class.java) + assertNotNull(result) + assertEquals(ingestStatus.jobId, result.jobId) + assertEquals(ingestStatus.executionStatus, result.executionStatus) + assertEquals(ingestStatus.timestamp, result.timestamp) + } + + @Test + fun testToJsonString_validIngestStatus() { + val jsonString = jsonMapper.toJsonString(ingestStatus, IngestStatus::class.java) + assert(jsonString == ingestStatusStr) + } + + + @Test + fun testFromJsonString_validErrorStatus() { + val result: ErrorStatus = jsonMapper.fromJsonString(errorStatusStr, ErrorStatus::class.java) + assertNotNull(result) + assertEquals(errorStatus.message, result.message) + } + + @Test + fun testToJsonString_validErrorStatus() { + val jsonString = jsonMapper.toJsonString(errorStatus, ErrorStatus::class.java) + assert(jsonString == errorStatusStr) + } + + @Serializable + data class TestObject(val name: String, val age: Int) + + @Test + fun testFromJsonString_validJson() { + val jsonString = """{"name":"John Doe","age":30}""" + val type: Type = TestObject::class.java + val result: TestObject = jsonMapper.fromJsonString(jsonString, type) + assertNotNull(result) + assertEquals("John Doe", result.name) + assertEquals(30, result.age) + } + + @Test + fun testFromJsonString_invalidJson() { + val jsonString = """{"name":"John Doe","age":"thirty"}""" + val type: Type = TestObject::class.java + val exception = assertThrows(Exception::class.java) { + jsonMapper.fromJsonString(jsonString, type) + } + assertTrue(exception.message!!.contains("Error while deserializing JSON")) + } + + @Test + fun testToJsonString_validObject() { + val testObject = TestObject("John Doe", 30) + val type: Type = TestObject::class.java + val jsonString = jsonMapper.toJsonString(testObject, type) + assertNotNull(jsonString) + assertTrue(jsonString.contains("John Doe")) + assertTrue(jsonString.contains("30")) + } + +}