About Jakub Nabrdalik

Jakub is a software developer: programmer, architect, analyst, team leader, project manager and coach at TouK. Infected with eXtreme Programming and Software Craftsmanship. Test driving and pair programming web and enterprise applications since 2005 in several languages.

Getting rid of null parameters with a simple spring aspect

What is the most hated and at the same time the most popular exception in the world?

I bet it’s the NullPointerException.

NullPointerException can mean anything, from simple “ups, I didn’t think that can be null” to hours and days of debugging of third-party libraries (try using Dozer for complicated transformations, I dare you).

The funny thing is, it’s trivial to get rid of all the NullPointerExceptions in your code. This triviality is a side effect of a technique called “Design by Contract”.

I won’t go into much details about the theory, you can find everything you need on Wikipedia, but in the nutshell Design by Contract means:

  • each method has a precondition (what it expects before being called)
  • each method has a postcondition (what it guarantees, what is returned)
  • each class has an constraint on its state (class invariant)

So at the beginning of each method you check whether preconditions are met, at the end, whether postconditions and invariant are met, and if something’s wrong you throw an exception saying what is wrong.

Using Spring’s internal static methods that throw appropriate exceptions (IllegalArgumentException), it can look something like this:

import static org.springframework.util.Assert.notNull;
import static org.springframework.util.StringUtils.hasText;

public class BranchCreator {
    public Story createNewBranch(Story story, User user, String title) {
        verifyParameters(story, user, title);
        Story branch = //... the body of the class returnig an object
        verifyRetunedValue(branch);
        return branch;
    }

    private void verifyParameters(Story story, User user, String title) {
        notNull(story);
        notNull(user);
        hasText(title);
    }

    private void verifyRetunedValue(Story branch) {
        notNull(branch);
    }
}

You can also use Validate class from apache commons instead of spring’s notNull/hasText.

Usually I just check preconditions and write tests for postconditions and constraints. But still, this is all boiler plate code. To move it out of your class, you can use many Design by Contract libraries, for example
SpringContracts, or Contract4J. Either way you end up checking the preconditions on every public method.

And guess what? Except for Data Transfer Objects and some setters, every public method I write expects its parameters NOT to be null.

So to save us some writing of this boiler plate ocde, how about adding a simple aspect that will make it impossible in the whole application, to pass null to anything other than DTOs and setters? Without any additional libraries (I assume you are already using Spring Framework), annotations, and what else.

Why would I like to not allow for nulls in parameters? Because we have method overloading in modern languages. Seriously, how often do you want to see something like this:

Address address = AddressFactory.create(null, null, null, null);

And this is not much better either

Microsoft.Office.Interop.Excel.Workbook theWorkbook = ExcelObj.Workbooks.Open(openFileDialog.FileName, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing);

 
The solution

So here is a simple solution: you add one class to your project and a few lines of spring IoC configuration.

The class (aspect) looks like this:

import org.aspectj.lang.JoinPoint;
import static org.springframework.util.Assert.notNull;

public class NotNullParametersAspect {
    public void throwExceptionIfParametersAreNull(JoinPoint joinPoint) {
        for(Object argument : joinPoint.getArgs()) {
            notNull(argument);
        }
    }
}

And the spring configuration is here (remember to change the namespace to your project).

<aop:config proxy-target-class='true'> 
    <aop:aspect ref='notNullParametersAspect'>
        <aop:pointcut expression='execution(public * eu.solidcraft.*..*.*(..))
                          && !execution(public * eu.solidcraft.*..*Dto.*(..))
                          && !execution(public * eu.solidcraft.*..*.set*(..))' id='allPublicApplicationOperationsExceptDtoAndSetters'> 
            <aop:before method='throwExceptionIfParametersAreNull' pointcut-ref='allPublicApplicationOperationsExceptDtoAndSetters'></aop:before>     
        </aop:pointcut> 

        <task:annotation-driven>
            <bean class='eu.solidcraft.aspects.NotNullParametersAspect' id='notNullParametersAspect'></bean>
        </task:annotation-driven>
    </aop:aspect>
</aop:config>

The ‘&&’ is no error, it’s just && condition escaped in xml. If you do not understand aspectj pointcut definition syntaxt, here is a little cheat sheet.

And here is a test telling us that the configuration is succesfull.

public class NotNullParametersAspectIntegrationTest extends AbstractIntegrationTest {
    @Resource(name = 'userFeedbackFacade')
    private UserFeedbackFacade userFeedbackFacade;

    @Test(expected = IllegalArgumentException.class)
    public void shouldThrowExceptionIfParametersAreNull() {
        //when
        userFeedbackFacade.sendFeedback(null);

        //then exception is thrown
    }

    @Test
    public void shouldNotThrowExceptionForNullParametersOnDto() {
        //when
        UserBookmarkDto userBookmarkDto = new UserBookmarkDto();
        userBookmarkDto.withChapter(null);
        StoryAncestorDto ancestorDto = new StoryAncestorDto(null, null, null, null);

        //then no exception is thrown
    }
}

AbstractIntegrationTest is a simple class that starts the spring test context. You can use AbstractTransactionalJUnit4SpringContextTests with @ContextConfiguration(..) instead.

The catch

Ah yes, there is a catch. Since spring AOP uses either J2SE dynamic proxies basing on an interface or aspectj CGLIB proxies, every class will either need an interface (for simple proxy based aspect weaving) or a constructor without any parameters (for cglib weaving). The good news is that the constructor can be private.
 

Reference: Getting rid of null parameters with a simple spring aspect from our JCG partner Jakub Nabrdalik at the Solid Craft blog.

Do you want to know how to develop your skillset to become a Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you two of our best selling eBooks for FREE!

JPA Mini Book

Learn how to leverage the power of JPA in order to create robust and flexible Java applications. With this Mini Book, you will get introduced to JPA and smoothly transition to more advanced concepts.

JVM Troubleshooting Guide

The Java virtual machine is really the foundation of any Java EE platform. Learn how to master it with this advanced guide!

Given email address is already subscribed, thank you!
Oops. Something went wrong. Please try again later.
Please provide a valid email address.
Thank you, your sign-up request was successful! Please check your e-mail inbox.
Please complete the CAPTCHA.
Please fill in the required fields.

One Response to "Getting rid of null parameters with a simple spring aspect"

  1. Nice. I prefer using the AspectJ compiler with before-constructor and before- & after-method execution advice along with @NotNull (and any other JSR 303 validation annotations).

    Curious: why did you use ? NotNullParametersAspect doesn’t use any annotations, so the could be defined regularly under the element. Am I missing something there?

Leave a Reply


+ four = 7



Java Code Geeks and all content copyright © 2010-2014, Exelixis Media Ltd | Terms of Use | Privacy Policy | Contact
All trademarks and registered trademarks appearing on Java Code Geeks are the property of their respective owners.
Java is a trademark or registered trademark of Oracle Corporation in the United States and other countries.
Java Code Geeks is not connected to Oracle Corporation and is not sponsored by Oracle Corporation.
Do you want to know how to develop your skillset and become a ...
Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you two of our best selling eBooks for FREE!

Get ready to Rock!
You can download the complementary eBooks using the links below:
Close