aboutsummaryrefslogtreecommitdiff
path: root/src/main/kotlin/pl/treksoft/kvision/remote
diff options
context:
space:
mode:
authorRobert Jaros <rjaros@finn.pl>2018-10-13 03:37:40 +0200
committerRobert Jaros <rjaros@finn.pl>2018-10-13 03:37:40 +0200
commitebce2c4b839c0b2f8be78bc31c1ce12c45a0164c (patch)
tree7cac3c5449eb8aa398b279d62d9a67ed34fa4115 /src/main/kotlin/pl/treksoft/kvision/remote
parent470953c78c2509224bb452c16f8bbea54e53b3d7 (diff)
downloadkvision-ebce2c4b839c0b2f8be78bc31c1ce12c45a0164c.tar.gz
kvision-ebce2c4b839c0b2f8be78bc31c1ce12c45a0164c.tar.bz2
kvision-ebce2c4b839c0b2f8be78bc31c1ce12c45a0164c.zip
Major refactoring of the multi-platform components.
Dependencies upgrade. A lot of code style fixes.
Diffstat (limited to 'src/main/kotlin/pl/treksoft/kvision/remote')
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/remote/CallAgent.kt12
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/remote/RemoteAgent.kt307
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/remote/Security.kt1
3 files changed, 247 insertions, 73 deletions
diff --git a/src/main/kotlin/pl/treksoft/kvision/remote/CallAgent.kt b/src/main/kotlin/pl/treksoft/kvision/remote/CallAgent.kt
index 4247b0b7..a48a6b1f 100644
--- a/src/main/kotlin/pl/treksoft/kvision/remote/CallAgent.kt
+++ b/src/main/kotlin/pl/treksoft/kvision/remote/CallAgent.kt
@@ -21,10 +21,10 @@
*/
package pl.treksoft.kvision.remote
-import kotlinx.serialization.json.JSON
import pl.treksoft.jquery.JQueryAjaxSettings
import pl.treksoft.jquery.JQueryXHR
import pl.treksoft.jquery.jQuery
+import pl.treksoft.kvision.utils.JSON
import pl.treksoft.kvision.utils.obj
import kotlin.js.Promise
import kotlin.js.undefined
@@ -56,8 +56,8 @@ open class CallAgent {
method: RpcHttpMethod = RpcHttpMethod.POST
): Promise<String> {
val jsonRpcRequest = JsonRpcRequest(counter++, url, data)
- val jsonData = JSON.stringify(jsonRpcRequest)
- return Promise({ resolve, reject ->
+ val jsonData = JSON.plain.stringify(jsonRpcRequest)
+ return Promise { resolve, reject ->
jQuery.ajax(url, obj {
this.contentType = "application/json"
this.data = jsonData
@@ -85,7 +85,7 @@ open class CallAgent {
}
}
})
- })
+ }
}
/**
@@ -103,7 +103,7 @@ open class CallAgent {
contentType: String = "application/json",
beforeSend: ((JQueryXHR, JQueryAjaxSettings) -> Boolean)? = null
): Promise<dynamic> {
- return Promise({ resolve, reject ->
+ return Promise { resolve, reject ->
jQuery.ajax(url, obj {
this.contentType = contentType
this.data = data
@@ -127,6 +127,6 @@ open class CallAgent {
}
this.beforeSend = beforeSend
})
- })
+ }
}
}
diff --git a/src/main/kotlin/pl/treksoft/kvision/remote/RemoteAgent.kt b/src/main/kotlin/pl/treksoft/kvision/remote/RemoteAgent.kt
index 25c20445..b4c8561e 100644
--- a/src/main/kotlin/pl/treksoft/kvision/remote/RemoteAgent.kt
+++ b/src/main/kotlin/pl/treksoft/kvision/remote/RemoteAgent.kt
@@ -24,25 +24,24 @@ package pl.treksoft.kvision.remote
import kotlinx.coroutines.Deferred
import kotlinx.coroutines.asDeferred
import kotlinx.serialization.KSerializer
-import kotlinx.serialization.internal.ArrayListSerializer
-import kotlinx.serialization.internal.BooleanSerializer
-import kotlinx.serialization.internal.CharSerializer
-import kotlinx.serialization.internal.DoubleSerializer
-import kotlinx.serialization.internal.LongSerializer
-import kotlinx.serialization.internal.StringSerializer
-import kotlinx.serialization.json.JSON
+import kotlinx.serialization.internal.*
import kotlinx.serialization.list
import kotlinx.serialization.serializer
-import kotlin.js.js
+import pl.treksoft.kvision.types.DateSerializer
+import pl.treksoft.kvision.types.toStringF
+import pl.treksoft.kvision.utils.JSON
+import kotlin.js.Date
import kotlin.reflect.KClass
import kotlin.js.JSON as NativeJSON
-internal class NonStandardTypeException(type: String) : Exception("Non standard type: $type!")
+internal class NotStandardTypeException(type: String) : Exception("Not a standard type: $type!")
+
+internal class NotEnumTypeException : Exception("Not the Enum type!")
/**
* Client side agent for JSON-RPC remote calls.
*/
-@Suppress("EXPERIMENTAL_FEATURE_WARNING", "LargeClass", "TooManyFunctions")
+@Suppress("LargeClass", "TooManyFunctions")
open class RemoteAgent<out T>(val serviceManager: ServiceManager<T>) {
val callAgent = CallAgent()
@@ -55,9 +54,15 @@ open class RemoteAgent<out T>(val serviceManager: ServiceManager<T>) {
serviceManager.getCalls()[function.toString()] ?: throw IllegalStateException("Function not specified!")
return callAgent.jsonRpcCall(url, method = method).then {
try {
+ @Suppress("UNCHECKED_CAST")
deserialize<RET>(it, RET::class.js.name)
- } catch (t: NonStandardTypeException) {
- JSON.nonstrict.parse(RET::class.serializer(), it)
+ } catch (t: NotStandardTypeException) {
+ try {
+ @Suppress("UNCHECKED_CAST")
+ tryDeserializeEnum(RET::class as KClass<Any>, it) as RET
+ } catch (t: NotEnumTypeException) {
+ JSON.nonstrict.parse(RET::class.serializer(), it)
+ }
}
}.asDeferred()
}
@@ -72,9 +77,14 @@ open class RemoteAgent<out T>(val serviceManager: ServiceManager<T>) {
serviceManager.getCalls()[function.toString()] ?: throw IllegalStateException("Function not specified!")
return callAgent.jsonRpcCall(url, method = method).then {
try {
- deserializeLists<RET>(it, RET::class.js.name)
- } catch (t: NonStandardTypeException) {
- JSON.nonstrict.parse(RET::class.serializer().list, it)
+ deserializeList<RET>(it, RET::class.js.name)
+ } catch (t: NotStandardTypeException) {
+ try {
+ @Suppress("UNCHECKED_CAST")
+ tryDeserializeEnumList(RET::class as KClass<Any>, it) as List<RET>
+ } catch (t: NotEnumTypeException) {
+ JSON.nonstrict.parse(RET::class.serializer().list, it)
+ }
}
}.asDeferred()
}
@@ -92,9 +102,14 @@ open class RemoteAgent<out T>(val serviceManager: ServiceManager<T>) {
return callAgent.jsonRpcCall(url, listOf(data), method).then {
try {
@Suppress("UNCHECKED_CAST")
- deserialize<RET>(it, (RET::class as KClass<Any>).js.name)
- } catch (t: NonStandardTypeException) {
- JSON.nonstrict.parse(RET::class.serializer(), it)
+ deserialize<RET>(it, RET::class.js.name)
+ } catch (t: NotStandardTypeException) {
+ try {
+ @Suppress("UNCHECKED_CAST")
+ tryDeserializeEnum(RET::class as KClass<Any>, it) as RET
+ } catch (t: NotEnumTypeException) {
+ JSON.nonstrict.parse(RET::class.serializer(), it)
+ }
}
}.asDeferred()
}
@@ -111,9 +126,14 @@ open class RemoteAgent<out T>(val serviceManager: ServiceManager<T>) {
serviceManager.getCalls()[function.toString()] ?: throw IllegalStateException("Function not specified!")
return callAgent.jsonRpcCall(url, listOf(data), method).then {
try {
- deserializeLists<RET>(it, RET::class.js.name)
- } catch (t: NonStandardTypeException) {
- JSON.nonstrict.parse(RET::class.serializer().list, it)
+ deserializeList<RET>(it, RET::class.js.name)
+ } catch (t: NotStandardTypeException) {
+ try {
+ @Suppress("UNCHECKED_CAST")
+ tryDeserializeEnumList(RET::class as KClass<Any>, it) as List<RET>
+ } catch (t: NotEnumTypeException) {
+ JSON.nonstrict.parse(RET::class.serializer().list, it)
+ }
}
}.asDeferred()
}
@@ -131,9 +151,15 @@ open class RemoteAgent<out T>(val serviceManager: ServiceManager<T>) {
serviceManager.getCalls()[function.toString()] ?: throw IllegalStateException("Function not specified!")
return callAgent.jsonRpcCall(url, listOf(data1, data2), method).then {
try {
+ @Suppress("UNCHECKED_CAST")
deserialize<RET>(it, RET::class.js.name)
- } catch (t: NonStandardTypeException) {
- JSON.nonstrict.parse(RET::class.serializer(), it)
+ } catch (t: NotStandardTypeException) {
+ try {
+ @Suppress("UNCHECKED_CAST")
+ tryDeserializeEnum(RET::class as KClass<Any>, it) as RET
+ } catch (t: NotEnumTypeException) {
+ JSON.nonstrict.parse(RET::class.serializer(), it)
+ }
}
}.asDeferred()
}
@@ -151,9 +177,14 @@ open class RemoteAgent<out T>(val serviceManager: ServiceManager<T>) {
serviceManager.getCalls()[function.toString()] ?: throw IllegalStateException("Function not specified!")
return callAgent.jsonRpcCall(url, listOf(data1, data2), method).then {
try {
- deserializeLists<RET>(it, RET::class.js.name)
- } catch (t: NonStandardTypeException) {
- JSON.nonstrict.parse(RET::class.serializer().list, it)
+ deserializeList<RET>(it, RET::class.js.name)
+ } catch (t: NotStandardTypeException) {
+ try {
+ @Suppress("UNCHECKED_CAST")
+ tryDeserializeEnumList(RET::class as KClass<Any>, it) as List<RET>
+ } catch (t: NotEnumTypeException) {
+ JSON.nonstrict.parse(RET::class.serializer().list, it)
+ }
}
}.asDeferred()
}
@@ -173,9 +204,15 @@ open class RemoteAgent<out T>(val serviceManager: ServiceManager<T>) {
serviceManager.getCalls()[function.toString()] ?: throw IllegalStateException("Function not specified!")
return callAgent.jsonRpcCall(url, listOf(data1, data2, data3), method).then {
try {
+ @Suppress("UNCHECKED_CAST")
deserialize<RET>(it, RET::class.js.name)
- } catch (t: NonStandardTypeException) {
- JSON.nonstrict.parse(RET::class.serializer(), it)
+ } catch (t: NotStandardTypeException) {
+ try {
+ @Suppress("UNCHECKED_CAST")
+ tryDeserializeEnum(RET::class as KClass<Any>, it) as RET
+ } catch (t: NotEnumTypeException) {
+ JSON.nonstrict.parse(RET::class.serializer(), it)
+ }
}
}.asDeferred()
}
@@ -195,9 +232,14 @@ open class RemoteAgent<out T>(val serviceManager: ServiceManager<T>) {
serviceManager.getCalls()[function.toString()] ?: throw IllegalStateException("Function not specified!")
return callAgent.jsonRpcCall(url, listOf(data1, data2, data3), method).then {
try {
- deserializeLists<RET>(it, RET::class.js.name)
- } catch (t: NonStandardTypeException) {
- JSON.nonstrict.parse(RET::class.serializer().list, it)
+ deserializeList<RET>(it, RET::class.js.name)
+ } catch (t: NotStandardTypeException) {
+ try {
+ @Suppress("UNCHECKED_CAST")
+ tryDeserializeEnumList(RET::class as KClass<Any>, it) as List<RET>
+ } catch (t: NotEnumTypeException) {
+ JSON.nonstrict.parse(RET::class.serializer().list, it)
+ }
}
}.asDeferred()
}
@@ -224,9 +266,15 @@ open class RemoteAgent<out T>(val serviceManager: ServiceManager<T>) {
serviceManager.getCalls()[function.toString()] ?: throw IllegalStateException("Function not specified!")
return callAgent.jsonRpcCall(url, listOf(data1, data2, data3, data4), method).then {
try {
+ @Suppress("UNCHECKED_CAST")
deserialize<RET>(it, RET::class.js.name)
- } catch (t: NonStandardTypeException) {
- JSON.nonstrict.parse(RET::class.serializer(), it)
+ } catch (t: NotStandardTypeException) {
+ try {
+ @Suppress("UNCHECKED_CAST")
+ tryDeserializeEnum(RET::class as KClass<Any>, it) as RET
+ } catch (t: NotEnumTypeException) {
+ JSON.nonstrict.parse(RET::class.serializer(), it)
+ }
}
}.asDeferred()
}
@@ -253,9 +301,14 @@ open class RemoteAgent<out T>(val serviceManager: ServiceManager<T>) {
serviceManager.getCalls()[function.toString()] ?: throw IllegalStateException("Function not specified!")
return callAgent.jsonRpcCall(url, listOf(data1, data2, data3, data4), method).then {
try {
- deserializeLists<RET>(it, RET::class.js.name)
- } catch (t: NonStandardTypeException) {
- JSON.nonstrict.parse(RET::class.serializer().list, it)
+ deserializeList<RET>(it, RET::class.js.name)
+ } catch (t: NotStandardTypeException) {
+ try {
+ @Suppress("UNCHECKED_CAST")
+ tryDeserializeEnumList(RET::class as KClass<Any>, it) as List<RET>
+ } catch (t: NotEnumTypeException) {
+ JSON.nonstrict.parse(RET::class.serializer().list, it)
+ }
}
}.asDeferred()
}
@@ -287,9 +340,15 @@ open class RemoteAgent<out T>(val serviceManager: ServiceManager<T>) {
serviceManager.getCalls()[function.toString()] ?: throw IllegalStateException("Function not specified!")
return callAgent.jsonRpcCall(url, listOf(data1, data2, data3, data4, data5), method).then {
try {
+ @Suppress("UNCHECKED_CAST")
deserialize<RET>(it, RET::class.js.name)
- } catch (t: NonStandardTypeException) {
- JSON.nonstrict.parse(RET::class.serializer(), it)
+ } catch (t: NotStandardTypeException) {
+ try {
+ @Suppress("UNCHECKED_CAST")
+ tryDeserializeEnum(RET::class as KClass<Any>, it) as RET
+ } catch (t: NotEnumTypeException) {
+ JSON.nonstrict.parse(RET::class.serializer(), it)
+ }
}
}.asDeferred()
}
@@ -321,9 +380,14 @@ open class RemoteAgent<out T>(val serviceManager: ServiceManager<T>) {
serviceManager.getCalls()[function.toString()] ?: throw IllegalStateException("Function not specified!")
return callAgent.jsonRpcCall(url, listOf(data1, data2, data3, data4, data5), method).then {
try {
- deserializeLists<RET>(it, RET::class.js.name)
- } catch (t: NonStandardTypeException) {
- JSON.nonstrict.parse(RET::class.serializer().list, it)
+ deserializeList<RET>(it, RET::class.js.name)
+ } catch (t: NotStandardTypeException) {
+ try {
+ @Suppress("UNCHECKED_CAST")
+ tryDeserializeEnumList(RET::class as KClass<Any>, it) as List<RET>
+ } catch (t: NotEnumTypeException) {
+ JSON.nonstrict.parse(RET::class.serializer().list, it)
+ }
}
}.asDeferred()
}
@@ -337,18 +401,81 @@ open class RemoteAgent<out T>(val serviceManager: ServiceManager<T>) {
inline fun <reified PAR> serialize(value: PAR, serializer: KSerializer<PAR>?): String? {
return value?.let {
if (serializer != null) {
- JSON.stringify(serializer, it)
+ JSON.plain.stringify(serializer, it)
} else {
- if (it is Enum<*>) {
- "\"$it\""
- } else {
- try {
+ @Suppress("UNCHECKED_CAST")
+ trySerialize((PAR::class as KClass<Any>), it as Any)
+ }
+ }
+ }
+
+ /**
+ * @suppress
+ * Internal function
+ */
+ @Suppress("ComplexMethod", "TooGenericExceptionCaught", "NestedBlockDepth")
+ fun trySerialize(kClass: KClass<Any>, value: Any): String {
+ return if (value is List<*>) {
+ if (value.size > 0) {
+ when {
+ value[0] is String ->
+ @Suppress("UNCHECKED_CAST")
+ JSON.plain.stringify(ArrayListSerializer(StringSerializer) as KSerializer<Any>, value)
+ value[0] is Date ->
+ @Suppress("UNCHECKED_CAST")
+ JSON.plain.stringify(ArrayListSerializer(DateSerializer) as KSerializer<Any>, value)
+ value[0] is Int ->
+ @Suppress("UNCHECKED_CAST")
+ JSON.plain.stringify(ArrayListSerializer(IntSerializer) as KSerializer<Any>, value)
+ value[0] is Long ->
+ @Suppress("UNCHECKED_CAST")
+ JSON.plain.stringify(ArrayListSerializer(LongSerializer) as KSerializer<Any>, value)
+ value[0] is Boolean ->
@Suppress("UNCHECKED_CAST")
- JSON.stringify((PAR::class as KClass<Any>).serializer(), it as Any)
+ JSON.plain.stringify(ArrayListSerializer(BooleanSerializer) as KSerializer<Any>, value)
+ value[0] is Float ->
+ @Suppress("UNCHECKED_CAST")
+ JSON.plain.stringify(ArrayListSerializer(FloatSerializer) as KSerializer<Any>, value)
+ value[0] is Double ->
+ @Suppress("UNCHECKED_CAST")
+ JSON.plain.stringify(ArrayListSerializer(DoubleSerializer) as KSerializer<Any>, value)
+ value[0] is Char ->
+ @Suppress("UNCHECKED_CAST")
+ JSON.plain.stringify(ArrayListSerializer(CharSerializer) as KSerializer<Any>, value)
+ value[0] is Short ->
+ @Suppress("UNCHECKED_CAST")
+ JSON.plain.stringify(ArrayListSerializer(ShortSerializer) as KSerializer<Any>, value)
+ value[0] is Byte ->
+ @Suppress("UNCHECKED_CAST")
+ JSON.plain.stringify(ArrayListSerializer(ByteSerializer) as KSerializer<Any>, value)
+ value[0] is Enum<*> -> "[" + value.joinToString(",") { "\"$it\"" } + "]"
+ else -> try {
+ @Suppress("UNCHECKED_CAST")
+ JSON.plain.stringify(ArrayListSerializer(kClass.serializer()) as KSerializer<Any>, value)
} catch (e: Throwable) {
- it.toString()
+ try {
+ @Suppress("UNCHECKED_CAST")
+ JSON.plain.stringify(ArrayListSerializer(StringSerializer) as KSerializer<Any>, value)
+ } catch (e: Throwable) {
+ value.toString()
+ }
}
}
+ } else {
+ "[]"
+ }
+ } else {
+ when (value) {
+ is Enum<*> -> "\"$value\""
+ is String -> value
+ is Char -> "\"$value\""
+ is Date -> "\"${value.toStringF()}\""
+ else -> try {
+ @Suppress("UNCHECKED_CAST")
+ JSON.plain.stringify(kClass.serializer(), value)
+ } catch (e: Throwable) {
+ value.toString()
+ }
}
}
}
@@ -357,15 +484,37 @@ open class RemoteAgent<out T>(val serviceManager: ServiceManager<T>) {
* @suppress
* Internal function
*/
- @Suppress("UNCHECKED_CAST")
- fun <RET> deserialize(value: String, type: String): RET {
- return when (type) {
- "String" -> JSON.parse(StringSerializer, value) as RET
- "Number" -> JSON.parse(DoubleSerializer, value) as RET
- "Long" -> JSON.parse(LongSerializer, value) as RET
- "Boolean" -> JSON.parse(BooleanSerializer, value) as RET
- "Char" -> JSON.parse(CharSerializer, value) as RET
- else -> throw NonStandardTypeException(type)
+ @Suppress("UNCHECKED_CAST", "ComplexMethod")
+ fun <RET> deserialize(value: String, jsType: String): RET {
+ return when (jsType) {
+ "String" -> JSON.plain.parse(StringSerializer, value) as RET
+ "Number" -> JSON.plain.parse(DoubleSerializer, value) as RET
+ "Long" -> JSON.plain.parse(LongSerializer, value) as RET
+ "Boolean" -> JSON.plain.parse(BooleanSerializer, value) as RET
+ "BoxedChar" -> JSON.plain.parse(CharSerializer, value) as RET
+ "Short" -> JSON.plain.parse(ShortSerializer, value) as RET
+ "Date" -> JSON.plain.parse(DateSerializer, value) as RET
+ "Byte" -> JSON.plain.parse(ByteSerializer, value) as RET
+ else -> throw NotStandardTypeException(jsType)
+ }
+ }
+
+ /**
+ * @suppress
+ * Internal function
+ */
+ @Suppress("UNCHECKED_CAST", "ComplexMethod")
+ fun <RET> deserializeList(value: String, jsType: String): List<RET> {
+ return when (jsType) {
+ "String" -> JSON.plain.parse(ArrayListSerializer(StringSerializer), value) as List<RET>
+ "Number" -> JSON.plain.parse(ArrayListSerializer(DoubleSerializer), value) as List<RET>
+ "Long" -> JSON.plain.parse(ArrayListSerializer(LongSerializer), value) as List<RET>
+ "Boolean" -> JSON.plain.parse(ArrayListSerializer(BooleanSerializer), value) as List<RET>
+ "BoxedChar" -> JSON.plain.parse(ArrayListSerializer(CharSerializer), value) as List<RET>
+ "Short" -> JSON.plain.parse(ArrayListSerializer(ShortSerializer), value) as List<RET>
+ "Date" -> JSON.plain.parse(ArrayListSerializer(DateSerializer), value) as List<RET>
+ "Byte" -> JSON.plain.parse(ArrayListSerializer(ByteSerializer), value) as List<RET>
+ else -> throw NotStandardTypeException(jsType)
}
}
@@ -373,15 +522,41 @@ open class RemoteAgent<out T>(val serviceManager: ServiceManager<T>) {
* @suppress
* Internal function
*/
- @Suppress("UNCHECKED_CAST")
- fun <RET> deserializeLists(value: String, type: String): List<RET> {
- return when (type) {
- "String" -> JSON.parse(ArrayListSerializer(StringSerializer), value) as List<RET>
- "Number" -> JSON.parse(ArrayListSerializer(DoubleSerializer), value) as List<RET>
- "Long" -> JSON.parse(ArrayListSerializer(LongSerializer), value) as List<RET>
- "Boolean" -> JSON.parse(ArrayListSerializer(BooleanSerializer), value) as List<RET>
- "Char" -> JSON.parse(ArrayListSerializer(CharSerializer), value) as List<RET>
- else -> throw NonStandardTypeException(type)
+ @Suppress("TooGenericExceptionCaught", "ThrowsCount")
+ fun tryDeserializeEnum(kClass: KClass<Any>, value: String): Any {
+ return try {
+ if (kClass.asDynamic().jClass.`$metadata$`.interfaces[0].name == "Enum") {
+ findEnumValue(kClass, JSON.plain.parse(StringSerializer, value)) ?: throw NotEnumTypeException()
+ } else {
+ throw NotEnumTypeException()
+ }
+ } catch (e: Throwable) {
+ throw NotEnumTypeException()
+ }
+ }
+
+ /**
+ * @suppress
+ * Internal function
+ */
+ @Suppress("TooGenericExceptionCaught", "ThrowsCount")
+ fun tryDeserializeEnumList(kClass: KClass<Any>, value: String): List<Any> {
+ return try {
+ if (kClass.asDynamic().jClass.`$metadata$`.interfaces[0].name == "Enum") {
+ JSON.plain.parse(ArrayListSerializer(StringSerializer), value).map {
+ findEnumValue(kClass, JSON.plain.parse(StringSerializer, it)) ?: throw NotEnumTypeException()
+ }
+ } else {
+ throw NotEnumTypeException()
+ }
+ } catch (e: Throwable) {
+ throw NotEnumTypeException()
+ }
+ }
+
+ private fun findEnumValue(kClass: KClass<Any>, value: String): Any? {
+ return (kClass.asDynamic().jClass.values() as Array<Any>).find {
+ it.asDynamic().name == value
}
}
}
diff --git a/src/main/kotlin/pl/treksoft/kvision/remote/Security.kt b/src/main/kotlin/pl/treksoft/kvision/remote/Security.kt
index 56141f5e..bf77a06b 100644
--- a/src/main/kotlin/pl/treksoft/kvision/remote/Security.kt
+++ b/src/main/kotlin/pl/treksoft/kvision/remote/Security.kt
@@ -61,7 +61,6 @@ class LoginService {
/**
* Pac4j form login dispatcher.
*/
-@Suppress("EXPERIMENTAL_FEATURE_WARNING")
abstract class SecurityMgr {
private var isLoggedIn = false