开发者

Spring MVC 3 - Binding an 'immutable' object to a form

开发者 https://www.devze.com 2023-04-12 23:25 出处:网络
I have several thoroughly unit-tested and finely crafted rich DDD model classes, with final immutable invariants and integrity checks. Objec开发者_开发问答t\'s instantiation happens through adequate c

I have several thoroughly unit-tested and finely crafted rich DDD model classes, with final immutable invariants and integrity checks. Objec开发者_开发问答t's instantiation happens through adequate constructors, static factory methods and even via Builders.

Now, I have to provide a Spring MVC form to create new instances of some classes.

It seems to me (I'm not an expert) that I have to provide empty constructor and attribute's setters for all form's backing classes I want to bind.

So, what should I do ?

Create anemic objects dedicated to form backing and transfer the informations to my domain model (so much for the DRY principle...) calling the appropriate methods / builder ?

Or is there a mecanisms that I missed that can save my day ? :)

Thank you in advance for your wisdom !


The objects that are used for binding with the presentation layers are normally called view models and they are DTOs purposed toward displaying data mapped from domain objects and then mapping user input back to domain objects. View models typically look very similar to the domain objects they represent however there are some important differences:

  1. Data from the domain objects may be flattened or otherwise transformed to fit the requirements of a given view. Having the mapping be in plain objects is easier to manage than mappings in the presentation framework, such as MVC. It is easier to debug and detect errors.

  2. A given view may require data from multiple domain objects - there may not be a single domain object that fits requirements of a view. A view model can be populated by multiple domain objects.

  3. A view model is normally designed with a specific presentation framework in mind and as such may utilize framework specific attributes for binding and client side validation. As you stated, a typical requirement is for a parameterless constructor, which is fine for a view model. Again, it is much easier to test and manage a view model than some sort of complex mapping mechanism.

View models appear to violate the DRY principle, however after a closer look the responsibility of the view model is different, so with the single responsibility principle in mind it is appropriate to have two classes. Also, take a look at this article discussing the fallacy of reuse often lead by the DRY principle.

Furthermore, view models are indeed anemic, though they may have a constructor accepting a domain object as a parameter and a method for creating and updating a domain object using the values in the view model as input. From experience I find that it is a good practice to create a view model class for every domain entity that is going to be rendered by the presentation layer. It is easier to manage the double class hierarchy of domain objects and view models than it is to manage complex mapping mechanisms.

Note also, there are libraries that attempt to simplify the mapping between view models and domain objects, for example AutoMapper for the .NET Framework.


Yes you will need to create Objects for the form to take all the input, and the update the your model with this objects in one operation.

But I wont call this objects anemic (especially if you do DDD). This objects represent one unit of work. So this are Domain Concepts too!


I solved this by creating a DTO Interface:

public interface DTO<T> {
    T getDomainObject();

    void loadFromDomainObject(T domainObject);
}

public class PersonDTO implements DTO<Person> {
    private String firstName;
    private String lastName;

    public PersonDTO() {
        super();
    }

    // setters, getters ...

    @Override
    public Person getDomainObject() {
        return new Person(firstName, lastName);
    }

    @Override
    public void loadFromDomainObject(Person person) {
        this.firstName = person.getFirstName();
        this.lastName = person.getLastName();
    }

    // validation methods, view formatting methods, etc
}

This also stops view validation and formatting stuff from leaking into the domain model. I really dislike having Spring specific (or other framework specific) annotations (@Value, etc) and javax.validation annotations in my domain objects.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号