bittersweetryan
bittersweetryan

Reputation: 3443

Is there a pattern for using DTO's without having to duplicate the domain object's properties?

I'd like to use DTO's in my view models in lieu of my domain objects, however I'm having a hard time justifying the maintenance overhead of having to maintain two sets of properties for each domain object.

I was wondering if anyone has implemented or knows of a pattern where the properties of a domain object are separated from the object's actions without having to maintain two sets of properties.

One thought I had would be to have my domain object be only properties and attaching the actions as a subclass:

public class Person{
    private String firstName;
    private String lastName;

    public String getFirstName(){
        return this.firstName;
    }

    public String setFirstName(string firstName){
        this.firstName = firstName;
    }

    ...
}

public class PersonActions extends Person{
    public void save(){
        ...
    }

    public Person get(){

    }
}

This way still feels a bit kludgy as I'd have to pass around a PersonAction class if I wanted a full representation of the domain object.

Upvotes: 22

Views: 3902

Answers (4)

Christian Bongiorno
Christian Bongiorno

Reputation: 5648

Here is another idea:

Use the domain object and only annotate the methods you want exposed. You can make it so they require explicit exposition by Qualifying access type as NONE that way you don't have accidental data exposure

Example:

@Entity // hibernate
@XmlAccessorType(XmlAccessType.NONE) // for DTO
@XmlRootElement
public class Survey {
    @Column(name = "Title") // hibernate 
    @Basic // hibernate
    @XmlElement // for use as DTO
    private String title;

    @XmlElement(name = "report")
    public SurveyReport getSurveyReport() {
          // ... do some stuff here
    }
}

By using this approach you get the best of both worlds. Additionally, you can expose 'meta' information with methods and then annotate the method (available because of XmlAccessType.NONE).

The biggest drawbacks I see:

  1. Annotation explosion resulting in difficult to maintain code

  2. Monolithic object with many methods

    • Which may be great for view consumption but not really so appropriate for internal code
    • Leading to API confusion
    • see #1
  3. At the end of the day you may not be able to represent the view you want without combining information from multiple domain objects; leaving you right back to needing an explicit DTO anyways

Upvotes: 2

BalusC
BalusC

Reputation: 1108692

Just make your model (Person) a property of your controller (PersonActions):

public class PersonActions {

    private Person person;

    public PersonActions() {
        person = new Person(); // Or get existing one from DAO in case of edit.
    }

    public void save() {
        somePersonDAO.save(person);
    }

    public Person getPerson() {
        return person;
    }

}

Based on your question history I understand that you're using Struts. In that case, it's good to know that JSP EL supports nested object properties, something like this to retrieve the values:

${personActions.person.firstName}
${personActions.person.lastName}

There's no need to flatten them by duplicating the properties in the controller.

Upvotes: 1

Andre Rodrigues
Andre Rodrigues

Reputation: 2234

You could use an interface exposing only your object's data, without any domain methods. You'd still need to maintain two classes, but that would be a lot easier since most of the changes could be refactored by your IDE (Eclipse for example). Here's an example:

public interface PersonView {
    String getFirstName();
    String setFirstName();
}

public void Person implements PersonView {
    private String firstName;

    @Override // This annotation guarantees the interface is correct 
    public String getFirstName() {
        return firstName;
    }

    ...domain methods...
}

Is not a perfect solution, but it's a pretty clean one.

As for the problem itself, I for one don't really mind exposing the whole object to the view layer. IMHO, I don't think hiding some methods is worth the overhead. The team should have the discipline to use the objects wisely, but that's just my opinion.

Upvotes: 3

Shiraz Bhaiji
Shiraz Bhaiji

Reputation: 65381

One approach is to have a property in your View Model which is your DTO object.

Another approach is to duplicate the properties, but use something similar to AutoMapper to map between the objects.

In our latest project we have the DTO object as a property, but we also expose the individual properties in the View Model, which reference the properties in the DTO object.

Upvotes: 0

Related Questions