Прежде всего, половина используемых вами комбинаториков создается как Parser[String]
, и именно аннотация вашего типа преобразует их в Parser[Any]
(что разрешено из-за ковариантности, но также совершенно бесполезно в этом случае).
Итак, у вас действительно есть что-то вроде:
class RequestMappingParser extends JavaTokenParsers {
def requestMapping: Parser[String ~ List[String ~ String ~ String] ~ String] = "@RequestMapping(" ~ commaDelimitedSeq ~ ")"
def commaDelimitedSeq: Parser[List[String ~ String ~ String]] = repsep(keyValue, ",")
def keyValue: Parser[String ~ String ~ String] = key ~ "=" ~ value
def key: Parser[String] = "value" | "method"
def value: Parser[String] = """[^)]*""".r
}
Тогда мы могли бы использовать map
или ^^
для настройки типов - раньше это было сложно, потому что у нас было Any
, но если бы мы не избавится от типа, мы сможем легко сопоставить шаблон.
class RequestMappingParser extends JavaTokenParsers {
// result of this parser will be ethier "value" or "method"
def key: Parser[String] = "value" | "method"
def value: Parser[String] = """[^),]*""".r // you had an error here, you were missing "," to separate items
// here we'll map String ~ String ~ String to tuple - we'll drop unused "=" in the process
def keyValue: Parser[(String, String)] = (key ~ "=" ~ value).map {
case k ~ _ ~ v => k -> v
}
// repsep wil return List[(String, String)], which we'll map to Map
def commaDelimitedSeq: Parser[Map[String, String]] = repsep(keyValue, ",").map(_.toMap)
// this would give us String ~ Map[String, String] ~ String, but we don't need
// these String constants. Also we can map things into out final result
def requestMapping: Parser[MethodRequestMapping] = ("@RequestMapping(" ~ commaDelimitedSeq ~ ")").map {
case _ ~ map ~ _ =>
new MethodRequestMapping(value = map("value"), method = map("method"))
}
}
val parser = new RequestMappingParser()
val parsed = "@RequestMapping(value = \"/ex/foos\", method = RequestMethod.GET)"
val result = parser.parse(parser.requestMapping, parsed).get
// result.value == "\"/ex/foos\""
// result.method == "RequestMethod.GET"
Тем не менее, использование этой библиотеки комбинаций парсеров не рекомендуется, в основном из-за того, что она медленная. Для производства рекомендуется использовать что-то вроде FastParse , которое имеет более быструю реализацию и больше функций.