Design Patterns – Should Form Object Be Considered a DTO?

designdesign-patternsenterprise-architectureobject-oriented-design

I got this from one of online video tutorials. Author binds form data not to Value Object directly, but first to validable DTO, and THEN to Value Object, using service.

Example:

package com.foo.spring.dto;

import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;

public class SignupForm {

    @NotNull
    @Size(min=1, max=255, message="{sizeError}")
    @Pattern(regexp="[A-Za-z0-9._%-=]+@[A-Za-z0-9.=]+\\.[A-Za-z]{2,4}", message="{emailValidationError}")
    private String email;

    @NotNull
    @Size(min=1, max=100, message="{sizeError}")
    private String name;

    @NotNull
    @Size(min=1, max=30, message="{sizeError}")
    private String password;

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public String toString() {
        return "SignupForm [email=" + email + ", name=" + name + ", password="
                + password + "]";
    }

}

Part of controller:

@RequestMapping(value = "/signup", method = RequestMethod.POST)
    public String signup(
            @ModelAttribute("signupForm") @Valid SignupForm signupForm,
            BindingResult result, RedirectAttributes redirectAttributes) {

        if (result.hasErrors()) {
            return "signup";
        }

        userService.signup(signupForm);

        MyUtil.flash(redirectAttributes, "success", "signupSuccess");

        Logger.debug(signupForm.toString());

        return "redirect:/";
    }

Part of service:

@Override
    public void signup(SignupForm signupForm) {

        User user = new User();
        user.setEmail(signupForm.getEmail());
        user.setName(signupForm.getName());
        user.setPassword(signupForm.getPassword());
        userRepository.save(user);
    }

My question is – is this a real DTO? Is this considered a good practice? (I know some of you hate this term)Or should it be place somewhere else on other layer? I mean, sure, you can perform object validation on Entity directly, but there are many cases (complex forms) where you are calling and using multiple entities at once, so you want to move validation to more specific class.

Best Answer

It is not a real DTO, according to this definition of DTO. In that definition, a DTO is a streamlined, packaged object or group of objects without real behaviour.

On the other hand, it is certainly a transfer object, by definition, and it certainly (likely) can package more than one object. Putting validation, especially inter-object validation in it makes sense to me.

The don't repeat yourself (DRY) principle applies here. Validation of the business object has to be done whether you get your data from a a database, a web front end, a desktop GUI, or inter-application communication. That means that you need validation in the business object.

That being said, there are certain kinds of validation that only make sense for web-page transfer objects, particularly those that involve translation of encodings, e.g., CP1290 to UTF-8. These are the kinds of validations that you need to do on the web form.

Related Topic