Search code examples
javadesign-patternsgenericsdaodto

How do Generics and Fields assist DAO Pattern in Standalone Java applications


//Interface DAO

    public abstract class BaseDAO<T extends BaseDTO> {


    public void update(T t) throws DBException {
     Field[] fieldsToInsert = t.getClass().getDeclaredFields();
    //code to update database object academic or event
    }

     public Integer create(T t) throws DBException {
      Field[] fieldsToInsert = t.getClass().getDeclaredFields();
    //code to create academic or event in database
    }

} 



//Concrete DAOs
public class AcademicDAO extends BaseDAO<AcademicDTO> {
//provide implementation
}

public class EventDAO extends BaseDAO<EventDTO> {
//provide implementation
}



//Transfer object
public class AcademicDTO extends BaseDTO {
   String title;
   String surname;
   //getters and setters
}


public class BaseDTO {

    protected Integer ID;

    public Integer getID() {
        return ID;
    }

    public void setID(Integer ID) {
        this.ID = ID;
    }
}

Hello Guys, I have a sample code on me that follows the above structure to create a small java application to manage academics and events. It is leniently following this pattern

1- You experts are familiar with this pattern more than me. I would like to understand why generics are used in this case so DAOs can extend and implement a generic base class. It would be great if one can show how generics here may be advantageous using an example.

2 - I have also witnessed the use of java Fields. Is there a link between generics and Fields?

I would like to document DAO pattern in an academic report, but I am finding difficult to understand how Generics and Reflect Field play a part here. Do they support flexibility and loose coupling?


Solution

  • The code you've provided is reusable set of logic to load and persist entities. Many times, in an application of non-trivial size, you'll wind up persisting many different types of objects. In this example, you can define as many objects as necessary, but only define the logic to actually save and load once. By asking the DTO what Field objects are there, it can get at the data to help construct queries for loading and saving.

    Generics allow you to use this pattern while maintaining type safety. AcademicDAO can only handle AcadmeicDTO. You can't use AcademicDAO to store EventDTO. Generics allow the instance of the class to rely on a more specific type when dealing with the Field objects. If you didn't have generics, the BaseDAO would take Object, and you wouldn't be able to access any methods except those that Object provides because the JVM wouldn't know what class is provided, so it has to limit it's knowledge to that of Object. Using getClass().getDeclaredFields() bypasses that limitation because getClass() returns the actual class of the Object parameter.

    Field is just a way to use reflection to access the values of the properties in each DTO. If you had to access the fields directly, with getTitle(), you couldn't reuse a generic base class to do your persistence. What would happen when you needed to access EventDTO? You would have to provide logic for that. Field allows you to skip that logic.

    Edit:

    To explain what I mean by accessing getID, you could do the following within BaseDAO because T is known to be a BaseDTO with a getID() method defined:

    public abstract class BaseDAO<T extends BaseDTO> {
    
        public boolean update(T t) throws DBException {
            Integer id = t.getID();
            Field[] fields = t.getClass().getDeclaredFields();
            // Assuming you have a db object to execute queries using bind variables:
            boolean success = db.execute("UPDATE table SET ... WHERE id = ?", id.intValue());
            return success;
        }
    }
    

    If you had this instead (in a non-generic class):

    public boolean update(Object o) throws DBException {
        // This line doesn't work, since Object doesn't have a getID() method.
        Integer id = t.getID();
        Field[] fields = o.getClass().getDeclaredFields();
    
        boolean success = db.execute("UPDATE table SET ... WHERE id = ?", id.intValue());
        return success;
    }
    

    You'd have to look through those Field objects, or ask for the ID field and assume it existed.