json - 将 Scala/Circe 中的 YAML 解析为具有联合类型的案例类
问题描述
我有一个 YAML 文件,其中包含以下示例中定义的 3 种类型的字段。本质上,我希望能够将其解析为代表这些数据模型的通用案例类。
这个 YAML 文件会经常更改,包括字段名称、值等。唯一不会更改的是每种数据类型的高级格式(见下文)
最大的问题是如何定义一个在同一字段中接受多种类型并将 YAML 解析为它们的案例类?
大多数网上的例子似乎都没有关于这个主题,所以我尝试了一些不同的东西,最终都失败了。当我收到以下错误时,似乎在 circe 库中使用像 Either 这样的 sum 类型存在问题。我也尝试使用 asealed trait
和 union 类型无济于事。
示例 YAML 文件:
name: ExampleYamlMapping
version: 0.0
mappings:
# Single Value Field
- name: fieldtype1
value: "singlevalue"
# Multivalue Fields, Unformatted
- name: fieldtype2
value:
- "multivalue"
- "multivalue1"
# Formatted Multivalue field
- name: fieldtype3
content_type: "formatted multivalue"
format: "key1 | key2"
mappings:
- name: key1 # Single Value Field
value: "singlevalue"
- name: key2 # Multivalue Field, Unformatted
value:
- "multivalue1"
- "multivalue2"
示例案例类:
case class UnorderedField(name: String, value: Either[String, List[String]])
case class OrderedMultiValueField(content_type: String,
format: String,
mappings: List[Either[UnorderedField, OrderedMultiValueField]])
case class ContentMappingExample(
name: String,
version: String,
mappings: List[Either[UnorderedField, OrderedMultiValueField]]
)
解析逻辑:
import io.circe.generic.auto._
import io.circe.{Error, Json, ParsingFailure, yaml}
val mappingSource = scala.io.Source.fromFile(mappingFilePath)
mappingData = try mappingSource.mkString finally mappingSource.close()
val mappings: Either[ParsingFailure, Json] = yaml.parser.parse(mappingData)
val contentMapping: ContentMappingExample = mappings
.leftMap(err => err: Error)
.flatMap(_.as[ContentMappingExample])
.valueOr(throw _)
错误信息是:
CNil: DownArray,DownField(mappings)
DecodingFailure(CNil, List(DownArray, DownField(mappings)))
解决方案
对此进行更新:我发现您可以创建代数数据类型 (ADT) 并在 circe 中定义自定义编码器。我遵循以下适用于我的示例:https ://circe.github.io/circe/codecs/adt.html