Kotlin JavaFX项目自定义BuilderFactory触发IllegalStateException问题
你遇到的IllegalStateException是因为自定义的BrikkCanvasBuilderFactory没有处理JavaFX默认工厂返回null的情况。JavaFX的JavaFXBuilderFactory并非对所有类都能返回有效的Builder实例——当它找不到对应类的Builder实现时,会返回null。而你的Kotlin代码中,getBuilder方法的返回类型被声明为非空的Builder<*>,当默认工厂返回null时,Kotlin的非空检查就会触发这个异常,哪怕你还没在FXML中使用<BrikkCanvas>标签(加载FXML时会对所有用到的标准控件尝试获取Builder)。
我们需要修改BrikkCanvasBuilderFactory的实现,允许返回null,同时保持自定义控件的Builder逻辑正常工作:
1. 调整getBuilder方法的返回类型
将方法返回类型改为可空的Builder<*>?,这样当默认工厂返回null时,我们可以直接传递这个值,而不会触发非空断言异常:
class BrikkCanvasBuilderFactory : BuilderFactory { private val defaultBuilderFactory = JavaFXBuilderFactory() // 修改返回类型为可空,匹配Java接口的原始定义 override fun getBuilder(clazz: Class<*>): Builder<*>? = if (clazz == BrikkCanvas::class.java) { BrikkCanvasBuilder() } else { defaultBuilderFactory.getBuilder(clazz) // 允许返回null } private class BrikkCanvasBuilder : Builder<BrikkCanvas> { var width: Double = 0.0 var height: Double = 0.0 var rows: Int = 0 var cols: Int = 0 override fun build(): BrikkCanvas = BrikkCanvas(width, height, rows, cols) } }
2. (后续使用注意)确保FXML属性与Builder字段匹配
当你后续在FXML中添加<BrikkCanvas>标签时,要确保属性名称和Builder中的字段完全一致,示例如下:
<BrikkCanvas width="600.0" height="400.0" rows="10" cols="10" />
3. (可选)增强加载逻辑的异常处理
你的FXML加载代码本身没有问题,但可以添加异常处理,方便后续排查问题:
fun startTheGame(playerName: String) { try { val loader = FXMLLoader(App::class.java.getResource("game.fxml"), null, BrikkCanvasBuilderFactory()) val scene = Scene(loader.load()) val controller = loader.getController<GameController>() primaryStage.scene = scene } catch (e: Exception) { e.printStackTrace() // 可以在这里添加弹窗提示等用户友好的错误处理 } }
JavaFX的BuilderFactory接口在Java中原本就允许getBuilder返回null——当返回null时,FXML加载器会尝试使用其他方式创建实例(比如查找类的无参构造方法,或者使用属性注入)。修改Kotlin中的返回类型为可空,就和Java接口的原始定义对齐了,避免了非空检查触发的异常。
内容的提问来源于stack exchange,提问作者pjaro

