1

After reading this article, I change return value of service method entity into DTO.

But I'm little confused in this below situation.

Entity A <- Repository A <- Service A

Entity B <- Repository B <- Service B

Then , If Service B need to access entity A ,so call method in Service A. Since the result of that method is DTO ,not entity, I'm having a hard time dealing with DTO A in Service B.

Should I call repository A in Service B? or should I call Service A in Service B and use modelmapper to covert dto to entity in service B?


// Controller code
@RestController 
public FooDTO getSomeFoo(){    
    return new FooDTO(service.getFoo()) 
}  


// Service code
@Service 
public Foo getFoo(){     
    return repository.find(~) 
}

1 Answers1

1

In my opinion, unless you really want to protect your entities to be changed elsewhere other than the corresponding Service, I would avoid DTOs in calls inside the service layer. This means that it is ok to return Entities in methods that you know that are called by other Services in your application, unless you really want to, most probably, over-engineer your application. Having said that you should return DTOs only in the methods that are called by your Controller layer so that they are used in your REST API (assuming you have one). Of course, this requires discipline and making sure you don't call methods on your Controller that are supposed to be called only by Services. There is an architecture that tries to tackle this (if you want to read more about it --> https://medium.com/@shivendraodean/software-architecture-the-onion-architecture-1b235bec1dec) and you can try to take advantage of package protected feature to guarantee this.

Should I call repository A in Service B?

Definitely not. You should never (never may be a strong word, but you should at least strive hard to avoid it) do this, otherwise your code will turn into a complete mess without any structure whatsoever.

João Dias
  • 16,277
  • 6
  • 33
  • 45
  • First, Dias thanks for your kind answer! According to my understading of your answer, method in serivce can return entity. But what if some method is used by both controller and service, should I seperate It nevertheless both methods do the same thing? or can I just write method in service which return entity, and in controller(REST)code, return DTO made from entity? Is it okay? Below one is example of my second approach `@RestController public FooDTO getSomeFoo(){ return new FooDTO(service.getFoo()) } @Service public Foo getFoo(){ return repository.find(~) } ` – Sung Woo Hwang Aug 25 '21 at 17:50
  • I add example code of above comment's second approach. Could you tell your opinion? – Sung Woo Hwang Aug 25 '21 at 17:54
  • 2
    If you want to keep the DTO logic and creation inside the Services layer I would create two methods: `public Foo getFoo()` and `public Foo getFooDto()` (that basically delegates to `getFoo()`). If you are ok with moving the DTO logic and creation then your solution is fine. But if you do this I would suggest you do this for all other DTOs as well. Nevertheless, I would go for the two different methods. – João Dias Aug 25 '21 at 18:12
  • Thanks for your kind reply Dias, I have one more question. _**But if you do this I would suggest you do this for all other DTOs as well**_ does this means ,in every controller method, generating dto from entity logic should be written? – Sung Woo Hwang Aug 25 '21 at 18:22
  • 1
    I mean that you either have the DTO creation in the Service layer (for all Services and DTOs) or you have it in the Controller layer. I would go for the Service layer but if you prefer to keep it in the Controller layer the important thing is to be consistent do that for all DTOs. If your mapping logic is complex enough you may want to implement it in a dedicated Class (I would call it a Mapper). – João Dias Aug 25 '21 at 18:34
  • Thakns for your help Dias, your answer was very helpful :D – Sung Woo Hwang Aug 25 '21 at 18:37