• Addresses #24963

Comment From: quaff

@jhoeller Could you review it?

Comment From: quaff

Rebased to main, ready for review.

Comment From: quaff

Thanks for the PR @quaff - This looks promising as it fixes another issue that was reported against generics handling.

Unfortunately, the build is broken with those changes, see https://ge.spring.io/s/kktsevdqhmgqc/tests/overview?outcome=FAILED.

The failed tests should adapt changes on ResolvableType.java, I've updated the commit.

Comment From: snicoll

The failed tests should adapt changes on ResolvableType.java, I've updated the commit.

With those changes in place, you had to change some assertions that looks invalid to me now. For instance, event listening that accepts a String as input would be considered if the type is EntityWrapper<?>. Same for an event that accepts an EntityWrapper<?> would now accept a List<?>.

This may be something that wrong elsewhere that the fix reveals but changing the assertion isn't what I had in mind.

Given the impact this has so late, I've moved this one for 6.2. If you have time to review the above, that would be much appreciated.

Comment From: quaff

The failed tests should adapt changes on ResolvableType.java, I've updated the commit.

With those changes in place, you had to change some assertions that looks invalid to me now. For instance, event listening that accepts a String as input would be considered if the type is EntityWrapper<?>. Same for an event that accepts an EntityWrapper<?> would now accept a List<?>.

This may be something that wrong elsewhere that the fix reveals but changing the assertion isn't what I had in mind.

Given the impact this has so late, I've moved this one for 6.2. If you have time to review the above, that would be much appreciated.

I've fixed that, please review. @snicoll

Comment From: quaff

Any chance to bring this to 6.1? @jhoeller @snicoll

Comment From: snicoll

@quaff please refrain from ping like this. You've already ping me once and trust that we're doing our best to handle it in time if we can.

Comment From: snicoll

@quaff with https://github.com/spring-projects/spring-framework/issues/31690#issuecomment-1831867944 some code that we didn't intend to have has been reverted. If you have time to rebase, it would be much appreciated.

Comment From: quaff

@quaff with #31690 (comment) some code that we didn't intend to have has been reverted. If you have time to rebase, it would be much appreciated.

Done.

Comment From: kilink

We happened to be testing our apps on the latest Spring snapshot, and I believe this change has introduced an infinite recursion bug which causes a StackOverFlowError. When we start several of our Spring Boot apps, we end up with the following error:

Exception in thread "main" java.lang.StackOverflowError
    at org.springframework.util.ObjectUtils.nullSafeHashCode(ObjectUtils.java:451)
    at org.springframework.core.ResolvableType.calculateHashCode(ResolvableType.java:1012)
    at org.springframework.core.ResolvableType.hashCode(ResolvableType.java:1000)
    at org.springframework.util.ObjectUtils.nullSafeHashCode(ObjectUtils.java:451)
    at org.springframework.core.ResolvableType.calculateHashCode(ResolvableType.java:1012)
    at org.springframework.core.ResolvableType.hashCode(ResolvableType.java:1000)
    at org.springframework.util.ObjectUtils.nullSafeHashCode(ObjectUtils.java:451)

I narrowed it down to a specific ApplicationEvent which triggers it. The following will reproduce the problem:

AvailabilityChangeEvent<LivenessState> event = new AvailabilityChangeEvent<>(new Object(), LivenessState.CORRECT);
ResolvableType resolvableType = ResolvableType.forInstance(event);
resolvableType.hasUnresolvableGenerics();

AvailabilityChangeEvent and LivenessState are both classes from Spring Boot.

Comment From: kilink

Looks like it can be reproduced directly with just an Enum:

enum Foo { BAR }
ResolvableType.forType(Foo.class.getGenericSuperclass()).hasUnresolvableGenerics();
// or
ResolvableType.forClassWithGenerics(Enum.class, Foo.class).hasUnresolvableGenerics();

Comment From: kilink

Seems like it's self-bounding generics that are the problem, the following triggers the bug as well:

class Foo<T extends Foo<T>> {}
class Bar extends Foo<Bar> {}

ResolvableType.forInstance(new Bar()).hasUnresolvableGenerics();