Posts Tagged ‘spring mvc’

Writing a Spring MVC macro in Clojure (part 2)

January 2, 2010

In a previous post, we wrote a Clojure program that implemented two very simple Spring MVC Controllers. The program contained 15 lines of (mainly boilerplate) code. We’ll reduce that to the following:

(ns com.vxcompany.clojuremvc.example
  (:use com.vxcompany.clojuremvc.mvcmacro))

(defmapping com.vxcompany.clojuremvc.MyMapping

  ("/index.html"
    [:index {:info "Life's so much cooler with macros!"}])

  ("/another.html"
    [:another {:info "It's really cooler!"}]))

In part 1 of this manual, we already made a first step. Now, let’s glue the pieces together.

I’m sorry, I lied

My first version of the MVC macro does NOT work. When trying, it went fine when I used the macro within the same jar. It also went fine, when I first expanded the macro manually (macroexpand ‘(defmapping …)). But when I compiled one project with an unexpanded (defmapping), and tried to use that mapping from another project: BAM! The JVM complained that it could not find a method postinit31.

The very short summary is, that in the very special case of (genclass), the macro is expanded at different times. (gensym) might evaluate to different values. And if it does, the JVM looks for postinit33, where it may have been generated as postinit29. So, we should not use (gensym) for generating method names! See also the more detailed explanation here.

To ensure unique method names, we’ll do something else. The post-init method for a mapping com.foo.MyMapping will be -MyMapping-postinit. The following code strips the fully qualified class name:

(defn strip
  "Takes the substring of a string, starting at the index returned by
   the application of (function string)."
  [string function]
  (.substring string (function string)))

;;; with the above function, this does it:
(strip (str name) #(inc (.lastIndexOf % ".")))

Making things more Clojurish

We can now take the macro we created in part 1 of the manual, and paste some code into the post-init method, so the class actually contains the mapping. For each mapping above (index.html and another.html), we’ll generate the necessary boilerplate code, and let Clojure paste the url, view name and model in it. We’ll do that in a moment.

First, let’s make things just a little bit nicer. In the original Clojure MVC controller, we used plain strings as keys for the model (“info”). Spring MVC indeed needs strings for the keys. However, in Clojure, we can also use keywords (:info). Can’t we use keywords in our own code, and let the macro convert the keyword into a string?

This function converts any value to a string. If the value is a keyword, the name of the keyword is returned. Otherwise, a default string conversion is done. We used (cond) instead of (if), so we can easily add more cases later. The last case, true, is an easy way to specify a default case.

(defn tostr
  "Replaces the value by a string, e.g. :a becomes \"a\"."
  [val]
  (cond
    (instance? clojure.lang.Keyword val) (name val)
    true (str val)))

The next function takes a map (in our case, the model) and does the above conversion to each key in a map. Idiomatic for functional languages, we made the function recursive:

(defn keys-to-strings
  "Takes a map and converts its keys into strings, e.g. {:a 1} becomes {\"a\" 1}"
  [a-map]
  (loop [restmap a-map acc {}]
    (if (empty? restmap)
      acc
      (let [[key val] (first restmap)]
        (recur (rest restmap) (conj acc [(tostr key) val]))))))

The macro

With the above adjustments, the macro now becomes:

(defmacro defmapping
  "Defines a Spring MVC URL mapping. See example at
   https://groovyguts.wordpress.com/2010/01/02/writing-a-spring-mvc-macro-in-clojure-part-2/"
  [name & body]
  (let [this (gensym "this")
        shortname (strip (str name) #(inc (.lastIndexOf % ".")))]
    `(do
       (defn ~(symbol (str "-" shortname "-postinit")) [~this]
         ~@(for [[url handler] body]
             `(.registerHandler ~this ~url
                 (proxy [AbstractController] []
                   (handleRequestInternal [request# response#]
                     (let [[view# model#] ~handler]
                       (ModelAndView. (tostr view#) (keys-to-strings model#))))))))
       (gen-class
         :name ~name
         :extends
         org.springframework.web.servlet.handler.AbstractUrlHandlerMapping
         :post-init ~(str shortname "-postinit")
         ))))

The for loop adds all the boilerplate code for each mapping in our definition. Note we have to splice ~@, because for returns a single list of statements. We need the separate statements instead of the list. Also note how we fill in the ~url, view# and model# in the template code.

With this macro, we can specify the mapping as we did at the top of this post.

Did we really need a macro?

There’s one question I didn’t answer. Did we really need a macro? Writing macros is more difficult than writing functions. The rule is: use functions if you can. Use macros only if you cannot do the same thing with functions only.

In this case, we clearly need a macro. There is code in the macro, we only want to evaluate AFTER the macro has been expanded. Take the (gen-class) specification. (gen-class) is evaluated at compile time! Functions are not evaluated at compile time! Putting (gen-class) within a function instead of a macro, would have caused very strange effects. Also, we’re passing parameters to the macro (e.g. a class name), that we don’t want to evaluate before calling the macro. Function parameters are always evaluated before the function is called.

So in this case it’s clear. But don’t forget to always ask yourself if you really need a macro, before writing one!

Summary

We showed how powerful macros are. The original 15 line UrlMapperHandler code, was reduced to a few lines only, that express the intention of the code much better. Of course, this took some effort. We had to write a macro. But we can reuse the macro each time we need it. And the actual code is much cleaner! In Java, doing the same thing would definitely have been more difficult!

Writing a Spring MVC macro in Clojure (part 1)

December 25, 2009

In a previous post I wrote how to write Spring MVC Controllers in Clojure. The result worked, but contained a lot of boilerplate code. Boilerplate code may be an essential part of a Java program, but in Clojure it certainly isn’t. In fact, because of Lisp’s powerful macro system, in Clojure we can eliminate boilerplate code completely! How? Let’s find out, by writing a macro for creating a Spring MVC controller class.

Macros: a very short introduction

In Lisp, there is no fundamental distinction between data structures and programs. Programs work on data structures. Programs create data structures, read data structures and manipulate data structure. But a Lisp program in itself is also a data structure. Consider the following program:

(* (+ 1 1) 2)

The program is a list (or a Lisp form) with three elements. The first element, *, is the operator. The other elements are parameters to the operator. The second element is another list, that can be decomposed the same way.

Since a program is a list, we can use normal list operators to manipulate it. The following expression replaces the 2 by a 3 in the above expression.

(replace {2 3} '(* (+ 1 1) 2))

Why is this so powerful? In Lisp, like any other programming language, you can write a function that operates on data structures. But since in Lisp programs are also data structures, you can manipulate Lisp code in exactly the same way as data. This makes it possible to extend the language, in ways you’d never thought were possible. In Java, you had to wait for years until they finally built in an extended for loop. In Lisp? You’d have extended the language yourself with just a few lines of code. How? You’d have written a macro.

A macro is like a function, but different. A function returns a value. A macro returns a piece of executable code, that is then evaluated.

The parameters to a function are first evaluated and then passed to the function. The parameters to a macro are first passed to the macro. The macro manipulates the parameters and transforms them into (another) piece of executable code. The return value of the macro is evaluated by Lisp.

Macro evaluation goes in two steps:

  1. Macro expansion: the macro is executed and returns a piece of Lisp program
  2. Evaluation: the piece of Lisp program returned by the macro is interpreted by the compiler and executed

Generating the class

Let’s start with generating an empty subclass of the Spring AbstractUrlHandlerMapping. The macro extension will exist of a (gen-class) command, that generates a class at compile time. The name of the class will be a parameter to the macro. We will write the macro in such a way that

(defmapping com.my.Mapping)

defines an (empty) subclass com.my.Mapping of AbstractUrlHandlerMapping.

The basic steps for writing a macro are easy:

  1. Backquote ` the code template you want to generate.
  2. Escape ~ the macro parameters in the code template.
  3. Write code that performs the actual transformations on the code (this is the tough part!)

Let’s apply the first two steps.

(defmacro defmapping [name]
  `(gen-class
    :name ~name
    :extends org.springframework.web.servlet.handler.AbstractUrlHandlerMapping))

(defmapping com.my.Mapping)

(defn -main []
  (println (com.my.Mapping.)))

The backquoted (`) code is returned literally by the macro. Except the ~name. The ~ character tells Clojure that name, unless the rest of the code, should actually be evaluated when generating the macro expansion. To see the result of the macro expansion, type (macroexpand ‘(defmapping com.my.Mapping)) at the REPL.

Adding post-init

Now, let’s make the class actually do something when it’s constructed. We want the macro to return two Lisp forms:

  1. A definition of the -post-init function, and
  2. the above form, that defines the class and refers to the post-init function

However, a macro, like a function, can only return one form. Therefore, we have to wrap the two forms in a (do).

The naive approach would be just to add the post-init method:

(defmacro defmapping [name]
  `(do
    (defn -post-init [this]
      (println "in init"))
    (gen-class
      :name ~name
      :extends org.springframework.web.servlet.handler.AbstractUrlHandlerMapping
      :post-init post-init)))

However, when we compile this, it yields a “Can’t refer to qualified var that doesn’t exist”. What is happening?

Macros in Common Lisp are vulnerable for a mistake called variable capture. Suppose that you wrote a macro that expands to code that uses a variable foo. Suppose that someone else uses the macro within a piece of code, that also uses the variable foo. When the macro is expanded, the piece of code and the macro expansion may interoperate in unintended ways. This is a dangerous and common mistake in Common Lisp.

Clojure protects you from this error. Each symbol you use in a Clojure macro must refer to an existing, qualified name. Otherwise, you’ll get errors like “Can’t intern namespace-qualified symbol” or the error above.

Luckily, the solution is easy. To make sure that variable capture doesn’t occur, you have to let Clojure generate the symbol names for you. You can do this in two ways:

  • Extend the name in your macro code with #. Clojure will generate a unique name, that won’t collide with names in code that’s using the macro. In our example, we will use this# instead of this.
  • Use an explicit (gensym) command. (gensym) generates a new unique symbol for you, that you can assign to a variable and use in your macro. Because we need the post-init symbol in two different occurrences (-post-init and post-init), we will use this approach for
    post-init.

Our code now becomes:

(defmacro defmapping [name]
  (let [post-init (gensym)]
    `(do
       (defn ~(symbol (str "-" post-init)) [this#]
         (println "in init"))
       (gen-class
         :name ~name
         :extends org.springframework.web.servlet.handler.AbstractUrlHandlerMapping
         :post-init ~post-init
         ))))

Note the following things:

  • The first command, (let [post-init (gensym)] is NOT within the back quote. Therefore, this code is actually evaluated at macro expansion time. The command defines a variable binding post-init, that exists at macro expansion time only.
  • (str “-” post-init) builds a string that prefixes the generated name for the post-init method with a minus. (symbol) translates the string back into a Clojure symbol that can be used within a (defn). Because it is the RESULT of this expression that must be inserted in the macro expansion, and not the expression itself, we escape it with a ~.
  • Just like ~name, we also prefix ~post-init. We do not want the literal value “post-init” as the name of our post-init method, but the value of the post-init variable.
  • All other code within the back quote is returned by the macro literally, and evaluated after returning from the macro.

What’s next?

We created a macro that generates a subclass of AbstractUrlHandlerMapping with a parameterisable name. I explained why macros are so powerful. And I showed you the basic concepts how you create a macro.

The macro itself doesn’t do much yet. In a next post, we’ll add functionality to the class. I’ll show you how you can easily eliminate all the boiler plate code, by just specifying it once and forever in a single macro.