Sunday, November 22, 2009

Enforcing method contracts with AspectJ and Spring EL

After reading a bit about the new Expression Language in Spring 3 I decided to try to use it to implement a very basic version of Design by Contract. I thought it would be nice to be able to specify pre and post conditions for methods in the expression language, e.g.

public class Stack {

@Require("value != null")
@Ensure("top().equals(value)")
public void push(String value) {
values.add(value);
}
}


It turned out that there were two problems with this approach:




  • The Spring EL saw the “value” and tried to find a matching property in the root object of the evaluation context. To access named variables you have to write “#value”. Not quite as aesthetically pleasing and a bit error prone, but easy enough.


  • The other problem was that there is no way to get at the parameter names using Java reflection of course. Luckily someone solved this problem for me. At codehaus there is this library Paranamer which will read the parameter names from the debug info in the class files.



So my annotations then looked like this:



public class Stack {

@Require("#value != null")
@Ensure("top().equals(#value)")
public void push(String value) {
values.add(value);
}
}


Enforcing the Contract



The annotation classes themselves are pretty boring, they only contain a value and specify that they only apply to methods and are retained at runtime.



@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Require {
public String value();
}


The fun part is evaluating these pre and post conditions.  It turned out that AspectJ makes it quite easy with its support for annotation based pointcuts:



public aspect ContractEnforcer {
pointcut methodWithPrecondition() : execution(@Require * *(..));
pointcut methodWithPostcondition() : execution(@Ensure * *(..));
pointcut methodWithContract() : methodWithPrecondition() || methodWithPostcondition();
ThreadLocal inContractCheck = new ThreadLocal();

Object around(): methodWithContract() {
if(Boolean.TRUE.equals(inContractCheck.get())) {
return proceed();
}
inContractCheck.set(Boolean.TRUE);
Object result = null;
try {
Signature sig = thisJoinPointStaticPart.getSignature();
if(sig instanceof MethodSignature) {
Method method = ((MethodSignature) sig).getMethod();
Paranamer paranamer = new BytecodeReadingParanamer();
String[] parameterNames = paranamer.lookupParameterNames(method);
Require precondition = method.getAnnotation(Require.class);
if(precondition != null) {
enforcePrecondition(precondition.value(), sig, parameterNames, thisJoinPoint.getArgs(), thisJoinPoint.getTarget());
}
result = proceed();
Ensure postcondition = method.getAnnotation(Ensure.class);
if(postcondition != null) {
enforcePostcondition(postcondition.value(),sig, parameterNames, thisJoinPoint.getArgs(), thisJoinPoint.getTarget(), result);
}
}
} finally {
inContractCheck.set(Boolean.FALSE);
}
return result;
}

private void enforcePrecondition(String condition, Signature signature, String[] parameterNames, Object[] parameterValues, Object target) {
if(!conditionSatisfied(condition, parameterNames, parameterValues, target, null)) {
throw new PreconditionViolationException(condition, signature.toString(), parameterNames, parameterValues);
}
}

private void enforcePostcondition(String condition, Signature signature, String[] parameterNames, Object[] parameterValues, Object target, Object methodResult) {
if(!conditionSatisfied(condition, parameterNames, parameterValues, target, methodResult)) {
throw new PostconditionViolationException(condition, signature.toString(), parameterNames, parameterValues, methodResult);
}
}
private boolean conditionSatisfied(String condition, String[] parameterNames, Object[] parameterValues, Object target, Object methodResult) {
try {
ExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression(condition);
EvaluationContext context = new StandardEvaluationContext(target);
for(int index = 0; index < parameterNames.length; index++) {
context.setVariable(parameterNames[index], parameterValues[index]);
}
context.setVariable("result", methodResult);
Boolean result = exp.getValue(context, Boolean.class);
if(result == null) return false;
return result;
} catch(ParameterNamesNotFoundException e) {
System.out.println("Could not check condition - parameter names not available");
} catch(ParseException e) {
System.out.println("Could not check condition: " + e);
} catch (EvaluationException e) {
System.out.println("Could not check condition: " + e);
}
return false;
}
}


So it turned out to be quite easy to provide this very basic contract enforcement. The ThreadLocal is in there to make it possible to use methods with contract annotations within the contract conditions of other methods. That way only the “top most” conditions are checked.



Of course there is a lot to be done but I think this approach looks quite promising. I expect Spring EL support to arrive pretty soon in most IDEs and then it probably won’t be too difficult to provide code completion and error checking for the pre and post conditions in the IDE.

Friday, October 23, 2009

A first look at Spring Roo

I have finally found the time to have a look at Spring Roo. Generating a JPA model and some controllers for it took next to no time even without reading the documenation. What really surprised me was the extensive use of Aspect/J in the generated code.
For every bean Roo generated four Aspect/J files so that my Java bean contained only the private fields and  annotations. Getters and Setters were added as aspects. So was the generated ID field, the toString method and some finder methods.
The generated Spring MVC controller was also divided into a nearly empty Java class and an Aspect/J file containing all the necessary methods for a CRUD application, e.g.
@RequestMapping(value = "/place/form", method = RequestMethod.GET)    
public String PlaceController.createForm(ModelMap modelMap) {    
    modelMap.addAttribute("place", new Place());        
    return "place/create";        
}   

While this certainly keeps the generated Java source clean I’m not quite certain if I like this heavy reliance on aspects. It’s a nice showcase for what can be done with Aspect/J but I wonder how difficult it will be to maintain a Roo application. Guess I’ll have to play around with it a little more…

Monday, July 6, 2009

Transitions and Exceptions

There's this nice little feature in Spring Webflow that allows you to transition to a specific flow state when an exception occurs. Let's consider a simple example: If one of the methods you call from within a flow throws an exception you can send the user to an error page:
<view-state id="whatever">
<on-entry>
<evaluate expression="myService.doSomething()" />
</on-entry>
<transition on-exception="example.Exception" to="my-error-page" />
</view-state>



If you want to send the user to the same error page no matter in which state the exception occurs, you can define this transition as a global transition. Combined with flow inheritance you can take this one step further and define consistent exception handling for all your flows. Quite nifty.





There's just one thing to keep in mind however. This isn't quite obvious and it's also not mentioned in the documentation which is otherwise pretty good: The transition matches only if an exception of the exact class you specified if thrown. It will not match subclasses of the specified exception. Instead Webflow will unpack the exception until it either reaches the root cause or finds a match for your on-exception class.





So let's say you have the following exception hierarchy:

package example;

public class SystemException extends java.lang.RuntimeException {
public SystemException(java.lang.Throwable cause) {
super(cause);
}
}

package example;

public class MyServiceException extends SystemException {
public MyServiceException (java.lang.Throwable cause) {
super(cause);
}
}






And this flow definition excerpt:




<view-state id="whatever">
<on-entry>
<evaluate expression="myService.doSomething()" />
</on-entry>
<transition on-exception="example.SystemException" to="my-error-page" />
<transition on-exception="java.lang.RuntimeException" to="fatal-error-page" />
</view-state>






Now let's assume doSomething does something stupid like

try {
int id = Integer.parseInt(parameterString);
} catch(NumberFormatException e) {
throw new MyServiceException(e);
}



I bet that at first glance any Java programmer would expect the user to see my-error-page or at least fatal-error-page. Instead the user will get to see a very confusing stack trace because Webflow will look at your on-exception transition and (leaving out some Webflow specific exceptions wrapped around our exception) check if





  1. MyServiceException == SystemException


  2. NumberFormatException == SystemException


  3. MyServiceException == RuntimeException


  4. NumberFormatException == RuntimeException


and then, having found no exact match, proceed to the standard exception handler which simply displays the full stack trace. Now if you change your view-state definition to

<view-state id="whatever">
<on-entry>
<evaluate expression="myService.doSomething()" />
</on-entry>
<transition on-exception="example.SystemException" to="my-error-page" />
<transition on-exception="example.MyServiceException" to="my-error-page" />
<transition on-exception="java.lang.RuntimeException" to="fatal-error-page" />
</view-state>



then Webflow will find an exact match for the second transition and send the user to the error page.





Conclusion





Even if Spring Webflow's exception handling mechanism looks very much like a try/catch block it behaves differently. I still find it quite useful for handling specific exceptions in specific circumstances. But to reliably send the user to an error page I'd use some other mechanism as it will quickly become cumbersome and error prone to list all the exceptions that might possibly occur.

Saturday, July 4, 2009

Spring Webflow and JSF: Trouble with end-states

I've been using Spring Webflow 2 and JSF for some time months now and there's still one thing that bothers me (well, actually more than one, but this seems fundamental):

How do you reconcile the different approaches to state handling between these two frameworks? While Webflow makes it very easy to handle the current state of a Wizard-like pageflow that state is lost when you reach an end state. Say you have a very simple pageflow containing just three pages:
<view-state id="enter-details">
<transititon on="continue" to="check-details">
</view-state>
<view-state id="check-details">
<transition on="confirm" to="confirmed">
</view-state>
<end-state id="confirmed"/>

Using this flow with JSF you can use all the usual JSF components on the first two pages (the view states). The last page is a different story however. Since this is an end state Webflow will purge the flow state. Fine and dandy if it weren't for JSF's ugly reliance on the component tree to handle command buttons and links.

So what happens if you have a <h:commandbutton> or something similiar on your end state's page and the user clicks on that button? Well, surprise, the user gets redirected to the first page. As far as I can tell, JSF tries to find the current state but Webflow (correctly) determines that the requested flow has ended. Standard behaviour in this case is to redirect to the start page of the flow.

So on my current project we have built our site out of Webflows that are wired together using standard HTML links ("output links" in JSF parlance). Not really a nice solution but for now it works.


The drawbacks:

  • Some pages are enclosed in flows even though they aren't part of a "real" process (e.g. an overview page). Those flows don't even have natural end states.

  • You have to be extra careful not to use commandLinks, commandButtons or anything similiar on your end states' views. And this distinction between regular view and end state views makes working with templates quite ugly..

I'm still looking for a better way to mix free-style navigation with flows in JSF but so far I've come up blank.