8

I have following class:

public class Publisher<T> { private static final Class[] SUPPORTED_CLASSES = new Class[]{T1.class, T2.class}; public Publisher() { if(Arrays.asList(SUPPORTED_CLASSES).contains(T)) { // error: expression expected! System.out.println("Class not supported!"); } } } 

How can I check if class parameter conforms to the implementation?
In the above example I cannot use class parameter T as a parameter.

9
  • Check this thread stackoverflow.com/questions/3403909/… Commented Oct 19, 2017 at 12:22
  • 3
    Why do you want this, if I may ask? Commented Oct 19, 2017 at 12:24
  • @MCEmperor I wanted to check if class is supported and log warning message if necessary Commented Oct 19, 2017 at 12:37
  • 1
    What you are trying to do is an abuse of generics. Generics are a compile time feature to ensure type safety, but you are trying to enforce at runtime something that cannot be verified at compile time. Why is it necessary to restrict the allowed type parameters? Commented Oct 19, 2017 at 12:38
  • 4
    Why are you not simply using a S that is only defined in T1 and T2, use an interface IPublisher, add it to both class and then Publish<T extends IPublisher> ... you can remove that list and this condition. You know that T will be an instance of IPublisher. Commented Oct 19, 2017 at 12:38

3 Answers 3

13

Why this doesn't work

You are trying to access a generic type at runtime, which does not work in this case, because of type erasure.

How to fix

The simplest way to fix this is to take a Class<T> in the constructor, which will give you the type at run time, you can then check if the List contains the value you have been given.

Example code

public Publisher(Class<T> clazz) { if(!SUPPORTED_CLASSES.contains(clazz)) { System.out.println("Class not supported!"); } } 

Possible issues

Your code does not currently support subtypes, which may cause issues, unless you are ok with this (you may work on Lists, but not necessarily ArrayLists), this does beak the LSP though.

Sign up to request clarification or add additional context in comments.

2 Comments

I'd say that an even more fundamental reason why the OP's code doesn't work is that type arguments such as T designate types, not objects. In particular, they are not the same as and do not represent objects of type java.lang.Class, such as the ones the OP's array contains. Types are not valid ordinary arguments.
LSP is only a problem if OP's class is supposed to be covariant in T. If it's contra- or invariant, this is an entirely legal (if weird and non-OOP) way of doing things.
6

Though some other answers are quite good, I would like to propose another workaround:

You could create an empty interface MyInterface, and have all the classes in your list implement this interface. Then, you can change your class declaration to:

public class Publisher<T extends S, MyInterface> 

which will achieve your purpose.

3 Comments

This is a better solution if you have control of all of the classes you need to support, but if you need to support classes you haven't written you may need to do it a different way.
@jrtapsell in the worst case, if you don't have to support too many class, using a bridge for each class you need (a simple wrapper in fact) implementing the interface
When your solution only works with classes which implement a specific interface, you don't need that list of compatible classes anymore and can just declare the class as public class Publisher<T extends MyInterface>
4

You'll need to pass the class into the constructor:

public Publisher(Class<T> clazz) { if(!SUPPORTED_CLASSES.contains(clazz)) { System.out.println("Class not supported!"); } } 

because T isn't available at runtime: exactly the same code will be executed for new Publisher<T1>() and new Publisher<T3>().

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.