Can Spring DAO be merged into Service layer? - java

I'm developing a web application with spring framework and mybatis.
In most cases(at least for me), DAO's methods are very short something like this:
public class UserDaoImpl extends SqlSessionDaoSupport implements UserDao {
public User getUser(String userId) {
return (User) getSqlSession().selectOne("org.mybatis.spring.sample.mapper.UserMapper.getUser", userId);
}
}
So basically, I need to write a method(e.g. getUser(String userId)) in DAO for each query which is being forwarded to service objects where it is being used. It seems unnecessarally redundunt to me.
My co-worker is trying to make it simple. He wrote CommonDao like this:
#Repository
public class CommonDao {
#Autowired
private SqlSessionTemplate sqlSession;
public Object insert(String queryId, Object params) {
return sqlSession.insert(queryId, params);
}
public Object update(String queryId, Object params) {
return sqlSession.update(queryId, params);
}
public Object delete(String queryId, Object params) {
return sqlSession.delete(queryId, params);
}
public Object selectOne(String queryId) {
return sqlSession.selectOne(queryId);
}
public Object selectOne(String queryId, Object params) {
return sqlSession.selectOne(queryId, params);
}
}
So we can use these methods in services like:
#Service
public class CrudService {
...
#Autowired
private CommonDao commonDao;
...
public UserDto selectUser(Integer userId) {
...
UserDto userDto = (UserDto) commonDao.selectOne("org.mybatis.spring.sample.mapper.UserMapper.getUser", userId);
...
}
}
I'm kinda like this approch since it makes codes simpler. But I'm not sure it is a good prectice to follow.

To avoid a boilerplate code and at the same time have type safety and leave your service layer free from DAO implementation details use spring-mybatis MapperScannerConfigurer.
In this case you can replace your DAOs with type-safe mappers.
The equivalent of your DAO
public class UserDaoImpl extends SqlSessionDaoSupport implements UserDao {
public User getUser(String userId) {
return (User)getSqlSession().selectOne(
"org.mybatis.spring.sample.mapper.UserMapper.getUser", userId);
}
}
will be this mapper class
package org.mybatis.spring.sample.mapper;
interface UserMapper {
User getUser(String userId);
}
If you rename it to UserDao you will not need to change your services at all. Service only depends on the declared mapper interface.
Note that you need to define this interface in order to have type safety and also define the dependency of you service.
Of course you need configure spring-mybatis so that it generates mapper implementation based on the mapper interfaces defined in your code. This is rather straightforward and there are many options how to do that.

Hmm, what you are struggling with, is normal in MyBatis.
Your co-worker pointed you in some direction... But what is the real value of CommonDao in this shape? For me it's not very useful. You still need almost the same amount of code - and still you have to do a lot of casting.
As #Rom Konoval said, there is MapperScannerConfigurer which can generate mapper implementations - this way you don't write redundant implementations and have the benefit of a type safety - type casting still happens but is hidden from you. You can try it.
Here is a sample usage on the GitHub.
Alternatively, you can create DAO implementations by yourself (as you already did) or just use the SqlSessionTemplate directly in your Services. Up to you. Just keep your code base as small as possible and follow a common sense.

Related

Can i use generic method to acess data from different entities in hibernate

For example: i have User.class and Post.Class
I want to get all rows from this tables with hibernate.
It is done with
TypedQuery<Post> query = SessionFactory.getCurrentSession().createQuery("from Post");
Also i have dao layer, UserDao and PostDao. and i have abstract class CrudDao with methods like:
public abstract class CrudDao<T> {
#Transactional
public void save(T entity) {
SessionFactory.getCurrentSession().save(entity);
}
}
So my user and post dao just extend this crudDao and i don't need to write save method for them. When i want to get all rows i need to write "from MyEntitie". But i want to make this method also abstract, so i don't need to write it multiple times for each dao. But i can't write "from T" in abstract method.
I also tried to do like this:
List<T> getAll(Class<T> type){
CriteriaQuery<T> criteria = builder.createQuery(type);
criteria.from(type);
return
SessionFactory.getCurrentSession().createQuery(criteria).getResultList();
}
So in my service i call my dao like this:
PostDao.getAll(Post.class);
And i was told that my service shouldn't know about my entity and my dao call in service should be
PostDao.getAll();
And if i do like this ^ i need to write getAll method in every dao and it looks like a lot of copypasted code.
Can yoy give me some advice on how to do it or how you do it in your projects?
What i learned from deHaar reply:
You can create abstract methods with generic dao and call generic class if you create a variable of this generic type/ For example my generic dao:
public abstract class CrudDao<T> {
private Class<T> type;
public CrudDao(Class<T> type){
this.type = type;
}
#Transactional
public T getById(,int postId) {
return sessionFactory.getCurrentSession().get(type, postId);
}
}
So you need only to write a constructor that calls superclass constructor in your child Dao's that extend generic dao.
Like :
public class PostCommentDao extends CrudDao<PostComment> {
public PostCommentDao(){
super(PostComment.class);
}
}
And now everything works from generic dao!
As Tanos said: small price to pay for salvation.
In my opinion, generic DAO is an antipattern. Spring provides you with excellent three-tier architecture made of #Controller (for mvc and rest), #Service (for functionality reusability) and #Repository (for data access). It's okay to have a little bit more code just to leave it with a single responsibility.

Persistence Class in Java

I am working on a JavaEE project. All/Most classes i am working on reside on the data base. There fore all must support creating, editing and deleting a database entry.
I don't want to use any frameworks.I planed to execute the queries using the traditional prepared statements.
Currently I implemented it as follows
public interface Entity{
public boolean create(Entity e);//executes a query with the objects fields
public boolean change(Entity e);//executes a query to update fields of the entity
public boolean delete(Entity e);//deletes the entry
public ArrayList<Entity> getAll();//retrives all the entries in the database
}
Now my question
I'm i doing it right?
If a class inherites form a class that implements this interface how should it handel the methods? Should it override or call the super and add more code to handle more fields
Should i create another utility class to send the queries or is it ok if i add the database actions in the same class?
Appreciate in advance!
You are saying, that you are working on a Java EE project - so why don't use the APIs provided by it? There's a simple recommendation: Use JPA for it and only don't use prepared statements for CRUD operations of Java objects and don't reinvent an Entity which you already have at hand, together with an EntityManager doing all the operations you need on it.
What you are trying to implement is called a Data Access Object interface. It is in fact a well known and good practice, but judging from your interface name you want to use the CRUD methods directly whitin your entities and is not a good idea.
You should create an interface, say
public interface BookDAO{
public Book create(Book book);
public List<Book> read();
public Book update(Book book);
public Book delete(Book book);
}
with the CRUD methods. Then you can implement such interface depending on your database, say
class MySqlBookDAOImpl implements BookDAO{
private Connection conn;
private Connection getConnection(){
if(conn==null)
conn = mySqlConnectionPool.getConnection();
return conn;
};
#Override
public Book create(Book book){
Connection conn = getConnection();
String query = "INSERT... "
};
#Override
public List<Book> read(){
Connection conn = getConnection();
String query = "SELECT... "
};
#Override
public Book update(Book book){
Connection conn = getConnection();
String query = "UPDATE... "
};
#Override
public Book delete(Book book){
Connection conn = getConnection();
String query = "DELETE... "
};
}
and implement the abstract methods to communicate with the database using the correct database driver (depends also from your connection policies).
Regarding your other 2 questions:
When implementing a method from an interface you always ovveride it. You can't call a super method just because there is no super method. You call super only when you extend and override the method from the parent class.
The DAO should take care of sending the queries to the database and the DAO is going to create them within its methods.
Why are you so reluctant to use a framework or built in API? There are really good ones that can spare you a lot of work (like JPA).
You should distinguish entities and DAOs. Entities are the data, DAOs interact with the DB.
For example:
public interface Entity<K extends Serializable> {
K getId();
}
public interface Dao<K extends Serializable, E extends Entity<K>> {
E create(E entity);
E update(E entity);
E delete(E entity);
E get(K id);
List<E> getAll();
}
Then, implementations:
public class User implements Entity<Integer> {
private Integer id;
public User(Integer id) {
this.id = id;
}
#Override
public Integer getId() {
return id;
}
}
public class UserDao implements Dao<Integer, User> {
#Override
public User create(User entity) {
// build query
}
#Override
public User update(User entity) {
// build query
}
#Override
public User delete(User entity) {
// build query
}
#Override
public User get(Integer id) {
// build query
}
#Override
public List<User> getAll() {
// build query
}
}
This can be improved by having a BaseDao abstract class for example, since DAOs will have common code for sure.
Actually I can see you are missing a very basic operation wchich is acceessing objects:
public boolean read(Entity e);
You should also reconsider your class name to have a more relevant one (what this class is intended to do) since naming it as Entity gives the allure of a bean entity not a data access interface layer. Something like CommonDao:
public interface CommonDao {
//...
}
This class can be extended following your Entity type.
You may also need to revise your method signatures, e.g. deleting an entity should only need its identifier.
Update your class also to use Java Generics which will let you gain in reusability and make your class accept any entity type:
public interface CommonDao<T> {
T create(T entity);
//...
}
I highly recommand #sp00m solution.

Java- Passing unknown DAO

I created a common method in which I will pass a DAO but it will not be a one DAO. Like i will be passing not only StudentDao but also TeachersDao and ClubsDao.
Originally, this is my method:
public static String getSomething(StudentDao, String id){
Properties proFind = new Properties();
proFind.put(StudentDao.ID, id);
dao.select(proFind).get(0);
return somethingINeed;
}
But then I've decided that to use only one method, make it something generic..
Somthing like this:
public static <T> String getSomething(Class<T> dao, String id){
Properties proFind = new Properties();
proFind.put(StudentDao.ID, id);
dao.select(proFind).get(0);
return somethingINeed;
}
but this is not correct.
So my objective is to pass any Dao in that method.
Did i miss something in java?
Any idea or enlightenment is greatly appreciated.
[EDIT]
All my Daos extends Dao which is and interface.
My concern is just this method in which how I can use any Dao.
The attributes used can be found in the interface Dao also.
I agree with Kayaman's comment above.
Your service/business tier should be interfacing with multiple DAOs to perform CRUD operations on different entities e.g. Student, Teacher.
public class MyService {
private StudentDao studentDao;
private TeacherDao teacherDao;
// Daos injected
public Student findStudent(Long id) {
return this.studentDao.find(id);
}
// Other methods involving students or teachers
}
Trying to have one generic DAO is cumbersome and not good design in my opinion.
If you have a base DAO and base entity classes, you can still push a lot of the boilerplate CRUD code into the base classes. When I first started using DAOs, I found the following article very useful: Don't repeat the DAO!
thats why java created Interfaceenter link description here or Inheritance
just create a DAO interface or base class and change your method to
public static String getSomething(Dao dao, String id)
Use this
public static String getSomething(Object dao, String id){
if(dao instanceOf StudentDao){
// do your code
}
else if(dao instanceOf AnotherDao){
// do your code
}
and so on.............

How to Autowire business objects in Spring

I'm following the Controller -> Service -> DAO pattern. When I call a DAO implementation, I get back a DTO/Data object. Which then gets passed to the service layer, bringing together it's respective business object and it's data object. Like so:
public User getUserById(int id) {
return new User(userDAO.getUserById(id));
}
class User {
private UserDTO userDTO;
public User(UserDTO userDTO) {
this.userDTO = userDTO;
}
}
What I'd like to do is wrap ALL my business logic inside the business class but I require additional dependencies.
For example, I'd like to be able to do something like this:
//... some code
User user = userService.getByUserId(1);
user.delete(); // this should delete the user from the database
In order for me to delete the user this way, I would need to Autowire the UserService into the business class but this will not work since I am manually instantiating the User class in the User Service.
class User {
#Autowired
private UserService userService; // this won't work since I call instantiate User myself, ie. new User()
private UserDTO userDTO;
public User(UserDTO userDTO) {
this.userDTO = userDTO;
}
public boolean delete() {
userService.deleteByUserId(userDTO.getId());
}
}
Is there a pattern I can follow to allow me to do what I want?
I don't think it's a good design to have business class as a member of your DTO objects.
A more proper approach would be to have your delete method in the business class. That would help loose coupling.
I think you can do this with the #Configurable annotation, though this really isn't how Spring is supposed to work. It will add lots of overhead to your application and make debugging harder.
http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/aop.html#aop-atconfigurable

How generic DAO can return same type for all different DAO implementations?

I'm creating generic DAO for my DataNucleus JDO DAOs. Generic DAO will do get, update, delete, create operations and some other generic operations, so those implementations can be just extended in more specific DAOs.
Is it possible to somehow extend generic DAO and have it return correct types when for example get object by id?
User user = userDao.get(userId); // Is this possible when UserDao extends generic DAO ?? userDao should return user of type User instead of object.
Yes, it is possible to do this with generics:
public abstract class Dao<T> {
public T get(String id) { ... }
...
}
public class UserDao extends Dao<User> {
...
}
UserDao userDao = new UserDao();
User user = userDao.get(userId); //Returns a User
Depending on your needs, Dao<T> can be an abstract base class, or a generic interface (e.g. public interface IDao<T> { ... }
Part of your question has already been answered by verdesmarald. I would like to add one important change in verdesmarald's code
You should prefer composition over inheritance. Instead of extending UserDao from Dao, UserDao should have a Dao. This way, your code will not be bound to a single implementation and mocking the Dao during unit testing will be possible.

Categories

Resources