Should a DTO parser/mapper wrap and rethrow domain exceptions? - java

Let's say I have this value object:
public class Latitude {
private Double value;
public Latitude(Double value) {
if (value < -180 || value > 180) {
throw RuntimeException("Invalid value for latitude");
}
this.value = value;
}
public Double getValue() {
return this.value;
}
}
And this DTO:
public class LatitudeDTO {
private Double value;
public Double getValue() {
return this.value;
}
}
I want to create a Parser, so I can use it in the application service in this way:
Latitude latitude = latitudeParser.fromDTO(latitudeDTO);
I'm considering two option for implementing this parser. Option #1:
public class LatitudeParser {
public Latitude fromDTO(LatitudeDTO latitudeDTO) throws DtoParserException {
try {
return new Latitude(latitudeDTO.getValue());
} catch(RuntimeException e) {
throw new DtoParserException(e);
}
}
}
Option #2:
public class LatitudeParser {
public Latitude fromDTO(LatitudeDTO latitudeDTO) throws DtoParserException {
if (value < -180 || value > 180) {
throw DtoParserException("Invalid value for latitude");
}
return new Latitude(latitudeDTO.getValue());
}
}
In both cases, DtoParserException is later mapped to 400 Bad Request, when it reaches the presentation layer.
Now, for me option #1 is better, because there's no repetition of the validation rule. However, I've heard that everything that is sent to the domain must be validated before and in this sense the exceptions thrown by the domain layer point out a bug in the application layer code. In this case I shoudn't use domain exceptions to inform the user of my application that the data inputted is invalid.
So, should the parser make its own validations or use the domain validation? It seems so weird to just replicate the validation in the parser.

everything that is sent to the domain must be validated before
I would personally rephrase this to "Everything that makes it into the domain layer is valid". I'm saying this because one reason to use value objects as parameters into the domain layer is that it removes the need for format validation logic in the domain layer. Compare the following to signatures:
public void RegisterUser(string firstName, string lastName, string phoneNumber, string email)
vs
public void RegisterUser(FullName name, PhoneNumber phoneNumber, Email email)
In the second scenario, you can be certain that all parameters are non null and with correctly formatted data.
So, when it says that "must be validated before", in this case, the constructor of the value object is already "before" getting into the business logic layer.
What I would say is that RuntimeException is not a very good name for that exception. Note that exceptions are part of the "Contract" of a class. In the case of the value object, the constructor, the public properties and the exceptions are part of its contract, so you'd probably have something like InvalidCoordinatesException or similar.
The reason I'm saying this is that the DTO parser logic probably belongs to the same layer that currently handles your DtoParserException, so maybe you don't need to translate the exception at all and you directly can handle the InvalidCoordinatesException (or a base ValueObjectValidationException). But that's for your consideration.

Related

Is it correct application of the SRP(single responsibility principle)?

I have a java class:
class User {
private String name;
private String address;
private int age;
private BigDecimal salary;
// other fields
//getters setters
}
I can receive a map of new values in these fields and update it. It looks like this: ChangeItem changeItem where changeItem.key is field's name and changeItem.value is the field's value
I create strategies for updating each field. For example common interface:
public interface UpdateStrategy<T> {
T updateField(T t, ChangeItem changeItem) throws ValidationExceptions;
}
And some implementation:
public class UpdateNameStrategy implements UpdateStrategy<User> {
private static final Pattern USER_NAME = Pattern.compile(...);
#Override
public User updateField(User user, ChangeItem changeItem) throws ValidationExceptions {
String fieldValue = changeItem.value;
if (!validate(fieldValue))
throw new ValidationExceptions(changeItem);
user.setName(fieldValue);
return user;
}
private boolean validate(String value){
return USER_NAME.matcher(value).matches();
}
}
In the real project I have 40 fields and 40 strategies for each field(with different validation and logic).
I think this class violates the SRP(single responsibility principle). And I move validation logic to separately class. I change the validation method to:
public class UpdateNameStrategy implements UpdateStrategy<User> {
#Override
public User updateField(User user, ChangeItem changeItem) throws ValidationExceptions {
String fieldValue = changeItem.value;
ValidateFieldStrategy fieldValidator = new UserNameValidate(fieldValue);
if (!fieldValidator.validate())
throw new ValidationExceptions(changeItem);
return user;
}
}
and
public class UserNameValidate implements ValidateFieldStrategy {
private static final Pattern USER_NAME = Pattern.compile(...);
private String value;
public UserNameValidate(String value) {
this.value = value;
}
#Override
public boolean validate() {
return USER_NAME.matcher(value).matches();
}
}
And now I have 40 strategies for update fields and 40 validators. Is it the correct way? Or maybe I can change this code more clear?
I'm sorry for being blunt, my eyes are bleeding while looking at this. You took one unnecessarily complicated validation model and you split it in two to make it even more complicated. And none of it has much to do with the Single Responsibility Principle.
Without knowing anything specific to your domain problem, this looks like a superfluous usage of the Strategy pattern.
I've never seen a legitimate domain problem requiring a validation strategy split like this, for every single field.
An object in a domain is not just a collection of fields. It is also behavior governing the fields (which is the object state) and the rules governing the mutability of that state.
In general we want rich objects with behavior. And that behavior typically includes validation.
I sincerely doubt that every single field in a model requires validation to this level of granularity. Put the validation in the object's setter methods and be done with it.
You are killing yourself doing all this elaborate setup. We all want structure, but at some point all of this is just ceremony for building very tall sand castles.
Validation in general is part of an object. And an object is responsible, it is its responsibility to govern its state, the collection of fields and values it possesses and controls.
Single Responsibility Principle does not mean extracting the responsibility of validating fields out of an object. That responsibility is intrinsic to the object.
Single Responsibility Principle concerns itself with "external" responsibility, the responsibility of an object to provide a single coherent function (or set of coherent functions) to someone that uses that object.
Consider a Printer object. This object is responsible to print. It is not responsible to manage the network connections between a printer and a user, for instance.
SRP is not limited to classes, but also packages and modules. A Mathematics module should provide you with, obviously, mathematical routines. It should not provide routines for filesystem manipulation, right?
That's what the SRP is about. What you are doing, extracting validation behavior out of an object, that has little, if anything, to do with SRP.
Sometimes one might want to extract out common validation routines (check if a string is black or null, or whether a number is a natural number.)
So you might have a class like this:
public class User {
// some fields, blah blah
public void setName(final String aName){
if( aName == null || a.aName.trim().length() < 1){
throw new SomeException("empty string blah blah");
}
this.name=aName.trim(); // model requires this to be trimmed.
}
public void setRawField(final String aValue){
if( aName == null || a.aName.trim().length() < 1){
throw new SomeException("empty string blah blah");
}
this.rawField=aValue; // model requires this to not be trimmed.
}
public void setRawField2(final String aValue){
// model requires this field to be non-null,
// can be blank, and if not blank, must be all lower case.
if(aValue == null) {
throw new NullPointerException("null string blah blah");
}
this.rawField2=aValue.toLowerCase();
}
changed into a class that delegates minutia to an external validation utility class or module.
public class User {
// some fields, blah blah
public void setName(final String aName){
// model requires this to be trimmed
this.name=Validator.notEmptyOrDie(aName).trim();
}
public void setRawField(final String aValue){
// model requires this to *not* be trimmed
this.rawField=Validator.notEmptyOrDie(aValue);
}
public void setRawField2(final String aValue){
// model requires this field to be non-null,
// can be blank, and if not blank, must be all lower case.
// too contrive to refactor, leave it here.
if(aValue == null) {
throw new NullPointerException("null string blah blah");
}
this.rawField2=aValue.toLowerCase();
}
public class Validator {
static public String notEmptyOrDie(final String aString){
if( aString == null || aString.trim().length() < 1){
throw new SomeException("empty string blah blah");
}
return aString;
}
This is an approach I actually follow, to refactor parts of common validation. I factor out minutia.
But the core validation logic, if any, it remains in the object. Notice that validation is still part of the User class. All that got extracted is the minutia.
The logic that declares the intent of validation (check if black or die) still remains part of the User class. It is intrinsic to the class' behavior.
In some models, the User class might not require validation at all. It might be just a data shuttle, a POJO.
OTH, in a model that requires it to validate its state, that state should usually go inside the class, and a developer must have a very good argument for extricating that logic the way you did in your sample code.
SRP says nothing about how you compose responsibility internal to the object, only external to consumers of said object.
As a rule of thumb, validation of object fields belong to the object as logic internal to the object. It is intrinsic to the object's behavior, invariants, pre conditions and post conditions.
Very rarely you extract out the entire validation out of an object (unless we are talking about POJOs serialized and deserialized by an external package, and with validations added declaratively via annotations or some sort of controlling configuration descriptor.)
Hit me up if you still have any questions. Not sure how fast I can answer back, but I don't mind to answer questions if I can.
**** EDIT ***
User #qujck mentions the valid concern in this proposed approach, that it is not possible to differentiate all validation exceptions (becuase they use common exceptions for all.)
One possibility (which I've used) is to have overloaded and/or polymorphic validators:
public class Validator {
static public String notEmptyOrDie(final String aString){
return Validator.notEmptyOrDie(aString, null);
}
static public String notEmptyOrDie(final String aString,
final String aFieldName){
if( aString == null || aString.trim().length() < 1){
throw new SomeException(
(aFieldName==null? "" : aFieldName + " ")
+ "empty string blah blah");
}
return aString;
}
}
If one uses a hierarchy of validation exceptions with common constructors, then one could take this further by passing the desired exception class, and use reflection to create instances to be thrown.
I've done that also. Actually, I'm doing that now for a common error-throwing mechanism in an EJB layer that itself reaches to another system via network protocols.
But that's something I do to cope with an existing system, not something I would do if I had a design choice. And it still limits itself to refactoring validation or error handling to its core elements.
Actual, object-specific validation still remains at/within the object itself.

DRYing up controller - method that returns entity or redirects (in Java, Spring)

I have a controller that has a few methods that get an optional of entity from service, checks if is present and proceeds with some other actions or redirects with message "Entity not found".
It looks like that:
#GetMapping("action")
public String method(#PathVariable Long id,
final RedirectAttributes redirectAttributes){
Optional<Entity> eOpt = entityService.findById(id);
if(eOpt.isEmpty()){
alertHandler.set(redirectAttributes, Status.ENTITY_NOT_FOUND);
return "redirect:/entity/list"
}
Entity e = eOpt.get();
// other actions that are using e
return "view-name";
}
The six lines repeat in a few methods and for different entities too. Is there a way to assign it to some private method? The only thing I came up with is using a private method like:
private Optional<Entity> getEntityOpt(Long id){
Optional<Entity> eOpt = entityService.findById(id);
if(eOpt.isEmpty()){
alertHandler.set(redirectAttributes, Status.ENTITY_NOT_FOUND);
}
return Optional.empty();
}
This only saves me one line in mapped methods, so I don't have to set up alert message. Otherwise I still have to check again if the Optional is empty to redirect it.
So I guess the question really is - can I set up the private method to either return entity or redirect like:
Entity e = getEntityOrRedirect(Long id);
or maybe you have different ways to handle that problem. Or maybe it is what it is and you have to repeat yourself...
You may treat empty Optional as an exceptional situation.
In that case you may provide your own RuntimeException containing path to redirect.
public class EntityNotFoundException extends RuntimeException {
private final String fallbackView;
public EntityNotFoundException(final String fallbackView) {
this.fallbackView = fallbackView;
}
public String getFallbackView() {
return fallbackView;
}
Then provide a method annotated with #ExceptionHandler to your controller class (or if the situation is common for multiple controllers then provide such method to class annotated with #ControllerAdvice). Your exception handler should catch just defined exception and do a redirect.
#ExceptionHandler(EntityNotFoundException.class)
public String redirectOnEntityNotFoundException(final EntityNotFoundException exception,
final RedirectAttributes redirectAttributes) {
alertHandler.set(redirectAttributes, Status.ENTITY_NOT_FOUND);
return exception.getFallbackView();
}
Finally you achieved some kind of getEntityOrRedirect. Now you may use the above setup as following:
#GetMapping("action")
public String method(#PathVariable Long id){
Entity e = entityService.findById(id)
.orElseThrow(() -> new EntityNotFoundException("redirect:/entity/list"));
// other actions that are using e
return "view-name";
}
Code not tested so apologize for typos in advance.
Note I believe it would work for Spring >= 4.3.5 as otherwise RedirectAttributes wouldn't be resolved for #ExceptionHandler (as stated here)

AssertJ: Testing exceptions with messages generated with String.format

I'm wondering if there is a clean and complete way to assert on the message attached to a thrown exception when that message was generated using String.format(). For example, a class like:
public class Car {
public static final String DRIVE_ERROR = "Can't drive while car %s is parked!";
private String name;
private boolean parked;
public Car(String name) {
this.name = name;
this.parked = true;
}
public void drive() {
if (parked) {
throw new IllegalStateException(String.format(DRIVE_ERROR, name));
}
}
}
(Sorry for the weird example, just trying to keep it as simple as possible)
Now if I were testing the car, I'd have a class like this:
public class CarTest {
#Test
public void drive_test() {
Car car = new Car("Greased Lightning");
assertThatThrownBy(() -> car.drive())
.isInstanceOf(IllegalStateException.class)
.hasMessageContaining("???");
}
}
The question is, what is the best way to assert on the message? In this example, I could separate out the declaration of the name of the car, then use String format myself to grab the static string from Car and format in the name, but that seems like a lot of extra code, and can't be easily used in a lot of instances (eg. when the item that goes in the formatted string is determined at runtime). What I'd really like to be able to do is pass the error message string to hasMessageContaining and have it ignore the "%s" placeholder and accept anything in that spot. Is there a way to do regex matching of Strings with assertJ? Or some other way of doing this cleanly?
EDIT: I'm also open to alternatives on throwing exceptions that have messages that are easier to test. One solution is just using String concatenation, like throw new Exception(STATIC_ERROR_MESSAGE + name) and then testing that the message contains the first part, but that really limits your message formatting ability and doesn't look very clean.
Exception message assertions are limited compared to regular String assertion.
What you could do is use matches or containsPattern assertions, ex:
#Test
public void test() {
// GIVEN some preconditions
// WHEN
Throwable thrown = catchThrowableOfType(() -> { throw new IllegalStateException("boom!"); },
IllegalStateException.class);
// THEN
assertThat(thrown.getMessage()).matches(".oo.")
.containsPattern("oo.");
// or even better thanks to Rolland Illig suggestion
assertThat(thrown).hasMessageMatching(".oo.");
}
Note that by using catchThrowableOfType you don't have to check that the caught exception is of the expected type anymore.

Hibernate validation with strong typing in Jersey with Jackson

I am implementing a REST API using Jersey. I want to validate all of the inputs to my service (query params, path params, DTOs) and am looking into some options - one that looks like it does the job is Jersey Bean Validation. I also want to have everything in the service strongly typed - for example, instead of using String to represent all of the bits of data, where you'd have a function like this:
public Order getOrder(String customerId);
Instead define types for each bit of data (the benefit of this is to let the compiler catch incorrect data being passed to functions, being able to obfuscate the underlying value in the toString method for logging, knowing that the value is definitely valid if you have an instance and so on), so you end up with functions like this:
public Order getOrder(CustomerId customerId);
And types like this:
public class CustomerId {
private final String value;
public CustomerId(String value) {
this.value = validate(value);
}
public String getValue() {
return value;
}
private String validate(String value) {
// Do some validation here
}
}
The Jersey Bean Validation examples do not use strong types like above. For example:
#Path("/")
class MyResourceClass {
#POST
#Consumes("application/x-www-form-urlencoded")
public void registerUser(
#Pattern(regexp="[a-zA-Z -]{1,50}") #FormParam("name") String name) {
...
}
}
The build in validation is nice in that you get some features for free:
400 bad request exception returned on any validation error
Optionally include the validation error in the response
None of the code in your function gets executed if validation fails
However, there are a few problems:
You have to remember to include the annotations everywhere the data
can be input to your system, so it's hard to apply consistently
You may end up with different definitions of what is valid for a type
You don't get the strong typing benefits mentioned above
Does anyone know of a way to get all of these benefits. I tried defining a type like this:
public class CustomerId {
private final String value;
public CustomerId(String value) {
this.value = validate(value);
}
public String getValue() {
return value;
}
private String validate(String value) {
if (!Pattern.matches("[a-zA-Z -]{1,50}", value)) {
throw new ConstraintViolationException(new HashSet<ConstraintViolation<?>>());
}
return value;
}
}
But it seems the exception doesn't get handled the same way by Jersey, and the response code you get if the validation fails is 404 instead of 400.
Does anyone know of a way to get the best of both worlds?
This is from the spec, in regards to how errors are handle when constructing #XxxParams
... if the [..] is annotated with #MatrixParam, #QueryParam or #PathParam then an implementation MUST generate an instance of NotFoundException (404 status) that wraps the thrown exception and no entity; if the field or property is annotated with #HeaderParam or #CookieParam then an implementation MUST generate an instance of
BadRequestException (400 status) that wraps the thrown exception and no entity.
Though not listed here, #FormParam falls under the 400 bracket.
"Does anyone know of a way to get the best of both worlds?"
We can override this behavior by throwing a WebApplicationException. We could then create an ExceptionMapper for the exception, and then just delegate to the ExceptionMapper that normally handles ConstraintViolationException. I couldn't find any clear detail on this behavior. I mean you would expect that the ExceptionMapper should get called anyway, but it doesn't if it is isn't an instance of WebApplicationException. So you can make your exception extend WebApplicationException.
public static class MyException extends WebApplicationException {
private final ConstraintViolationException cve;
public MyException(ConstraintViolationException cve) {
this.cve = cve;
}
public ConstraintViolationException getConstraintViolationException() {
return cve;
}
}
Then create an ExceptionMapper for it. In the mapper, we simply delegate to the original mapper that handles ConstraintViolationException
public static class MyExceptionMapper implements ExceptionMapper<MyException> {
#Context
private Providers providers;
#Override
public Response toResponse(MyException exception) {
ExceptionMapper<ValidationException> mapper
= providers.getExceptionMapper(ValidationException.class);
return mapper.toResponse(exception.getConstraintViolationException());
}
}
Then you can just throw MyException. If you don't care for an error response body, and all you want is a 400 status, you can forget everything above and simply throw a BadRequestException. Or if you don't care for the response entity that the ConstraintViolationException mapper sends out, you can create your own response in the MyExceptionMapper, or create a Response inside the CustomerId class and pass it the BadRequestException constructor. So you have some options.
A headache from this approach I could see is that you need to create your own ConstraintViolation. That can get old really quick.
The other approach I could see is to use #BeanParam and #Valid
public static class CustomerId {
#FormParam("cust")
#Pattern(regexp="[a-zA-Z -]{1,50}")
private String value;
public void setValue(String value) {
this.value = value;
}
public String getValue() {
return value;
}
}
#POST
#Path("form")
#Consumes("application/x-www-form-urlencoded")
public String postForm(#BeanParam #Valid CustomerId custId) {
The problem with this approach is that your bean is now stuck with #FormParam and is not reusable with other #XxxParams.
So you have some trade-offs. Hope this gives you some good information to work with.
UPDATE
Oh and the last option I can think of, is similar to second one above, but you aren't tied to the #XxxParam in the bean
public static class CustomerId {
//#FormParam("cust")
#javax.validation.constraints.Pattern(regexp="[a-zA-Z -]{1,50}")
private String value;
public CustomerId(String value) {
//this.value = validate(value);
this.value = value;
}
...
}
#POST
#Path("form")
#Consumes("application/x-www-form-urlencoded")
public String postForm(#FormParam("cust") #Valid CustomerId custId) {
Think the last option might be the way to go, but you still need to remember to always annotate with #Valid, which sounds like something you were trying to avoid.

Returns empty data structure (entity) instead of null, is it good?

I've been working on a project which has been developed by other developers. In this project, any method that returns an entity or object is designed to return a special value called EMPTY_VALUE.
public Customer getCustomer() {
if (everythingFine) {
return realCustomer();
} else {
Customer.EMPTY_VALUE;
}
}
And the Customer class:
public class Customer {
public static final Customer EMPTY_VALUE = new Customer();
private String firstName;
private STring lastName;
public Customer() {
this.firstName = "";
this.lastName = "";
}
}
In other places that use the getCustomer() method:
Customer customer = getCustomer();
if (customer != Customer.EMPTY_VALUE) {
doSomething(customer);
}
Does the above way has any advantages over the null-checking? Does it buy us anything?
Customer customer = getCustomer();
if (customer != null) {
doSomething(customer);
}
This is an example of the Null Object Pattern. The advantage is that you can remove explicit null checks by instead just using an object that does a default behavior. In this case, the null object returns empty strings when its fields are queried, so if that's what you want in the case of no result anyway, you just saved yourself a check for null. Obviously like all design patterns, its usefulness depends on the particular situation.
I don't like the idea of creating a dummy empty Customer object. What are the semantics of it? Is it a real Customer or not?
I would prefer to use something like Optional from Guava in this situation or might just use null depending on the client code. Read the description in the link to see common uses and the API for Optional.
I would say neither. Don't return null or a return special "error-object" from a method. Let them throw an exception instead. That way you don't need to "check" every time you you call it.
public Customer getCustomer() {
if (everythingFine) {
return realCustomer();
throw new NoCustomerException();
}
And the code using the method would be a lot simpler:
doSomething(getCustomer());
It could be (like the example above) an runtime exception or a checked exception.
If you have to choose between the two I would choose the non-null variant, just like I would choose to return an empty list from a method instead of null. I would however urge you not to write any special code to handle that special object, it should be handled like any other customer.

Categories