DaedTech

Stories about Software

By

JUnit Revisited

Just as a warning, in this short post, I’m going to be writing unit tests that verify that primitives in Java do what they should and basically that gravity is still turned on. The reason for that is that I’d like to showcase some new Java unit testing goodies I’ve recently discovered since coming back into the Java fold a little here and there lately. I firmly believe that the more conversationally readable the contents of unit tests are, the more effective they will be at defining functional and internal requirements as well as showcasing the behavior of the system.

@Test
public void two_ints_are_equal() {
	int x = 4;
	int y = 4;
	assertThat(x, is(y));
}

Coming from the .NET world and using MSTest, I’m used to semantics of Assert.AreEqual<int>(x, y) where, by convention, the “control” or expected value goes on the left and the actual value goes on the right. This is a compelling alternative in that it reads like a sentence, which is always good. The MSTest version reads “Are equal x and y” whereas this reads “x is y.” The less it reads like Yoda is talking, the better. So what enables this goodness?

import static org.junit.Assert.assertThat;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.not;
import static org.junit.matchers.JUnitMatchers.*;

The first import gives you assertThat(), obviously. assertThat() as shown above takes two parameters (there is an overload that takes a string as an additional parameter to let you specify a failure message): a generic type for the first parameter, and a “matcher” for the second parameter. Matchers perform evaluations on types and can be chained together in fluent fashion to allow construction of sentences that flow. For instance, you can chain the is() matcher and the not() matcher to get the following test:

@Test
public void two_ints_are_not_equal() {
	int x = 4;
	int y = 5;
	assertThat(x, is(not(y)));
}

This really just scratches the surface and there are lots of additional matchers from hamcrest as well. You can even extend the functionality by defining your own matchers to cater to the ubiquitous language of the domain that you’re using. This just barely scratches the surface, but if you’re a java developer and haven’t given these a look, I’d suggest doing so. If you’re a .NET developer, it’s worth taking a peek at what’s going on elsewhere and perhaps defining your own such constructs if you’re feeling ambitious or looking for existing ones. In fact, if you know of good ones, please post ‘em — I always like seeing what’s out there.

By

Programatically Filling Out PDFs in Java

I just got done dealing with an interesting problem. I had one of those PDFs that’s a form you can fill out and was tasked with programatically filling it out. So, I busted out my google-fu and came across PDFBox. It’s a handy and fairly no-nonsense little utility not just for filling out forms, but for manipulating PDFs in general. I had no idea something like this existed (mainly because I’d never really thought about it).

I downloaded the jar for PDFBox and wrote a simple class to test out my theory. In setting up the class and poking around randomly in the documentation, I saw that the main object of interest was a PDDocument. So, I set about instantiating one and discovered that you needed to use something called a COSDocument, which took something called a RandomAccess (not the standard version of the file, but a special version from PDFBox), and then my eyes started to cross and I pulled back and discovered that this is really what I want:

Much easier. Now, as I got down to business of trying this out, I discovered via runtime exception that I needed two external dependencies. One was apache commons logging and the other was something called fontbox that was right there along with the PDFBox download, but I ignored in the beginning. Probably with this code alone you wouldn’t necessarily hit both of those problems, but you will eventually, so better to add those jars right up front.

So far I was able successfully to open a PDF and save it as another file, which isn’t exactly a new capability for any programming language with file I/O, so I added something a little more concrete to the mix:

Lo and behold, liftoff. I actually got the right number of pages in the document. Now I was getting somewhere. Time to get down to the real business. I did this by going to the “Cookbook” section of the project and seeing what was under form generation. Seeing that this just took me to the javadoc for examples, I went and downloaded the example code and pasted it into my project (modifying it to conform to the Egyptian-style braces. In this fashion, I had a method that would print out all of the fields in the PDF as well as a method that would let me set fields by name. When I ran the one that printed out all of the fields, I got a runtime exception about some deprecated method and I discovered that in the source code for that method, it just threw an exception. Presumably, the written examples predated some change that had deprecated that method — deprecated it with extreme prejudice!

Well, I’d like to say that I fought the good fight, but I didn’t. I just deleted the offending call since it was just writing to console. So here is the end result of that effort:

Going forward, I’ll certainly factor this into a new class and probably extract some methods and improve warning avoidance, but that’s the gist of it. This didn’t exactly take a long time, but it probably could have gone quicker if I’d known a little more up-front and had all example code in one place. Hopefully it helps you in that capacity.

By

Faking Tomcat Support in IntelliJ IDEA Community Version

A while back, I blogged about my switch from Eclipse to the community (free) version of IntelliJ IDEA. After that, I went on a number of trips out of town, felt out the job market a bit, and generally engaged in a series of activities that have kept me too busy to work on my home automation. In the last week, however, that’s changed and I’ve revisited it.

The first thing that I decided to do was play with Ant a bit to create an environment where I could build and run the application locally. I’m in a bit of a catch-22 with IntelliJ at the moment. I might be interested in purchasing the Ultimate Edition, but not before I take it out for a few months and kick the tires. But, in order to do that without pain, I kind of need the server support for what I’m doing, which is only available in Ultimate. So, I’m faking it. I created the following Ant build.xml:

<?xml version="1.0" ?>
<project name="Daedalus" default="war">

    <path id="compile.classpath">
        <fileset dir="WebContent/WEB-INF/lib">
            <include name="*.jar"/>
        </fileset>
    </path>

    <target name="init">
        <mkdir dir="build/classes"/>
        <mkdir dir="dist" />
    </target>

    <target name="compile" depends="init" >
        <javac destdir="build/classes" debug="true" srcdir="src">
            <classpath refid="compile.classpath"/>
        </javac>
    </target>

    <target name="war" depends="compile">
        <war destfile="C:\program files\Tomcat 6.0\webapps\Daedalus.war" webxml="WebContent/WEB-INF/web.xml">
            <fileset dir="WebContent"/>
            <fileset dir="src"/>
            <lib dir="WebContent/WEB-INF/lib"/>
            <classes dir="build/classes"/>
        </war>
        <exec executable="C:\program files\Tomcat 6.0\bin\startup.bat"/>
        <property name="browser" location="C:/Documents and Settings/Erik/Local Settings/Application Data/Google/Chrome/Application/chrome.exe"/>
        <exec executable="${browser}" spawn="true">
            <arg value="http://localhost:8080/Daedalus/"/>
        </exec>
    </target>

    <target name="clean">
        <delete dir="dist" />
        <delete dir="build" />
    </target>

</project>

The other build targets are somewhat standard, if memory serves (I was never particularly adept with Ant, and now I’m several years removed from using it). But, the interesting one is the “war” target, which I’m probably going to rename here shortly. This first compiles the project into a deployable WAR file and plops it into the local Tomcat webapps directory, which is where the it needs to be for me to run it locally in a browser.

With that in place, I’ve added the next line, which starts the web server. In the way I invoke it, a command window pops up, and I can stop the server by closing it. Once the server is started, I launch chrome to the URL where the application will be. This works, but I’d like to refine it a bit. Here are some things that I think should happen:

  1. First of all, DRY isn’t just for code. I’m defining “Daedalus.war” and “http://localhost:8080/Daedalus” and if I decide to change the deployable name, there are two failure points. I’m going to correct that.
  2. And, as long as I’m changing the “destfile” property of the war file, I might as well define a descriptive constant for the Tomcat webapps directory.
  3. Secondly, “browser” isn’t a particularly good property name for Chrome, so I’m going to rename it.
  4. Along those same lines, I’m going to create a property for Internet Explorer as well
  5. I’m also going to create build targets for chrome and internet explorer so that I can choose which one to run without modifying the build.xml file.
  6. Finally, I’m going to decouple the building of the War from the starting of the server and decouple both of those from opening a browser. That way I won’t have to repeat myself in the internet explorer and chrome versions.

Here’s what it looks like now:

<?xml version="1.0" ?>
<project name="Daedalus" default="runChrome">

    <property name="chrome" location="C:/Documents and Settings/Erik/Local Settings/Application Data/Google/Chrome/Application/chrome.exe"/>
    <property name="iexplorer" location="c:/Program Files/Internet Explorer/iexplore.exe"/>
    <property name="tomcatHome" location="C:/program files/Tomcat 6.0"/>
    <property name="webroot" location="${tomcatHome}/webapps"/>
    <property name="tomcatServerStart" location="${tomcatHome}/bin/startup.bat"/>
    <property name="localWebServer" location="http://localhost:8080"/>

    <property name="deploymentTargetName" value="Daedalus"/>

    <path id="compile.classpath">
        <fileset dir="WebContent/WEB-INF/lib">
            <include name="*.jar"/>
        </fileset>
    </path>

    <target name="init">
        <mkdir dir="build/classes"/>
        <mkdir dir="dist" />
    </target>

    <target name="compile" depends="init" >
        <javac destdir="build/classes" debug="true" srcdir="src">
            <classpath refid="compile.classpath"/>
        </javac>
    </target>

    <target name="war" depends="compile">
        <war destfile="${webroot}\${deploymentTargetName}.war" webxml="WebContent/WEB-INF/web.xml">
            <fileset dir="WebContent"/>
            <fileset dir="src"/>
            <lib dir="WebContent/WEB-INF/lib"/>
            <classes dir="build/classes"/>
        </war>
    </target>

    <target name="startTomcat" depends="war">
        <exec executable="${tomcatServerStart}"/>
    </target>

    <target name="runChrome" depends="startTomcat">
        <exec executable="${chrome}" spawn="true">
            <arg value="http://localhost:8080/${deploymentTargetName}/"/>
        </exec>
    </target>

    <target name="runInternetExplorer" depends="startTomcat">
        <exec executable="${iexplorer}" spawn="true">
            <arg value="http://localhost:8080/${deploymentTargetName}/"/>
        </exec>
    </target>

    <target name="clean">
        <delete dir="dist" />
        <delete dir="build" />
    </target>

</project>

So, I’m relatively pleased with this for the time being. Two small caveats with this approach, though. The first is that I don’t really like duplicating the “http://localhost:8080″ as the server’s localhost, but I’m unlikely ever to change this, and if I abstract that out to a constant, it fails for some reason that I haven’t seriously looked into (and realistically, probably won’t for now). The second is that I start the server, but you have to manually stop it. That’s kind of ick, but I’ll live with it for now. If/when I put together a better scheme, I’ll post it.

But, with this you get support for Tomcat with IntelliJ IDEA community edition. It’s obviously not nearly as snazzy as having it integrated to the IDE, but if you’re in my boat, this is nice. I’ve automated most of the stuff that I’d rely on the IDE to do, and I’ve done it without spending a few hundred dollars I’m not yet sure I can justify. Cheers if this helps you.

By

IntelliJ IDEA: Saying Goodbye to Eclipse

I received a recommendation from Ted Young recently to try a switch to IntelliJ IDEA as an alternative to Eclipse IDE. I’ve been using Eclipse for years, but figured I’d give this tool a try, as it’s brought to you by the clever folks that make Resharper. Uncle Bob uses it in his series of Clean Code videos as well. I’ve been watching these lately, and his fluency with that IDE is making me long for something a little more… polished than Eclipse. I guess I’m spoiled by Visual Studio.

Anyway, I’ve installed the Community version of IntelliJ. Over the weekend, I spent a few hours porting my home automation project, Daedalus, to be usable by IntelliJ. Mostly, this involved turning it into a Maven project, and then ironing out a handful of miscellaneous details and quirks. I’m already much happier with this IDE than I was with Eclipse.

For starters, the Intelli-Sense (or whatever it’s called) is vastly superior to Eclipse. The static analysis for things like non-compiling code is also much snappier and prettier. And, beyond that, little things do what I’m used to from Visual Studio (e.g. ctrl-tab between code files). It’s weird, but a few things like that here and there really add up to being happier with the user experience. Using IntelliJ feels like coming home, which is impressive, since I’ve never used it (and I don’t even use ReSharper). Color me impressed.

Here is a handful of other miscellaneous observations so far:

  • Ctrl-W and Ctrl-Shift-W widen and narrow selected scope, respectively (equivalent of the numpad + and – in CodeRush).
  • Getting my black background seemed pretty tedious. I didn’t discover until the end that if I set some high level setting with black background, that mostly became default.
  • On the flip side, the color scheme in there is awesome – I can vary RGB ratios and darkness independently, meaning I can keep the default color scheme, but make all the foreground colors a lot lighter so they show up on black.
  • If you download the Community (read: free) version, bear in mind that you get no server integration. It took me a long time to figure out that I couldn’t integrate Tomcat as that’s only for the pay-to-play version
  • The last bullet isn’t a major hindrance. I just set up an Ant build to deploy a WAR file and set the Ant build up to run after successful compile when I want to deploy. The only thing I lose is the ability to start Tomcat in the IDE and browse in the IDE but both of those were pretty flaky in Eclipse anyway. Keeping a browser window open isn’t the end of the world.
  • When I go to commit to SVN, a window pops up with code analysis messages, giving me what I assume is the Java equivalent of StyleCop or FX Cop. This is pretty awesome since my idiomatic Java is pretty rusty. I imagine this will help shake off some of that rust.
  • Still haven’t worked out all of the shortcuts for running tests in TDD. Options seem better than Eclipse, but I still have to tame them.
  • The project/module definition in place of Eclipse’s workspace/project definition is a little odd, but whatever.

That’s about it, so far. I’ll probably have more posts to add as I go. I wish I had documented and blogged about the conversion from Eclipse, as that was relatively straightforward, but with a few gotchas, since I didn’t have Maven set up for Eclipse and I did have the Spring/Tomcat/Jstl dependencies. Thing is, I kind of started off not thinking I was actually going to switch and just doing some exploratory puttering, so I didn’t get into the documentation mindset until it was too late. Oh well, c’est la vie. If anyone’s curious about anything I did, please feel free to comment or shoot me an email.

At any rate, I think I’m probably going to close the books on Eclipse. I suspect that my only future debate here is whether or not to upgrade to the paid Ultimate version of IntelliJ. Given that I alternate between .NET and Java, the relative synergy between IntelliJ and Visual Studio is simply too huge an advantage to pass up. I realize that Eclipse probably has a richer plugin library, but to be honest, my opinion of Eclipse has always more or less been “meh, it works, I guess”, rather than “ooh, this is nice!” After even just a few days with IntelliJ, it’s hard to see myself going back.

By

Recognizing Test Smells

Tonight, I was plodding through the process of getting to know MongoDB and its java driver, TDD style. This is an interesting experience, as most of one’s development is going to involve technologies with which one is familiar and working out designs. This is classic problem isolation — all of your tools are familiar, and you have only to work out the design itself. In this case, I have two problems – the technology and the design aren’t familiar. In situations like this, it’s even more important to follow your nose when it comes to smells in code or tests, as you’re really flailing around in the dark. These may be the only things that guide a technology initiate to good practice short of taking a class or reading some books (and even then, they’re important, because you can only learn so much without getting your hands dirty.

So, I found myself with the following code during TDD (not a finished product):

public class LightServiceMongoImpl implements LightService {

	public static final String ROOM_KEY = "room";
	
	public static final String EQUALS_KEY = "$eq";
	
	private DBCollection _collection;
	
	public LightServiceMongoImpl(DBCollection collection) {
		if(collection == null)
			throw new IllegalArgumentException("Collection cannot be null.");
		
		_collection = collection;
	}

	@Override
	public Collection<Light> getLightsInRoom(String roomName) {
		
		ArrayList<Light> myLights = new ArrayList<Light>();
		
		BasicDBObject myQuery = new BasicDBObject();
		myQuery.put(ROOM_KEY, new BasicDBObject(EQUALS_KEY, roomName));
		DBCursor myCursor = _collection.find(myQuery);
		
		while(myCursor != null && myCursor.hasNext()) {
			myLights.add(new Light("asdf", "1"));
		}
		
		return myLights;
	}
}

I’m in the middle of developing a query that will take the following document structure and parse it into a series of Light objects:

{ "_id" : ObjectId("4f7d2ba6fd5a306d82687d48"), "room" : "Den" }
{ "_id" : ObjectId("4f7d2baafd5a306d82687d49"), "room" : "Foyer" }
{ "_id" : ObjectId("4f7d2fdcfd5a306d82687d4a"), "room" : "Master Bedroom" }
{ "_id" : ObjectId("4f7d301afd5a306d82687d4b"), "room" : "Guest Bedroom" }
{ "_id" : ObjectId("4f7d2b98fd5a306d82687d47"), "code" : "A", "lights" : [ { "name" : "Overhead", "code" : "1" } ], "room" : "Kitchen" }

Each document corresponds to a room with a room name, a room code, and 0 to n lights, each of which are sub-documents. This may not be the ideal structure for what I’m trying to accomplish, but it’s a working structure, and these are growing pains.

Clearly, my code doesn’t yet work, but all tests so far pass. I looked at this class critically and decided I’d been a bit lax in the “refactor” portion of “red-green-refactor” and getLightsInRoom() was getting a little unwieldy. So, I refactored to this:

public class LightServiceMongoImpl implements LightService {

	public static final String ROOM_KEY = "room";
	
	public static final String EQUALS_KEY = "$eq";
	
	private DBCollection _collection;
	
	public LightServiceMongoImpl(DBCollection collection) {
		if(collection == null)
			throw new IllegalArgumentException("Collection cannot be null.");
		
		_collection = collection;
	}

	@Override
	public Collection<Light> getLightsInRoom(String roomName) {
		
		ArrayList<Light> myLights = new ArrayList<Light>();
		
		DBCursor myCursor = getCursorForRoomName(roomName);
		
		while(myCursor != null && myCursor.hasNext()) {
			myLights.add(new Light("asdf", "1"));
		}
		
		return myLights;
	}

	/**
	 * Given a room name, get a cursor that matches
	 * @param roomName - Name of the room for which to get a cursor
	 * @return The cursor retrieved
	 */
	private DBCursor getCursorForRoomName(String roomName) {
		
		BasicDBObject myQuery = buildRoomNameQuery(roomName);
		DBCursor myCursor = _collection.find(myQuery);
		
		return myCursor;
	}

	/**
	 * Construct the query for a given room name
	 * @param roomName - room name for which to build the query
	 * @return - query object in question
	 */
	private BasicDBObject buildRoomNameQuery(String roomName) {
		
		BasicDBObject myQuery = new BasicDBObject();
		myQuery.put(ROOM_KEY, new BasicDBObject(EQUALS_KEY, roomName));
		
		return myQuery;
	}
}

Ah, much better. Again, I don’t know any design practices, but separating the parsing of the returned document from the construction of the query from the retrieval of the cursor seems like it is likely to come in handy later if there’s a need to divvy up responsibilities. So, I turned to my most recent test (it’s a passing test):

@Test
public void returns_collection_with_count_of_one_when_matching_record_has_lights_collection_with_one_element() {

	BasicDBObject myLight = new BasicDBObject();
	myLight.put("name", "overhead");
	myLight.put("light", "1");
	
	ArrayList<BasicDBObject> myLights = new ArrayList<BasicDBObject>();
	myLights.add(myLight);
				
	BasicDBObject myRoom = new BasicDBObject();
	myRoom.put("lights", myLights);  
	
	DBObject myMockDatabaseObject = mock(DBObject.class);
	Mockito.when(myMockDatabaseObject.get(RoomServiceMongoImpl.ROOM_NAME_KEY)).thenReturn(myRoom);
	
	DBCursor myMockCursor = mock(DBCursor.class);
	Mockito.when(myMockCursor.next()).thenReturn(myMockDatabaseObject).thenReturn(myMockDatabaseObject).thenReturn(null);
	Mockito.when(myMockCursor.hasNext()).thenReturn(true).thenReturn(false);
						
	DBCollection myMockCollection = PowerMockito.mock(DBCollection.class);
	Mockito.when(myMockCollection.find(any(DBObject.class))).thenReturn(myMockCursor);
	
	LightServiceMongoImpl myService = buildTarget(myMockCollection);
	
	assertEquals(1, myService.getLightsInRoom("asdf").size());
}

Yeesh. I had been so focused on figuring out the MongoDB API that I had allowed myself to be the proverbial boiled frog. That’s a hideous test, and I see that I’m starting to duplicate logic like that in a few of my tests. I had written this off as beyond my control because the Mongo API is such that I need a collection in order to get a cursor, which will give me a database object. If these data access classes (called services temporarily until I set up a proper domain) don’t retain a reference to the collection, they can’t requery the database.

But, that reasoning is no good. The fact that some API works in a certain way is no excuse for me to violate the Law of Demeter. I’m storing a reference to a collection so that I can ask it for a cursor, which I then ask for a DB object. What I really want is a DBObject to parse, and that’s it. It’s time for me to introduce some other class that encapsulates all of that and returns DBObjects to me, which I will parse into my DTOs. I have a sneaking suspicion that doing this will make my test setup much less ugly.

So, on a hunch, I’m going to split responsibilities here such that my service invokes an API that takes a query as an argument and returns a series of DBObject:

public interface MongoQueryService {

	void ExecuteQuery(BasicDBObject query);
	
	Boolean HasNext();
	
	DBObject getNext();
}

Now, I bet I can use this to make the class under test a bit more focused and my test setup a lot less painful. Here is my refactored class:

public class LightServiceMongoImpl implements LightService {

	public static final String ROOM_KEY = "room";
	
	public static final String EQUALS_KEY = "$eq";
	
	private MongoQueryService _service;
	
	public LightServiceMongoImpl(MongoQueryService service) {
		if(service == null)
			throw new IllegalArgumentException("Collection cannot be null.");
		
		_service = service;
	}

	@Override
	public Collection<Light> getLightsInRoom(String roomName) {
		
		ArrayList<Light> myLights = new ArrayList<Light>();
		
		_service.executeQuery(buildRoomNameQuery(roomName));
		
		while(_service.hasNext()) {
			myLights.add(new Light("asdf", "1"));
		}
		
		return myLights;
	}

	/**
	 * Construct the query for a given room name
	 * @param roomName - room name for which to build the query
	 * @return - query object in question
	 */
	private BasicDBObject buildRoomNameQuery(String roomName) {
		
		BasicDBObject myQuery = new BasicDBObject();
		myQuery.put(ROOM_KEY, new BasicDBObject(EQUALS_KEY, roomName));
		
		return myQuery;
	}
}

The collection is gone, as is the intermediate cursor object. In its stead I have the new query service interface that I’ve defined (I’m going to sort out the naming and package structure when I have a better grasp on things). Now, let’s take a look at the refactored test:

@Test
public void returns_collection_with_count_of_one_when_service_hasNext_is_true() {

	MongoQueryService myMockService = mock(MongoQueryService.class);
	Mockito.when(myMockService.hasNext()).thenReturn(true).thenReturn(false);
	
	LightServiceMongoImpl myService = buildTarget(myMockService);
	
	assertEquals(1, myService.getLightsInRoom("asdf").size());
}

Ah… I love the smell of deleted code in the (very early) morning. Smells like… victory! Now, granted, the implementation is still obtuse, and at some point, I’m going to have to deal with the fact that I probably won’t build a light for a null return value from the query service, which might mean revisiting this test, but I’d much rather start simple and add complexity than start complex and add complexity or, worse yet, start complex and have unnecessary complexity.

This new class is substantially easier to reason about. When clients call it, I build a query object to get what I want, tell some API to execute the query, and then iterate through the results. I’m no longer managing mixed levels of abstraction, handling a database collection, a database object iterator, and database object parsing in one flat class. Instead, I handle query construction and the parsing of query results, which is the same level of abstraction. And, for my good faith refactoring effort, I’m rewarded with a wonderfully simple unit test to run. Now, I can write tests about the query I’m constructing and handling the results of the query (and, if I decide I need to decouple query construction and result processing, which seems like a wise step to do at some point, it will be much easier).

The lesson here is to keep your nose open not just for smells in your code, but for smells in your tests. In my code, I had a law of demeter violation (and will probably have another one when I implement the query service, but I’ll deal with that during another refactor cycle). In my test, I had burgeoning test setup. In general, this can’t be ignored, but it’s especially important not to ignore this when you don’t really know what you’re doing. I don’t know enough about MongoDB, Mongo’s Java driver, JUnit, Mockito, etc to have the luxury of knowing when a smell is indicative of a problem and when it’s not. In this scenario, I have to be very careful to avoid smells if I’m going to have any hope of creating a good design on the fly while teaching myself multiple technologies.

In a similar situation, I’d advise you to take the same approach. My two cents, anyway.

By

JUnit for C# Developers 8 – Obeying Demeter and Going Beyond the Tests

Last time in this series, I pulled an “Empire Strikes Back” and ended on a bit of a down note. This time around, I’d like to explore how I’ve alleviated my Law of Demeter problems, and about how fixing a code smell in my tests pushed me into a better design.

Up until now, I’ve been blogging as I go, but this one is all in the past tense — the work is done as I type this. I set out tonight with only one goal, get rid of my LOD violations, and this is where it took me.

Rethinking my Class

Recall that last time, I was passing in a database object, querying that for a collection, querying that for a cursor, and then querying the cursor for my actual database objects that I parsed and returned from the service. After a bit of trial and error and research, I decided that my service class needed to encapsulate the collection since, as best as I can tell from whatever Eclipse’s version of Intellisense is called, cursors are forward only and then you need to get another one. So, if I don’t pass in the collection at least, my service method will only work once. Fine – not thrilled about the collection.cursor.objects thing, but it’s at least pulling one LOD violation out.

I now have a handful of tests that look like this:

@Test
public void returns_room_model_with_roomName_from_database_room_key() {
	
	String myRoomName = "Rumpus Room.  Yeah, that's right.  I said Rumpus Room.";
	
	DBObject myMockDatabaseObject = mock(DBObject.class);
	Mockito.when(myMockDatabaseObject.get(RoomServiceMongoImpl.ROOM_NAME_KEY)).thenReturn(myRoomName);
	
	DBCursor myMockCursor = mock(DBCursor.class);
	Mockito.when(myMockCursor.next()).thenReturn(myMockDatabaseObject).thenReturn(myMockDatabaseObject).thenReturn(null);
	Mockito.when(myMockCursor.hasNext()).thenReturn(true).thenReturn(true).thenReturn(false);
			
	DBCollection myMockCollection = PowerMockito.mock(DBCollection.class);
	Mockito.when(myMockCollection.find()).thenReturn(myMockCursor);
	
	RoomServiceMongoImpl myService = BuildTarget(myMockCollection);
	
	assertEquals(myRoomName, myService.getAllRooms().toArray(new Room[2])[0].getRoomName());
}

and my class became:

public class RoomServiceMongoImpl implements RoomService {

	public static final String ROOM_CODE_KEY = "room_code";

	public static final String ROOM_NAME_KEY = "room";
	
	private DBCollection _collection;
	
	public RoomServiceMongoImpl(DBCollection collection) {
		_collection = collection;
	}

	@Override
	public Collection<Room> getAllRooms() {
		Collection<Room> myRooms = new ArrayList<Room>();
		
		DBCursor myCursor = _collection.find();
		while(myCursor != null && myCursor.hasNext()) {
			RoomModel myModel = buildRoomModel(myCursor.next());
			if(myModel != null)
				myRooms.add(myModel);
		}
		
		return myRooms;
	}
	
	private RoomModel buildRoomModel(DBObject roomObject) {
		Object myRoomName = roomObject.get(ROOM_NAME_KEY);
		char myRoomCode = getRoomCode(roomObject.get(ROOM_CODE_KEY));
		
		if(myRoomName != null) {
			return new RoomModel(myRoomName.toString(), null, myRoomCode);
		}
		return null;
	}

	private char getRoomCode(Object myRoomCode) {
		return myRoomCode != null && myRoomCode.toString() != null && myRoomCode.toString().length() > 0 ?
				myRoomCode.toString().charAt(0) : 0;
	}
}

A lot cleaner and more manageable following some good TDD if I do say so myself (though I may be whiffing on some finer points of the language as I’m still rusty from 2 years of mostly uninterrupted C#). I’m still not thrilled about the heavy test setup overhead, but I’ve made incremental progress.

Now, where things got interesting is in wiring this up through Spring and MongoDB. The class works in test, but I need now to figure out how to use my spring-servlet.xml to get an instance of the collection injected into my class’s constructor. I wanted to do this (1) without defining any additional code and (2) without resotring to static implementations or singletons. For (1) I’d rather leave the DB setup stuff in XML as much as possible and for (2) I try to avoid static at all costs unless there’s some compelling argument that doesn’t lean prominently on a premise of “it’s more convenient”. Static is about as flexible as a diamond.

So, here is what I did:

<!-- This is the "Mongo" object where you specify connection credentials -->
    <bean id ="mongo" class="com.mongodb.Mongo">
    	<constructor-arg index="0" type="java.lang.String" value="192.168.2.191"/>
    </bean>
    
    <!--  This is the database returned from the mongo object (the daedalus) database -->
    <bean id="mongoDatabase" factory-bean="mongo" factory-method="getDB">
    	<constructor-arg index="0" value="daedalus"/>
    </bean>
    
    <!-- This is the "house" collection, which is a collection of rooms  -->
    <bean id="mongoHouseCollection" factory-bean="mongoDatabase" factory-method="getCollection">
    	<constructor-arg index="0" value="house"/>
    </bean>

I discovered that I can use factory-bean and factory-method attributes to invoke instance methods on beans that I’d created, turning their return values into other beans. I also learned that “constructor-arg” is rather unfortunately named in that it actually just translates to “arguments to the method in question”. So, in the case of the mongoDatabase bean, I’m getting it from my mongo object’s getDB() method with a string parameter of “daeadlus”. On the whole, the beans above translate to new Mongo(“192.168.2.191″).getDB(“daedalus”).getCollection(“house”) being stored in the “mongoHouseCollection” bean, which I injected into my service. When I wired and fired it, it worked perfectly the first time.

So, this post has been a little thin on actual information about JUnit (really just the denouement to my last post), but there is a nugget in here for spring wireup, and, I think the most important lesson for me is that the design benefits to TDD go beyond just code. By taking my test smell seriously, I wound up with a design where I completely factored the database setup garbage out of my code, which is clearly a good thing. Now, I’ve been around the block enough times that this would have happened regardless, but it was interesting to note that making a testability/clean-code decision and sticking to my guns teased out a macroscopic design improvement.

By

JUnit for C# Developers 7 – Law of Demeter and Temporal Mocking

Last time in this series, I posted about a good reminder of a couple of principles of good object oriented design (respecting the Law of Demeter and avoiding static method invocations as much as possible). Today, I’m going to double back on this consciously a bit to explore some more possibilities in JUnit. Don’t worry – I will fix the design in subsequent posts.

Goals

Today, I’d like to accomplish the following:

  1. Have a mock change with each invocation
  2. Mock a low of demeter violation in as little code as possible

To the Code!

If you’ve followed my last few posts, you’ve noticed that I setup MongoDB. So, logically, the next step is connecting to it with my application, and the next step after that is mocking this connection so that I can unit test the logic (well, since I’m following TDD, technically the mocking comes first). Through trial and error in a throw-away piece of code, I discovered that I could access my database as so:

public class HouseServiceMongoImpl implements HouseService {

	private Mongo _mongoConnection;
	
	private DB _database;
	
	public HouseServiceMongoImpl() {
		try {
			_mongoConnection = new Mongo( "192.168.2.191" , 27017 );
			_database = _mongoConnection.getDB("daedalus");
		} catch (UnknownHostException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (MongoException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	@Override
	public House getHouse() {
		DBCollection myCollection = _database.getCollection("house");
		DBCursor myCursor = myCollection.find();
				
		List<String> myStrings = new ArrayList<String>();
		
		while(myCursor.hasNext()) {
			myStrings.add(myCursor.next().get("room").toString());
		}
		return new HouseModel(myStrings);
	}
	
}

Notice here that I’ve inlined instantiation of my dependencies in a form bad for testability. I won’t repeat this mistake in the actual, TDD version. This was just for me to see what actually worked and provide some context for what I’m trying to do. In my real class, RoomServiceMongoImpl, I’m going to be returning a collection of room objects, rather than a house object. So, without further ado, on to the TDD. To get things started, I wrote the following test:

public class RoomServiceMongoImplTest {

	private static RoomServiceMongoImpl BuildTarget(DB database) {
		
		return new RoomServiceMongoImpl(database);
		
	}
		
	public static class getAllRooms {
		
		/*
		 * If the driver gives us back nothing for this collection, return an empty collection to clients
		 */
		@Test
		public void returns_empty_list_when_database_get_collection_returns_null_for_house() {
			
			DB myMockDatabase = mock(DB.class);
			Mockito.when(myMockDatabase.getCollection(Mockito.matches("house"))).thenReturn(null);
			RoomServiceMongoImpl myService = BuildTarget(myMockDatabase);
			
			assertEquals(0, myService.getAllRooms().size());
		}
	}
}

This allowed me to create the room service and inject into it the DB object, since as far as I can tell, I gain nothing by injecting the Mongo object. So, my first test is that we get back a null object in the form of an empty list when the MongoDB collection requested is empty. This makes sense, as it means we have no house (and thus no rooms).

When doing TDD, I’ve gotten in the habit of teasing out any control flow by varying up the return value of the method. So, the first test returns an empty collection. The next test will return count of one. The next will return a bunch. The one after that may go back to zero but in a different set of circumstances. This sort of progression allows me to make progress while covering all my bases. So, here, I’m going to do the setup necessary for a list with a single item to be returned.

But… as it turns out, this isn’t trivial. From my database, I’m getting a collection, which I’m asking for a database cursor, which I’m asking in a loop for an object called “next”, which I’m then asking for my actual room’s string value (its name). This has the Law-of-Demeter violating form db.getCollection().find().next().get(string). Ugh. That’s a lot of mocking, and creating mocks this way is the smell of LOD violations in your code. But, let’s suck it up for now and create the mocks:

@Test
public void returns_list_with_one_item_when_db_returns_matching_cursor() {

	DBObject myMockDatabaseObject = mock(DBObject.class);
	Mockito.when(myMockDatabaseObject.get(Mockito.anyString())).thenReturn("asdf");
	
	DBCursor myMockCursor = mock(DBCursor.class);
	Mockito.when(myMockCursor.next()).thenReturn(myMockDatabaseObject);
			
	DBCollection myMockCollection = PowerMockito.mock(DBCollection.class);
	Mockito.when(myMockCollection.find()).thenReturn(myMockCursor);
	
	DB myMockDatabase = mock(DB.class);
	Mockito.when(myMockDatabase.getCollection(Mockito.matches("house"))).thenReturn(myMockCollection);
	
	RoomServiceMongoImpl myService = BuildTarget(myMockDatabase);
	
	assertEquals(1, myService.getAllRooms().size());
}

This was particularly annoying to write since it cost me a good bit of frustration trying to figure out why I was getting cryptic error messages about the wrong return type. Turns out it was because the collection.find() method is final, requiring me to use PowerMockito (this stack overflow post ended my suffering and I voted the poster up both for the question and his self-answer as my way of saying thanks). But, I was done, and the following class made the test pass:

public class RoomServiceMongoImpl implements RoomService {

	/**
	 * This is the MongoDB database object we'll use for our queries
	 */
	private DB _database;
	
	/**
	 * Dependency injected constructor
	 * @param database
	 */
	public RoomServiceMongoImpl(DB database) {
		_database = database;
	}

	@Override
	public Collection<Room> getAllRooms() {
		Collection<Room> myRooms = new ArrayList<Room>();
		
		if(_database.getCollection("house") != null && _database.getCollection("house").find().next().get("bkag") != null) {
			myRooms.add(new RoomModel("blah", null, 'A'));
		}
		return myRooms;
	}
}

Hideous, with all of those LOD violations, but functional. So now, the next step is to factor the code toward something less obtuse with my TDD, and an excellent way to do this is the case of two strings in the database. But, in order to make that happen, the cursor mock’s next() method has to first return a DB object and then return null. It just so happens that this is goal number one, and it can be achieved as follows:

DBCursor myMockCursor = mock(DBCursor.class);
Mockito.when(myMockCursor.next()).thenReturn(myMockDatabaseObject).thenReturn(myMockDatabaseObject).thenReturn(null);
Mockito.when(myMockCursor.hasNext()).thenReturn(true).thenReturn(true).thenReturn(false);

Note the chained returns calls. I took what I had in the previous test and turned it into this code, and then amended the expected size of the collection returned to be 2 using hasNext() and next(). I also had to go back and add similar code to the previous test for completeness sake. With this in place, the CUT getAllRooms() method became:

@Override
public Collection<Room> getAllRooms() {
	Collection<Room> myRooms = new ArrayList<Room>();
	DBCollection myCollection = _database.getCollection("house");
	if(myCollection != null) {
		DBCursor myCursor = myCollection.find();
		if(myCursor != null) {
			while(myCursor.hasNext()) {
				myRooms.add(new RoomModel(myCursor.next().get("asdf").toString(), null, 'A'));
			}
		}
	}
	return myRooms;
}

Man, that’s ugly. But, it works, and that’s what matters. We’re going to pretty this up and make it more robust later during the “refactor” cycles of red-green-refactor. So, on to goal number two, which is to compact the mock setup code somewhat. Granted, the pain of this setup indicates a design smell and there is a good argument that we should not deoderize these test smells. But, given that this is partially an endeavor for me to learn and blog about the mocking tools available with JUnit, I’m going to make an exception, with a promise to myself that I will pay off this loan of technical debt later by doing what I can to cut down on the database boilerplate I don’t need in this class. I came up with this:

@Test
public void returns_list_with_one_item_when_db_returns_matching_cursor() {

	DBObject myMockDatabaseObject = mock(DBObject.class);
	Mockito.when(myMockDatabaseObject.get(Mockito.anyString())).thenReturn("asdf");
			
	DB myMockDatabase = mock(DB.class);
	
	Mockito.when(myMockDatabase.getCollection(Mockito.matches("house"))).thenReturn(PowerMockito.mock(DBCollection.class));
	Mockito.when(myMockDatabase.getCollection(Mockito.matches("house")).find()).thenReturn(mock(DBCursor.class));
	Mockito.when(myMockDatabase.getCollection(Mockito.matches("house")).find().next()).thenReturn(myMockDatabaseObject).thenReturn(null);
	Mockito.when(myMockDatabase.getCollection(Mockito.matches("house")).find().hasNext()).thenReturn(true).thenReturn(false);
	
	RoomServiceMongoImpl myService = BuildTarget(myMockDatabase);
	
	assertEquals(1, myService.getAllRooms().size());
}

But, it throws a null reference exception on the first find() setup (second Mockito.when() line) and it doesn’t really save any code anyway, so I see no advantage to going this route. My instincts were against it anyway, and since it doesn’t work as fluidly as I hoped it might (I feel like I could probably get this fluent-style to work with enough persistence) and doesn’t save us code, forget it. Nothing ventured, nothing gained. I’ll have to be satisfied that this fluent-chaining appears possible, but might be a stone better left un-turned in favor of going back and cleaning up my code by eliminating LOD violations and generally seeking not to have them.

These posts are getting a little fewer and further between now as I’m less frequently blazing new trails in my work. I will probably check back in on this line of posts when I factor the design of this a bit, as kind of a MongoDB/JUnit fusion post.

By

Configuring Fedora and MongoDB

In my last post, I covered installing MongoDB on Fedora. This is another post as much for my reference as for anything else, and I’ll go over here getting set up so that my application successfully uses the MongoDB server.

When I left off last time, I had successfully configured the server to allow me to create documents using the mongo command line utility. So, I created a collection and a document and was ready to access it from my web application. Following the examples in the MongoDB java tutorial, I created the following implementation of my HouseService interface that I had previously hard coded room values into:

public class HouseServiceMongoImpl implements HouseService {

	private Mongo _mongoConnection;
	
	private DB _database;
	
	public HouseServiceMongoImpl() {
		try {
			_mongoConnection = new Mongo( "192.168.2.191" , 27017 );
			_database = _mongoConnection.getDB("daedalus");
		} catch (UnknownHostException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (MongoException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	@Override
	public House getHouse() {
		DBCollection myCollection = _database.getCollection("house");
		DBCursor myCursor = myCollection.find();
				
		List<String> myStrings = new ArrayList<String>();
		
		while(myCursor.hasNext()) {
			myStrings.add(myCursor.next().get("room").toString());
		}
		return new HouseModel(myStrings);
	}
	
}

I felt pretty good about that, and so I fired up the local process and promptly got an error:

java.io.IOException: couldn't connect to [/192.168.2.191:27017] bc:java.net.NoRouteToHostException: No route to host: connect

IP address was resolving correctly, but a cryptic “NoRouteToHoseException”. I deployed my app to the server, “daedalus” and it ran fine, as-is. I was glad to see that my code was working as I expected with Mongo, but I didn’t want to have to deploy to the server every time I wanted to run the application, so I started poking around for a fix. I had no luck connection through the browser either. Something was strange.

At this point, I remembered a similar annoyance in dealing with MySQL, and for some reason “iptables” popped into my head. After poking around a little for syntax particulars, I ran the following commands:

iptables -A INPUT -m state --state NEW -m tcp -p tcp --dport 27017 -j ACCEPT
iptables -A INPUT -m state --state NEW -m tcp -p tcp --dport 28017 -j ACCEPT

Sure enough, that did the trick. Accessing MongoDB through the browser now yielded:

I had been struggling to figure out what I needed to do to the mongo installation, but the problem was with the Linux firewall (or, more specifically, the fact that I hadn’t set it up to allow connections on these ports). To make my changes permanent, I added the following to /etc/sysconfig/iptables

-A INPUT -m state --state NEW -m tcp -p tcp --dport 27017 -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 28017 -j ACCEPT

I felt good about this, since I saw my handiwork in the same file opening up ports for MySQL and Tomcat. To verify that this bit of goodness stuck around, I rebooted and re-ran the web app on my client desktop…

By

JSTL Core ForEach Loop

Today, I was pleasantly surprised at how easy a time I had setting up some JSP pages to interact with my ongoing Java/Spring MVC home automation server. I seem to remember the setup for this being annoying in a past Java life, but my experience today was the opposite. So, here is a brief summary of what I did.

My plan is to install MongoDB to store the data that I’m going to use. I don’t know if this is the right choice, but it seems like a lightweight one in that I can always go “heavier” with a RDBMS later, if that seems warranted. There’s also a bit of a “let’s try it out” motivation for me in that I can add another tool to my toolbox in the process. But, that’s a task for another time (and probably another post). For now, I’m going to mimic having a persistence structure with the following java class:

public class HouseServiceBasicImpl implements HouseService {

	@Override
	public House getHouse() {
		// TODO replace with actual implementation
		List<String> myRoomList = Arrays.asList("Kitchen", "Dining Rooom", "Bedroom"); 
		return new HouseModel(myRoomList);
	}
}

The House interface currently contains only a collection of room names. Here is the controller that uses the service:

@RequestMapping("/rooms")
public class HouseRoomController {

	private HouseService _houseService;
	
	/**
	 * Dependency injected constructor
	 * @param service
	 */
	public HouseRoomController(HouseService service) {
		if(service == null)
			throw new IllegalArgumentException("service");
		
		_houseService = service;
	}

	@RequestMapping("/rooms")
	public ModelAndView rooms() {

		//@TODO get rid of the law of demeter violation here - this should just pass the house to the model and view
		ModelAndView myModelAndView = new ModelAndView();
		Collection<String> myRoomNames = _houseService.getHouse() == null ? new ArrayList<String>() : _houseService.getHouse().getRoomNames();
		myModelAndView.addObject("rooms", myRoomNames);
		
		return myModelAndView;
	}
}

All we do here is pull the list of rooms from the service, and add them as a model to a ModelAndView with key “rooms”. With that in place, I wrote the following jsp page:

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>

<jsp:include page="header.jsp"/>

<table>
	<c:forEach var="roomName" items="${rooms}">
		<tr><td>
			<a class="button" href='<c:out value="${roomName}"/>.htm'><c:out value="${roomName}"/></a>
		</td></tr>
	</c:forEach>
</table>

From there, I wired up my spring-servlet.xml with all the proper beans and tried to build, only to get an error: “The absolute uri: http://java.sun.com/jsp/jstl/core cannot be resolved.” After some mild poking around on google, I learned that I didn’t have “standard.jar” in my WEB-INF\lib folder, and I needed it there. I found the jar at this site, downloaded it, and stuck it in that folder, and I was able to build.

From there, I ran the app on the server, and got an exception, though this was easy to track down. I had omitted an equals somewhere. Once I corrected that, I saw my page with my three rooms, as expected. And, I was pretty pleased.

I don’t know if it’s that I’m a lot more experienced at programming in general, or if Spring/Java/Eclipse has gotten easier to setup and use, but everything is much easier for me this time around than I remember from some years back. I suspect it’s a little from column A and a little from column B. One of the things that the .NET world has always seemed to have on the Java world is that everything is easier to setup and hit the ground running with. It seems as though the Java community is making noticeable strides in this department.

By

Basic Spring MVC spring-servlet.xml Configuration

Tonight, I enjoyed a nice success. Specifically, I enjoyed the kind of success that I’ve found tends invariably to arise from using TDD — I wired some things together and discovered that everything just worked (well, at least my java code did – I did have a slight oops with javascript typos, but that’s to be expected in an environment where I get no feedback until runtime). And, what made this extra sweet is that I’m designing a server that turns lights on and off in my house. This means that at the eureka, breakthrough moment, you don’t find out from a running application or a successfully parsed file or anything as mundane as that. You’re treated to your house lighting up like a Christmas Tree to celebrate your success! (And then you’re thankful that the “off” also works because your sleeping girlfriend is probably not amused by this development.)

But, my purpose here is neither to gloat nor to stump for TDD. Instead, I wanted to give a nod to how easy it was for me to wire things up in Spring MVC 3, and what an improvement I perceive this to be from some years and versions back. Since I was doing TDD, I was basically isolating two classes that I have collaborating them and testing them individually. These classes are LightManipulationServiceHeyuImpl, which implements LightManipulationService and LightController:

public interface LightManipulationService {

	/**
	 * Turns the light in question on or off
	 * @param light - the light to toggle
	 * @param isOn - the setting (true for on, false for off)
	 * @return whether or not the operation was successful
	 */
	Boolean toggleLight(Light light, Boolean isOn);
	
	/**
	 * Change the brightness of a light
	 * @param light - the light to modify
	 * @param brightnessChange - the brightness change (positive for brighter, negative for dimmer)
	 * @return whether or not the operation succeeded
	 */
	Boolean changeBrightness(Light light, int brightnessChange);
}

public class LightManipulationServiceHeyuImpl implements LightManipulationService {

	public static final String OFF_COMMAND = "off ";

	public static final String ON_COMMAND = "on ";

	public static final String HEYU_COMMAND = "/usr/local/heyu-2.6.0/heyu ";
	
	private Runtime _runtime;
	
	/**
	 * Dependency injected constructor
	 * @param runtime - runtime to use for executing shell commands
	 */
	public LightManipulationServiceHeyuImpl(Runtime runtime) {
		if(runtime == null)
			throw new IllegalArgumentException("runtime");
		_runtime = runtime;
	}
	
	@Override
	public Boolean toggleLight(Light light, Boolean isOn) {
		try {
			String myCommand = isOn ? ON_COMMAND : OFF_COMMAND;
			return _runtime.exec(HEYU_COMMAND + myCommand + light.getLightCode()) != null;
		} catch (IOException e) {
			return false;
		}
	}

	@Override
	public Boolean changeBrightness(Light light, int brightnessChange) {
		// TODO Auto-generated method stub
		return null;
	}
}

RequestMapping("/light")
public class LightController {

	private LightManipulationService _lightService;
	
	public LightController(LightManipulationService lightManipulationService) {
		if(lightManipulationService == null) throw new IllegalArgumentException("lightManipulationService");
		_lightService = lightManipulationService;
	}

	@RequestMapping("/light")
	public ModelAndView light() {
		return new ModelAndView();
	}

	/**
	 * Toggles the light described by room and light names on or off (command)
	 * @param room - Name of the room we find this light in
	 * @param light - Name of the light itself
	 * @param command - Whether to turn the light on or off
	 */
	@RequestMapping(value="/{room}/{light}/{command}", method=RequestMethod.PUT)
	public void toggleLight(@PathVariable String room, @PathVariable String light, @PathVariable String command) {
		_lightService.toggleLight(new Light(room, light), command.toLowerCase().equals("on"));
	}
}

This was all tested and looking good for the time being, so I figured I’d take a break from implementation and, well, see if any of it actually worked. Up until this point, I hadn’t bothered with any wireup, so I figured this would be an adventure. But, it wasn’t. A little google-fu and everything worked. I figured it would be easy enough to declare beans to do setter injection (I remembered this from the Spring MVC 1 days), but I thought that I might get snagged a little with constructor injection. I thought I might get snagged a lot with the fact that I wanted to inject the result of the static method Runtime.getRuntime() into my service.

But, I had no trouble in either case.

    <bean id="shell" class="java.lang.Runtime" factory-method="getRuntime"/>
    
    <bean id="heyuService" class="com.daedtech.daedalus.services.LightManipulationServiceHeyuImpl">
    	<constructor-arg index="0" type="java.lang.Runtime" ref="shell"/>
    </bean>
    
    
    <bean id="lightController" class="com.daedtech.daedalus.controller.LightController">
    	<constructor-arg index="0" ref="heyuService"/>
    </bean>

The first thing I set up was my service, using the familiar bean id and class syntax. From here, I located the constructor injection tag, but decided to come back to it since I thought the static method was going to be ugly. I then created the lightController bean and this is when I found the syntax for the constructor injection tag: constructor-arg. I specified which 0-indexed constructor argument I was supplying and referred it to my service bean. Simple enough. I don’t know whether the index is necessary with only one parameter or not, but hey, it’s working. I’ll figure that out when I need to.

From there, the static thing was surprisingly and pleasantly easy. I don’t know whether Runtime.getRuntime() is actually considered a factory method or not, but by using it in this fashion, I was able to accomplish what I wanted. This is going to come in extremely handy for cases where I have to pull things out of some framework or library static state and I don’t want to take that inline dependency to impede flexibility/testability.

And, really, that was it. I fired this up with my unit tested classes and absolutely nothing happened. I peered at the JSP pages and the javascript in them, realized I had forgotten a comma, fired again, and was dazzled by the lightshow in my house. So kudos to Spring MVC. Easy and flexible is always nice.

Acknowledgements | Contact | About | Social Media