user7085962 user7085962 - 1 month ago 8
Java Question

Calling constructor of generic type?

I am trying to make my own repository for my database to learn, so I am trying something like this:

@Override
public <T extends DatabaseObject> List<T> getList() {
Cursor cursor = getCursor(somehowGetClassOfT(), null, null); //how to do this?
//excess code removed, rest of function not relevant to question
return list;
}

protected <T extends DatabaseObject> Cursor getCursor(Class<T> clazz, String selection, String[] selectionArgs) {
DatabaseObject databaseObject = instantiateFromT(clazz); //how to do this?
String tableName = databaseObject.getTableName();
String[] projection = databaseObject.getProjection();
String sortOrder = databaseObject.getDefaultOrderColumn() + " " + DEFAULT_SORT_ORDER;
Cursor cursor = database.query(
tableName,
projection,
selection,
selectionArgs,
null,
null,
sortOrder
);
return cursor;
}


In other words I have many classes that extend DatabaseObject, and I want to be able to construct a Cursor for them dynamically.

I've defined basic methods in a DatabaseObject such as getting the table name, String array of column names, etc, but since I cannot override static methods via interface (for things like table name), I have to instantiate a blank object so I can get the table name with a getter.

However, I am not sure how to implement:


  1. somehowGetClassOfT()
    . Whatever
    T
    is, I want to pass the class for it into the Cursor function.

  2. instantiateFromT(clazz)
    . Given some class, call the constructor so I can get access to that object's table/projection/sort fields.



Or is all of this possible by using "reflection" that I've been hearing about?

Answer

Generics are not reified at run-time. Since the information is not present, it must be stored at compile-time by introducing a private field with the class. Generics are useful if you want to have a repository by type of DatabaseObject concrete. Otherwise, you don't need to use generic if you want directly to work with DatabaseObject interface.

Here an example by starting from your code :

public abstract class MyRepository<T extends DatabaseObject> {

    private Class<T> type;

    public MyRepository(Class<T> type) {
      this.type = type;
    }

    public <T> List<T> getList() {
      Cursor cursor = getCursor(null, null); // how to do this?
      // excess code removed, rest of function not relevant to question
      return null;
    }

    protected <T extends DatabaseObject> Cursor getCursor(String selection, String[] selectionArgs) {
      DatabaseObject databaseObject = instantiateFromType(); // how to do this?
      String tableName = databaseObject.getTableName();
      String[] projection = databaseObject.getProjection();
      String sortOrder = databaseObject.getDefaultOrderColumn() + " " + DEFAULT_SORT_ORDER;
      Cursor cursor = database.query(
        tableName,
        projection,
        selection,
        selectionArgs,
        null,
        null,
        sortOrder);
      return cursor;
    }

    private DatabaseObject instantiateFromType() {
      try {
          T interfaceType = (T) type.newInstance();
          return interfaceType;
      }
      catch (Exception e) {
          // TODO to handle
       }
      return null;
    }
}

Here your DogRepository :

public class DogRepository extends MyRepository<Dog> {

    public DogRepository(Class<Dog> type) {
      super(type);
    }

}

with a Dog which implements DatabaseObject:

public class Dog implements DatabaseObject{
   //todo
}
Comments