3

I have a function:

add(Collection<?> many)

I call it like this:

Collection<NewClass> awa = new ArrayList<NewClass>();
add(awa)

How do I get the <?> type? in that function?

many.getClass() gives ArrayList.

Why I need this? Trying to make a generic DAO method for adding a Collection of < ? >.

EDIT:

tried like this:

public static void add(Collection<?> many)  {
    Type typeArg = ((ParameterizedType)Testing.class.getGenericSuperclass()).getActualTypeArguments()[0];
    System.out.println(typeArg);
}

    Collection<NewClass> awa = new ArrayList<NewClass>();


    add(awa);

got error:

Exception in thread "main" java.lang.ClassCastException: java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType
9
  • 7
    Type erasure is going to make that hard. Commented Aug 7, 2012 at 14:10
  • Why do you need to know the type? Commented Aug 7, 2012 at 14:14
  • @Code-Guru : Hibernate adds element to database by classname Commented Aug 7, 2012 at 14:15
  • @Jaanus Hibernate reads type parameters via reflection API from field or properties declarations. Commented Aug 7, 2012 at 14:48
  • @PiotrGwiazda what do you mean? Commented Aug 7, 2012 at 14:49

4 Answers 4

4

many.getClass() gives ArrayList.

Sure, that sounds right.

What if you do many.get(0).getClass() instead? Here we're interrogating the element, and not the container, if that makes sense. I'm a C#er, so this may not be 100% the right way to do this, but it's the route I would take in C#.

Sign up to request clarification or add additional context in comments.

2 Comments

This way you get the type of the first element. If the elements in the list don't have the same type this could easily be the most specific type. You would need to iterate over all elements and get the most generic type.
I assumed they would have the same type across all elements, and that he would use a guard clause, yes.
1

You could go around this issue and make your method generic, eg:

public <T> void add(Collection<T> blah){}

you can call it then by

this.<NewClass>add(awa);

if it's in a different class then

DifferentClass dc = new DifferentClass();
dc.<NewClass>add(awa);

5 Comments

To be correct, the method and Call are in different Class. Will it work?
sure, just use the class name/instance name instead of "this". (see edit)
Ok but how I get the class? This sends the class, but how I get it?
You would use T for the type inside of your method. If you mean you need to do conditionals based on what type of collection is passed in, then you would need to have a second parameter that somehow tells you the type. There is no non-overkill way (see Piotr's answer) for getting the type of a generic that I know of.
There is no reason to do this. It adds nothing to what he's already doing with ?
1

Why not try something like this :

public class Test {

  Test() {
    Collection<Integer> ints = new ArrayList<Integer>();
    add(ints, Integer.class);
    Collection<String> strings = new ArrayList<String>();
    add(strings, String.class);
  }

  public final <T> void add(Collection<T> many, Class<T> type) {
    System.out.println(type.getName());
    // do whatever needed.
  }

}

7 Comments

There was just a small mistake. It is the right idea, due to type erasure you need to provide the type at runtime explicitely.
This seems incredible overkill, as you're passing in a reference to the type which you can infer from the element, no? Every element carries a type, indeed this is the point of Java. So if you have an element (the function got called) then you have a type. There's no need to carry this extra baggage.
You can't infer the generic collection type from the element type. If each and every element is java.lang.String the collection type could still be java.lang.Object. There is no hint whatsoever.
The collection will always be just a collection. Collections are not interesting.
The generic collection parameter type, of course... that is what is needed for further processing (persisting or whatever).
|
1

You can check actual type arguments on runtime but you can read this only via reflection API from field, method, constructor etc. Sample below:

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;


public class TypesSample {

    public List<String> sampleList;


    public static void main(String[] args) throws Exception {
        Field f = TypesSample.class.getField("sampleList");
        ParameterizedType paramType = (ParameterizedType)f.getGenericType();
        Type typeArgument = paramType.getActualTypeArguments()[0];
        System.out.println(paramType.toString() + " with argument : " + typeArgument.toString());
    }


}

it says : java.util.List<java.lang.String> with argument : class java.lang.String

You won't get actual parameter type from object reference because of type erasure.

//edit:

This is what you can do for your situation:

abstract class GenericDAO<T> {

    public void add(Collection<T> many) {
        Type typeArg = ((ParameterizedType)this.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
        System.out.println("This is a DAO for " + typeArg);
    }

}

    // create DAOs that define what type parameter is   
class IntegerDAO extends GenericDAO<Integer> {}
class StringDAO extends GenericDAO<String> {}

and then :

GenericDAO<Integer> integerDAO = new IntegerDAO();
integerDAO.add(Arrays.asList(1,2,3));
GenericDAO<String> stringDAO = new StringDAO();
stringDAO.add(Arrays.asList("A","B","C"));

says: This is a DAO for class java.lang.Integer This is a DAO for class java.lang.String

But you need to explicitly declare what T is by extending generic class.

12 Comments

How to do this with a method parameter Collection<?> param?
doesn't really answer the question. answers a different question
@newacct actually second example is the only way to implement generic DAO and infer generic parameter. First example just defines the problem.
It still is only a workaround for the original question. But as the original question has to be answered with "impossible", good workarounds are all you can get.
Got error Exception in thread "main" java.lang.ClassCastException: java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType Look first post
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.