Pergunta

I want to apply a generic design pattern for my DAO layer, such that I can switch between third-party ORM easily (Hibernate, JPA, etc.). Apparently we have some common methods for all DAOs like:

  • public void create(T entity);
  • public void update(T entity);
  • public void delete(Object pk);
  • public T read(Object pk);
  • public List readAll();

All DAOs have to inherit these methods plus additional methods specific for each DAO, I found the following design pattern suitable for me but I don't know how to use it in order to have all the common methods and the specialized one appear on the same DAO reference:

First we will make an interface for all common methods:

public interface GenericDAOINT<T> {

    public void create(T entity);

    public void update(T entity);

    public void delete(Object pk);

    public T read(Object pk);

    public List<T> readAll();

}

and we will make an abstract class that implements that interface:

public abstract class GenericDAOHibernate<T> implements GenericDAOINT<T> {
    private Class<T> persistentClass;
    private Session session;
    private static SessionFactory sessionFactory;
    private static Logger LOGGER = Logger.getLogger("InfoLogging");

    public GenericDAOHibernate(T theClass) {
        this.persistentClass = (Class<T>) theClass;
        session = sessionFactory.openSession();
    }

    public Class<T> getPersistentClass() {
        return persistentClass;
    }

    public void setPersistentClass(Class<T> persistentClass) {
        this.persistentClass = persistentClass;
    }

    static {
        sessionFactory = new Configuration().configure("hibernate.cfg.xml")
                        .buildSessionFactory();
    }

    public Session getSession() {
        return session;
    }

    public void create(T entity) {
        // implementation
    }

    public void update(T entity) {}

    public void delete(Object pk) {}

    public T read(Object pk) {}

    public List<T> readAll() {}
}

After that we will make a DAOFactory that will enable me to switch between different ORM smoothly:

public abstract class DAOFactory {
    public static DAOFactory getInstance(Class factory) {
        try {
            return (DAOFactory) factory.newInstance();
        } catch (Exception e) {
            throw new RuntimeException("Couldn't create DAOFactory: " + factory);
        }
    }
    // return reference to any desired dao in order to call specialized methods
    public abstract RegionHome getRegionDAO();
    public abstract ServicesHome getServicesDAO();
    public abstract StatusHome getStatusDAO();
}

Next we will make a DAOFactory for hibernate or any other pluggable ORM:

public class DAOFactoryHibernate extends DAOFactory {

    public GenericDAOHibernate<?> instantiateDAO(Class<?> daoClass)
    {
        try
        {
            GenericDAOHibernate<?> dao = (GenericDAOHibernate<?>) daoClass.newInstance();    // Exception is thrown here
            return dao;
        } catch (Exception e) {
            System.out.println(e.toString());
            throw new RuntimeException("Can not instantiate DAO: " + daoClass, e);
        }
    }

    @Override
    public RegionHome getRegionDAO() {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public ServicesHome getServicesDAO() {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public StatusHome getStatusDAO() {
        // TODO Auto-generated method stub
        return null;
    }
}

in order to add specialization to each DAO we will make an Interface for each DAO, that interface will extend GenericDAOINT to include the common methods in each DAO for the ServicesDAO we will do the following:

public interface ServicesDAO<T> extends GenericDAOINT<ServicesHome> {

    public void specializedMethod();

}

and finally we will make a concrete class for ServicesDAO specific for Hibernate as follows:

public class ServicesDAOHibernate extends GenericDAOHibernate implements ServicesDAO {

    public ServicesDAOHibernate(Class theClass) {
        super(theClass);
        // TODO Auto-generated constructor stub
    }

    @Override
    public void specializedMethod() {
        System.err.println("Specialized Method");
    }

}

I think that these pattern facilitate the process of switching between ORM easily and flexible but the other side I told you about is that I want to call all the methods (Common + Specialized) on the same reference for each DAO, I tried the following client code:

public class test {
    public static void main(String args[]) {

    DAOFactoryHibernate DFH = (DAOFactoryHibernate) DAOFactory.getInstance(DAOFactoryHibernate.class);
    ServicesDAOHibernate serviceObjectDAO=(ServicesDAOHibernate) DFH.instantiateDAO(ServicesDAOHibernate.class);
    serviceObjectDAO.specializedMethod();

}

but I got the following exception:

Exception in thread "main" java.lang.RuntimeException: Can not instantiate DAO: class ServicesDAOHibernate
    Caused by: java.lang.InstantiationException: ServicesDAOHibernate
    at java.lang.Class.newInstance0(Class.java:340)
    at java.lang.Class.newInstance(Class.java:308)
    at DAOFactoryHibernate.instantiateDAO(DAOFactoryHibernate.java:9)

I want to know how to call all the methods (Common + Specialized) on the same reference like the previous client code.

Foi útil?

Solução

I wish you would have posted the full stack trace (you're missing a caused-by which has the root cause of the issue). But from looking at your code, your issue seems to be you're calling a no-arg constructor on ServicesDAOHibernate via Class.newInstance() and that class doesn't have a no-arg constructor. You want to use

return (GenericDAOHibernate<?>) daoClass.getConstructor(Class.class)
  .newInstance(daoClass);
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top