Generic type declaration for reflection

I asked a question about the differences between

public static <T> void work(Class<T> type, T instance); 

and

 public static <T, S extends T> void work(Class<T> type, S instance); 

I think I should explain what exactly I want to know. Perhaps updating the original question is not suitable for this time, so I am asking another question.

Let's say I want to make one reflected method to call those marshal methods that are defined in Marshaller , for example

 void marshal(Object element, ContentHandler handler) void marshal(Object element, File output) void marshal(Object element, Node node) 

etc.

One of the methods I'm working on is

 void marshal(Object jaxbElement, Class<?> targetType, Object target) 

Implementation is simple

  • Find method looks like marshal(Ljava/lang/Object;Ljava/lang/Class;)V using Object.class and targetType
  • call the method with element and target .

Thus, any unit testing code can be referenced as

 marshal(element, ContentHandler.class, handler); marshal(element, File.class, new File("text.xml")); 

In this case, how to define the marshal method? Is there a difference between

 <T> marshal(Object element, Class<T> targetType, T target); 

and

 <T, S extends T> marshal(Object element, Class<T> targetType, S target) 

?

Additional comments for answers

I think I need targetType for a quick and direct method that is looking for the correct method.

Without targetType I need to repeat all methods like

 for (Method method : Marshaller.class.getMethods()) { // check modifiers, name, return type, and so on. if (!method.getParameterTypes()[1].isAssignableFrom(target.getClass())) { } } 

Adding another version for this would be better, I think. :)

0
source share
3 answers

It is hard to understand why you want a class object, because if you have an instance of T , you can do this in a method:

 Class<T> targetType = target.getClass(); // class may be derived from the instance 

However, if you really need to go through the class, I think you want this:

 <T> void marshal(Object element, Class<? super T> targetType, T target) { } 

Using Class<? super T> Class<? super T> , you get the flexibility of passing a class that is a superclass of an instance without an additional parameter to the generic method.

+1
source

If you assign a class to T, you do not need to feed it in the arguments, so <T, S extends T> marshal(Object element, S target) should be enough. But since S extends T , S can be recognized as T

If you do not need only methods that are only in class S , you can omit it and write

 <T> marshal(Object element, T target) 

However, since you are creating a generic method, you probably won't need to declare S. This is for the following reason:

  • if the methods of S are different from T, there is no good way to define the methods of several different classes of S. If they do not have a common interface, but then you could also use a common interface like T

  • if the methods of S do not differ, there is no reason to specifically designate it as a common operand.

+1
source

What sets of arguments do not differ

<T> marshal(Object element, Class<T> targetType, T target);

and

<T, S extends T> marshal(Object element, Class<T> targetType, S target)

can take.

Therefore, if you are writing an API, you should prefer a simpler one that has fewer type parameters, i.e. without S .

+1
source

Source: https://habr.com/ru/post/1494256/


All Articles