如何检测Scala Chimney类型转换中的隐藏失效问题
Chimney转换中检测静默丢弃字段的方案
问题描述
假设我们有两个Scala样例类:
case class A(a: Int, b: String, x: Boolean) case class B(a: Int, b: String) val a = A(1, "test", true)
调用a.transformInto[B]会成功返回B(1, "test"),但源类型A中的字段x会被静默丢弃。我们需要检测并记录这类静默失效问题,想知道是否可以通过Chimney原生能力实现检测,还是必须手动对比字段名称/数量。
解决方案
Chimney提供了原生方案来处理这个问题,不需要手动校验字段:
1. 编译期严格检测(推荐)
Chimney默认采用宽松模式,会自动忽略源类型中目标类型没有的字段。你可以启用严格模式,让编译器直接报错,拦截这种静默丢弃的情况。
有两种开启方式:
- 全局生效:在
build.sbt中添加编译参数,让所有Chimney转换默认使用严格模式:libraryDependencies += "io.scalaland" %% "chimney" % "0.8.0" // 替换为你的实际版本 scalacOptions += "-Xmacro-settings:chimney.strictMode=true" - 局部生效:针对单个转换操作开启严格模式,使用
withStrictMode链式调用:import io.scalaland.chimney.dsl._ val a = A(1, "test", true) // 编译报错:提示A的字段x不存在于B中 val b = a.transformInto[B].withStrictMode
2. 运行期记录丢弃字段
如果需要在运行期记录被丢弃的字段而非编译报错,可以借助Chimney的TransformerF自定义转换逻辑,收集丢弃的字段信息:
import io.scalaland.chimney.{Transformer, TransformerF} import io.scalaland.chimney.dsl._ import scala.reflect.runtime.universe.TypeTag // 定义结果类型,包含转换后的值和丢弃的字段列表 case class LoggedTransformation[T](value: T, discardedFields: List[String]) // 自定义TransformerF,实现字段检测与日志收集 implicit def loggingTransformer[A, B](implicit baseTransformer: Transformer[A, B], sourceTag: TypeTag[A], targetTag: TypeTag[B] ): TransformerF[LoggedTransformation, A, B] = (source: A) => { // 获取样例类的所有字段名 val sourceFields = sourceTag.tpe.decls.collect { case m if m.isMethod && m.asMethod.isCaseAccessor => m.name.toString }.toSet val targetFields = targetTag.tpe.decls.collect { case m if m.isMethod && m.asMethod.isCaseAccessor => m.name.toString }.toSet // 计算被丢弃的字段 val discarded = sourceFields.diff(targetFields).toList // 返回包含日志的结果 LoggedTransformation(baseTransformer.transform(source), discarded) } // 使用示例 val a = A(1, "test", true) val result = a.transformIntoF[LoggedTransformation, B] // result: LoggedTransformation[B] = LoggedTransformation(B(1,"test"), List("x")) // 可针对discardedFields做日志记录
内容的提问来源于stack exchange,提问作者NiceOneMoney
相关产品推荐
相关产品推荐

