Romualdo Rubens de Freitas Romualdo Rubens de Freitas -3 years ago 129
Java Question

Java method returning two or more generic types

There are a lot of questions regarding Java methods returning generic types, but none of them helped me out so far.

So here's my code:

interface DAO<K, T> {
void insert(T t);
void update(K k, T t);
void delete(K k);
void delete();
T select(K k);
List<T> select();
}

public class CourseDAO implements DAO<String, Course> {
public void insert(Course t) {}
public void update(String k, Course t) {}
public void delete(String k) {}
public void delete() {}
public Course select(String k) {}
public List<Course> select() {}
}

public class StudentDAO implements DAO<Long, Student> {
public void insert(Student t) {}
public void update(Long k, Student t) {}
public void delete(Long k) {}
public void delete() {}
public Student select(Long k) {}
public List<Student> select() {}
}

public enum EntityType { COURSE, STUDENT }


Now I want a factory method which accepts an
EntityType
parameter and return an instance of
CourseDAO
or
StudentDAO
depending on the parameter value.

I tried the code below without success:

public <K,T> DAO<K,T> createDAOFactory(EntityType type) {
switch (type) {
case COURSE : return (K,T) new CourseDAO(); break;
case STUDENT : return (K,T) new StudentDAO(); break;
}
return null;
}


Could anyone help me in writing and invoking this method???

Cheers,

Romualdo.

Answer Source

The cast you're looking for is (DAO<K,T>). But you'll get a warning because generic type erasure makes it unsafe. Another inherent risk in the switch factory is that you might forget to create a corresponding case when you add a new EntityType. A safer alternative would be to redefine EntityType with generic types, and let it be the factory. Unfortunately, this isn't possible with proper enums, but you can simulate it like this:

abstract class EntityType<K, T> {
    public abstract DAO<K, T> createDAO();

    public static final EntityType<String, Course> COURSE = new EntityType<String, Course>() {
        @Override
        public DAO<String, Course> createDAO() {
            return new CourseDAO();
        }
    };
    public static final EntityType<Long, Student> STUDENT = new EntityType<Long, Student>() {
        @Override
        public DAO<Long, Student> createDAO() {
            return new StudentDAO();
        }
    };
}

Or you can use lambdas to reduce the boilerplate:

class EntityType<K, T> {
    private final Supplier<DAO<K, T>> constructor;

    private EntityType(Supplier<DAO<K, T>> constructor) {
        this.constructor = constructor;
    }

    public DAO<K, T> createDAO() {
        return constructor.get();
    }

    public static final EntityType<String, Course> COURSE = new EntityType<>(CourseDAO::new);
    public static final EntityType<Long, Student> STUDENT = new EntityType<>(StudentDAO::new);
}

Now, instead of calling createDAOFactory(EntityType.COURSE), you would just call EntityType.COURSE.createDAO().

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download