Search code examples
javagenericsclasspolymorphismparameter-passing

How can I pass a Class as parameter and return a generic collection in Java?


I am designing a simple Data Access Object for my Java application. I have a few classes (records) that represents a single row in tables like User and Fruit.

I would like to have a single method for getting all records of a specific type.

For the moment I have it like this:

public List<User> getAllUsers() {
 ...
}

public List<Fruit> getAllFruits() {
 ...
}

....

But I would like to have a single polymorphic method like this (wrong):

public List<T> getAllRecords(Class<T> type) {
    if(type instanceof User) {
        // Use JDBC and SQL SELECT * FROM user
    } else if(type instanceof Fruit) {
        // Use JDBC and SQL SELECT * FROM fruit
    }
    return collection;
}

Example for uses:

List<Fruit> fruits = myDataAccessObject.getAllRecrods(Fruit.class);
List<User> users = myDataAccessObject.getAllRecords(User.class);

How can I do this in Java?


Solution

  • Since you say that you don't want you data access methods in different classes(in the comment to anish's answer),I thought why not try something like this.

    public class Records {
    
        public interface RecordFetcher<T>{
            public List<T> getRecords();
        }
        static RecordFetcher<Fruit> Fruit=new RecordFetcher<Fruit>(){
            public List<Fruit> getRecords() {
                ...
            }
        };
    
    
        static RecordFetcher<User> User=new RecordFetcher<User>(){
            public List<User> getRecords() {
                ...
            }   
        };
    
        public static void main(String[] args) {
            List<Fruit> fruitRecords=Records.Fruit.getRecords();
            List<User> userRecords=Records.User.getRecords();
    
        }
    }
    

    EDIT:

    I would like to add one more of my implementation.

    public class Test 
    { 
        public static void main(String[] args) 
        { 
           Test dataAccess=new Test();
           List<Fruit> FruitList=dataAccess.getAllRecords(Fruit.myType);
           List<User> UserList=dataAccess.getAllRecords(User.myType);
        } 
        <T> List<T> getAllRecords(T cl)
        {
            List<T> list=new ArrayList<T>();
            if(cl instanceof Fruit)
            {
                 // Use JDBC and SQL SELECT * FROM fruit
            }
            else if(cl instanceof User)
            {
                // Use JDBC and SQL SELECT * FROM user
            }
            return list;
        }
    }
    class Fruit
    {
        static final Fruit myType;
        static {myType=new Fruit();}
    }
    class User
    {
        static final User myType;
        static {myType=new User();}
    }
    

    EDIT:

    I think this implementation is just as you have asked

    public class Test 
    { 
        public static void main(String[] args) throws InstantiationException, IllegalAccessException 
        { 
           Test dataAccess=new Test();
          
           List<Fruit> FruitList=dataAccess.getAllRecords(Fruit.class);
          
           List<User> UserList=dataAccess.getAllRecords(User.class);
          
        } 
        <T> List<T> getAllRecords(Class<T> cl) throws InstantiationException, IllegalAccessException
        {
            T inst=cl.newInstance();
            List<T> list=new ArrayList<T>();
            if(inst instanceof Fruit)
            {
                 // Use JDBC and SQL SELECT * FROM fruit
            }
            else if(inst instanceof User)
            {
                // Use JDBC and SQL SELECT * FROM user
            }
            return list;
        }
    }