JAW Speak

Jonathan Andrew Wolter

Archive for March, 2009

Wrestling the Untestable Into Testable Code: Example with Test Driven SimpleTagSupport for custom JSP Tag

with one comment

Reading time: 3 – 5 minutes

Let’s say app servers must be stateless. There is no affinity for a user pinned to a particular app server, so two requests will likely be handled by different Tomcats, Jetty’s, etc. This means nothing can go in HttpSession (we also can’t use clustering). And when it’s ecommerce, we can’t require cookies or that might cost millions in lost revenue. Given these constraints, you have one valid option left: custom url rewriting over all our links (GET’s) and with hidden form fields (POST’s).

You can edit every link and every form to pass some unique id around. But what if you have two or three id’s that need to pass around for legacy reasons? Sounds like a custom tag would be nice. Something you can put in your jsp’s (oh yeah, let’s say we’re using jsp’s too).

This introduces me to the testability challenge. Write your own tag extending SimpleTagSupport that would ensure parameters were always in a link, and write another tag to write out the three hidden input fields inside every form.

But, SimpleTagSupport is part of the good old servlet and jsp API, so it’s very bloated with context objects, deep inheritance, callbacks, and cruft that makes for difficult unit testing. Just look at the public interface, one method: public void doTag() throws JspException, IOException.

Here’s my test driven test case (with 100% coverage, through the public API), which takes advantage of Spring MVC’s MockHttpServletRequest and MockHttpServletResponse objects (which are really fakes). I’m also using Mockito, which I prefer over EasyMock and JMock.

package com.jawspeak.dotcom.tag;
 
import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.Test;
import static org.mockito.Mockito.*;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.mock.web.MockPageContext;
 
import javax.servlet.jsp.tagext.JspFragment;
import java.io.StringWriter;
import java.io.Writer;
 
public class StatefulLinkTagTest_SettingSessionId {
	private StatefulLinkTag statefulLinkTag = new StatefulLinkTag();
	private MockHttpServletRequest request = new MockHttpServletRequest();
	private MockHttpServletResponse response = new MockHttpServletResponse();
	private static final String SESSION_ID = "ADFHE13";
 
	@Before
	public void given() throws Exception {
		request.setAttribute("sid", SESSION_ID);
		statefulLinkTag.setJspContext(new MockPageContext(null, request, response));
		JspFragment jspBodyFragment = mock(JspFragment.class);
		doAnswer(new FakeJspBodyAnswerer()).when(jspBodyFragment)
                        .invoke((Writer) anyObject());
		statefulLinkTag.setJspBody(jspBodyFragment);
	}
 
	@Test
	public void shouldRenderLinkWhenThereIsNoParameter() throws Exception {
		statefulLinkTag.setHref("/myPage.html");
		statefulLinkTag.doTag();
		String contentAsString = response.getContentAsString();
		assertEquals("<a href=\"/myPage.html?sid=" + 
                     SESSION_ID + "\">link text body</a>", contentAsString);
	}
 
	@Test
	public void shouldRenderLinkWhenThereIsAlreadyAParameter() throws Exception {
		statefulLinkTag.setHref("/myPage.html?my_param=foo");
		statefulLinkTag.doTag();
		String contentAsString = response.getContentAsString();
		assertEquals("<a href=\"/myPage.html?my_param=foo&sid=" + 
                    SESSION_ID + "\">link text body</a>", contentAsString);
	}
 
	/** Mockito Answer implementation to manipulate the parameters we pass 
	 * into JspFragment.invoke() due to the ugly servlet API. */
	private static class FakeJspBodyAnswerer implements Answer {
		public Object answer(InvocationOnMock invocationOnMock) throws Throwable {
			StringWriter writer = (StringWriter) invocationOnMock.getArguments()[0];
			writer.write("link text body");
			return null;
		}
	}
}

As for the implementation, it’s pretty straightforward after writing the tests. It doesn’t show covering multiple ID’s appended to the link, but it is now easy to test drive implementing them.

package com.jawspeak.dotcom.tag;
 
import javax.servlet.http.HttpServletRequest;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.SimpleTagSupport;
import java.io.IOException;
import java.io.StringWriter;
 
public class StatefulLinkTag extends SimpleTagSupport {
	private String href;
 
	public void setHref(String href) {
		this.href = href;
	}
 
	@Override
	public void doTag() throws JspException, IOException {
		PageContext pageContext = (PageContext) getJspContext();
		getJspContext().getOut().print(createTagText(
                      (HttpServletRequest) pageContext.getRequest()));
	}
 
	private String createTagText(HttpServletRequest request)
                       throws IOException, JspException {
		StringWriter stringWriter = new StringWriter();
		stringWriter.append("<a href=\"");
		stringWriter.append(href);
		if (href.indexOf("?") > 0) {
			stringWriter.append("&sid=");
		} else {
			stringWriter.append("?sid=");
		}
		stringWriter.append((String)request.getAttribute("sid"));
		stringWriter.append("\">");
		getJspBody().invoke(stringWriter);
		stringWriter.append("</a>");
		return stringWriter.toString();
	}
}

Questions, comments? Want to bash Java and tell me why I should be using Ruby, Erlang or Scala? For more about the SimpleTagSupport interface check here.

Written by Jonathan

March 24th, 2009 at 9:06 pm

Reminder: OOPSLA Submissions Due March 19th

without comments

Reading time: 2 – 3 minutes

I’m involved in helping review the tutorial. Do you  have something others would be interested in learning about? Please consider submitting a proposal, but do it fast since they are due March 19th. Here’s what the Tutorials are described as:

OOPSLA tutorials are half-day classes, taught by experts, designed to help software professionals rapidly come up to speed on a specific technology or methodology. Tutorials can be lecture-oriented or participatory.

OOPSLA tutorial attendees deserve the highest standard of excellence in tutorial preparation and delivery. Tutorial presenters are typically experts in their chosen topic and experienced speakers skilled in preparing and delivering educational presentations. When selecting tutorials, we will consider the presenter’s knowledge of the proposed topic and past success at teaching it.

If you’re interested, it’s not too late — and every submission helps ensure the quality of what is selected is the best possible. Do please consider a submission.

Below is the more generic announcement for all OOPSLA things:

OOPSLA 2009 Call for Submissions

http://www.oopsla.org/submit

OOPSLA solicits contributions that explore all facets of programming, systems, languages, or applications.  Topics span a range of issues at the intersection between programming languages and software engineering. Moreover, OOPSLA is a key forum for introducing and discussing key programming models, programming methods, and related software engineering ideas, technologies, tools, and applications.

So OOPSLA is seeking contributions that address current software challenges, such as programmer productivity, security and reliability, ultra-large scale systems, and evolving hardware platforms.  Of particular interest are those contributions addressing OOPSLA 2009’s focus on:

  • Scaling: Multi-Core to Cloud
  • Mashups of Models, Data and Code
  • Tools for Reliability and Evolution
  • Enterprise Agile Management

Here are the important dates:

Call for Papers
March 19, 2009
Due date for Research Program, Onward!, Practitioner Reports,
Educators’ Symposium, Essays, and proposals for Tutorials, Panels,
Workshops, and DesignFest

July 2, 2009
Due date for Posters, Demonstrations, Student Research Competition,
Doctoral Symposium, Onward! Films, and Student Volunteers

OOPSLA 2009
Oct 25-29, Orlando

For more information go to http://www.oopsla.org

Written by Jonathan

March 15th, 2009 at 6:36 pm

Posted in code

Using (These) Anonymous Inner Classes is Probably Too Clever for Your Own Good

with 3 comments

Reading time: 3 – 5 minutes

Sometimes it is tempting to have less verbose Java code and be clever. Say you have an object you need to build and set several properties on it, then use it. This way looks clever, but is a bad idea – especially in production code. Read on for why.

  	TripChoice myTrip = new TripChoice() {{
                        // look at these clever initialization blocks!
			setDestination("San Francisco");
			setAvailableRoutes(new HashSet() {{
				add("LAX-SFO");
				add("BUR-SFO");
				add("ONT-SFO");
			});
	   }};

This is a huge problem because it can cause a NotSerializableException or create a memory leak. How? Because with that clever anonymous class and initialization block, there is an implicit reference to the outer class’ instance. That outer class will not be garbage collected so long as there is one reference to the anonymous class. Worse, if we ever

Here’s the typical way to do it.

                // blah blah, this is typical, and a rather boring looking great big block of text.
		// (That's also probably scattered over several places in your code when you build these objects).
		TripChoice myTrip = new TripChoice();
		myTrip.setDestination("San Francisco");
		Set availableRoutes = new HashSet();
		availableRoutes.add("LAX-SFO");
		availableRoutes.add("BUR-SFO");
		availableRoutes.add("ONT-SFO");
		myTrip.setAvailableRoutes(availabileRoutes);

Here’s why this improved version is even not the best:

  • It uses setters. Setters allow your object to be constructed in an inconsistent state. There are some situations setters are fine (i.e. form backing objects) but often your code is more clear without setters. In this particular case the setters aren’t egregious, but I still consider them a smell and much more verbose way that constructor injection. Read more about the problem with setter injection here
  • It is verbose.
  • It is also mutable (often a negative), again a problem due to the use of setters.

So what’s the best way to do it? I have found constructor injection and in our particular example use of Google Collections. As for seeing an implementation of the best solution – just leave a comment.

Below is a full example you can run that illustrates the hard to catch serialization bug.

package com.jawspeak;
 
import com.google.common.collect.Lists;
import static org.junit.Assert.*;
import org.junit.Test;
 
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.NotSerializableException;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.List;
 
/**
 * Understands the danger of anonymous subclasses for lists.
 */
public class TooCleverForOurOwnGoodTest {
 
        @Test(expected = NotSerializableException.class)  // UPDATE: Thanks for the reminder from Dennis, below
	public void serializableDangerBugFromPatricksCleverness() throws IOException {
		// you think a List would be serializable, which it is. And so are Strings.
		final String myString = "3";
		List strings = new ArrayList() {
			add("one");
			add("two");
			// However, because there is an anonymous subclass of ArrayList created,
			// there is an implicit reference to the outer class, which is **not serializable**.
			// This is a nice feature, which lets us have closure-ish syntax in java, such as
			// the following reference to the outer myString.
			add(myString); // It will throw the exception even without this reference.
		}};
 
		// call your method that requires args to be serializable
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		ObjectOutputStream oos = new ObjectOutputStream(baos);
		oos.writeObject(strings);
		// The particular bug I had was even worse, because we were creating leaking a reference
		// through that List's implicit reference to the outer object.
	}
 
	@Test
	public void serializableDangerBugSafeButNotClever() throws IOException {
		// A List is serialiazable. And so are Strings.
		List strings = new ArrayList();
		strings.add("one");
		strings.add("two");
		// No longer is there a reference to the outer class.
 
		// call your method that requires args to be serializable
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		ObjectOutputStream oos = new ObjectOutputStream(baos);
		oos.writeObject(strings);
	}
 
	@Test
	public void serializableDangerBugSafeAndNiceLooking() throws IOException {
		// A List is serialiazable. And so are Strings.
		List strings = Lists.newArrayList("one", "two");
 
		// call your method that requires args to be serializable
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		ObjectOutputStream oos = new ObjectOutputStream(baos);
		oos.writeObject(strings);
	}
}

Written by Jonathan

March 10th, 2009 at 11:33 pm

Posted in Uncategorized, code, java, testability

Tagged with , ,