0

I am trying to find a generic type using Google's Guava TypeToken library. I am not able to find the actual calls to use with the correct parameters to extract the type I want.

public class BaseEntity { }
public class BaseResource { }
public class EntityService<E extends BaseEntity, R extends BaseResource> { }

public class TestEntity extends BaseEntity { }
public class TestResource extends BaseResource { }
public class TestEntityService extends EntityService<TestEntity, TestResource> { }

public class EntityRsqlPredicateBuilder<
  S extends EntityService<E, R>, 
  E extends BaseEntity, 
  R extends BaseResource> 
{
  EntityRsqlPredicateBuilder() {
    // I would like to get the the class type for E (i.e. TestEntity.class) 
    Class<E> entityClass = ???
  }
}

// in code, use EntityRsqlPredicateBuilder
EntityRsqlPredicateBuilder<TestEntityService> = new EntityRsqlPredicateBuilder();

My backup strategy is just to pass the class into the EntityRsqlPredicateBuilder. However, this seems like code duplication when the type should already be known.

Appreciate any ideas on how to do this.

Ken Joyner
  • 921
  • 9
  • 14
  • Possible duplicate of [How to determine the class of a generic type?](http://stackoverflow.com/questions/182636/how-to-determine-the-class-of-a-generic-type) – MartinS Mar 05 '16 at 17:57
  • Yes, though I was hoping for a better answer using Guava TypeToken. I think the answer below by Louis provides an easier solution but has the same limitations (using an anonymous subclass) as the solutions listed in the link you provided. – Ken Joyner Mar 05 '16 at 19:31

1 Answers1

3

TypeToken cannot do what you're trying to do the way you're trying to do it -- nothing can. The way your code is currently written will unavoidably lose that information due to type erasure.

The TypeToken documentation does, however, show you how to do something that works that's close to what you're trying to do:

Capture a generic type with a (usually anonymous) subclass and resolve it against a context class that knows what the type parameters are. For example:

  abstract class IKnowMyType<T> {
     TypeToken<T> type = new TypeToken<T>(getClass()) {};
   }
   new IKnowMyType<String>() {}.type => String

So if you make EntityRsqlPredicateBuilder abstract, and then you create it using new EntityRsqlPredicateBuilder<TestEntityService, TestEntity, TestResource>() {}, that'd work.

Louis Wasserman
  • 191,574
  • 25
  • 345
  • 413
  • This does work. However, trying to decide whether the resulting interface is any better. On one hand, users would need to create an anonymous subclass and specify the parameters as you wrote or on the other hand, clients would need to pass the classes in constructor arguments (e.g. new EntityRsqlPredicateBuilder(TestEntityService.class, TestEntity.class, TestResource.class), assuming all three class types were needed to be known. – Ken Joyner Mar 05 '16 at 19:20