Java & Kotlin – Two different islands in the same sea

Most people know that Java is named after the volcano dotted island lying between Sumatra and Bali, that’s at the geographic and economic centre of Indonesia.

It was no coincidence that JetBrains, the developers of Kotlin, based in Saint Petersburg, Russia should stick with the island theme, what with Kotlin running on the Java Virtual Machine (JVM) and Kotlin’s heavy reliance on Java code from the existing Java Class Library. Kotlin is named after a Russian island located 32 kilometres west of Saint Petersburg in the Baltic Sea.

As of Android Studio 3.0 (released in October 2017), Kotlin is fully supported by Google for use with their Android operating system, and is directly included in the IDE’s installation package as an alternative to the standard Java compiler. The Android Kotlin compiler lets the user choose between targeting Java 6, Java 7, or Java 8 compatible bytecode.

Kotlin is also a great fit for developing server-side applications, allowing you to write concise and expressive code while maintaining full compatibility with existing Java-based technology stacks and a smooth learning curve.

As a big fan of Enterprise Java Beans (EJBs)  deployed on Red Hat’s JBoss & WildFly Application Servers I have been experimenting writing my EJBs in Kotlin and including them in an existing Java server-side project deployed on RedHat’s WildFly 13.0.0.Final.

We’ll start by creating a simple Kotlin EJB which has a method to print to the WildFly log the ubiquitous “Hello Kotlin World”.

Each method name is preceded with the keyword ‘fun’, for Function. The ‘Unit’ keyword is used to specify that this method is void. The ‘override’ modifier, similar to @Override annotation in Java, is uses to mark methods that override those from the interface. Unlike Java, using  the override modifier is mandatory in Kotlin.

import javax.ejb.LocalBean
import javax.ejb.Stateless

@Stateless
@LocalBean
open class NOTiFYKotlinEJB : NOTiFYKotlinEJBInterface {

    /**
     *
     */
    override fun sayHelloKotlinWorld(): Unit {
        println("***** Hello Kotlin World .....")
    }
}

The local interface for our EJB.

interface NOTiFYKotlinEJBInterface {

    fun sayHelloKotlinWorld() : Unit {}

}

The EJB is call from our Controller. We Inject the Kotlin EJB into the POJO using EE8 standard CDI.

@Path("/")
public class NOTiFYwellController {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Inject
    private NOTiFYKotlinEJB nOTiFYKotlinEJB;

    public NOTiFYwellController() {
    }

    /**
     *
     * @return Response
     */
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    @Path("/say-hello-kotlin-world")
    public Response sayHelloKotlinWorld() {
        logger.info(">>>> sayHelloKotlinWorld nOTiFYEJB = {}", nOTiFYKotlinEJB);

        nOTiFYKotlinEJB.sayHelloKotlinWorld();

        return null; // Just for test
    }
}

We could also convert the ‘Controller’ to Kotlin as well:

@Path("/")
open class NOTiFYwellKotlinController {

    @Inject
    private lateinit var nOTiFYKotlinEJB: NOTiFYKotlinEJB

    @GET
    @Produces(MediaType.APPLICATION_JSON)
    @Path("/say-hello-kotlin-world")
    open fun sayHelloKotlinWorld(): Unit {
        nOTiFYKotlinEJB.sayHelloKotlinWorld()
    }
}

Using Gradle we package everything up into a JAR file, which along with our WAR file is put inside an EAR file. Make sure you include the standard Kotlin library in your Grade Build:

compile group: 'org.jetbrains.kotlin', name: 'kotlin-stdlib', version: '1.2.60'

The EAR file  is deployed onto our JBoss WildFly 13.0.0.Final Application Server using the HAL Management Console.

See Using Gradle in IntelliJ IDEA for your build.

Here the log shows our Kotlin EJB being deployed:

15:59:12,815 INFO  [org.jboss.as.ejb3.deployment] (MSC service thread 1-2) WFLYEJB0473: JNDI bindings for session bean named 'NOTiFYKotlinEJB' in deployment unit 'subdeployment "NOTiFYwellJAR.jar" of deployment "NOTiFYwell.ear"' are as follows:

 java:global/NOTiFYwell/NOTiFYwellJAR/NOTiFYKotlinEJB!com.notifywell.kotlin.ejb.NOTiFYKotlinEJB

 java:app/NOTiFYwellJAR/NOTiFYKotlinEJB!com.notifywell.kotlin.ejb.NOTiFYKotlinEJB

 java:module/NOTiFYKotlinEJB!com.notifywell.kotlin.ejb.NOTiFYKotlinEJB

 ejb:NOTiFYwell/NOTiFYwellJAR/NOTiFYKotlinEJB!com.notifywell.kotlin.ejb.NOTiFYKotlinEJB

 java:global/NOTiFYwell/NOTiFYwellJAR/NOTiFYKotlinEJB

 java:app/NOTiFYwellJAR/NOTiFYKotlinEJB

 java:module/NOTiFYKotlinEJB

We then call our ‘Web Service’ from the JUnit 5 test:

@Test
public final void testSayHelloKotlinWorld() throws Exception {
    System.out.println(">>>>> testSayHelloKotlinWorld .....");

    String url = "http://127.0.0.1:8080/NOTiFYwell/notifywell/say-hello-kotlin-world";

    HttpGet httpGet = new HttpGet(url);
    httpGet.setHeader(CONTENT_TYPE, APPLICATION_JSON);

    // Execute and get the response.
    HttpClient httpClient = HttpClientBuilder.create().build();
    HttpResponse response = httpClient.execute(httpGet);

    System.out.println(">>>>> testSayHelloKotlinWorld response getStatus = " + response.getStatusLine().getStatusCode());
}

In the JBoss WildFly log we can see the ‘logger.info’ message from the Controller and the ‘println’ from the Kotlin EJB.

16:04:04,407 INFO  [com.notifywell.controller.NOTiFYwellController] (default task-1) >>>> sayHelloKotlinWorld nOTiFYEJB = Proxy for view class: com.notifywell.kotlin.ejb.NOTiFYKotlinEJB of EJB: NOTiFYKotlinEJB

16:04:04,417 INFO  [stdout] (default task-1) ***** Hello Kotlin World .....

Whilst it only the simplest of examples it shows how easily an EJB can be converted from Java to Kotlin.

Using Kotlin for Server-side Development

Kotlin is a great fit for developing server-side applications, allowing you to write concise and expressive code while maintaining full compatibility with existing Java-based technology stacks and a smooth learning curve:

  • Expressiveness: Kotlin’s innovative language features, such as its support for type-safe builders and delegated properties, help build powerful and easy-to-use abstractions.
  • Scalability: Kotlin’s support for coroutines helps build server-side applications that scale to massive numbers of clients with modest hardware requirements.
  • Interoperability: Kotlin is fully compatible with all Java-based frameworks, which lets you stay on your familiar technology stack while reaping the benefits of a more modern language.
  • Migration: Kotlin supports gradual, step by step migration of large codebases from Java to Kotlin. You can start writing new code in Kotlin while keeping older parts of your system in Java.
  • Tooling: In addition to great IDE support in general, Kotlin offers framework-specific tooling (for example, for Spring) in the plugin for IntelliJ IDEA Ultimate.

Go on, do some Island hopping.

Leave a Reply

Your e-mail address will not be published. Required fields are marked *