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;
    }
10
  • Where and how do you call getResponseProcessor()?
    – Smutje
    Commented Oct 7, 2014 at 10:42
  • Are you not just missing the public class ResponseProcessorFactory<T> ? Commented Oct 7, 2014 at 10:43
  • Is this (observing the generic type during runtime) the problem you are looking for?
    – SME_Dev
    Commented Oct 7, 2014 at 10:44
  • @Smutje : I have added the actual usage. Please check. Commented Oct 7, 2014 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. Commented Oct 7, 2014 at 10:54

3 Answers 3

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>>() {});
1
  • Type erasure. Bang on ! This is the reason why my approach wasn't working. Thanks man ! Commented Oct 7, 2014 at 13:33
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;
    }
}
2
  • Note that this only work if the type parameter is a non-generic type. In gauravsapiens's example, with List<Dashboard>, 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
    Commented Oct 7, 2014 at 11:20
  • I know this work. Have tried it already. Was curious why the approach I was using didn't work. Thanks ! Commented Oct 7, 2014 at 13:32
0

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

private ResponseProcessor<List<String>> getResponseProcessor() {
    return ResponseProcessorFactory.newResponseProcessor();
}
1
  • Yes, it seems your actual usage does not reflect your problem as you nowhere cast to ResponseProcessor<List<String>>.
    – Smutje
    Commented Oct 7, 2014 at 11:15

Not the answer you're looking for? Browse other questions tagged or ask your own question.