Tornadofx: Working with spring boot

Created on 26 May 2017  路  21Comments  路  Source: edvin/tornadofx

Hi,Sir. I am so happy to find your working well project about javafx using kotlin. Now, I want to using your tornadofx into springboot, but I have try it for three days, Now I couldn't write a demo for spring boot use case. Can you give me a demo or give me some advice?

Most helpful comment

OK, try this:

  1. Delete TornadoSpringBootTestApplication.kt
  2. Delete ApplicationContextProvider.kt
  3. Remove the @Component annotation from MainView
  4. Modify MyApp to this:
@SpringBootApplication
class MyApp : App(MainView::class) {
    override fun init() {
        super.init()
        val applicationContext = SpringApplication.run(MyApp::class.java);
        FX.dicontainer = object : DIContainer {
            override fun <T : Any> getInstance(type: KClass<T>): T = applicationContext.getBean(type.java)
            override fun <T : Any> getInstance(type: KClass<T>, name: String): T = applicationContext.getBean(type.java, name)
        }
    }
}
  1. Run this class as the main application entrypoint. Optionally add a main method at the package level that does Application.launch(MyApp::class.java) if you need to.

Your MainView class now looks like this:

class MainView : View("My View") {
    val helloBean: HelloBean by di()

    override val root = borderpane {
        center {
            button("fadfadsf") {
                action {
                    helloBean.callPrint()
                }
            }
        }
    }
}

Does that work for you?

All 21 comments

Hi :) I'm glad to hear that. I'm not entirely sure what gain would come from including Spring Boot in a TornadoFX Application, so I haven't investigated integration support for it. What do you feel is the benefit from this approach?

Hi,Sir. Thank you for your timely reply. In fact, I have try a project using springboot in tornadofx. The problem I faced is the DI, I have read your powerful tornadofx guide doc and get the approach uisng spring(not spring boot):

class SpringExampleApp : App(SpringExampleView::class) {
init {
val springContext = ClassPathXmlApplicationContext("beans.xml")
FX.dicontainer = object : DIContainer {
override fun <T : Any> getInstance(type: KClass<T>): T = springContext.get
Bean(type.java)
}
}
}

and the DI is on the way var someBean by di()
But, the springboot DI is auto, so the two ways is conflict. I couldn't solve this problem.

I added a callback that allows you to post process any beans after they have been instantiated by the TornadoFX framework. This would allow you to call beanFactory.autowireBean(component) and then use the normal @Autowired annotations in your Components. This requires you to use 1.7.6-SNAPSHOT for now. Do something like this in a bean that you make sure to initialize eagerly:

class ComponentPostProcessor : InitializingBean {
    @Autowired private lateinit var beanFactory: AutowireCapableBeanFactory

    override fun afterPropertiesSet() {
        FX.onComponentInitialized { beanFactory.autowireBean(it) }
    }
}

Does that help you?

I am sorry to tell you I have been trying for whole night, but I still can not make it. I have pushed my test project to github (https://github.com/spartajet/tornado-spring-boot-test). Could you check my code and tell me how to modify my project. It's very simple, Thank you !!!

Ok, will check it tonight :)

I've tracked this to something that looks like a deadlock in DefaultSingletonBeanRegistry on line 187:

synchronized (this.singletonObjects) {

Something is already holding this lock, so it never finishes. Not sure what causes it yet. Will try to investigate more.

Seems to be related to this:

https://jira.spring.io/browse/SPR-8471

OK, try this:

  1. Delete TornadoSpringBootTestApplication.kt
  2. Delete ApplicationContextProvider.kt
  3. Remove the @Component annotation from MainView
  4. Modify MyApp to this:
@SpringBootApplication
class MyApp : App(MainView::class) {
    override fun init() {
        super.init()
        val applicationContext = SpringApplication.run(MyApp::class.java);
        FX.dicontainer = object : DIContainer {
            override fun <T : Any> getInstance(type: KClass<T>): T = applicationContext.getBean(type.java)
            override fun <T : Any> getInstance(type: KClass<T>, name: String): T = applicationContext.getBean(type.java, name)
        }
    }
}
  1. Run this class as the main application entrypoint. Optionally add a main method at the package level that does Application.launch(MyApp::class.java) if you need to.

Your MainView class now looks like this:

class MainView : View("My View") {
    val helloBean: HelloBean by di()

    override val root = borderpane {
        center {
            button("fadfadsf") {
                action {
                    helloBean.callPrint()
                }
            }
        }
    }
}

Does that work for you?

Thank you , I get your tips and hava a test

Wa , you are my hero, code perform perfectly!
I am so Thank you!
Then I will trans all my javafx project to tornadofx framework,
Thank you very much!!!

I have push the code to the project to help other people!

Very glad to hear that :) Let me know if you run into any more issues :)

No, I think I can solve other problems, Thank you!!!

As of 2018, it seems like the above code is still needed to be able to use spring boot properly with tornadoFx. It would be very appreciated if @Autowired annotations just worked out of the box.

TornadoFX will not support a Spring annotation out of the box. The integration stub works well AFAIK, and writing by di() is the preferred way of wiring third party beans into a TornadoFX component.

good to know. what about java lombok?

What about lombok?

Well, it is not supported. Will it ever be?

What do you mean? TornadoFX is written in and for Kotlin, and as such has no need for lombok. However, Java classes compiled with lombok can be used in any Kotlin application without issues. I do this myself successfully in several projects.

So I can generate builders with some kind of annotation in Kotlin then? I'm curious now

It sounds like you鈥檙e asking if you can use Lombok with Kotlin, which makes no sense. Kotlin doesn鈥檛 need builders. I think you need to read up on Kotlin :)

Was this page helpful?
0 / 5 - 0 ratings