在 Scala 中使用验证构建对象,在 Anorm 解析器中使用它

阿琼慕克吉

我有一个简单的案例类金额如下

case class Amount(value: Long, 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")

我如何使这项工作?

更新

了解从@MikeAllen的响应后,我决定离开case class Amountobject Amount为是,而不是我写了一个自定义的解析器金额如下

    implicit private val amountParser = for {
        value <- long("value")
        currencyCode <- str("currency_code")
      } yield { 
           Amount(value, currencyCode) 
      }
迈克艾伦

斯卡拉编译器会自动生成一个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并将货币代码字段从 aString转换为 a ,作为解析器的一部分:CurrencyAmount

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 *)

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

如何使用Anorm管理Scala枚举?

来自分类Dev

在Scala中使用anorm时发生运行时错误

来自分类Dev

使用Scala anorm流API检索元组列表

来自分类Dev

无法使用Play for Scala和Anorm从表单插入值

来自分类Dev

在scala中使用Anorm从executeInsert()中获取java.math.BigInteger

来自分类Dev

使用Anorm RowParser

来自分类Dev

如何在Anorm查询中使用“喜欢”?

来自分类Dev

使用Anorm进行SELECT ... FOR UPDATE

来自分类Dev

使用Anorm进行SELECT ... FOR UPDATE

来自分类Dev

将Scala Anorm记录转换为特定对象

来自分类Dev

使用Scala解析器组合器解析句子

来自分类Dev

使用Scala解析器组合器解析句子

来自分类Dev

Scala解析器组合器:使用packratparsers获得stackoverflow

来自分类Dev

如何在Play之外使用Anorm?

来自分类Dev

如何使用Anorm从Postgres获取'Char'值

来自分类Dev

如何使用Anorm从Postgres获取'Char'值

来自分类Dev

在Scala Anorm中映射的结果

来自分类Dev

使用Scala的解析器repsep拆分字符串

来自分类Dev

在路由解析器中使用订阅

来自分类Dev

在子解析器中使用`err`

来自分类Dev

在Java中使用Scala对象?

来自分类Dev

在 Java 中使用 Scala 对象

来自分类Dev

Scala解析器组合器:使用可选的初始字符来解析术语

来自分类Dev

在Scala中使用PlayFramework进行Json验证

来自分类Dev

在anorm vs slick上播放scala建议

来自分类Dev

我应该使用executeUpdate还是execute通过Anorm删除行?

来自分类Dev

使用Anorm在PostgreSQL中插入图像文件

来自分类Dev

使用Anorm批量插入具有很多列的表

来自分类Dev

使用Anorm未选择结果时如何执行代码?