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.............
Related
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.
I have a Java class like the following:
public class MyClass {
/** Database Connection. */
private dbCon;
public MyClass() {
dbCon = ...
}
public void doSomethingWith(MyData data) {
data = convertData(data);
dbCon.storeData(data);
}
private MyData convertData(MyData data) {
// Some complex logic...
return data;
}
}
since the true logic of this class lies in the convertData() method, I want to write a Unit Test for this method.
So I read this post
How do I test a private function or a class that has private methods, fields or inner classes?
where a lot of people say that the need to test a private method is a design smell. How can it be done better?
I see 2 approaches:
Extract the convertData() method into some utility class with a public api. But I think this would be also bad practice since such utility classes will violate the single responsibilty principle, unless I create a lot of utility classes with maybe only one or two methods.
Write a second constructor that allows injection of the dbCon, which allows me to inject a mocked version of the database connection and run my test against the public doSomething() method. This would be my preferred approach, but there are also discussions about how the need of mocking is also a code smell.
Are there any best practices regarding this problem?
Extract the convertData() method into some utility class with a public api. But I think this would be also bad practice since such utility classes will violate the single responsibility principle, unless I create a lot of utility classes with maybe only one or two methods.
You interpretation of this is wrong. That is exactly what the SRP and SoC (Separation of Concerns) suggests
public interface MyDataConverter {
MyData convertData(MyData data);
}
public class MyDataConverterImplementation implements MyDataConverter {
public MyData convertData(MyData data) {
// Some complex logic...
return data;
}
}
convertData implementation can be now tested in isolation and independent of MyClass
Write a second constructor that allows injection of the dbCon, which allows me to inject a mocked version of the database connection and run my test against the public doSomething() method. This would be my preferred approach, but there are also discussions about how the need of mocking is also a code smell.
Wrong again. Research Explicit Dependency Principle.
public class MyClass {
private DbConnection dbCon;
private MyDataConverter converter;
public MyClass(DbConnection dbCon, MyDataConverter converter) {
this.dbCon = dbCon;
this.converter = converter;
}
public void doSomethingWith(MyData data) {
data = converter.convertData(data);
dbCon.storeData(data);
}
}
MyClass is now more honest about what it needs to perform its desired function.
It can also be unit tested in isolation with the injection of mocked dependencies.
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.
Using the generic dao pattern, I define the generic interface:
public interface GenericDao<T extends DataObject, ID extends Serializable> {
T save(T t);
void delete(ID id);
T findById(ID id);
Class<T> getPersistentClass();
}
I then implemented an default GenericDaoImpl implementation to perform these functions with the following constructor:
public GenericDaoImpl(Class<T> clazz) {
this.persistentClass = clazz;
DaoRegistry.getInstance().register(clazz, this);
}
The point of the DaoRegistry is to look up a Dao by the class associating to it. This allows me to extend GenericDaoImpl and overwrite methods for objects that requires special handling:
DaoRegistry.getInstance().getDao(someClass.getClass()).save(someClass);
While it works, there are a few things that I don't like about it:
DaoRegistry is an singleton
The logic of calling save is complicated
Is there a better way to do this?
Edit
I am not looking to debate whether Singleton is an anti-pattern or not.
First of all, what is your problem with DaoRegistry being singleton?
Anyway, you could have an abstract base class for your entities that'd implement save like this
public T save(){
DaoRegistry.getInstance().getDao(this.getClass()).save(this);
}
then you could simply call someEntity.save()
Or it may be more straightforward if the entity classes itself implemented the whole GenericDao interface (save, delete and find methods), so the contents of your GenericDaoImpl would be in the base class of your entities.
It could be better to use instance of DaoRegistry instead of static methods. It would make it more manageable for test configurations. You could implement it as
#Component("daoRegistry")
public class DaoRegistry {
#Autowired
private List<GenericDao> customDaos;
private GenericDao defaultDao = new GenericDaoImpl();
public <T> T getDao(Class<T> clazz) {
// search customDaos for matching clazz, return default dao otherwise
}
}
Also you could add save method to it and rename accordingly. All customised daos should be available as beans.
Using Hibernate 3.6.8.Final and Spring 3.0.5.RELEASE , I'm trying to add some Common DAO functionality for classes that have multiple implementations overridden higher up to implement the specific classes however it doesn't work for DetachedCriteria.
Example:
In base class:
public interface ICat {
public void setMeowSound(String meow);
public String getMeowSound();
}
Then each inherited project would define the hibernate annotations.
e.g.
#Entity
#Table(name="SQUAWKY_CATS")
public class SquawkyMeowingCat implements ICat, Serializable {
#Id
#Column(name="SQUAWK_NAME")
private String meow;
public String getMeowSound() {
return meow;
}
public void setMeowString(String meow) {
this.meow = meow;
}
}
This means I can use:
Criteria criteria = Session.createCriteria(ICat.class);
And Spring/Hibernate knows that it pulls the annotations for ICat from the concrete inheritance in the particular project.
However if I try to do:
DetachedCriteria subQuery = DetachedCriteria.forClass(ICat.class,"inner"); // etcetera
then I get an Unknown entity at runtime for ICat.
Now this makes sense as in the first instance is creating it off the Session so it has all the configuration that it needs whereas the DetachedCriteria is a static method however it errors when trying to do the
criteria.list()
by which time it has picked up the Session and should know that ICat is actually a SquawkyMeowingCat which has all the annotations.
So my questions are two part:
1) Is this known behaviour and will be like this forever more?
2) Can anyone think of a simple way around it without using an Interface and concrete ClassHolder which hands back the instance of the class it needs to create?
I'm not sure about the case of the DetachedCriteria, but one way to avoid explicit dependence on the concrete class might be to query Hibernate's metadata using the interface:
public <T> Class<? extends T> findEntityClassForEntityInterface(
SessionFactory sessionFactory,
Class<T> entityInterface
) {
for (ClassMetadata metadata : sessionFactory.getAllClassMetadata().values()) {
Class entityClass = metadata.getMappedClass(EntityMode.POJO);
if (entityInterface.isAssignableFrom(entityClass)) {
return entityClass;
}
}
return null;
}
With the usual caveats about the robustness of illustrative code spippets.