不是解决方案,只是一个非常初步的模型
+---------------------------------------------------------+
| |
| D I S C L A I M E R |
| |
| This is a mock-up. It is not type-safe. It relies on |
| runtime reflection (even worse: it relies on |
| Java-reflection!). Do not use this in production. |
| |
| If you can come up with a type-safe solution, I will |
| definitely take a look at it and upvote your answer. |
| |
+---------------------------------------------------------+
您已经明确说过类型安全是必须的,因此下面的代码不能算作解决方案。但是,在进一步调查之前,也许您想尝试一个纯粹的基于运行时反射的实现,以更好地理解需求。这是一个非常快速和肮脏的模型实现:
import scala.language.dynamics
class DynamicBuilder[X](underConstruction: X) extends Dynamic {
val clazz = underConstruction.getClass
def applyDynamic(name: String)(arg: Any): DynamicBuilder[X] = {
if (name.startsWith("with")) {
val propertyName = name.drop(4)
val setterName = "set" + propertyName
clazz.getDeclaredMethods().
find(_.getName == setterName).
fold(throw new IllegalArgumentException("No method " + setterName)) {
m =>
m.invoke(underConstruction, arg.asInstanceOf[java.lang.Object])
this
}
} else {
throw new IllegalArgumentException("Expected 'result' or 'withXYZ'")
}
}
def result(): X = underConstruction
}
object DynamicBuilder {
def build[A](a: A) = new DynamicBuilder[A](a)
}
一旦build
- 方法被导入
import DynamicBuilder.build
并且对应 POJO 的类的定义在范围内
class SomethingElse(val p5: String) {
var bar: String = _
def setBar(s: String): Unit = { bar = s }
override def toString = s"SomethingElse[p5 = $p5, bar = $bar]"
}
class SomeBigJavaObj(val p1: Float, val p2: Double) {
var foo: Int = 0
var bar: String = _
var sthElse: SomethingElse = _
def setFoo(i: Int): Unit = { foo = i }
def setBar(s: String): Unit = { bar = s }
def setSomethingElse(s: SomethingElse): Unit = { sthElse = s }
override def toString: String =
s"""|SomeBigJavaObj[
| p1 = $p1, p2 = $p2,
| foo = $foo, bar = $bar,
| sthElse = $sthElse
|]""".stripMargin
}
并且还定义了您示例中的所有必需变量p1
,...p6
val p1 = 3.1415f
val p2 = 12345678d
val p3 = 42
val p4 = "BAR"
val p5 = "P5"
val p6 = "b-a-r"
您可以完全使用问题中的语法:
val obj: SomeBigJavaObj =
build(new SomeBigJavaObj(p1, p2))
.withFoo(p3)
.withBar(p4)
.withSomethingElse(
build(new SomethingElse(p5))
.withBar(p6)
.result()
)
.result()
结果如下所示:
println(obj)
// Output:
// SomeBigJavaObj[
// p1 = 3.1415, p2 = 1.2345678E7,
// foo = 42, bar = BAR,
// sthElse = SomethingElse[p5 = P5, bar = b-a-r]
// ]
目前,这个想法只是为了看看当你尝试将它与一个更现实的例子一起使用时它失败的严重程度。事实证明,一切都稍微复杂一点:
- 也许有些二传手是通用的
- 也许他们中的一些人使用带有 Java 奇怪的调用站点差异的 Java 通配符
- 也许除了 setter 之外,还有其他一些将多个参数作为可变参数的方法
- 也许有重载的 setter 名称相同但参数类型不同。
- 等等
我知道这不是一个解决方案,但是,我希望这可能有助于作为额外的可行性检查,并且在投入更多时间和精力于类型安全宏之前,它可能有助于使要求更加精确基于的解决方案。
如果这大致符合您的要求,我可能会考虑更新答案。如果这根本没有帮助,我将删除答案。