The goal of Quality-Check is to provide a small Java library for basic runtime code quality checks. It provides similar features to org.springframework.util.Assert [1] or com.google.common.base.Preconditions [2] without the need to include big libraries or frameworks such as Spring or Guava. The package Quality-Check tries to replace these libraries and provide all the basic code quality checks you need. (If you're familiar with those classes, just look at our comparison page.)
The checks provided here are typically used to validate method parameters and detect errors during runtime. To detect errors before runtime we use JSR-305 Annotations. With these annotations you are able to detect possible bugs earlier. For more informations look at FindBugs™ JSR-305 support.
We think that our module is particularly suitable for APIs, which contain their own domain objects and services that are validated using Quality-Check not only functionally, but also technically. More over we provide an easy to use fail-fast description of an API to immediately report at its interface any failure or condition that is likely to lead to failure.
We noticed that many projects just copy org.springframework.util.Assert or com.google.common.base.Preconditions to get access to these quality checks. Therefore we provide these features and a small library that can be included in any application without big overhead.
We think that checks of method arguments are not only assertion tests it's more over a condition to work properly. Beyond this, it supports you to write faster contracts for your methods and classes. If nothing of this package make sense look at the concept design by contract.
/** * Sets the given object if it is not null. * * @throws IllegalArgumentException * if the given argument is {@code null} */ setObject(final Object object) { if (object != null) { throw new IllegalArgumentException("Argument 'object' must not be null."); } this.object = object; }
can be replaces by:
/** * Sets the given object if it is not null. */ @ArgumentsChecked setObject(final Object object) { this.object = Check.notNull(object); }
Quality-Check brings several advantages to your project. If used extensivel throughout your codebase, you will benefit from the following points. We will outline each one in a short paragraph below.
Quality-Checks to check the input arguments of a method, such as Check.isNull(object) or Check.positionIndex(4, myList.size()) should be applied to every argument of every public method in your class, service or component. Why is that? If you check all arguments as soon as they are passed to your code, you do not need to deal with invalid argument values through the rest of your component or class. For example, if every public method ensures that no null values are passed to the class, you do not have to care about null values in your private methods.
Therefore, Quality-Checks assist you in preventing technical errors in your classes, because they only have to work with valid arguments.
Often, in Java development, you have to deal with NullPointerExceptions or other faults which can be tracked back to invalid values passed to methods and handed further down till they crash in your code. Sometimes it is hard to trace down where the invalid value came from. To identify invalid values as soon as possible and detect errors where they occur, we suggest to guard every public method with Quality-Checks.
Using quality checks, erroneous input arguments are identified, as soon as they are passed to your component.
If you add checks for method arguments manually, you will notice that you have to write additional tests using invalid method arguments to cover these branches. One example for a manual check is here:
void doSomething(final List<String> list) { if( list == null ) { throw new IllegalArgumentException("Argument 'list' must not be null."); } if( list.isEmpty() ) { throw new IllegalArgumentException("Argument 'list' must not be empty."); } }
In this example, you would have to write two additional tests (one with a null list and one with an empty list), just to test these to branches - or, if you do not, your branch coverage will go down.
Quality-Checks will save you from doing so! As calls to Check.* are method calls you will cover them in any test automatically. We make sure that Quality-Check works, so that you do not have to test it. See the example below:
@ArgumentsChecked void doSomething(final List<String> list) { Check.isNull(list, "list"); Check.isEmpty(list, "list"); }
Similar to the example of the branch coverage, you also write a lot of JavaDoc documentation for exceptions thrown in your methods, which check for illegal input parameters.
/** * Method does something. * * @throws IllegalArgumentException if list is null. * @throws AnotherIllegalArgumentException if list is empty. */ void doSomething(final List<String> list) { if( list == null ) { throw new IllegalArgumentException("Argument 'list' must not be null."); } if( list.isEmpty() ) { throw new AnotherIllegalArgumentException("Argument 'list' must not be empty."); } }
As quality check throws the exceptions and your code does not there is no need for you to document these exceptions. You can focus on the real important documentation of exceptions which might be thrown by business logic. To show the caller of the method that quality-checks are in place and certain exceptions might be thrown, we add an @ArgumentsChecked annotation.
Your participation in this project is much appreciated!