Lets assume a simple Spring MVC Controller that receives the ID of a domain object. The Controller should call a service that should do something with that domain object.
Where do you "convert" the ID of the domain object into the domain object by loading it from the database? This should not be done by the Controller. So the service method interface has to use accept the ID of the domain object instead of the domain object itself. But the interface of the service would be nicer if it takes the domain object as a parameter.
What are your thoughts about this common use case? How do you solve this?
The controller should pass the id down into the service layer and then get back whatever is needed to render the rest of the HTTP response.
So -
Map<String,Object> doGet (#RequestParam("id") int id) {
return serviceLayer.getStuffByDomainObjectId(id);
}
Anything else is just going to be polluting the web layer, which shouldn't care at all about persistence. The entire purpose of the service layer is to get domain objects and tell them to perform their business logic. So, a database call should reside in the service layer as such -
public Map<String,Object> getStuffByDomainObjectId(int id) {
DomainObject domainObject = dao.getDomainObjectById(id);
domainObject.businessLogicMethod();
return domainObject.map();
}
in a project of mine I used the service layer:
class ProductService {
void removeById(long id);
}
I think this would depend on whether the service is remote or local. As a rule I try to pass IDs where possible to remote services but prefer objects for local ones.
The reasoning behind this is that it reduces network traffic by only sending what is absolutely necessary to remote services and prevents multiple calls to DAOs for local services (although with Hibernate caching this might be a mute point for local services).
Related
I understand that it is probably better to pass objects into a service method, but is this still the case if the caller would first have to look up the object before calling the service? And if so, why?
Example
Let's say I have a RoleService, that adds a role to the given user. And let's say the RoleService is called via a web controller or possibly a REST API. The web controller takes the userId and roleId as input from the web request.
Would I be better off using this service method?
public void addRoleToUser(long userId, long roleId) {
User user = userRepository.find(userId);
Role role = userRepository.find(roleId);
user.addRole(role);
}
Or this one? The web controller would obviously need to retrieve both objects before calling the service in this case.
public void addRoleToUser(User user, Role role) {
user.addRole(role);
userRepository.save(user);
}
Whether called via a web controller or a REST API, the incoming request would only be giving the 2 ID's, so you have to do the find() calls somewhere.
You certainly cannot trust the caller to have up-to-date information about the two objects, and it's a waste to transmit the full objects if you're only going to use the ID's anyway.
It is common to have the service API also be the database transaction boundary (service class or method annotated with #Transactional), so it is best to have the service method do the find() and addRole() calls, so they all execute in a single database transaction.
We are using the Play! framework for HTTP sessions.
tenantId and ipAddress are columns that are common across multiple tables.
When the user is logged in, we are storing the tenantId in HttpContextSession
Whenever we require the ip address of the user we are using Http.Context.current().request().remoteAddress() to store the ip address.
We have huge set of queries written and now we want to save or query in a generic way for tenantId.
All the queries goes via GenericDao
Can we use the following in GenericDao to get tenant Id so that we can append in all queries?
Http.Context.session().get("tenantId");
what would be the best approach to save or retrieve these details?
Thanks.
You don't want your DAO to have to depend on presentation layer things like an HTTP session. I would recommend an abstraction to hide these details.
Create an interface called TenantIdProvider and inject it into your DAO. It would look something like this:
public interface TenantIdProvider
{
String getTenantId();
}
Then create an implementation called HttpSessionTenantIdProvider.
class HttpSessionTenantIdProvider implements TenantIdProvider
{
#Override
public String getTenantId()
{
return Http.Context.session().get("tenantId");
}
}
Now your GenericDAO can have a reference to TenantIdProvider and every query that needs the tenantId can get it through the TenantIdProvider and not have any dependency on the play framework or any other presentation layer that you use.
This really becomes important if you end up having scheduled jobs that run and send notifications or some other task, and they use this DAO. If this DAO depended on an HTTP session it would not be possible. Your job app could create a TenantIdProvider that just returned "system" or something like that.
I want to know the use of service classes in J2EE.
I have 2 projects.
One is in spring hibernate integration.That project contain DAO,MODEL,SERVICE and CONTROLLER.Within that The request is access by the controller and send to the values to the dao class through the service class.
2nd project contain only BEAN,CONTROLLER and DERIVED classes.Within that the request is access by the controller and send the values directly to the derived class.Query is written in this derived class.
I want to know the difference between these two projects. Why we use service class ?
in my experience, service class contains all business , calculate, logic
for example in login module :
base on MVC pattern
Model class (DAO,MODEL is call model) : User, UserDAO
Controller : UserController
View : LoginPage
That's doesn't mean we cannot create another class like Service
we can have UserBusinessthis class contain all method, logic realted to User like validateUserLogin ... etc
application may work like :
User access LoginPageinput value and submit => UserController=> UserBusiness=> UserDAO
we need divide to easy handle and maintain
In spring we have some annotation like
#Business
#Repository
#Controller
that is a maker spring will create a object , we no need to using "new" keyword.
Controllers: are used to just delegating the calls, meaning once the request arrive on controller it will forward it to relative service
Services: Service are develop to write the business logic in general.
Dao: Data transfer object, which intend to deal with the DTO's
So, Briefly, when Spring MVC receive a call. I will lend to controller, controller than redirects it to respective service. Service performs business login if any on the api call and than delegated data updation to DAO layer.
I have a Spring form which is called AddNewItemForm and contains the validation annotations.
This form is the parameter of my Spring RestController addNewItem() method and it will be validated, the results being stored in BindingResults.
From my controller I need to call the service. Here is my question. Is it ok to have a method inside my service with this signature
public Item add(AddNewItemForm form)
or is it better to have it like
public Item add(Item item)
I am thinking that the form is only needed for the controller validation but the service doesn't need to know about it. It just needs to know how to operate with entities.
I suppose that I should construct my Item in the controller, with all the data I have and then pass this item to the service add(item) method.
Am I right?
Think of it in terms of dependencies: your web layer always needs to know about your service module and by passing the AddNewItemForm (which I assume exists in your web module/package) back to your service you now have a circular dependency.
Dependencies should only flow downwards:
Repository > Service > Web
From my point of view the service should not know about your command object (AddNewItemForm) since they are totally independent.
I agree with your last suggestion, you have to construct your model object before calling your service. Basically in your controller or with the help of an utility class.
I have a web application using jdbc for database calls.
I have a service, dto and dao layer.
I have a request xml which is huge. Can I pass the request object to dao method or should I transfer the request to a dto model and then pass the dto object as a paramter to my dao method?
Which is the right approach??
public TestServiceClass addSurveySubmitDetails(TestRequestXML testRequestXML){
//call to dao method
TestDao = testdao = new TestDao(testRequestXML);
}
OR
public TestServiceClass addSurveySubmitDetails(TestRequestXML testRequestXML){
//create dto object
TestDTO testDTO = new TestDTO();
testDTO .setId(testRequestXML);
//call to dao method
TestDao = testdao = new TestDao(testDTO );
}
Which is the right approach??
I don't think there is a right or wrong answer. It's pretty subjective in my opinion.
But I personally like to have a thin layer between the controllers and the services (assuming you're using the MVC pattern), that its only task is to convert requests (XML, Json, etc) to domain objects.
It is quite useful when you have complex domain objects or aggregates of which you need to show information in a view.
It depends on your architecture, but as DTO is Data Transfer Object there's no reason to use them between service and dao layers.
You can have one for service layer I suppose like in code sample below, but anyway it depends on your application's architecture.
public TestServiceClass addSurveySubmitDetails(TestDTO testDTO){
TestRequestXML testRequestXML = testDTO.getId();
TestDao = testdao = new TestDao(testRequestXML);
}
More on DTO's
Data Transfer Object
LocalDTO
YAGNI is good idea, keep it simple design, where possible
DTOs are really intended for remote calls. If you're sending data over the network to a different virtual machine, use a DTO. If you're sending data to another local class on the same virtual machine, don't bother with a DTO. A DTO is just an efficient way to transfer data remotely. It doesn't really have any advantages anywhere else.