0

I'm trying to use Spring DI for kotlin-javafx desktop app but Spring doesn't inject a beans to lateinit property.

Here is my starter class

package ui

@Component
class Starter : Application() {

    override fun start(primaryStage: Stage?) {

        val root : Parent = FXMLLoader.load(javaClass.getResource("/view/main.fxml"))
        primaryStage?.title = "Title"
        primaryStage?.scene = Scene(root)
        primaryStage?.show()
    }

    companion object {
        @JvmStatic
        fun main(args: Array<String>) {
            AnnotationConfigApplicationContext(SpringConfig::class.java)

            launch(Starter::class.java, *args)
        }
    }   

}

Here is my Spring-config class

package config

@Configuration
@ComponentScan(basePackages = arrayOf("domain", "ui"))
open class SpringConfig {   

}

Here is my bean that I want to inject

package domain

@Component
open class State {

    private val coinsState = mapOf(Coin.SYS to CoinState(Coin.SYS))

    fun setActiveForCoin(coin : Coin, isActive : Boolean) {
        val coin = coinsState[coin]
        if (coin == null) throw IllegalArgumentException("Coin $coin does not exist!")
        coin.isActive = isActive
    }
}

and finally my javafx controller which should receive a bean (instance of the controller created automatically, I just setup his name in .fxml file)

package ui.controller

@Component
class CoinController {

    @Autowired
    private lateinit var state : State

    @FXML
    fun showConfirmDialog(actionEvent: ActionEvent) {
        println(state)

        val alert = Alert(AlertType.CONFIRMATION)
        alert.title = "Confirmation Dialog"
        alert.headerText = "Look, a Confirmation Dialog"
        //alert.contentText = "Are you ok with this?"

        val result = alert.showAndWait()
        if (result.get() == ButtonType.OK) {
            // ... user chose OK
        } else {
            // ... user chose CANCEL or closed the dialog
        }
    }

}
Oleinik D
  • 95
  • 7
  • Please, provide packages name either – Artur Czopek Nov 27 '17 at 20:48
  • It's not clear how you are getting Spring to instantiate the controllers: by default they are just instantiated by the `FXMLLoader` directly. I don't know kotlin, but there is a related Java question at https://stackoverflow.com/questions/40539310/dependency-injection-and-javafx – James_D Nov 27 '17 at 21:14

1 Answers1

1

Have a look at GluonHQ Ignite and afterburner.fx. They're meant to provide DI capabilities to your JavaFX application. I usually prefer the first one, because it allows you to inject whatever DI framework you choose.

Simple app configuration with ignite will look like this:

class Starter: Application() {

    private val context = SpringContext(this) { listOf() /* collection of packages to scan for bean definitions */ }
    @Autowired 
    private lateinit var loader: FXMLLoader

    override fun start(primaryStage: Stage) {
        context.init()

        /* ... now your FXML controllers can use autowiring */
    }
}
Alex
  • 7,460
  • 2
  • 40
  • 51