From 5a8795a9c6a287c0479190c6abc8a46f5e003d37 Mon Sep 17 00:00:00 2001 From: Sergey Shanshin Date: Wed, 10 May 2023 17:35:37 +0300 Subject: [PATCH] Added FormatLanguage annotation to JSON (#2234) Resolves #2166 Co-authored-by: Leonid Startsev --- .../src/kotlinx/serialization/json/Json.kt | 14 +++++- .../json/internal/FormatLanguage.kt | 45 +++++++++++++++++++ .../json/internal/FormatLanguage.kt | 10 +++++ .../json/internal/IntelliJAnnotation.kt | 35 +++++++++++++++ .../json/internal/FormatLanguage.kt | 10 +++++ .../json/internal/FormatLanguage.kt | 10 +++++ .../json/internal/IntelliJAnnotation.kt | 35 +++++++++++++++ 7 files changed, 157 insertions(+), 2 deletions(-) create mode 100644 formats/json/commonMain/src/kotlinx/serialization/json/internal/FormatLanguage.kt create mode 100644 formats/json/jsMain/src/kotlinx/serialization/json/internal/FormatLanguage.kt create mode 100644 formats/json/jsMain/src/kotlinx/serialization/json/internal/IntelliJAnnotation.kt create mode 100644 formats/json/jvmMain/src/kotlinx/serialization/json/internal/FormatLanguage.kt create mode 100644 formats/json/nativeMain/src/kotlinx/serialization/json/internal/FormatLanguage.kt create mode 100644 formats/json/nativeMain/src/kotlinx/serialization/json/internal/IntelliJAnnotation.kt diff --git a/formats/json/commonMain/src/kotlinx/serialization/json/Json.kt b/formats/json/commonMain/src/kotlinx/serialization/json/Json.kt index 6f5ba9fb27..443f1dc3f9 100644 --- a/formats/json/commonMain/src/kotlinx/serialization/json/Json.kt +++ b/formats/json/commonMain/src/kotlinx/serialization/json/Json.kt @@ -85,13 +85,23 @@ public sealed class Json( } } + /** + * Decodes and deserializes the given JSON [string] to the value of type [T] using deserializer + * retrieved from the reified type parameter. + * + * @throws SerializationException in case of any decoding-specific error + * @throws IllegalArgumentException if the decoded input is not a valid instance of [T] + */ + public inline fun decodeFromString(@FormatLanguage("json", "", "") string: String): T = + decodeFromString(serializersModule.serializer(), string) + /** * Deserializes the given JSON [string] into a value of type [T] using the given [deserializer]. * * @throws [SerializationException] if the given JSON string is not a valid JSON input for the type [T] * @throws [IllegalArgumentException] if the decoded input cannot be represented as a valid instance of type [T] */ - public final override fun decodeFromString(deserializer: DeserializationStrategy, string: String): T { + public final override fun decodeFromString(deserializer: DeserializationStrategy, @FormatLanguage("json", "", "") string: String): T { val lexer = StringJsonLexer(string) val input = StreamingJsonDecoder(this, WriteMode.OBJ, lexer, deserializer.descriptor, null) val result = input.decodeSerializableValue(deserializer) @@ -122,7 +132,7 @@ public sealed class Json( * * @throws [SerializationException] if the given string is not a valid JSON */ - public fun parseToJsonElement(string: String): JsonElement { + public fun parseToJsonElement(@FormatLanguage("json", "", "") string: String): JsonElement { return decodeFromString(JsonElementSerializer, string) } } diff --git a/formats/json/commonMain/src/kotlinx/serialization/json/internal/FormatLanguage.kt b/formats/json/commonMain/src/kotlinx/serialization/json/internal/FormatLanguage.kt new file mode 100644 index 0000000000..275aa71ac9 --- /dev/null +++ b/formats/json/commonMain/src/kotlinx/serialization/json/internal/FormatLanguage.kt @@ -0,0 +1,45 @@ +package kotlinx.serialization.json.internal; + +import kotlinx.serialization.InternalSerializationApi + +/** + * Multiplatform analogue of `org.intellij.lang.annotations.Language` annotation. + * + * An alias is used instead of class, because the actual class in the JVM will conflict with the class from the stdlib - + * we want to avoid the situation with different classes having the same fully-qualified name. + * [see](https://github.com/JetBrains/java-annotations/issues/34) + * + * Specifies that an element of the program represents a string that is a source code on a specified language. + * Code editors may use this annotation to enable syntax highlighting, code completion and other features + * inside the literals that assigned to the annotated variables, passed as arguments to the annotated parameters, + * or returned from the annotated methods. + *

+ * This annotation also could be used as a meta-annotation, to define derived annotations for convenience. + * E.g. the following annotation could be defined to annotate the strings that represent Java methods: + * + *

+ *   @Language(value = "JAVA", prefix = "class X{", suffix = "}")
+ *   @interface JavaMethod {}
+ * 
+ *

+ * Note that using the derived annotation as meta-annotation is not supported. + * Meta-annotation works only one level deep. + */ + +@InternalSerializationApi +@Retention(AnnotationRetention.BINARY) +@Target( + AnnotationTarget.FUNCTION, + AnnotationTarget.PROPERTY_GETTER, + AnnotationTarget.PROPERTY_SETTER, + AnnotationTarget.FIELD, + AnnotationTarget.VALUE_PARAMETER, + AnnotationTarget.LOCAL_VARIABLE, + AnnotationTarget.ANNOTATION_CLASS +) +public expect annotation class FormatLanguage( + public val value: String, + // default parameters are not used due to https://youtrack.jetbrains.com/issue/KT-25946/ + public val prefix: String, + public val suffix: String, +) diff --git a/formats/json/jsMain/src/kotlinx/serialization/json/internal/FormatLanguage.kt b/formats/json/jsMain/src/kotlinx/serialization/json/internal/FormatLanguage.kt new file mode 100644 index 0000000000..6804859d16 --- /dev/null +++ b/formats/json/jsMain/src/kotlinx/serialization/json/internal/FormatLanguage.kt @@ -0,0 +1,10 @@ +/* + * Copyright 2017-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. + */ + +package kotlinx.serialization.json.internal; + +import kotlinx.serialization.InternalSerializationApi + +@InternalSerializationApi +public actual typealias FormatLanguage = org.intellij.lang.annotations.Language diff --git a/formats/json/jsMain/src/kotlinx/serialization/json/internal/IntelliJAnnotation.kt b/formats/json/jsMain/src/kotlinx/serialization/json/internal/IntelliJAnnotation.kt new file mode 100644 index 0000000000..ab81e5be84 --- /dev/null +++ b/formats/json/jsMain/src/kotlinx/serialization/json/internal/IntelliJAnnotation.kt @@ -0,0 +1,35 @@ +/* + * Copyright 2017-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. + */ + +@file:Suppress("PackageDirectoryMismatch") + +package org.intellij.lang.annotations + +import kotlinx.serialization.InternalSerializationApi + +/** + * JS implementation of JVM-only `org.intellij.lang.annotations.Language` class, adds syntax support by IDE. + * + * This class is missing from the Kotlin/JS targets, so it needs to be distributed along with the serialization runtime. + * + * Copy-paste from [https://github.com/JetBrains/java-annotations](https://github.com/JetBrains/java-annotations). + * + * @see [kotlinx.serialization.json.internal.FormatLanguage] + */ +@InternalSerializationApi +@Retention(AnnotationRetention.BINARY) +@Target( + AnnotationTarget.FUNCTION, + AnnotationTarget.PROPERTY_GETTER, + AnnotationTarget.PROPERTY_SETTER, + AnnotationTarget.FIELD, + AnnotationTarget.VALUE_PARAMETER, + AnnotationTarget.LOCAL_VARIABLE, + AnnotationTarget.ANNOTATION_CLASS, +) +public annotation class Language( + val value: String, + val prefix: String = "", + val suffix: String = "", +) diff --git a/formats/json/jvmMain/src/kotlinx/serialization/json/internal/FormatLanguage.kt b/formats/json/jvmMain/src/kotlinx/serialization/json/internal/FormatLanguage.kt new file mode 100644 index 0000000000..9eedf1b8cb --- /dev/null +++ b/formats/json/jvmMain/src/kotlinx/serialization/json/internal/FormatLanguage.kt @@ -0,0 +1,10 @@ +/* + * Copyright 2017-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. + */ + +package kotlinx.serialization.json.internal; + +import kotlinx.serialization.InternalSerializationApi + +@InternalSerializationApi +public actual typealias FormatLanguage = org.intellij.lang.annotations.Language \ No newline at end of file diff --git a/formats/json/nativeMain/src/kotlinx/serialization/json/internal/FormatLanguage.kt b/formats/json/nativeMain/src/kotlinx/serialization/json/internal/FormatLanguage.kt new file mode 100644 index 0000000000..9eedf1b8cb --- /dev/null +++ b/formats/json/nativeMain/src/kotlinx/serialization/json/internal/FormatLanguage.kt @@ -0,0 +1,10 @@ +/* + * Copyright 2017-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. + */ + +package kotlinx.serialization.json.internal; + +import kotlinx.serialization.InternalSerializationApi + +@InternalSerializationApi +public actual typealias FormatLanguage = org.intellij.lang.annotations.Language \ No newline at end of file diff --git a/formats/json/nativeMain/src/kotlinx/serialization/json/internal/IntelliJAnnotation.kt b/formats/json/nativeMain/src/kotlinx/serialization/json/internal/IntelliJAnnotation.kt new file mode 100644 index 0000000000..8bf11d3708 --- /dev/null +++ b/formats/json/nativeMain/src/kotlinx/serialization/json/internal/IntelliJAnnotation.kt @@ -0,0 +1,35 @@ +/* + * Copyright 2017-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. + */ + +@file:Suppress("PackageDirectoryMismatch") + +package org.intellij.lang.annotations + +import kotlinx.serialization.InternalSerializationApi + +/** + * Native implementation of JVM-only `org.intellij.lang.annotations.Language` class, adds syntax support by IDE. + * + * This class is missing from the Kotlin/Native targets, so it needs to be distributed along with the serialization runtime. + * + * Copy-paste from [https://github.com/JetBrains/java-annotations](https://github.com/JetBrains/java-annotations). + * + * @see [kotlinx.serialization.json.internal.FormatLanguage] + */ +@InternalSerializationApi +@Retention(AnnotationRetention.BINARY) +@Target( + AnnotationTarget.FUNCTION, + AnnotationTarget.PROPERTY_GETTER, + AnnotationTarget.PROPERTY_SETTER, + AnnotationTarget.FIELD, + AnnotationTarget.VALUE_PARAMETER, + AnnotationTarget.LOCAL_VARIABLE, + AnnotationTarget.ANNOTATION_CLASS, +) +public annotation class Language( + val value: String, + val prefix: String = "", + val suffix: String = "", +) \ No newline at end of file