The intersection of technology and leadership

Category: Scala

Constructor work in Scala

In the java/ruby world, I am used to ensuring my objects are created in a valid state. This often means validating/converting constructor arguments into a format necessary for the rest of the class to do its work. In java, the code (non-compilable) might look like:

public class MyObject {
  ...

  public MyObject(Set<String> values) {
     this.internalRepresentation = convertToLowerCase(values)
  }

  ...
}

In scala, most examples out there seem to only chain constructors, and not necessarily do any work to that. I looked on stackoverflow and found this answer although it doesn’t feel particularly clean to me for some reason. My scala code now looks like this:

class MyObject(var values: Set[String]) {
  values = values.map(s => s.toLowerCase)
  ...
}

What I don’t like about this is that I had to elevate my field to being mutable, or had to have two immutable fields on the class (the temporary one for the constructor, and the one that I really want to use). The tests are passing, but I’m sure there is a better way.

International character encodings and Winstone

I’m writing a little web application to help me learn some German (yeah, a bit of yak-shaving) and I wanted to deploy it locally using an executable jar. I wrote about how to do this previously using winstone and that worked pretty well. Unlike dealing with a normal English character set, dealing with letters like ß, Ä, Ü and Ö are pretty important.

It looks like, by default, serving static HTML from winstone doesn’t seem to work unless you explicitly specify the character encoding as UTF-8. A simple web-filter applied to all URLs helps us here. Here’s an example in scala:

import javax.servlet._

class ForceUtf8EncodingFilter extends Filter {
  def doFilter(request:ServletRequest, response : ServletResponse, chain: FilterChain) {
    response.setCharacterEncoding("UTF-8")
    chain.doFilter(request, response)
  }

  def init(config: FilterConfig) { }

  def destroy() { }
}

Adding toSortedSet on Seq in Scala

We recently wanted to do some transformation on our small XML document in order to present some information on it. In this example, our example looks like this:

&lt;basket&gt;
  &lt;item cost=&quot;.99&quot; discountCode=&quot;A5&quot;&gt;Last year's red Christmas baubles&lt;/item&gt;
  &lt;item cost=&quot;.10&quot; discountCode=&quot;A5&quot;&gt;Halloween lamps&lt;/item&gt;
  &lt;item cost=&quot;101.99&quot; &gt;Pine Tree&lt;/item&gt;
  &lt;item cost=&quot;20&quot; discountCode=&quot;B2&quot;&gt;Gold star&lt;/item&gt;
&lt;/basket&gt;

It’s a pretty simple structure with some simple rules. A basket can contain one or more items. Each item has:

  • A simple description
  • A cost in dollars
  • An optional discount code

The task we had was to display a list of human-readable discounts that had been applied to this particular basket. In the example given about the discount codes are A5 and B2.

We have a very simple list of known discounts, and can implement a simple conversion function:

object Discounts {
  def displayString(code : String): String = {
    code match  {
      case &quot;A5&quot; =&gt; &quot;Reduced to clear&quot;
      case &quot;B2&quot; =&gt; &quot;Pre-Christmas offer&quot;
    }
  }
}

We already had a class that wrapped this small XML document, creating a cached field for the item nodes.

class Basket(val rootNode: Node) {
  private lazy val items = (rootNode \ &quot;item&quot;);
}

We can then apply a series of functions to convert the items:

class Basket(val rootNode: Node) {
  private lazy val items = (rootNode \ &quot;item&quot;);

  lazy val discountsApplied = 
    items.map(item =&gt; item.attribute(&quot;discountCode&quot;)
         .map(attribute =&gt; displayString(attribute.text)))
         .flatten
}

The above code pulls out all the “discountCode” attributes, and applies a conversion function to convert them to human-readable form. Since item.attribute returns an Option, we use flatten to get rid of elements that are essentially null.

Unfortunately, while there is a toSet method, and a list, there isn’t a great way to do both inbuilt. However, by constructing a TreeSet (a sorted set), we can append all the results and get the same effect. We end up with the following:

class Basket(val rootNode: Node) {
  private lazy val items = (rootNode \ &quot;item&quot;);

  lazy val discountsApplied = sortedUniqueSet(
    items.map(item =&gt; item.attribute(&quot;discountCode&quot;)
         .map(attribute =&gt; displayString(attribute.text)))
         .flatten)

  private def sortedUniqueSet(sequence: Seq[String]) = {
    TreeSet.empty[String] ++ sequence
  }
}

String XML interpolation in Scala

In java, if you’re formatting a small XML document, it might be tempting to simply do a String.format to substitute it directly into a string. Transitioning into scala, this is then easy to convert into one of their XML representations with XML.loadString. You might very well end up with code that looks like this:

val myValue = "will be substituted"
val xml = XML.loadString(String.format("<node>%s</node>", node))

You can actually just do this inline with scala directly, and end up with this instead

val myValue = "will be substituted"
val xml = <node>{myValue}</node>

Neat-o!

Running Scalatra Tests with JUnit (in a maven or ant build)

I’ve been playing around with Scalatra and one of the things that wasn’t quite obvious was when I had it running as part of a test run build (using the JUnit) runner, these tests weren’t getting picked up.

The key to this was ensuring you annotate the class with the @RunWith(classOf[JUnitRunner]) attribute as part of the build.

package com.thekua.scala.example

import org.scalatra.test.scalatest.ScalatraFunSuite
import org.scalatest.matchers.ShouldMatchers
import org.scalatest.junit.{JUnitRunner, JUnitSuite}
import org.junit.runner.RunWith

@RunWith(classOf[JUnitRunner])
class JsonScalatraTest extends ScalatraFunSuite with ShouldMatchers {
  val servletHolder = addServlet(classOf[JsonifiedServlet], &quot;/*&quot;)
  servletHolder.setInitOrder(1) // force load on startup

  test(&quot;JSON support test&quot;) {
    get(&quot;/&quot;) {
      status should equal (200)
    }
  }
}

Smooth Scala XML APIs

As an alternative to using JAXB for reading input, we thought we’d try simply wrapping an XML document in a class structure. XML is a first class citizen in scala, so we thought we’d have a look at what it would be. Note that we don’t expect very large XML documents (they all easily fit into memory) but the external structure is a little bit ugly.

We inject the XML document into the class via the constructor and then using scala X-Path equivalents, we pull out the interesting fields. I have to admit it’s better than dealing with XML xpath in the java world, and the code is pretty simple.

I’ve written an equivalent to give you an idea of what we evolved from.

Given we have an XML document that looks like this (domain made up here)

&lt;profile&gt;
  &lt;names&gt;
     &lt;defaultName&gt;Harry Potter&lt;/defaultName&gt;
     &lt;alternativeNames&gt;
        &lt;name&gt;Harry&lt;/name&gt;
        &lt;name&gt;Mr Potter&lt;/name&gt;
     &lt;/alternativeNames&gt;
  &lt;/names&gt;
  &lt;contact&gt;
     &lt;email&gt;harry.potter@hogwarts.com&lt;/email&gt;
     &lt;website&gt;http://hogwarts.com&lt;/website&gt;
     &lt;phone&gt;http://hogwarts.com&lt;/phone&gt;     
  &lt;/contact&gt;
&lt;/profile&gt;

We ended up with a class that looks like this

import xml.Node
class Profile (xml: Node) {
  def name = {
    (xml \ &quot;names&quot; \ &quot;defaultName&quot;).text
  }

  def email = {
    (xml \ &quot;contact&quot; \ &quot;email&quot;).text
  }

  def website = {
    (xml \ &quot;contact&quot; \ &quot;website&quot;).text
  }

  def phone = {
    (xml \ &quot;contact&quot; \ &quot;phone&quot;).text
  }
}

We can apply a couple of small refactorings here. Simple one line expressions do not need curly braces. The class now becomes:

import xml.Node
class Profile (xml: Node) {
  def name =  (xml \ &quot;names&quot; \ &quot;defaultName&quot;).text
  def email = (xml \ &quot;contact&quot; \ &quot;email&quot;).text
  def website = (xml \ &quot;contact&quot; \ &quot;website&quot;).text
  def phone = (xml \ &quot;contact&quot; \ &quot;phone&quot;).text
}

Maybe we also wanted to remove a little bit of duplication in the xpath. Though this increases the size of the class a bit:

import xml.Node
class Profile (xml: Node) {
  def name =  (xml \ &quot;names&quot; \ &quot;defaultName&quot;).text
  def email = (contact \ &quot;email&quot;).text
  def website = (contact \ &quot;website&quot;).text
  def phone = (contact \ &quot;phone&quot;).text

  private def contact = (xml \ &quot;contact&quot;)
}

Since our XML structure will now change, we also had some feedback that we could use the lazy val option to cache the results. The code now looks like this:

import xml.Node
class Profile (xml: Node) {
  lazy val name =  (xml \ &quot;names&quot; \ &quot;defaultName&quot;).text
  lazy val email = (contact \ &quot;email&quot;).text
  lazy val website = (contact \ &quot;website&quot;).text
  lazy val phone = (contact \ &quot;phone&quot;).text

  lazy val contact = (xml \ &quot;contact&quot;)
}

I’m not so sure if the last two refactorings give much more than the second refactoring, but it certainly helped me learn a a bit more scala. I think we had some pretty good wins by dealing with XML the scala way. Our tests are very readable because you don’t have weird string concatenation or sucking in XML from a file to test it, and I think the code is quite readable. I would have preferred closer XPath-y syntax, but I guess learning the scala XML syntax for traversing XML isn’t too bad. The other good thing about this is that you don’t have to worry about null or non existant nodes – you simply get back an empty string. Pretty decent default behaviour for at least our use case.

© 2024 patkua@work

Theme by Anders NorenUp ↑