No_Name
No_Name

Reputation: 65

Obtaining types through parameters on Java

Certainly I'm quite new in all this Java stuff, so I have a question, I'm trying to deserialize a response obtained on a WCF service, everything works fine, but, I'm trying to make a generic function to do this.

Basically what I do is

public List<msg> GetService(String method){
    List<msg> response = new ArrayList<msg>();

    Type msgType = new TypeToken<List<msg>>(){}.getType();

    //Obtaining result
    response = uJSON.fromJson(serviceResponse, msgType);
    //uJSON is an instance of Gson library, for deserializing it just needs
    //the service response and a Class<T> or Type to reflect the obtained message
}

What I'm trying to do is obtaining the Type "msg" generic, it means...

public <thing> void GetInstanceService(String method){
     List<thing> response = new ArrayList<thing>();

     Type rType2 = new TypeToken<List<thing>>(){}.getType(); //Got java.util.List<thing>

     //And when I'm trying to deserialize I just obtain a List of object 
     //[java.lang.Object@5c7a987e, java.lang.Object@74b1a7a0]

     type2 = uJSON.fromJson(new String(entity), rType2);
}

But I'm calling like this.

comm.<msgType>GetInstanceService("listTestType");

So, when I call "GetInstanceService", "thing" is "msgType" Type, for the List<thing> and also response shouldn't be List<msgType> instead of List <Object>?

Besides, when I'm trying to explicitly pass the type through a "Type" parameter, it just causes me compilation time error like this.

public void GetInstanceService(Type type){
    List<type> type2 = new ArrayList<type>();  //Compilation time error

    //Or
    msgType oType = new msgType();
    Class classType = oType.getClass();
    List<classType> type3;    //Compilation time error
}

So, if none of these attempts was effective, how could I set the type for deserialization?

Upvotes: 2

Views: 1577

Answers (2)

Saintali
Saintali

Reputation: 4571

Guava class TypeToken does not support that mode of usage. You are creating the type token with a type variable and there not enough information for it to reconstruct List<String> from List<T>. You should create an instance of TypeToken where you have all the required compile-time information.

The documentation says:

Note that it's critical that the actual type argument is carried by a subclass. The following code is wrong because it only captures the <T> type variable of the listType() method signature; while <String> is lost in erasure:

class Util {
  static <T> TypeToken<List<T>> listType() {
    return new TypeToken<List<T>>() {};
  }
}

TypeToken<List<String>> stringListType = Util.<String>listType();

But as said above, you can instantiate the TypeToken at call-site, where all type info are available, and then pass it as a parameter. Something like this:

public <thing> void GetInstanceService(String method, TypeToken<List<thing>> token){
     List<thing> response = new ArrayList<thing>();

     Type rType2 = token.getType();

     type2 = uJSON.fromJson(new String(entity), rType2);
}

comm.GetInstanceService("listTestType", new TypeToken<List<msgType>>() {});

Update

Paul Bellora notes that you can also accept a parameter TypeToken<thing> token, and construct a TypeToken<List<thing>> inside the method from that token:

public <thing> void GetInstanceService(String method, TypeToken<thing> token) {
     List<thing> response = new ArrayList<thing>();

     Type rType2 = new TypeToken<List<thing>>() {}
         .where(new TypeParameter<thing>() {}, token); // where() binds "thing" to token
         .getType();

     type2 = uJSON.fromJson(new String(entity), rType2);
}

comm.GetInstanceService("listTestType", new TypeToken<msgType>() {});

Upvotes: 3

Bohemian
Bohemian

Reputation: 425198

Due to something called type erasure, the class object you need is not available at runtime.

However, there is a standard work-around: pass a type token into your method, like this:

public <T> List<T> getService(String method, Class<T> c) {
    // the caller has passed in the class object
    List<T> list = new ArrayList<T>();
    // fill list
    return list;
}

Upvotes: 2

Related Questions