Friday, June 29, 2007

More on calling domain object methods from JSPs

This is to follow up from yesterday's post about calling domain object methods from JSPs. If you'll recall, there were three methods proposed:

  • controller call: make the call in the controller, and pass the results as extra entries in the model
  • data transfer object: put the logic in a special object that provides no-argument methods for retrieving the data in the JSP page
  • taglib: create a taglib that essentially just allows the JSP to call the method itself
Having thought a bit about this for a day on the back burner, I'm pretty sure that going the taglib route is not quite the appropriate one here, at least for this method call (which was essentially a range query); so I think it comes down to either the controller call or the DTO.

So where do each of these make sense? I think if you are pretty sure that a standard web application is the only way you'll really be viewing these results, then the controller call makes a lot of sense, particularly when there's not a lot of model entries to make. The specific example we had, where we were storing a Post object and a List in the model, still keeps the controller pretty simple.

However, I think if you need to do this more than a handful of times, or if you know you are going to be calling the underlying business logic from multiple frontends (maybe via a SOAP web service to power a remote AJAX web widget), then it makes sense to start migrating towards the DTO solution. I'd actually take it a step further now, and encapsulate the DTO creation in a service:

public class PostController implements Controller {
  private PostDTOService postDTOService; // dependency
  public ModelAndView handleRequest(HttpServletRequest request,
                                    HttpServletResponse response) {
    String postId = request.getParameter("postId");
    PostDTO postDTO = postViewService.getDTO(postId, 0, 8);
    Map model = new HashMap();
    model.put("postDTO", postDTO);
    return new ModelAndView(..., model);
  }
}

public class PostDTOService {
  private PostDAO postDAO; // dependency
  public PostDTO getDTO(String postId, int first, int max) {
    Post post = postDao.getPostById(postId);
    if (post == null) return null;
    List<Comment> comments = post.getCommentsByRange(first, max);
    PostDTO dto = new PostDTO();
    dto.setPost(post);
    dto.setComments(comments);
    return dto;
  }
}

public class PostDTO {
  private Post post;
  private List<Comment> comments;
  public Post getPost() { ... }
  public void setPost(Post p) { ... }
  public List<Comment> getComments() { ... }
  public void setComments(List<Comment> cs) { ... }
}

Now everyone's roles can be pretty succinctly described:

  • controller: gather parameters from HTTP request and pass to service; place returned object in model and invoke view
  • service: makes the middleware logic calls to produce the needed data and instantiates the DTO
  • DTO: just carries the data around
  • JSP/view: renders the data contained in the DTO
So, my question to you is: is it too much trouble to add the service layer and DTO just to keep the controller and JSP simple, especially when there's no reason the controller couldn't do this? I'd say the service/DTO route probably has a more elegant design to it, but is there such a thing as going to extremes here?

2 comments:

Tamer said...
This comment has been removed by a blog administrator.
comment system said...

Well done written post ! The best thing I liked it description about 3 methods proposed. I used to remain confused in between them but you well explained everything and cleared my confusion.