Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 664
Jonas Avatar asked Aug 03 '10 13:08

Jonas


People also ask

How do I return a generic class type in Java?

(Yes, this is legal code; see Java Generics: Generic type defined as return type only.) The return type will be inferred from the caller. However, note the @SuppressWarnings annotation: that tells you that this code isn't typesafe. You have to verify it yourself, or you could get ClassCastExceptions at runtime.

How do you pass a class object as a parameter in Java?

We have a method coypObject() which accepts an object of the current class and initializes the instance variables with the variables of this object and returns it. In the main method we are instantiating the Student class and making a copy by passing it as an argument to the coypObject() method.

What kind of parameter type is used for a generic class to return and accept any types of object?

Which of these type parameters is used for a generic methods to return and accept any type of object? Explanation: T is used for type, A type variable can be any non-primitive type you specify: any class type, any interface type, any array type, or even another type variable.


1 Answers

It looks like you want to adapt what Josh Bloch calls a Typesafe Heterogenous Container pattern: you are passing a type token Class<T>, and you want back a List<T>.

Plain old THC can map a Class<T> to a T in a typesafe manner, but since you actually want a List<T> instead, then you want to use what Neal Gafter calls the super type tokens.

The following snippet is adapted from Crazy Bob Lee's code posted in Neal Gafter's blog:

public abstract class TypeReference<T> {     private final Type type;      protected TypeReference() {         Type superclass = getClass().getGenericSuperclass();         if (superclass instanceof Class<?>) {             throw new RuntimeException("Missing type parameter.");         }         this.type = ((ParameterizedType) superclass).getActualTypeArguments()[0];     }     public Type getType() {         return this.type;     } } 

Now you can create a super type token like these:

    TypeReference<String> stringTypeRef =             new TypeReference<String>(){};      TypeReference<Integer> integerTypeRef =             new TypeReference<Integer>(){};      TypeReference<List<Boolean>> listBoolTypeRef =             new TypeReference<List<Boolean>>(){}; 

Essentially you pass a TypeReference<T> instead of a Class<T>. The difference is that there is no List<String>.class, but you can make a TypeReference<List<String>>.

So now we can make our container as follows (the following is adapted from Josh Bloch's original code):

public class Favorites {     private Map<Type, Object> favorites =         new HashMap<Type, Object>();      public <T> void setFavorite(TypeReference<T> ref, T thing) {         favorites.put(ref.getType(), thing);     }     public <T> T getFavorite(TypeReference<T> ref) {         @SuppressWarnings("unchecked")         T ret = (T) favorites.get(ref.getType());         return ret;     } } 

Now we can put the two together:

    Favorites f = new Favorites();     f.setFavorite(stringTypeRef, "Java");     f.setFavorite(integerTypeRef, 42);     f.setFavorite(listBoolTypeRef, Arrays.asList(true, true));      String s = f.getFavorite(stringTypeRef);     int i = f.getFavorite(integerTypeRef);     List<Boolean> list = f.getFavorite(listBoolTypeRef);      System.out.println(s);    // "Java"     System.out.println(i);    // "42"     System.out.println(list); // "[true, true]" 

Neal Gafter argued in his blog that with some more bells and whistles, TypeReference for super type tokens will make a worthy inclusion in the JDK.

Attachments

  • Complete source code on ideone.com

References

  • Neal Gafter's Blog - Super Type Tokens
like image 131
polygenelubricants Avatar answered Sep 18 '22 12:09

polygenelubricants