diff options
| author | Fabian Schuiki | 2022-03-25 19:53:43 +0100 |
|---|---|---|
| committer | GitHub | 2022-03-25 18:53:43 +0000 |
| commit | a2d48a5896335a567ddb21ed87fe38cd65d4764d (patch) | |
| tree | 28c5fc6dd2795200fbb1d8bed5613d990d76ee93 /src | |
| parent | 8d2262c0566c5cc7fc66dec7d3e6d1f8102879b5 (diff) | |
Fix anno deserialization when class field is not first (#2501)
Update `findTypeHints` to allow for the "class" field in JSON objects to
appear anywhere in the object. This used to rely on the field being the
very first in the object, which is easily violated when reading JSON
data generated externally, since an object's order of fields is
unspecified and can be arbitrarily scrambled.
Fixes #2497.
Diffstat (limited to 'src')
| -rw-r--r-- | src/main/scala/firrtl/annotations/JsonProtocol.scala | 13 | ||||
| -rw-r--r-- | src/test/scala/firrtl/JsonProtocolSpec.scala | 12 |
2 files changed, 19 insertions, 6 deletions
diff --git a/src/main/scala/firrtl/annotations/JsonProtocol.scala b/src/main/scala/firrtl/annotations/JsonProtocol.scala index 6908a3a1..24ebc781 100644 --- a/src/main/scala/firrtl/annotations/JsonProtocol.scala +++ b/src/main/scala/firrtl/annotations/JsonProtocol.scala @@ -315,12 +315,13 @@ object JsonProtocol extends LazyLogging { // this used on the first invocation to check all annotations do so def findTypeHints(classInst: Seq[JValue], requireClassField: Boolean = false): Seq[String] = classInst .flatMap({ - case JObject(("class", JString(name)) :: fields) => name +: findTypeHints(fields.map(_._2)) - case obj: JObject if requireClassField => - throw new InvalidAnnotationJSONException(s"Expected field 'class' not found! $obj") - case JObject(fields) => findTypeHints(fields.map(_._2)) - case JArray(arr) => findTypeHints(arr) - case _ => Seq() + case JObject(fields) => + val hint = fields.collectFirst { case ("class", JString(name)) => name } + if (requireClassField && hint.isEmpty) + throw new InvalidAnnotationJSONException(s"Expected field 'class' not found! $fields") + hint ++: findTypeHints(fields.map(_._2)) + case JArray(arr) => findTypeHints(arr) + case _ => Seq() }) .distinct diff --git a/src/test/scala/firrtl/JsonProtocolSpec.scala b/src/test/scala/firrtl/JsonProtocolSpec.scala index 0da43204..3e07542b 100644 --- a/src/test/scala/firrtl/JsonProtocolSpec.scala +++ b/src/test/scala/firrtl/JsonProtocolSpec.scala @@ -31,6 +31,8 @@ object JsonProtocolTestClasses { with HasSerializationHints { def typeHints = Seq(param.getClass) } + + case class SimpleAnnotation(alpha: String) extends NoTargetAnnotation } import JsonProtocolTestClasses._ @@ -68,4 +70,14 @@ class JsonProtocolSpec extends AnyFlatSpec { val deserAnno = serializeAndDeserialize(anno) assert(anno == deserAnno) } + + "JSON object order" should "not affect deserialization" in { + val anno = SimpleAnnotation("hello") + val serializedAnno = """[{ + "alpha": "hello", + "class": "firrtlTests.JsonProtocolTestClasses$SimpleAnnotation" + }]""" + val deserAnno = JsonProtocol.deserialize(serializedAnno).head + assert(anno == deserAnno) + } } |
