1

I'm trying to do something like this :

public class ResponseProcessorFactory {

    public static <T> ResponseProcessor<T> newResponseProcessor(){
        return new GsonResponseProcessor<T>();
    }    
}

public class GsonResponseProcessor<T> implements ResponseProcessor<T> {

    protected T response;
    protected TypeToken typeToken;

    public GsonResponseProcessor() {
        this.typeToken = new TypeToken<T>(){};
    }

    @Override
    public void parse(String jsonString) throws JSONException, IOException {
            response = GsonHelper.getGsonInstance().fromJson(jsonString, typeToken.getType());
    }

    public T getResponse() {
        return response;
    }
}


private void ResponseProcessor getResponseProcessor(){
       return ResponseProcessorFactory<List<String>>.newResponseProcessor();
}

Now, whenever I invoke getResponseProcessor(), it doesn't return me the response processor for List<String>. Rather, it returns the default response processor for Object.

I'm sure, I'm missing some concept regarding generic. Can someone explain in detail ?

EDIT : The real usage is like this :

   public BaseRequestWithResponseProcessor<List<Dashboard>> getDashboards(Listener<List<Dashboard>> responseListener, ErrorListener errorListener) {
        String url = mBaseUrl + "/dashboard";

        ResponseProcessor<List<Dashboard>> responseProcessor = ResponseProcessorFactory.newResponseProcessor();

        AuthInfo authInfo = getAuthInfo();
        BaseRequestWithResponseProcessor<List<Dashboard>> request = new BaseRequestWithResponseProcessor<List<Dashboard>>(
                Method.GET, url, authInfo, null, responseProcessor, responseListener, errorListener);
        return request;
    }
Gaurav Arora
  • 17,124
  • 5
  • 33
  • 44
  • Where and how do you call `getResponseProcessor()`? – Smutje Oct 07 '14 at 10:42
  • Are you not just missing the public class ResponseProcessorFactory ? – Danny Gloudemans Oct 07 '14 at 10:43
  • Is [this](http://stackoverflow.com/questions/3403909/get-generic-type-of-class-at-runtime) (observing the generic type during runtime) the problem you are looking for? – SME_Dev Oct 07 '14 at 10:44
  • @Smutje : I have added the actual usage. Please check. – Gaurav Arora Oct 07 '14 at 10:53
  • @SME_Dev : I'm quite sure, that is specifically what the problem is. Though I want to be sure and get more insights on it. – Gaurav Arora Oct 07 '14 at 10:54
  • No, you did not add the actual usage for `getResponseProcessor`, only for `newResponseProcessor()`. – Smutje Oct 07 '14 at 10:54
  • `getResponseProcessor` was only a mock to explain my usage case. – Gaurav Arora Oct 07 '14 at 10:56
  • So why do you write this? And by the way, why should `ResponseProcessor> responseProcessor = ResponseProcessorFactory.newResponseProcessor();` return you a `ResponseProcessor>`? – Smutje Oct 07 '14 at 11:14
  • @Smutje : It's not unreasonable to assume the right kind of object would be returned. The right type for `T` in this case is actually chosen by type inference. It is however not possible to know what type this is inside the `newResponseProcessor` method. – Lii Oct 07 '14 at 11:47
  • @Lii OP confuses the method he claims to call, so I can't assume anything at the moment. – Smutje Oct 07 '14 at 12:06

3 Answers3

1

In the GsonResponseProcessor constructor type erasure has happened and at runtime only one version of the method will exist with the type variable T converted to Object.

In Java only one version of generic methods and classes will exist, the type parameters only exist during compile-time and will be replaced by Object during run-time.

Type tokens must be constructed with a concrete type to capture the type information. This is the whole point with them, to capture type information at a place where the concrete type is known. The token can then be stored in variables and later be used to lookup objects or get hold of the type information with reflection.

The solution here is that the caller of getResponseProcessor who knows the concrete type creates the type token and passes it as a parameter. You could also pass in a Class object if that works in you situation. If you want to use generic classes as tokens however, as in your example with List<Dashboard> you will need a type token.

Something like this:

ResponseProcessor<List<String>> p = ResponseProcessorFactory.newResponseProcessor(new TypeToken<List<String>>() {});
Lii
  • 11,553
  • 8
  • 64
  • 88
1

You can work around the type erasure by passing in the class type as method parameter.

public class ResponseProcessorFactory {

    public static <T> ResponseProcessor<T> newResponseProcessor(Class<T> type){
        return new GsonResponseProcessor<T>(type);
    }    
}

public class GsonResponseProcessor<T> implements ResponseProcessor<T> {

    protected T response;
    protected TypeToken typeToken;

    public GsonResponseProcessor(Class<T> type) {
        this.typeToken = TypeToken.get(type);//depends on the API version

        //this.typeToken = new TypeToken<T>(type);
        //this.typeToken = TypeToken.of(type);
    }

    @Override
    public void parse(String jsonString) throws JSONException, IOException {
            response = GsonHelper.getGsonInstance().fromJson(jsonString, typeToken.getType());
    }

    public T getResponse() {
        return response;
    }
}
SME_Dev
  • 1,880
  • 13
  • 23
  • Note that this only work if the `type` parameter is a non-generic type. In gauravsapiens's example, with `List`, you can only get the class object of the raw `List` type without the type parameter. You have to use a type token to capture the type parameter. – Lii Oct 07 '14 at 11:20
  • I know this work. Have tried it already. Was curious why the approach I was using didn't work. Thanks ! – Gaurav Arora Oct 07 '14 at 13:32
0

Have you tried changing the signature to the correct type, too?

private ResponseProcessor<List<String>> getResponseProcessor() {
    return ResponseProcessorFactory.newResponseProcessor();
}
Smutje
  • 17,733
  • 4
  • 24
  • 41
  • Yes, it seems your actual usage does not reflect your problem as you nowhere cast to `ResponseProcessor>`. – Smutje Oct 07 '14 at 11:15