Thursday, July 31, 2008

Stupid Scala Trick: Injecting Methods With Spring

I'm not sure why I came up with this idea, but it occurred to me that since functions are first class objects in Scala then I should be able to inject them as dependencies using the Spring framework. So I decided to give it a try (using constructor injection to make life simple).

First, I need a class that will have a method injected -


class User(val f: String => String) {

def b() = {f("hello")}

}

So, this class will have a method named f (which takes a String and returns a String) injected into it. It also has a method called b, which will use f.

Next up, a function that will be injected.

object func1 extends Function1[String, String] {
def apply(s: String): String = {s.toUpperCase()}
}

This is essentially the same as

def func1(s: String): String = {s.toUpperCase()}

Now, the Spring bean definition xml (which I'll save in a file called app.xml)

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">


<bean id="user" class="User">
<constructor-arg>
<bean class="func1$"/>
</constructor-arg>
</bean>
</beans>


Finally, a small application to fire up spring and test that injection worked


import org.springframework.context.support._

object SpringTest {

def main(args: Array[String]) = {

val context = new ClassPathXmlApplicationContext(Array[String]("app.xml"));
val user = context.getBean("user").asInstanceOf[User]
println(user.b())
println(user.f("world"))
}
}



And here's the output (minus some log4j warnings)


HELLO
WORLD

Friday, July 18, 2008

maven & build-helper

I ran into a little issue with maven and the build-helper plugin today.

The background is as follows - I was part-mavenizing a project (long, boring work related story) and I needed to generate some source code using JAXB (which was a trial in and of itself - we're compiling on Java 1.4 and JAXB hates Java 1.4 - in the end I needed to use antrun to run the 1.0.0 version of xjc) and then have it compile as part of the main compile process. So build-helper to the rescue. The documentation states that you just add the plugin to the build-


...
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>1.1</version>
<executions>
<execution>
<id>add-source</id>
<phase>generate-sources</phase>
<goals>
<goal>add-source</goal>
</goals>
<configuration>
<sources>
<source>some directory</source>
...
</sources>
</configuration>
</execution>
</executions>
</plugin>
...



Note the "some directory" for the source. I was trying to place the generated code into /target/generated-code/java, seeing as the generated code was output and output ends up in /target. It wouldn't work. I tried several variations on a theme, but as long as I kept trying to compile source that lived in target, maven would not see it. In the end, I placed the code in {$basedir}/src/generated/java (ie, in src, not target), pointed build-helper to it and it started to work.

While it works, it does mean I have more work ahead in order to get clean to work as expected.

Thursday, July 17, 2008

Processing/Scala Improvement

I've come up with an improvement to my Processing/Scala combination. Instead of using appletviewer, I've created an application object that fires up Swing and embeds the PApplet.

I first turned to the latest preprint of Programming in Scala which has a chapter dedicated to Scala Swing applications and then rapidly ran into issues. First, it doesn't mention that scala.swing isn't in the standard library (at least, not yet), so I had to track down a jar of version 0.3 and then add it to the classpath. Second, the example code in the book still doesn't work (it complains that += is not a member of Seq[Component] on the code that adds items to the main frame). So I gave up on using scala.swing and turned to the Scala wiki to see how to drive Swing directly. The result is


import javax.swing._

object TestRunner extends JFrame( "Test" )
{
def main( args: Array[String] ) =
{
setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
val t = new Test()
add( t );
t.init()
pack()
setVisible( true );
}
}

Wednesday, July 16, 2008

Combining Scala With Processing

I recently bought a copy of Ben Fry's "Visualizing Data", which explores data visualization (unsurprising, considering the title) using Processing. So, I got the idea of combining Processing with Scala, in order to get Scala's more advanced language features with Processing's easy to use graphics.

The key to combining the two is page 249 of Visualizing Data, which describes how to use Java instead of Processing's own Java like language. It was fairly trivial to convert the Java to Scala -


import processing.core._

class Test extends PApplet {
val bg = 0xFFEECC00

override def setup = {

size(400,400)
}


override def draw = {

background(bg)
line(mouseX, mouseY, width/2.0f, height/2.0f)
}
}


When you compile the code with scalac, you'll need to include Processing's core.jar on the classpath.

As you can probably tell from the processing base class, you end up with a good old fashioned Java applet. As it's been over 10 years since the last time I played with applets, it took a few minutes to get it to work. To cut a long story short, I did the following:

1) jar Test.class
2) copy core.jar from Processing into the current directory
3) copy scala-library.jar from Scala into the current directory
4) create a HTML file with the following:

<APPLET CODE=Test.class WIDTH=500 HEIGHT=500 ARCHIVE="Test.jar, core.jar, scala-library.jar">
</APPLET>

5) finally, start appletviewer:

appletviewer test.html


I'm certain there's a better way to package it all up, but like I said, it's been years since I played with applets.