Reputation: 7731
I've run into this pattern several times. In pseudo-code:
public class BlahResource {
if (thisError)
buildResponse(BAD_REQUEST);
if (thatError)
buildResponse(CONFLICT);
...
doSomething();
return buildResponse(SUCCESS);
}
Doesn't look too bad, but when you have a million error conditions to handle, too much business logic accretes into the Resource class and the noise quickly overwhelms the story of what the code is actually doing.
Since in a resource the error conditions are returning something, an exception thrown from a service doesn't seem right to me. And a status object encapsulating different combinations of return conditions and setups seems like overkill.
Is there something obvious I'm missing in how this can be coded in a logical, clear way? Possibly something functional/Guava/lambda-based that I'm missing, or just a regular OO solution.
Upvotes: 1
Views: 106
Reputation: 28519
There's a complete JSR-349 Bean Validation specification addressing these concerns
From the specification goals
Validating data is a common task that occurs throughout an application, from the presentation layer to the persistence layer. Often the same validation logic is implemented in each layer, proving to be time consuming and errorprone. To avoid duplication of these validations in each layer, developers often bundle validation logic directly into the domain model, cluttering domain classes with validation code that is, in fact, metadata about the class itself. This JSR defines a metadata model and API for JavaBean validation. The default metadata source is annotations, with the ability to override and extend the meta-data through the use of XML validation descriptors.
The hibernate-validator is the reference implementation, but just note that the implementation is not tied to any tier (nor web nor the persistence tier)
Going back to your resource code, this would mean that, by utilizing the custom constraints, your Resource would look something like
public class BlahResource {
@CheckBadRequest
@CheckConflict
private field
...
}
when the validation fails, the errors are stored inside ConstraintViolation that you can obtain through Validator interface. Those are the central points around which you should build your error handling mechanism, again a pseudo
Set<Constraintviolation<Resource>> violations = validator.validate(Resource);
Upvotes: 2