4
\$\begingroup\$

This is my first go at implementing the DAO pattern - let alone implementing it for MongoDB with Morphia - I was hoping someone could point out smells and answer questions from my below implementation.

public interface GenericDAO<T, K extends Serializable>
{
    public void insert(T entity);
    public T queryByKey(Class<T> typeClass, K id);
}

My implementation of GenericDAO for MongoDB extends Morphia's BasicDAO - does this seem like the correct placement for this extension? The super I'm leveraging is performing the connection for me, if I was to drop Morphia and use something else, I would have to change the constructors for each of my DAO implementations, and achieve connection in a different way - is this a common kind of change people make to their DAO definition?

public class GenericDAOMongoImpl<T, K extends Serializable> extends BasicDAO<T, K>
{
    public GenericDAOMongoImpl(Class<T> entityClass) throws UnknownHostException
    {
        super(entityClass, ConnectionManager.getDataStore());
    }   
}

All of my DTO's are coded against interfaces - this is so that I can use things like Morphia's annotations in my DTO's without coupling that specific DTO to any implementation technology.

public interface EntryDTO extends GenericDTO
{
}

@Entity
public class EntryDTOMongoImpl implements EntryDTO
{
    @Id
    private ObjectId id;
    private String name;
    private int age;
    private ArrayList<String> pets;

    public EntryDTOMongoImpl()
    {
       this.name = "Colin";
       this.age = 40;

       this.pets = new ArrayList<String>();
       pets.add("dog");
       pets.add("cat");
    }

    public int getAge()
    {
        return age;
    }

    public void setAge(int age)
    { 
        this.age = age;
    }

    public ObjectId getId()
    {
        return id;
    }

    public void setId(ObjectId id)
    {
        this.id = id;
    }

    public String getName()
    {
        return name;
    }

    public void setName(String name)
    {
        this.name = name;
    }

    public ArrayList<String> getPets()
    {
        return pets;
    }

    public void setPets(ArrayList<String> pets)
    {
        this.pets = pets;
    }        
}

Then my DAO implementation for EntryDTO reads below. Does it make sense that the EntryDAO interface is parameterized such that it accepts a generic variable that extends EntryDTO? I was hoping I could simply parameterize it with EntryDTO as the generic type, but this causes issues in the below Runner class when I pass the concrete Class EntryDTOMongoImpl.class to the queryByKey method?

public interface EntryDAO<T extends EntryDTO> extends GenericDAO<T, Serializable>
{
}

public class EntryDAOMongoImpl extends GenericDAOMongoImpl<EntryDTOMongoImpl, ObjectId> implements EntryDAO
{
    private static final Logger logger = Logger.getLogger(EntryDAOMongoImpl.class);

    public EntryDAOMongoImpl(Class<EntryDTOMongoImpl> entityClass) throws UnknownHostException
    {
        super(entityClass);
    }

    public void insert(Object entity)
    s
        save((EntryDTOMongoImpl) entity);
    }

    public Object queryByKey(Class typeClass, Serializable id)
    {
        EntryDTOMongoImpl dto = null;

        try
        {
            dto = (EntryDTOMongoImpl) ConnectionManager.getDataStore().get(typeClass, id);
        }
        catch(UnknownHostException ex)
        {
            logger.error(ex);
        }

        return dto;
    }
}

I'm then creating instances of my DAO's simply like below. This would ideally be done with some DI library.

public class Runner
{
    private static final Logger logger = Logger.getLogger(Runner.class);
    private EntryDAO entryDAO;

    public Runner() throws UnknownHostException
    {
        this.entryDAO = new EntryDAOMongoImpl(EntryDTOMongoImpl.class);
    }

    public static void main(String[] args) throws UnknownHostException
    {
        Runner runner = new Runner();

        EntryDTOMongoImpl dtoA = new EntryDTOMongoImpl();

        runner.entryDAO.insert(dtoA);
        EntryDTOMongoImpl foundA = (EntryDTOMongoImpl) runner.entryDAO.queryByKey(EntryDTOMongoImpl.class, dtoA.getId());

        logger.debug(dtoA.getId() + ", " + dtoA.getName());
        logger.debug(foundA.getId() + ", " + foundA.getName());
    }
}
\$\endgroup\$
3
  • \$\begingroup\$ What is exactly the question? \$\endgroup\$ Commented Feb 13, 2012 at 15:46
  • \$\begingroup\$ @GeorgeMauer - the questions are in bold on the original SO post. \$\endgroup\$
    – wulfgarpro
    Commented Feb 14, 2012 at 22:42
  • 1
    \$\begingroup\$ You should really take the effort to copy your question over! \$\endgroup\$
    – Torbjørn
    Commented Feb 15, 2012 at 5:39

1 Answer 1

4
\$\begingroup\$

I disagree with Generic DAO design, reason of it is :

You design generic dao with to generic type T, K, T for entity type and K for entity id. Now I say:

  1. What happen with this design if in a part of application we have an entity with two key as primary key (We have this allow in ORM)

  2. What happen with this design if we want more operation in data layer such as search or batch insert operations.

I suggest following design:

  • Have for any entity a interface with itself operation.
  • Have for any entity a or more implementation of above interface
  • Have an interface as DAOFactory
  • Have a or more implementation of DAOFactory(such as Spring implementation or Guice or manually or etc)

I show your application by my suggest design:

first I define a entity for sample it's Person:

public class Person 
{
   private long id;
   private String name;
   private int age; 

   /*
    *  define accessible methods
    */
}

Next define an interface as DAO for above entity:

public interface PersonDAO
{
    public void insert(Person entity);
    public Person queryByKey(long id);
    public void remove(long id);
    public List<Person> searchByCriteria(/*custom criteria*/);
}

In next step, we define implementation for PersonDAO interface by MongoDB:

public class MongoDBPersonDAO implements PersonDAO
{

    public void insert(Person entity)
    {
       /*
        *   MongoDB api for insert an entity
        */
    }

    public Person queryByKey(long id)
    {
       /*
        *   MongoDB api for find an entity by its id
        */
    }

    public void remove(long id)
    {
       /*
        *   MongoDB api for remove an entity by its id
        */
    }

    public List<Person> searchByCriteria(/*custom search criteria*/)
    {
       /*
        *   MongoDB api for find set of entity by set of search criteria
        */
    }
}

Now, we designed dao layer for Person entity. In next step we have to define a Factory API:

public DAOFactory
{
   public PersonDAO getPersonDAO();   

   /*
    *  define other abstract methods for other DAOs
    */
}

In next step we define an implementation for above factory, in this case we want define Spring implementation:

public SpringDAOFactory implements DAOFactory
{
   private ApplicationContext dao_ctx;
   /*
    *  define constructor that spring context files parameter
    */
   public SpringDAOFactory(String...contexts)
   {
      this.dao_ctx = new ClassPathXmlApplicationContext(contexts);
   }

   public PersonDAO getPersonDAO()
   {
      return dao_ctx.getBean(PersonDAO.class);
   }
}

saw we define a spring implementation of dao factory with context files path. We in next step show a sample of spring context:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">

   <bean id="PersonDao" class="MongoDBPersonDAO" scope="singleton">
       <!--
          do dependency injection
       -->   
   </bean>
</beans>

and in last we define a singleton dao factory by spring implementation as following:

DAOFactory dao_factory = new SpringDAOFactory(); // this instance have to singleton

and use dao_factory where need to it. With this define we separating DAO APIs from its implementation and PersonDao from its implementations also. With this design any entity has itself dao and its operations.

\$\endgroup\$
2
  • 1
    \$\begingroup\$ such as Spring implementation or Juice - here's typo? I think you mean Guice (google DI framework)? Can you add some example with Guice? Thanks \$\endgroup\$
    – MyTitle
    Commented Dec 25, 2012 at 14:56
  • 1
    \$\begingroup\$ @MyTitle Oh,Thanks, I correct it. Sorry, I don't working with Guice at real situation and only read its documents on web. \$\endgroup\$
    – Sam
    Commented Dec 26, 2012 at 10:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.