Alchemy Arguments
"Check Yo'self!"
Purpose
Part of the Alchemy Collection, Alchemy Arguments allows developers to perform fluid argument checking and validation.
Download
To use, simply add the following maven dependency.
Release
<dependency>
<groupId>tech.sirwellington.alchemy</groupId>
<artifactId>alchemy-arguments</artifactId>
<version>2.2.1</version>
</dependency>
Snapshot
First add the Snapshot Repository
<repository>
<id>ossrh</id>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
</repository>
<dependency>
<groupId>tech.sirwellington.alchemy</groupId>
<artifactId>alchemy-arguments</artifactId>
<version>2.3-SNAPSHOT</version>
</dependency>
API
The API of this library aims to use fluid-style language to argument checking and validation. It's like Hamcrest's Matchers, but with the additional ability to apply multiple conditions on a single argument.
Instead of
if (zipCode < 0)
{
throw new IllegalArgumentException("Zip Code must be positive");
}
if (zipCode > 99999)
{
throw new IllegalArgumentException("Zip Code cannot exceed 99999");
}
You can now just do:
checkThat(zipCode)
.is(positiveInteger())
.is(lessThanOrEqualTo(99999));
Multiple Arguments
You can also check multiple Arguments at the same time.
checkThat(firstName, middleName, lastName)
.are(nonEmptyString())
.are(stringWithLengthAtLeast(1));
Error Message
Each Assertion includes a specific error message in the Exception, but sometimes you want to include a
overrideMessage
more suited to the context.
checkThat(responseCode)
.usingMessage("Server Response not OK")
.is(equalTo(200));
Custom Exceptions
Sometimes an IllegalArgumentException
is not the Exception you want to throw.
For example,
@GET
public Response getCoffee(String nameField)
{
String nameField;
checkThat(nameField)
.usingMessage("missing name")
.is(nonEmptyString());
}
In stock Jersey, this would cause a 500, and make it seem like your Service failed.
You can throw a more specific Exceptions when making assertions.
checkThat(password)
.throwing(BadPasswordException.class)
.is(nonEmptyString())
.is(alphanumericString())
.is(stringWithLengthBetween(10, 20));
In the example above, if the password fails the checks, a BadPasswordException
will be thrown.
Compare that to:
if (Strings.isNullOrEmpty(password) &&
password.length() < MIN_LENGTH &&
password.length() > MAX_LENGTH)
{
throw new BadPasswordException("missing password");
}
Alternatively, you can also supply custom Exception throwing behavior. Let's try with an age check:
checkThat(age)
.throwing(ex -> new BadPasswordException(ex))
.is(positiveInteger())
.is(greaterThanOrEqualTo(18))
.is(lessThan(150));
This also allows you to decide what message to include in the exception, and whether to include or mask the underlying assertion error.
Custom Assertions
You can create your own library of custom assertions and reuse them. In fact, we encourage it. It is common to perform the same argument checks in multiple parts of the Codebase.
Thanks to the new Java 8 lambdas, it is much easier to create inline assertions in your code.
AlchemyAssertion<Car> sedan = car ->
{
if (!(car instanceof Sedan))
{
throw new FailedAssertionException("Expecting a Sedan");
}
};
checkThat(car)
.is(sedan);
AlchemyAssertion<Vehicle> truck = v ->
{
if (!(v instanceof Truck))
{
throw new FailedAssertionException("Expecting a Truck but got " + v);
}
};
//This masks the causing FailedAssertionException with a different exception and message.
checkThat(vehicle)
.throwing(ex -> new UnauthorizedException("Trucks only"))
.is(truck);
Building on Existing assertions can make for powerful checks.
public static AlchemyAssertion<Person> validPerson()
{
return person ->
{
checkThat(person).is(notNull);
checkThat(person.firstName, person.lastName)
.usingMessage("person is missing names")
.are(nonEmptyString());
checkThat(person.birthday)
.is(beforeNow());
};
}
// Reuse the argument checks
public String findUsername(Person person)
{
checkThat(person)
.is(validPerson());
//Proceed safely
}
Javadocs
Requirements
- Java 7
- Maven
Building
This project builds with maven. Just run a mvn clean install
to compile and install to your local maven repository
License
This Software is licensed under the Apache 2.0 License