【发布时间】:2019-10-31 11:06:02
【问题描述】:
我正在读取查询参数并将它们转换为Map[Symbol, String]。我想通过一组案例类为这些查询参数添加一些类型安全性。
这些case类会根据传入的http请求而有所不同,所以这需要支持不同的case类。
如果传入的查询参数与定义的case class 不匹配,则Parser 应返回None。
我尝试使用 shapeless 来实现通用解析器。如果所有参数的类型都是String,它就可以工作。但我需要支持任何类型的查询参数。
我已尝试合并本文中看到的隐式转换逻辑,但无法使其正常工作。 https://meta.plasm.us/posts/2015/11/08/type-classes-and-generic-derivation/(无形新手)
现有的Parser(没有字符串到类型的转换):
class Parser[A] {
def from[R <: HList]
(m: Map[Symbol, String])
(implicit
gen: LabelledGeneric.Aux[A, R],
fromMap: FromMap[R]
): Option[A] = fromMap(m).map(gen.from)
}
object Parser {
def to[A]: Parser[A] = new Parser[A]
}
描述问题的测试:
class ParserSpec extends FlatSpec with Matchers {
private val sampleName: String = "Bob"
private val sampleVersion: Int = 1
//Partial Solution
case class QueryParams(name: String, version: String)
//Full Solution (not working)
case class QueryParams2(name: String, version: Int)
"A Parser" should "parse query parameters from a map with only string values" in {
val mapOfQueryParams = Map('name -> sampleName, 'version -> sampleVersion.toString)
val result = Parser.to[QueryParams].from(mapOfQueryParams)
result shouldBe 'defined
result.get.name shouldEqual sampleName
result.get.version shouldEqual sampleVersion.toString
}
it should "parse query parameters from a map with any type of value" in {
val mapOfQueryParams = Map('name -> sampleName, 'version -> sampleVersion.toString)
val result = Parser.to[QueryParams2].from(mapOfQueryParams)
//result is not defined as it's not able to convert a string to integer
result shouldBe 'defined
result.get.name shouldEqual sampleName
result.get.version shouldEqual sampleVersion
}
}
【问题讨论】: