Coming Up for Air

Kotlin Faces

Thursday, October 29, 2015 |

There’s a chance that at least some of you saw the blog title and thought: "Ah ha! A Kotlin wrapper/helper for JSF!" and rushed over to check it out. If so, mission accomplished. :) This really isn’t anything that ambitious. Sorry. :)

At JavaOne this week, I spent a good deal of time talk to Hadi Hariri, Developer Advocacy Team Lead at JetBrains, about their Kotlin language. With my long background in Java webapps, I often reach for my webapp hammer when trying to learn a new language, so I asked Hadi what Kotlin library he would suggest. His answer, in a nutshell, was that the Java interop in Kotlin is so good, just use whatever you want, so I thought I’d put that to the test with a really simple JSF app. Here it is. First things first, you will probably want to use IntelliJ IDEA to help with the Kotlin syntax. Also being from JetBrains, IDE support is first rate. :) Before we get to the actual Kotlin, let’s get some minor details out of the way. First, the pom.xml:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
                        http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.steeplesoft</groupId>
    <artifactId>KotlinFaces</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <name>KotlinFaces</name>

    <properties>
        <endorsed.dir>${project.build.directory}/endorsed</endorsed.dir>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <kotlin.version>1.0.0-beta-1038</kotlin.version>
    </properties>
    <repositories>
        <repository>
            <id>sonatype.oss.snapshots</id>
            <name>Sonatype OSS Snapshot Repository</name>
            <url>http://oss.sonatype.org/content/repositories/snapshots</url>
            <releases>
                <enabled>false</enabled>
            </releases>
            <snapshots>
                <enabled>true</enabled>
            </snapshots>
        </repository>
    </repositories>

    <pluginRepositories>
        <pluginRepository>
            <id>sonatype.oss.snapshots</id>
            <name>Sonatype OSS Snapshot Repository</name>
            <url>http://oss.sonatype.org/content/repositories/snapshots</url>
            <releases>
                <enabled>false</enabled>
            </releases>
            <snapshots>
                <enabled>true</enabled>
            </snapshots>
        </pluginRepository>
    </pluginRepositories>

    <dependencies>
        <dependency>
            <groupId>javax</groupId>
            <artifactId>javaee-web-api</artifactId>
            <version>7.0</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.jetbrains.kotlin</groupId>
            <artifactId>kotlin-stdlib</artifactId>
            <version>${kotlin.version}</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <artifactId>kotlin-maven-plugin</artifactId>
                <groupId>org.jetbrains.kotlin</groupId>
                <version>${kotlin.version}</version>

                <executions>
                    <execution>
                        <id>compile</id>
                        <phase>process-sources</phase>
                        <goals>
                            <goal>compile</goal>
                        </goals>
                    </execution>

                    <execution>
                        <id>test-compile</id>
                        <phase>process-test-sources</phase>
                        <goals>
                            <goal>test-compile</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <compilerArguments>
                        <endorseddirs>${endorsed.dir}</endorseddirs>
                    </compilerArguments>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>2.3</version>
                <configuration>
                    <failOnMissingWebXml>false</failOnMissingWebXml>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

Pretty standard with the exception of the kotlin-maven-plugin and Kotlin runtime configuration and related repository entries. You’ll need one for the plugin, and another for runtime libs. Next, the Facelets page:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html">
    <h:head>
        <title>JSF+Kotlin Example</title>
    </h:head>
    <h:body>
        <h2>JSF+Kotlin Example</h2>
        <h:form>
            <p>Text from a Kotlin-based bean: #{myBean.text}</p>
            <h:inputText value="#{myBean.text}"></h:inputText>
            <h:commandButton value="Change Me"></h:commandButton>
        </h:form>
    </h:body>
</html>

Nothing unusual there. And now, the moment we’ve all been waiting for: The Kotlin-based managed bean:

1
2
3
4
5
@Named
@SessionScoped
class MyBean : Serializable {
    var text = "My Text"
}

That’s it. It’s a really dumb bean, but here’s an explanation:

  1. There are no parameters declared with the class, so we get a no arg ctor. This may or may not be idomatic Kotlin, but it’s good enough here. :)

  2. There’s a single property, text, defined. We give it a default value of "My Text" which also allows the compiler to infer the type, String.

  3. We are using Java EE annotations, @Named and @SessionScoped, seamlessly. Just add the imports and move along.

And…​ that’s it. Build the app (mvn package) and deploy to your favorite container and see it in all of its glory. Not an exciting app, but that I can make it work with a Kotlin-based class with minimal extra work (just a build tweak) is really cool. With a proof-of-concept done, it’s time to try something more complex, but that’s a story for another time. :)

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