From dc39c7d32d879ad1b816e079f3bd86af9961770a Mon Sep 17 00:00:00 2001 From: Shumaf Lovpache Date: Thu, 28 Nov 2024 17:54:59 +0200 Subject: [PATCH] [JavaScript Debugger, script debugger] WEB-70558 support reading of array of object or single object value In r1359167 Google introduced a breaking change: the type of the `Debugger.scriptParsed.debugSymbol` field was changed from `Debugger.DebugSymbols` to `array[Debugger.DebugSymbols]`. To provide backward compatibility with old browsers, this fix introduces a new reader method `readObjectArrayOrSingleObject` which used if some object property marked with `JsonArray` annotation. (cherry picked from commit 7847455a7c59cf7c7af3de9b991f2b6ca51928e7) IJ-CR-150473 GitOrigin-RevId: ae6d2a42490bdcbf867d2727ce8207695d6ee3c5 --- .../protocol-reader-runtime/src/annotations.kt | 9 ++++++++- .../org/jetbrains/jsonProtocol/JsonReaders.java | 9 +++++++++ .../protocol/protocol-reader/src/ArrayReader.kt | 16 +++++++++++----- .../protocol/protocol-reader/src/EnumReader.kt | 2 +- .../protocol-reader/src/InterfaceReader.kt | 9 +++------ .../protocol/protocol-reader/src/MapReader.kt | 2 +- .../protocol-reader/src/ObjectValueReader.kt | 10 ++++++++-- .../protocol-reader/src/PrimitiveValueReader.kt | 2 +- .../src/StringIntPairValueReader.kt | 2 +- .../protocol/protocol-reader/src/ValueReader.kt | 2 +- 10 files changed, 44 insertions(+), 19 deletions(-) diff --git a/platform/script-debugger/protocol/protocol-reader-runtime/src/annotations.kt b/platform/script-debugger/protocol/protocol-reader-runtime/src/annotations.kt index 3d1ce66cea80..21c8cfd1ebe5 100644 --- a/platform/script-debugger/protocol/protocol-reader-runtime/src/annotations.kt +++ b/platform/script-debugger/protocol/protocol-reader-runtime/src/annotations.kt @@ -22,7 +22,14 @@ import org.jetbrains.annotations.ApiStatus annotation class JsonField( val allowAnyPrimitiveValue: Boolean = false, // read any primitive value as String (true as true, number as string - don't try to parse) val allowAnyPrimitiveValueAndMap: Boolean = false, - val primitiveValue: String = "") + val primitiveValue: String = "", +) + +@ApiStatus.Internal +@Target(AnnotationTarget.PROPERTY, AnnotationTarget.FUNCTION) +annotation class JsonArray( + val allowSingleObject: Boolean = false, // when schema changes from {...} to [{...}] we need to handle both cases +) @ApiStatus.Internal @Target(AnnotationTarget.CLASS) diff --git a/platform/script-debugger/protocol/protocol-reader-runtime/src/org/jetbrains/jsonProtocol/JsonReaders.java b/platform/script-debugger/protocol/protocol-reader-runtime/src/org/jetbrains/jsonProtocol/JsonReaders.java index ff44074782fb..b4e7194c8e31 100644 --- a/platform/script-debugger/protocol/protocol-reader-runtime/src/org/jetbrains/jsonProtocol/JsonReaders.java +++ b/platform/script-debugger/protocol/protocol-reader-runtime/src/org/jetbrains/jsonProtocol/JsonReaders.java @@ -134,6 +134,15 @@ public final class JsonReaders { } } + public static List readObjectArrayOrSingleObject(@NotNull JsonReaderEx reader, @NotNull ObjectFactory factory) { + if (reader.peek() == JsonToken.BEGIN_OBJECT) { + return Collections.singletonList(factory.read(reader)); + } + else { + return readObjectArray(reader, factory); + } + } + public static List readObjectArray(@NotNull JsonReaderEx reader, @NotNull ObjectFactory factory) { if (reader.peek() == JsonToken.NULL) { reader.skipValue(); diff --git a/platform/script-debugger/protocol/protocol-reader/src/ArrayReader.kt b/platform/script-debugger/protocol/protocol-reader/src/ArrayReader.kt index c70e8137df9a..15b765617afa 100644 --- a/platform/script-debugger/protocol/protocol-reader/src/ArrayReader.kt +++ b/platform/script-debugger/protocol/protocol-reader/src/ArrayReader.kt @@ -1,6 +1,6 @@ package org.jetbrains.protocolReader -internal class ArrayReader(private val componentParser: ValueReader, private val isList: Boolean) : ValueReader() { +internal class ArrayReader(private val componentParser: ValueReader, private val isList: Boolean, private val allowSingleObject: Boolean) : ValueReader() { override fun appendFinishedValueTypeName(out: TextOutput) { if (isList) { out.append("List<") @@ -17,18 +17,24 @@ internal class ArrayReader(private val componentParser: ValueReader, private val out.append('>') } - override fun writeArrayReadCode(scope: ClassScope, subtyping: Boolean, out: TextOutput) { - beginReadCall("ObjectArray", subtyping, out) + override fun writeArrayReadCode(scope: ClassScope, subtyping: Boolean, allowSingleValue: Boolean, out: TextOutput) { + val readPostfix = if (allowSingleValue) { + "ObjectArrayOrSingleObject" + } + else { + "ObjectArray" + } + beginReadCall(readPostfix, subtyping, out) out .comma() // the trick with shadowing isn't very good, but at least it's simple .append("WrapperFactory { $READER_NAME -> ") - componentParser.writeArrayReadCode(scope, subtyping, out) + componentParser.writeArrayReadCode(scope, subtyping, allowSingleObject, out) out.append("}") out.append(')') } override fun writeReadCode(scope: ClassScope, subtyping: Boolean, out: TextOutput) { - componentParser.writeArrayReadCode(scope, subtyping, out) + componentParser.writeArrayReadCode(scope, subtyping, allowSingleObject, out) } } diff --git a/platform/script-debugger/protocol/protocol-reader/src/EnumReader.kt b/platform/script-debugger/protocol/protocol-reader/src/EnumReader.kt index 2d7f08de0e55..302d70b83423 100644 --- a/platform/script-debugger/protocol/protocol-reader/src/EnumReader.kt +++ b/platform/script-debugger/protocol/protocol-reader/src/EnumReader.kt @@ -5,7 +5,7 @@ internal class EnumReader(private val enumClass: Class>) : ValueReader() out.append(enumClass.canonicalName) } - override fun writeArrayReadCode(scope: ClassScope, subtyping: Boolean, out: TextOutput) { + override fun writeArrayReadCode(scope: ClassScope, subtyping: Boolean, allowSingleValue: Boolean, out: TextOutput) { beginReadCall("EnumArray", subtyping, out) out.comma().append(enumClass.canonicalName).append("::class.java)") } diff --git a/platform/script-debugger/protocol/protocol-reader/src/InterfaceReader.kt b/platform/script-debugger/protocol/protocol-reader/src/InterfaceReader.kt index 43bcc2fde63c..3f3a8e793b33 100644 --- a/platform/script-debugger/protocol/protocol-reader/src/InterfaceReader.kt +++ b/platform/script-debugger/protocol/protocol-reader/src/InterfaceReader.kt @@ -2,10 +2,7 @@ package org.jetbrains.protocolReader import org.jetbrains.io.JsonReaderEx -import org.jetbrains.jsonProtocol.JsonField -import org.jetbrains.jsonProtocol.JsonSubtype -import org.jetbrains.jsonProtocol.Optional -import org.jetbrains.jsonProtocol.StringIntPair +import org.jetbrains.jsonProtocol.* import java.lang.reflect.Method import java.lang.reflect.ParameterizedType import java.lang.reflect.Type @@ -157,7 +154,7 @@ internal class InterfaceReader(private val typeToTypeHandler: LinkedHashMap RAW_STRING_OR_MAP_PARSER type == JsonReaderEx::class.java -> JSON_PARSER type == StringIntPair::class.java -> STRING_INT_PAIR_PARSER - type.isArray -> ArrayReader(getFieldTypeParser(null, type.componentType, false, null), false) + type.isArray -> ArrayReader(getFieldTypeParser(null, type.componentType, false, null), false, member?.annotation()?.allowSingleObject == true) type.isEnum -> EnumReader(type as Class>) else -> { val ref = getTypeRef(type) @@ -176,7 +173,7 @@ internal class InterfaceReader(private val typeToTypeHandler: LinkedHashMap()?.allowSingleObject == true) else MapReader(componentParser) } else { throw UnsupportedOperationException("Method return type $type (generic) not supported") diff --git a/platform/script-debugger/protocol/protocol-reader/src/MapReader.kt b/platform/script-debugger/protocol/protocol-reader/src/MapReader.kt index d251d92acd17..1a48054d7409 100644 --- a/platform/script-debugger/protocol/protocol-reader/src/MapReader.kt +++ b/platform/script-debugger/protocol/protocol-reader/src/MapReader.kt @@ -20,7 +20,7 @@ internal class MapReader(private val componentParser: ValueReader) : ValueReader out.append(')') } - override fun writeArrayReadCode(scope: ClassScope, subtyping: Boolean, out: TextOutput) { + override fun writeArrayReadCode(scope: ClassScope, subtyping: Boolean, allowSingleValue: Boolean, out: TextOutput) { beginReadCall("ObjectArray", subtyping, out) out.comma().append("mapFactory(") if (componentParser is ObjectValueReader) { diff --git a/platform/script-debugger/protocol/protocol-reader/src/ObjectValueReader.kt b/platform/script-debugger/protocol/protocol-reader/src/ObjectValueReader.kt index da189f091b33..ff77d1a79f1d 100644 --- a/platform/script-debugger/protocol/protocol-reader/src/ObjectValueReader.kt +++ b/platform/script-debugger/protocol/protocol-reader/src/ObjectValueReader.kt @@ -29,8 +29,14 @@ internal class ObjectValueReader(val type: TypeRef<*>, private val isSubtyping: out.append(')') } - override fun writeArrayReadCode(scope: ClassScope, subtyping: Boolean, out: TextOutput) { - beginReadCall("ObjectArray", subtyping, out) + override fun writeArrayReadCode(scope: ClassScope, subtyping: Boolean, allowSingleValue: Boolean, out: TextOutput) { + val readPostfix = if (allowSingleValue) { + "ObjectArrayOrSingleObject" + } + else { + "ObjectArray" + } + beginReadCall(readPostfix, subtyping, out) writeFactoryArgument(scope, out) out.append(')') } diff --git a/platform/script-debugger/protocol/protocol-reader/src/PrimitiveValueReader.kt b/platform/script-debugger/protocol/protocol-reader/src/PrimitiveValueReader.kt index 1f1f74985f11..a4eaeda07db2 100644 --- a/platform/script-debugger/protocol/protocol-reader/src/PrimitiveValueReader.kt +++ b/platform/script-debugger/protocol/protocol-reader/src/PrimitiveValueReader.kt @@ -32,7 +32,7 @@ internal open class PrimitiveValueReader(val className: String, val defaultValue out.append(className) } - override fun writeArrayReadCode(scope: ClassScope, subtyping: Boolean, out: TextOutput) { + override fun writeArrayReadCode(scope: ClassScope, subtyping: Boolean, allowSingleValue: Boolean, out: TextOutput) { if (readPostfix == "String") { out.append("nextList") } diff --git a/platform/script-debugger/protocol/protocol-reader/src/StringIntPairValueReader.kt b/platform/script-debugger/protocol/protocol-reader/src/StringIntPairValueReader.kt index c72976fec32c..8ef8b2dc6bcc 100644 --- a/platform/script-debugger/protocol/protocol-reader/src/StringIntPairValueReader.kt +++ b/platform/script-debugger/protocol/protocol-reader/src/StringIntPairValueReader.kt @@ -8,7 +8,7 @@ internal class StringIntPairValueReader : ValueReader() { override fun writeReadCode(scope: ClassScope, subtyping: Boolean, out: TextOutput) { } - override fun writeArrayReadCode(scope: ClassScope, subtyping: Boolean, out: TextOutput) { + override fun writeArrayReadCode(scope: ClassScope, subtyping: Boolean, allowSingleValue: Boolean, out: TextOutput) { out.append("read").append("IntStringPairs").append('(') addReaderParameter(subtyping, out) out.append(')') diff --git a/platform/script-debugger/protocol/protocol-reader/src/ValueReader.kt b/platform/script-debugger/protocol/protocol-reader/src/ValueReader.kt index a291d4e47859..443c284810a1 100644 --- a/platform/script-debugger/protocol/protocol-reader/src/ValueReader.kt +++ b/platform/script-debugger/protocol/protocol-reader/src/ValueReader.kt @@ -24,7 +24,7 @@ internal abstract class ValueReader { abstract fun writeReadCode(scope: ClassScope, subtyping: Boolean, out: TextOutput) - open fun writeArrayReadCode(scope: ClassScope, subtyping: Boolean, out: TextOutput) { + open fun writeArrayReadCode(scope: ClassScope, subtyping: Boolean, allowSingleValue: Boolean, out: TextOutput) { throw UnsupportedOperationException() }