Using Vaadin 7 With Clojure

There are some good examples on how to compose a web application with Clojure and Vaadin < 7. However, the web application bootstrapping process has changed for Vaadin 7. In this post I will show you how to create a Clojure/Vaadin 7 web application.

First we need a web.xml file in src/main/webapp/WEB-INF that defines the Vaadin servlet and parametrizes it with our main UI 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
25
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
  version="2.5">
    <display-name>Clojure Vaadin 7 Application</display-name>
    <context-param>
        <description>Vaadin production mode</description>
        <param-name>productionMode</param-name>
        <param-value>false</param-value>
    </context-param>
    <servlet>
        <servlet-name>Clojure Vaadin 7 Application</servlet-name>
        <servlet-class>com.vaadin.server.VaadinServlet</servlet-class>
        <init-param>
            <description>Vaadin UI</description>
            <param-name>UI</param-name>
            <param-value>cljvaadin7.MyApplicationUI</param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>Clojure Vaadin 7 Application</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>
</web-app>

As there is no such thing as a class in Clojure, we will use its Java interoperability to create a Java class that serves as our Vaadin UI main class.

1
2
3
4
(ns cljvaadin7.MyApplicationUI
  (import [com.vaadin.ui VerticalLayout Label Button Button$ClickListener Notification])
  (:gen-class
    :extends com.vaadin.ui.UI))

:gen-class will make the namespace available as a Java class.

We override the init method of com.vaadin.ui.UI. This is the entry point for our web application. init in com.vaadin.ui.UI has only one argument (request). However, our Clojure -init function has two arguments. The reason is that the function will receive “this” as the first argument. Now we can build our UI.

1
2
3
4
5
6
7
8
9
10
11
12
13
(defn- create-button
  [caption action]
  (doto (Button. caption) (add-action action)))

(defn- create-main-layout
  []
  (doto (VerticalLayout.)
          (.addComponent (Label. "Hello Clojure-Vaadin 7!"))
          (.addComponent (create-button "Push me!" show-click-message))))

(defn -init
  [main-ui request]
  (doto main-ui (.setContent (create-main-layout))))

In Java, button actions are triggered by registering a click handler for the button. We have to do this in Clojure as well but we will hide the actual ClickListener and use a more functional approach. We create a new function add-action that expects a button and an action as arguments. action can be any Clojure function we want to be executed when the button is clicked. The helper function create-button-click-listener wraps a Vaadin ClickListener around the action function.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
(defn- show-click-message
  []
  (Notification/show "Button clicked"))

(defn- create-button-click-listener
  [action]
  (reify Button$ClickListener
            (buttonClick
              [_ evt]
              (action))))

(defn- add-action
  [button action]
  (.addListener button (create-button-click-listener action)))

The project file for building with Leiningen (and packaging with Maven) looks like this:

1
2
3
4
5
6
7
8
9
10
11
(defproject cljvaadin7 "0.1.0-SNAPSHOT"
  :description "Demonstrates how to integrate Clojure and Vaadin 7"
  :url "https://github.com/codebrickie/cljvaadin7"
  :license {:name "Eclipse Public License"
            :url "http://www.eclipse.org/legal/epl-v10.html"}
  :dependencies [[org.clojure/clojure "1.4.0"]
                 [com.vaadin/vaadin-server "7.0.0"]
                 [com.vaadin/vaadin-client-compiled "7.0.0"]
                 [com.vaadin/vaadin-themes "7.0.0"]
                 [javax.servlet/servlet-api "2.5"]]
  :aot [cljvaadin7.MyApplicationUI])

You can find the complete project on GitHub.

Comments