0

I'm trying to get the solution to achieve the following:

public final static <T> Class<Set<T>> getSetClass(Class<T> cls) {
    ...
}

Where cls is for example String.class and the method then returns the Class<Set<String>> object. But of course, as cls is variable, it could also get Boolean.class and then return a Class<Set<Boolean>> object.

How can I achieve this?

bartlaarhoven
  • 825
  • 2
  • 8
  • 21
  • you can have a look at this [link](http://stackoverflow.com/questions/3403909/get-generic-type-of-class-at-runtime) , may be solving your problem. – Ajay Sreeram Sep 06 '16 at 14:14
  • @Thilo I want to use a JSONPath library in a generic application where the return type is not known beforehand. So I need to execute this method: https://github.com/jayway/JsonPath/blob/master/json-path/src/main/java/com/jayway/jsonpath/internal/JsonContext.java#L157 where I can pass the expected return class. Sometimes I explicitly expect a Set of JSONObjects or a Set of Strings. I hoped I could achieve that this way.. – bartlaarhoven Sep 06 '16 at 14:15
  • I don't know that library, but that's probably what this `TypeRef` is for. A `Class` object won't capture enough information. – Thilo Sep 06 '16 at 14:17

3 Answers3

2

This works for me:

@SuppressWarnings("unchecked") 
public <T> Class<Set<T>> getSetClass(Class<T> cls) { 
  Set<T> set = new HashSet<>(); 
  return (Class<Set<T>>) set.getClass();
}

Well, it compiles; how useful it is to solve your "real" problem; I can't tell yet. And obviously; that cls parameters goes unused here.

But it does something:

@Test
public void test() {
    Class<Set<Integer>> setClass = new PartitionPropertiesTest().getSetClass(Integer.class);
    System.out.println("whatever: " + setClass);
}

prints:

whatever: class java.util.HashSet
GhostCat
  • 137,827
  • 25
  • 176
  • 248
  • But note that this generates a type warning (suppressed here), because the returned Class instance does not contain any information about `T`. All it knows is that it is a `Set` of something (the nature of which has been erased). – Thilo Sep 06 '16 at 14:22
  • I don't know how useful this is either, but this library I use wants to get the expected return type as a Class object. And I really want a Set of Strings or a Set of JSONObjects. So thanks, I'm going to accept this answer as it answers my question. Thanks also to @Thilo for pointing me to some of the theory. – bartlaarhoven Sep 06 '16 at 14:24
  • I think the library wants you to use the `TypeRef` version of the method instead of the `Class` version (for this exact reason): https://github.com/jayway/JsonPath/blob/master/json-path/src/main/java/com/jayway/jsonpath/TypeRef.java – Thilo Sep 06 '16 at 14:25
0

There is no Class<Set<String>> object.

Generic types are erased at runtime, so there is only an instance of Class<Set> (namely Set<?>.class) shared by all the Class<Set<?>>. There is no way to get back to String from this object.

For this very reason, your JSON library has a TypeRef class to capture the generic type information. You just use that instead of Class.

Thilo
  • 257,207
  • 101
  • 511
  • 656
  • How can I achieve this with the `TypeRef` then? In the documentation of `TypeRef` I also just see `TypeRef ref = new TypeRef>() { };` which is not going to solve my problem, as that `Integer` part should be parameterized... – bartlaarhoven Sep 06 '16 at 14:30
  • The documentation claims to capture the `Integer` part. – Thilo Sep 06 '16 at 21:39
  • This only works because you are making an anonymous subclass of `TypeRef` here (not the `{}` at the end). That way, the compiler has this information. – Thilo Sep 06 '16 at 21:40
-1

You mean, how to define that the return type depends on the parameter type?

Try this:

public final static <T> Class<Set<T>> getSetClass(Class<T> cls) {
    ...
}
Markus Mitterauer
  • 1,560
  • 1
  • 14
  • 28
  • Ah yeah that's the better way to define the method, but I'm looking for the actual body of the method to achieve it.. – bartlaarhoven Sep 06 '16 at 14:18
  • Your Question was not clear on what the problem is, an your code snippet only showed the method signature, so I thought there's the problem. – Markus Mitterauer Sep 06 '16 at 20:16