Archive for November, 2008

More ColdFusion Testing Woes With Java Objects

November 24, 2008

Once again, my team is currently working on a Flex-based mapping application and I’m working on the back-end using ColdFusion to grab the data from our SQL server, package it in a Java based data transfer object (DTO), and send it to the requesting Flex app.

Another minor glitch I ran into while trying to test the ColdFusion method calls is with the SerializeJSON function built into ColdFusion 8. Because of the way BlazeDS works, in order to send objects from the Flex app back to ColdFusion we have to convert the object to a JSON string, send it, and then rebuild the object in ColdFusion from the JSON string. My teammate explains the process in his blog entry about the tech stack “Flex, ColdFusion, Java, and BlazeDS: with JSON?

The issue is simple. I want to test methods in the ColdFusion service we are writing in ColdFusion before I try to call them from the Flex app. It should be easier to debug that way. So I create the object and use SerializeJSON to make the string to pass to the ColdFusion service method. But I get errors saying such and such property is not found when the service method tries to rebuild the object.

Here’s a simple example that demonstrates the issue

//suppose you have a Java class like so
public class BoundingBox extends DataTransferObject
	implements Serializable
{
	static final long serialVersionUID = -4519523511904622352L;
	//Properties
	private LatLngOnly upperLeftLatLng;
	private LatLngOnly lowerRightLatLng;

	//methods
	public BoundingBox() {}

	public BoundingBox(LatLngOnly upperLeft, LatLngOnly lowerRight)
	{
		this.upperLeftLatLng = upperLeft;
		this.lowerRightLatLng = lowerRight;
	}	

	…
	//various methods including getters and setters
	…
}


<cfscript>
bnd = CreateObject("java", "com.lampo.mapping.vo.BoundingBox").init();
bnd.upperLeftLatLng =
       CreateObject("java", "com.lampo.mapping.vo.LatLngOnly").init(1.23,3.45);
bnd.lowerRightLatLng =
       CreateObject("java", "com.lampo.mapping.vo.LatLngOnly").init(5.67,7.89);
</cfscript>

<cfset str = SerializeJSON(bnd) />
<cfset objBnd =
       CreateObject("java","com.lampo.mapping.vo.BoundingBox").makeFromJSON(str) />

Annoyingly it turns out SerializeJSON is changing some of the property names so they no longer match. While it is true ColdFusion is not case-sensitive, Java is and so capitalizing the first character of the property names causes havoc. If the property is a reference to an object, errors are thrown. If the property is a primitive, the values are not set correctly.

The only solution I have is to alter the JSON string and hard code it as an argument for the method I’m testing. You can do this manually or with some regular expression magic.

<cfset str = SerializeJSON(bnd) />

<cfset pos = REFind('\"[A-Z]',str) />
<cfloop condition="pos NEQ 0">
     <cfset str = Replace(str,Mid(str,pos,2),'"#LCase(Mid(str,pos+1,1))#','all') />
     <cfset pos = REFind('\"[A-Z]',str) />
</cfloop>

<cfset objBnd =
       CreateObject("java","com.lampo.mapping.vo.BoundingBox").makeFromJSON(str) />

Look under the turtle

November 14, 2008

Developers understand that code reuse necessitates a simple-to-learn interface.  Typically, this leaves us adding another layer of abstraction (aka. “turtle”) to the existing turtle-pile.  This is all wonderful and leaves us feeling warm and fuzzy, except that abstractions are leaky at best.  Usually these new clever interfaces simplify doing whatever you need to do (as long as it is what the API author says you want to do). This means that in order to consume another’s code, I must first learn his or her clever new interface and the interfaces below it.

Recent projects have brought me to the realization that sometimes it’s better to remove a layer of abstraction.  I recently built a solution that involved thermal transfer printing bar codes on pre-printed ticket stock.

The printer uses a proprietary Postscript-like language for creating fields and updating their values throughout the course of a print job.  The printer also came with several half-baked utilities to almost simplify the job of getting it to print what I want, but not quite.  After perusing the developer’s guide, it turned out to be as simple as sending control characters to a parallel port.  I wrote a ‘driver’ in ColdFusion that reads the ticket records from the database and generates a .prn file (just ASCII control codes).  Now I can simply cat the generated file to the fancy printer from any machine that has a parallel port regardless of operating system and without having to install printer drivers.

Albert Einstein is quoted as saying “Things should be made as simple as possible, but no simpler.”  In the example above, I had to learn something new either way—the formatting codes or the libraries that came with the printer.  The libraries failed to simplify the interaction because they did not provide a complete abstraction; I would still have to delve a layer deeper for some of the things I needed.

Think about the abstractions you provide.  Do they really simplify? Will a user of your API need to delve a layer deeper?  If so, you’ve only created an obstacle.

Let’s be really clever developers; let’s learn the abstractions we already have and create clever documentation for other developers.

Adobe Max 2008

November 4, 2008

Adobe Max 2008

We’re headed to Adobe Max, November 17-19!  This year, we’ll have a team of 5 out in California to check out the latest from Adobe.  If you’re planning on attending and would like to meet up, we’ll be wearing “code hope” t-shirts on Monday to make it easy to find us.  Or you can drop a comment here and we can schedule a time for coffee/food.

Also be sure to check out one of our latest projects at the MapQuest booth.  We’ve been having fun with their API and Flex. 🙂