[英]scala Play Anorm parser throws UnexpectedNullableFound in model
[英]Object construction with validation in Scala, using that in an Anorm parser
我有一個簡單的案例類金額如下
case class Amount(value: Long, currency: Currency)
還有一個附帶的對象,用於將字符串貨幣代碼轉換為Currency對象
object Amount {
private val log = Logger(getClass)
def apply(value: Long, currencyCode: String) : Amount = {
try {
Amount(value, Currency.getInstance(currencyCode))
} catch {
case e: Exception =>
log.error(s"Invalid currency code [$currencyCode]")
throw new Exception(s"Invalid currency code [$currencyCode]")
}
}
}
調用方式:
val amount : Amount = Amount(1234, "USD")
當我從數據庫中讀取一些數據時,我有一個自定義解析器,例如
implicit val amountParser = Macro.parser[Amount]("value", "currencyCode")
但是,編譯器抱怨
scala.ScalaReflectionException: value apply encapsulates multiple overloaded alternatives and cannot be treated as a method. Consider invoking `<offending symbol>.asTerm.alternatives` and manually picking the required method
[error] at scala.reflect.api.Symbols$SymbolApi$class.asMethod(Symbols.scala:228)
[error] at scala.reflect.internal.Symbols$SymbolContextApiImpl.asMethod(Symbols.scala:84)
[error] at anorm.Macro$.parserImpl(Macro.scala:70)
[error] at anorm.Macro$.namedParserImpl_(Macro.scala:25)
[error] implicit val amountParser = Macro.parser[Amount]("value", "currencyCode")
我該如何工作?
UPDATE
了解了@MikeAllen的響應后,我決定保留case class Amount
和object Amount
不變,而是為Amount編寫了一個自定義解析器,如下所示
implicit private val amountParser = for {
value <- long("value")
currencyCode <- str("currency_code")
} yield {
Amount(value, currencyCode)
}
Scala編譯器將自動生成一個Amount.apply
工廠方法來創建case class
實例,這就是為什么會出現此錯誤的原因-因為您有多個Amount.apply
方法。 其中一個采用類型( Long
, Currency
)的參數,另一個采用類型( Long
, String
)的參數。 錯誤消息表明,您需要從通過反射報告的重載替代項中選擇一種。
或者,您的案例類和同伴可以按以下方式重做:
final case class Amount(value: Long, currencyCode: String) {
/** Currency. Will create an exception on instantiation if code is invalid. */
val currency: Currency = {
try {
Currency.getInstance(currencyCode)
}
catch {
case e: Exception =>
Amount.log.error(s"Invalid currency code [$currencyCode]")
throw new Exception(s"Invalid currency code [$currencyCode]")
}
}
}
object Amount {
private val log = Logger(getClass)
}
誠然,這並不那么優雅,因為您現在有了一個字段currency
,它不是case類的參數之一,並且不能用於模式匹配,同時還帶有字符串形式。
更好的解決方案是保留原始case class
並將貨幣代碼字段從String
轉換為Currency
,然后再創建Amount
實例,作為解析器的一部分:
val amountMapping = {
get[Long]("value") ~ get[String]("currencyCode") map {
case value ~ currencyCode => {
val currency = {
try {
Currency.getInstance(currencyCode)
}
catch {
case e: Exception =>
Amount.log.error(s"Invalid currency code [$currencyCode]")
throw new Exception(s"Invalid currency code [$currencyCode]")
}
}
Amount(value, currency)
}
}
}
然后,您可以使用它來分析行,例如:
def amounts(): List[Amount] = SQL("select * from amounts").as(amountMapping *)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.