Coming Up for Air

Kotlin and CDI

Thursday, November 05, 2015 |

If you’ve been following my blog, you’ve probably noticed that I’ve been spending a lot of time with Kotlin of late. (For the curious, I really like it so far, but I haven’t done just a whole lot with it.) I’ve experimented with writing simple JSF and JAX-RS apps in it, largely to see if I can make it work. With those hurdles cleared, I’m trying something a bit more ambitious: a complete (if basic) Java EE application, written completely in Kotlin. Because I’m a sucker for a bad joke, I’ve dubbed the project KotlinEE. I’m not quite ready to walk through that application yet, but I what I would like to discuss now is an issue I ran into trying to get CDI working with Kotlin.

In theory, it should be pretty straightforward:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
@ApplicationScoped
class DatabaseService  {

    @PersistenceContext(unitName = "em")
    private lateinit var em : EntityManager

    init {
        println("Starting DatabaseService...")
    }

    fun getEntityManager() : EntityManager {
        println("***** From the server: ${em.delegate.javaClass.name}")
        return em
    }
}

Yes, that’s a really boring service, and, yes, I’m doing something dumb in exposing the EntityManager that way, but I’m just experimenting at the moment: can I expose a Kotlin class as a CDI bean and do something with it in my Arquillian test? The short answer is yes, but there’s a big-ish caveat.

By default, Kotlin defines all classes as public and final. Public, since most classes are public anyway and one of Kotlin’s goals is pragmatism, and final because it forces the library developer to think about which methods should be overridable, and prevents unintentional or undesirable overriding where it wasn’t planned for. This poses a problem for CDI (or at least Weld, the CDI implementation that GlassFish and Payara Server use): since these classes and methods are final, the CDI implementation can’t make proxies for them. My first attempt at working around this limitation (which is a JVM-level issue, for what it’s worth), was to mark everything as open:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
@ApplicationScoped
open class DatabaseServiceImpl  {

    @PersistenceContext(unitName = "em")
    private lateinit var em : EntityManager

    init {
        println("Starting DatabaseService...")
    }

    open fun getEntityManager() : EntityManager {
        println("***** From the server: ${em.delegate.javaClass.name}")
        return em
    }
}

That works, but it’s kind of ugly. If you have a large bean ("Split it up!", some will likely shout, but that’s not always possible, right? :), this can become very cumbersome very quickly, but it also negates Kotlin’s final-by-default protections. Another way, which I think is cleaner, is to define an interface, implement that on your bean, and use the interface as the injected type, rather than the class:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
interface DatabaseService {
    fun getEntityManager() : EntityManager
}

@ApplicationScoped
class DatabaseServiceImpl : DatabaseService {

    @PersistenceContext(unitName = "em")
    private lateinit var em : EntityManager

    init {
        println("Starting DatabaseService...")
    }

    override fun getEntityManager() : EntityManager {
        println("***** From the server: ${em.delegate.javaClass.name}")
        return em
    }
}

class MyOtherClass {
    @Inject
    lateinit var service : DatabaseService
}

Now I have a nice interface to provide the usual level of abstraction, and Weld/CDI can make the proxies needed to expose this class as a CDI bean.

What does the rest of the application configuration look like? You’ll have to wait a bit longer for that. :) Stay tuned…​

Search

    Quotes

    Sample quote

    Quote source

    About

    My name is Jason Lee. I am a software developer living in the middle of Oklahoma. I’ve been a professional developer since 1997, using a variety of languages, including Java, Javascript, PHP, Python, Delphi, and even a bit of C#. I currently work for Red Hat on the WildFly/EAP team, where, among other things, I maintain integrations for some MicroProfile specs, OpenTelemetry, Micrometer, Jakarta Faces, and Bean Validation. (Full resume here. LinkedIn profile)

    I am the president of the Oklahoma City JUG, and an occasional speaker at the JUG and a variety of technical conferences.

    On the personal side, I’m active in my church, and enjoy bass guitar, running, fishing, and a variety of martial arts. I’m also married to a beautiful woman, and have two boys, who, thankfully, look like their mother.

    My Links

    Publications