Skip to content

optimize TypeParameterResolver #3512

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

guanchengang
Copy link

optimize TypeParameterResolver

  1. The correct ownerType has been identified
  2. canonicalize type (In the original implementation, there would be a mix of JDK implementations such as sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl ...)
  3. optimized toString()
  4. when the specific generic is not declared, erase to the most appropriate upper bound
class A<T extends Serializable> {
  public T foo(T t) {
    return t;
  }
}

class B<T extends Number> extends A<T> {}

class C<T extends Integer> extends B<T> {}

Method m = A.class.getMethod("foo", Serializable.class);

// In old code, it's Object.class. Actually, Integer
System.out.println(TypeParameterResolver.resolveReturnType(m, C.class)); 

@harawata
Copy link
Member

Hello @guanchengang ,

T extends Integer is meaningless because Integer is final [1] [2].
And it is incorrect to expect Integer as the return type of C#foo() because "generic type invocation" is not performed at that point [3].

You will get Integer if you declare C with generic type invocation:

class C extends B<Integer> {}

[1] There should be a compiler warning: The type parameter T should not be bounded by the final type Integer. Final types cannot be further extended
[2] Explanation for why it is still compilable : https://stackoverflow.com/a/12475147/1261766
[3] https://docs.oracle.com/javase/tutorial/java/generics/types.html#instantiation

@guanchengang
Copy link
Author

I'm sorry I gave an inappropriate example @harawata.
I understand that classes modified with final cannot be extended. That is just an example. Nevertheless, I truly appreciate your help in looking up the information. I’m really grateful!
"generic type invocation" is not performed at this point,but we can still obtain the bounds information of generics
Let’s refocus on this issue:

class L0 {}
class L1 extends L0 {}

class A<AT extends L0> {
  public AT foo() {
    return null;
  }
}

class B0 extends A {
}

class B1<BT1 extends L0> extends A<BT1> {
}

class B2<BT2 extends L1> extends A<BT2> {
}

public static void main(String[] args) throws Exception {
  Method foo = A.class.getMethod("foo");
  System.out.println(TypeParameterResolver.resolveReturnType(foo, A.class)); // class com.example.Test$L0
  System.out.println(TypeParameterResolver.resolveReturnType(foo, B0.class)); // class com.example.Test$L0
  System.out.println(TypeParameterResolver.resolveReturnType(foo, B1.class)); // class java.lang.Object
  System.out.println(TypeParameterResolver.resolveReturnType(foo, B2.class)); // class java.lang.Object
}

Subclass loses more information after extending from A.
The bound of a subclass cannot exceed that of its parent class.
In the case of B1 and B2,the return type is parsed as Object.class. Obviously, their bounds cannot exceed L0, regardless of the specific type is declared or not.
IMHO, even if they are not erased as the most appropriate bound, they should not exceed L0.

@harawata
Copy link
Member

@guanchengang ,

Assuming you need this enhancement for some mappings in your MyBatis application (let me know if this is not the case), please create a small demo project that demonstrates the actual usage (including DB data, mapper, Java classes, etc.) and share it on your GitHub repo.

Here are some project templates and examples.
https://github.com/harawata/mybatis-issues

I couldn't think of a good example that benefit from this in the context of MyBatis mappings.

@guanchengang
Copy link
Author

@harawata
I just looked at the implementation of this class and felt that the return was slightly unreasonable, without encountering any actual problems.A more precise boundary should not bring more problems.
If you think this is unnecessary, I will roll back the implementation of this part. Can other optimization parts be considered for merging(ownerType, canonicalize type and toString)

@harawata
Copy link
Member

Thank you , @guanchengang !

I will look into it, but it might take a while as it's not an urgent matter.

@harawata
Copy link
Member

  1. canonicalize type (In the original implementation, there would be a mix of JDK implementations such as sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl ...)

Mixing ParameterizedType implementations should not be a problem.
What makes you think this is necessary? i.e. What is the problem?

@guanchengang
Copy link
Author

There may be some issues when comparing ParameterizedType with different implementations using equals (when they represent the same type, the implementations are different), although this situation will not occur now and we will not compare them (but we cannot guarantee in the future) Moreover, there are some differences in the behavior between our implementation and the standard implementation to some extent(although they are all minor). So I believe that still have some role to play.WDYT

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants