i'm thinking if i really need a service layer.
I'm using spring + hibernate for a desktop swing application and at this moment i have gui/swing layer->service layer->dao layer. I use spring only for @Transactional support and for IOC-injection
Best practice say that i have to write a service to use my daos, and put all transactions management in the service.
But i'm realizing that very very often, service layer only replicate dao methods, so for example:
// a DAO example
@Repository
public class CustomerHibernateDAO extends BaseHibernateDAO implements CustomerDAO {
public List<Customer> findAllCustomerILikeName(String name){
return getSession()
.createCriteria(Customer.class)
.add(Restriction.ilike("name", name))
.list();
}
}
// Customer service to use this dao...
@Service
@Transactional
public class CustomerService {
@Autowired
CustomerDAO customerDAO;
// Why i can't call DAO instead the service?
public List<Customer> getAllCustomersByName(String name){
return customerDAO.findAllCustomerILikeName(name);
}
}
This is a mine tipical usage of service layer... Hibernate is db-agnostic, spring are tecnology-agnostic: so, i really need it?
What about a unique Service class to manage all DAO?? I think this may be a good compromise, or, is a bad practice?
I know put @Transactional on DAO is a bad way, but at this moment i have to write services only for put @Transactional on it...
EDIT
More infos about my app.
My application is a management software and manage user registration, products, order and other things like those. In practice it contains a lot of read entity->edit->save entity or create->edit->save operations, and, thanks to hibernate, these operations are managed by ONE dao most of the time, becouse hibernate with @manyto... collection and cascade.save_update permits to save two or more entities in the same persist operation.
So, for example, in my items JFrame where i can insert, edit or create an Item(a product to sell) there are:
public ItemFrame(){
// the constructor
itemService=springAppContext.getBeans(ItemService.class);
}
public boolean validateForm(){
// test if the gui is correctly filled by user
}
public boolean save(){
// create an Item entity taking value from swing gui(JTextField etc)
Item item=new Item();
item.setName(nameTextField.getText());
item.setEtc...
// ItemService ' save method is a wrap around itemDao.save(item)...
itemService.save(item);
}
private void saveItemActionPerformed(ActionEvent evt){
// When i press SAVE button
if(validateForm()){
save();
}
}
This is what i have in the most of cases, so i think i fell in anemic-domain-antipattern...
Thanks.
If your service layer duplicates dao, you are not using service layer at all. I made the same mistake in few of my applications, I was wondering "why the service layer looks so ugly, and is duplicationg DAO"...
The service layer should be interface for your appliacation, this doest mean, that some methods are not the same in dao and in service, but the main part is significantly different. I cannot say this without viewing the rest of your code, but by your question (which is almost the same as were my questions few months ago), it seems to me, that you are using anemic domain model antipattern. In anemic domain model, your model contains only fields and getters, no real methods (behaviour), which violates fundamental object oriented principles (object == data + behaviour)...your behaviour is probably in something that looks like transaction script in service layer, but should be in your model (domain layer).
The way out of this is to use rich domain model (beans injected to model via @Configurable). You may say, that this violates the layers pattern and you will be probably correct. But I am convinced, that we should think about our application (domain+dao+service) as a single component (see Alistair Cockburn Hexagonal architecture/Ports and adapters).
Your swing app/web client will then be a client to your core component, you can then switch them without any limitations (beacause everything that modiefies data is in core).
But there is a limitation/drawback with this approach. If you will use some sort of security (Spring security) or active records via hibernate, than you should comunicate with all clients via DTO (not the entities itself), because when you contact entity, it may call service, which will active itself via transactional and can modify the database (bypass your security).
I hope, that I have guessed your architecture, if not, I am sorry for inventing the wheel here, but this post may help someone who doesnt know this (as was I few moths ago).
EDIT
to your edit: Even in simple CRUD application, some kind of actions should be in service layer - for example validation (not the validation "this is a number", but some business specific validation). This shouldn be in your view, because if you change it, you will have copy & paste it again. When you look at your code, you should ask a qeusting "if I decide to write thin client (view in web browser)", is there any code, that i will have to copy? If is the answer YES, than you should create an service method for this possibly remote call.
The other thing that you should/can do on service layer is autorization (is the user in this role permited to delete this entry). Than you will have to have an service layer for almost all of your entities, because simple user should be able to edit (delete) his entries, but probably should not delete other users. But user in role admin can do this.
Example code (part of article Service interface in my app (Spring security)):
@Secured("ROLE_EDITOR")
public void save(ArticleDTO selectedArticle, ArticleDetailsDTO selectedArticleDetails);
In comment service everybody can save their comments to articles....
And one last note: you should probably consider, if you need service layer at all. When its written in a nice way, your app will gain many qualities in its flexibility, reusability and maintainability. But it pretty hard and time consuming to write it. If you dont want to do this all this stuff (security, rich domain model, calling from more interfaces (changing view implementation)), you can live without it :-)