下面的例子和解释很长,所以这是我的问题的要点:当使用坚持执行字段注入的框架(在真正应该保持私有的字段上)时,如何处理 scalac 对私有字段的名称修饰?
我正在使用 ScalaFX/JavaFX 和 FXML 在 Scala 中编写应用程序。当您使用 FXML 在 JavaFX 中定义视图时,在 FXML 中定义的对象(例如按钮和文本字段)通过以下方式注入控制器:
- 向 FXML 元素添加
fx:id
属性 - 将(通常是私有的)字段添加到控制器,
@FXML
注释和字段名称与fx:id
FXML 中定义的属性的值匹配 - 当
FXMLoader
实例化控制器时,它会自动通过反射将带fx:id
注释的元素注入到控制器的匹配@FXML
注释字段中
我不是现场注入的忠实粉丝,但这就是 FXML 的工作方式。但是,由于编译器在某些情况下执行的字段名称修改,我在 Scala 中遇到了意想不到的复杂情况......
这是一个示例应用程序:
test/TestApp.scala(没什么意思,只需要运行示例)
package test
import javafx.application.Application
import javafx.fxml.FXMLLoader
import javafx.scene.{Scene, Parent}
import javafx.stage.Stage
object TestApp {
def main(args: Array[String]) {
Application.launch(classOf[TestApp], args: _*)
}
}
class TestApp extends Application {
override def start(primaryStage: Stage): Unit = {
val root: Parent = FXMLLoader.load(getClass.getResource("/test.fxml"))
val scene: Scene = new Scene(root, 200, 200)
primaryStage.setTitle("Test")
primaryStage.setScene(scene)
primaryStage.show()
}
}
test.fxml(视图)
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<VBox maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0"
prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.40" xmlns:fx="http://javafx.com/fxml/1"
fx:controller="test.TestController">
<children>
<CheckBox fx:id="testCheckBox" mnemonicParsing="false" text="CheckBox"/>
<Button fx:id="testButton" mnemonicParsing="false" text="Button"/>
</children>
</VBox>
test/TestController.scala(test.fxml 视图的控制器)
package test
import javafx.fxml.FXML
import javafx.scene.{control => jfxsc}
import scalafx.Includes._
class TestController {
@FXML private var testCheckBox: jfxsc.CheckBox = _
@FXML private var testButton: jfxsc.Button = _
def initialize(): Unit = {
println(s"testCheckBox=$testCheckBox")
println(s"testButton=$testButton")
testCheckBox.selected.onChange {
testButton.text = "changed"
}
}
}
运行应用程序时,println
语句显示testCheckBox
正确注入,但testButton
为空。如果我单击复选框,则如预期的那样,NullPointerException
调用时会出现testButton.text_=
.
查看编译的类时,原因很明显:
- 有一个类,用于方法中
TestController$$anonfun$initialize$1
传递给的匿名testCheckBox.selected.onChange()
函数initialize()
- 在
TestController
该类中,有两个私有字段:(testCheckBox
如预期的那样)和test$TestController$$testButton
(而不仅仅是testButton
),以及访问器/修改器方法。其中,只有访问器方法test$TestController$$testButton
是公开的。
显然,Scala 编译器修改了testButton
字段的名称,因为它必须公开其访问器方法(从 访问它TestController$$anonfun$initialize$1
)并且因为该字段和访问器/修改器方法应该保持相同的名称。
现在,最后,这是我的问题:是否有合理的解决方案来处理这种情况?现在,我所做的是公开这些字段:由于编译器不需要更改它们的可见性,它不会破坏它们的名称。但是,这些领域确实没有公开的业务。
注意:另一个解决方案是使用 scala-fxml 库,它完全隐藏了字段注入,但出于其他原因,我宁愿使用沼泽标准 FXML 加载。