Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I place validating constraints on my method input parameters?

Here is the typical way of accomplishing this goal:

public void myContractualMethod(final String x, final Set<String> y) {
    if ((x == null) || (x.isEmpty())) {
        throw new IllegalArgumentException("x cannot be null or empty");
    }
    if (y == null) {
        throw new IllegalArgumentException("y cannot be null");
    }
    // Now I can actually start writing purposeful 
    //    code to accomplish the goal of this method

I think this solution is ugly. Your methods quickly fill up with boilerplate code checking the valid input parameters contract, obscuring the heart of the method.

Here's what I'd like to have:

public void myContractualMethod(@NotNull @NotEmpty final String x, @NotNull final Set<String> y) {
    // Now I have a clean method body that isn't obscured by
    //    contract checking

If those annotations look like JSR 303/Bean Validation Spec, it's because I borrowed them. Unfortunitely they don't seem to work this way; they are intended for annotating instance variables, then running the object through a validator.

Which of the many Java design-by-contract frameworks provide the closest functionality to my "like to have" example? The exceptions that get thrown should be runtime exceptions (like IllegalArgumentExceptions) so encapsulation isn't broken.

like image 576
Robert Campbell Avatar asked Nov 27 '09 14:11

Robert Campbell


3 Answers

If you're looking for a fully fledged design-by-contract mechanism I'd take a look at some of the projects listed on the Wikipedia page for DBC.

If your looking for something simpler however, you could look at the Preconditions class from google collections, which provides a checkNotNull() method. So you can rewrite the code you posted to:

public void myContractualMethod(final String x, final Set<String> y) {
    checkNotNull(x);
    checkArgument(!x.isEmpty());
    checkNotNull(y);
}
like image 115
Jared Russell Avatar answered Sep 29 '22 02:09

Jared Russell


I've seen a technique by Eric Burke that is roughly like the following. It is an elegant use of static imports. The code reads very nicely.

To get the idea, here is the Contract class. It is minimal here, but can be easily filled out as needed.

package net.codetojoy;

public class Contract {
    public static void isNotNull(Object obj) {
        if (obj == null) throw new IllegalArgumentException("illegal null");
    }
    public static void isNotEmpty(String s) {
        if (s.isEmpty()) throw new IllegalArgumentException("illegal empty string");
    }
}

And here is an example usage. The foo() method illustrates the static imports:

package net.codetojoy;

import static net.codetojoy.Contract.*;

public class Example {
    public void foo(String str) {
        isNotNull(str);
        isNotEmpty(str);
        System.out.println("this is the string: " + str);
    }

    public static void main(String[] args) {
        Example ex = new Example();
        ex.foo("");
    }
}

Note: when experimenting, note that there may be a bug around doing this in the default package. I've certainly lost brain cells trying it.

like image 21
Michael Easter Avatar answered Sep 29 '22 02:09

Michael Easter


There is a small Java Argument Validation package, implemented as Plain Java. It comes with several standard checks / validations. And for those cases where someone need its own more specific validations, it comes with some helper methods. For validations that occur multiple times, just extend the interface ArgumentValidation, with your own And create the implementing class that extends from the class ArgumentValidationImpl.

like image 29
Verhagen Avatar answered Sep 29 '22 02:09

Verhagen