如何用Chimney将Scala嵌套样例类转换为含新增字段的类
问题与解决方案:Scala嵌套样例类转换(Chimney库)
问题背景
需要将package a下的嵌套样例类转换为package b下的结构,两者大部分字段一致,仅目标类b.InternalMyClientSettings多了一个需用常量填充的company字段。尝试使用Scalaland Chimney的into和transformInfo方法,未解决缺失字段的转换问题。
原类结构(package a)
package a import scala.concurrent.duration.{Duration, FiniteDuration} final case class mySettings(multicache: myCacheSetting, defaultTtlHours: Duration) final case class myCacheSetting( weightedRoundrobin: InternalWRRMultiCacheSetting, attempts: Int, clusters: Seq[MyClusterSetting] ) final case class MyClusterSetting(id: String, settings: InternalMyClientSettings) final case class InternalMyClientSettings( user: String, environment: Option[InternalMyClientEnvironmentSettings] ) final case class InternalMyClientEnvironmentSettings( socketTimeout: Option[FiniteDuration], connectTimeout: Option[FiniteDuration] ) final case class InternalWRRMultiCacheSetting(maxWeight: Int, incrementWeight: Int, decrementWeight: Int)
目标类结构(package b)
package b import scala.concurrent.duration.{Duration, FiniteDuration} final case class mySettings(multicache: myCacheSetting, defaultTtlHours: Duration) final case class myCacheSetting( weightedRoundrobin: InternalWRRMultiCacheSetting, attempts: Int, clusters: Seq[MyClusterSetting] ) final case class MyClusterSetting(id: String, settings: InternalMyClientSettings) final case class InternalMyClientSettings( user: String, company: String, environment: Option[InternalMyClientEnvironmentSettings] ) final case class InternalMyClientEnvironmentSettings( socketTimeout: Option[FiniteDuration], connectTimeout: Option[FiniteDuration] ) final case class InternalWRRMultiCacheSetting(maxWeight: Int, incrementWeight: Int, decrementWeight: Int)
解决方案
1. 基础依赖导入
确保项目已引入Chimney库(以sbt为例):
libraryDependencies += "io.scalaland" %% "chimney" % "0.8.0" // 替换为最新稳定版本
导入核心转换器:
import io.scalaland.chimney.dsl._
2. 两种实现方式
方式一:单次转换直接填充字段
在转换链中精准定位到嵌套层级,用withFieldConst给新增的company字段赋值:
val sourceSettings: a.mySettings = // 你的源实例 val targetSettings: b.mySettings = sourceSettings .into[b.mySettings] .withFieldComputed(_.multicache.clusters, clusters => clusters.map(cluster => cluster.into[b.MyClusterSetting] .withFieldConst(_.settings.company, "你的常量值") // 替换为实际常量 .transform ) ) .transform
方式二:定义复用的隐式转换器
如果需要重复使用转换逻辑,为嵌套类定义隐式转换器,Chimney会自动在顶层转换时应用:
import io.scalaland.chimney.Transformer // 定义a.InternalMyClientSettings到b.InternalMyClientSettings的隐式转换器 implicit val clientSettingsTransformer: Transformer[a.InternalMyClientSettings, b.InternalMyClientSettings] = Transformer.define[a.InternalMyClientSettings, b.InternalMyClientSettings] .withFieldConst(_.company, "你的常量值") // 替换为实际常量 .build // 顶层转换自动处理所有嵌套结构 val targetSettings: b.mySettings = sourceSettings.into[b.mySettings].transform
思路说明
- Chimney默认自动匹配同名同类型字段,但目标类新增字段时,必须显式提供填充逻辑。
- 方式一适合一次性转换,直接在转换链中处理嵌套层级的字段;方式二更适合需要多次复用转换逻辑的场景,通过隐式转换器简化顶层调用。
- 核心是定位到新增字段所在的嵌套层级:
mySettings→myCacheSetting→Seq[MyClusterSetting]→InternalMyClientSettings,确保赋值逻辑作用在正确的层级上。
内容的提问来源于stack exchange,提问作者Freez
相关产品推荐
相关产品推荐

