Spring DTO-DAO (Resource - entity) mapping goes in which application layer: Controller or Service?
Asked Answered
M

4

9

I'm writing a Spring (4.1.7) web application that exposes a RESTful service and wish to use DTO "resource" objects for communication between Controller and client browser rather than expose my persistence entities.

Currently the application has the following layers:

  • View (JSP/JSON)
  • Controller(s)
  • DAO (@Service)
  • DAO (@Repository)

My question is, where should I be mapping my DAO entities to DTO resources? I had a look at some examples using Spring HATEOAS and they show Resource objects extending ResourceSupport being mapped in the Controller. Is this the best way to do it, or should I be returning resources from the DAO Service?

I wish to add Link elements to the returned resource (for self and related resources), but can't see how Link elements would be resolved if processed in the Service without it having knowledge of the Controller and it's @RequestMapping. On the other hand, I don't know if it's good practice to clutter the Controller with the mapping either.

Messroom answered 27/7, 2015 at 2:30 Comment(0)
A
6

DTO ( Data Transfer Object) as obvious in its name, is used for transfering data out of your application. In your case the best place to put them is in your controller layer. You should only expose DTO's to UI and when you get a data from UI you should convert it to the business entity and call the below tier. The reason is, in this way you are free to change the business entitiy without breaking UI and leads to better maintenance. Also your business/DAO tier should be unaware of UI and DTO's for the same reason. So the best place to convert DTO to Business Entities and vice versa in your app is Controller tier.

PS:Take a look at Dozer too ;)

Anibalanica answered 27/7, 2015 at 3:0 Comment(0)
I
3

You can meet different approach from where a mapping can be called. See this tutorial for example: http://www.baeldung.com/entity-to-and-from-dto-for-a-java-spring-application or question: http://forum.spring.io/forum/other-spring-related/architecture/56753-controller-vs-service-vs-private-method-on-command-object. It also depends on how much logic are in your controllers.

I prefer mapping Entity<->DTO in util classes. And you are relatively free to choose, where from you call them. It seems that "The best design is the simplest design that works" - Einstein. Similar article about necessity of DTO: Should services always return DTOs, or can they also return domain models?

Isomerism answered 4/3, 2016 at 14:30 Comment(0)
C
2

A note At the time I wrote this answer I assumed that the DTO's you are talking about are request and response objects of the service layer. Thus I use the term DTO in this way and the term resource objects for your 'DTO' objects. I don't want to edit the whole answer right now. Therefore this hint.

where should I be mapping my DAO entities to DTO resources?

In the service layer. Normally the service layer implements use cases and is the transaction boundary.

E.g.

@Transactional
public OrderPlacedTO placeOrder(ShoppingCartTO cart)[
   OrderDao orderDao = ...
   // implement your use case here
   ...
}

I wish to add Link elements to the returned resource (for self and related resources), but can't see how Link elements would be resolved if processed in the Service without it having knowledge of the Controller and it's @RequestMapping

You are right. These information is only available in the controller. You can add a resource model, like a normal ui model.

E.g.

public class OrderPlacedRessource extends ResourceSupport {
   
    private Long oderNumber;
    
    public void setOrderNumber(Long orderNumber){ this.orderNumber = orderNumber; }
    public Long getOrderNumber() { return this.orderNumber }
}

and in your controller you can then use it and add links

@RequestMapping("/placeOrder")
public @ResponseBody OrderPlacedRessource placeOrderAction(HttpServletRequest request){
   OrderService service = ...;
   ShoppingCartTO cart = ...;

   OrderPlacedTO orderPlacedTO = service.placeOrder(cart);
   OrderPlacedRessource orderPlacedRes = new OrderPlacedModel();

   orderPlacedRes.setOrderNumber(orderPlacedTO.getOrderNumber());

   // since orderPlacedRes is a RessourceSupport we can add links
   // Use the HttpServletRequest to build your links
   Link link = new Link("http://localhost:8080/something");
   orderPlacedRes.addLink(link);

   return orderPlacedRes;
}

PS: Building links is easier if you use a org.springframework.hateoas.mvc.ControllerLinkBuilder. E.g

orderPlacedRes.add(linkTo(methodOn(YourController.class).orderOverview(userId)).withSelfRel());

See Building a Hypermedia-Driven RESTful Web Service for details.

Calamint answered 27/7, 2015 at 10:29 Comment(1)
Are you suggesting that I should actually implement 3 parallel models: DAO (e.g. OrderDao), DTO (e.g. OrderPlacedTo) and Resource (e.g. OrderPlacedResource)? This does address my concerns about the service being controller-aware (and vice versa), but as the data model grows this could spiral out of control.Messroom
Z
2

My opinion is to do the mapping in Controller layer as this layer is responsible for input/output. The service layer should be independent so that the same can be used to develop another interface.

Not much clutter will happen in Controller if you create Mapper classes and just them in your Controller layer.

Zacharyzacherie answered 4/3, 2016 at 15:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.