Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Guava TypeToken and generic classes

I'm using Guava TypeToken class in my project, but I'm getting an unexpected result.

I have MyGenericClass<T>:

public class MyGenericClass<T> implements MyInterface {

    private TypeToken<T> recordType;

    public MyGenericClass(String name) {
        this.recordType = new TypeToken<T>(getClass()) {};

        // ...
    }

    // ...

    @SuppressWarnings("unchecked")
    protected Class<T> getRecordType() {
        return (Class<T>) recordType.getRawType();
    }
}

So if I instantiate an object via new MyGenericClass<String>() and then invoke getRecordType() I expect to get java.lang.String, instead I'm getting java.lang.Object.

But, if I extend generic class:

public class MyStringImpl extends  MyGenericClass<String> {
    // ...
}

and instantiate this new class: new MyStringImpl() then I get the correct result.

Why is this happening? Is this the expected behaviour of TypeToken?

like image 870
davioooh Avatar asked Sep 30 '14 15:09

davioooh


1 Answers

To add some boring details to Ian's answer: It would be nice if TypeToken worked the way you expected, but this is impossible. When you declare

public class MyGenericClass<T> implements MyInterface {...}

the JVM sees something like

public class MyGenericClass<Object> implements MyInterface {...}

due to erasure.

But when you declare

public class MyStringImpl extends MyGenericClass<String> {...}

then in the definition of MyStringImpl the generics used are recorded and can be obtained via Class#getGenericSuperclass(). That's (a part of) the magic behind TypeToken.

like image 148
maaartinus Avatar answered Oct 09 '22 22:10

maaartinus