Skip to content

GH-1786 - Fix NPE in FormattableType.of() - #1787

Open
arimu1 wants to merge 1 commit into
spring-projects:mainfrom
arimu1:GH-1786-formattabletype-npe
Open

GH-1786 - Fix NPE in FormattableType.of()#1787
arimu1 wants to merge 1 commit into
spring-projects:mainfrom
arimu1:GH-1786-formattabletype-npe

Conversation

@arimu1

@arimu1 arimu1 commented Aug 5, 2026

Copy link
Copy Markdown

Summary

Fixes #1786.

When observability renders an observed method whose parameter type involves an unbounded wildcard (for example Class<?> as used by AbstractHttpMessageConverter.canWrite/canRead, or List<?> / List<T>), ResolvableType.resolve() returns null. Feeding that into FormattableType.of(Class) NPE'd on type.getTypeName().

This is the same root cause as #1748 / #1713. Main already routes through FormattableType.of(ResolvableType), but that factory used type.toString() as a type name. That:

  1. Does not correctly treat a bare ? / unresolvable type variable as the wildcard token for all call paths.
  2. Embeds generic arguments in the string, so DefaultObservedModule.render then double-appended them (List<?><?>) and mangled nested generics during package abbreviation (Map<String, List<?>>j.u.M.l.S.u.List<?>>).

Fix

FormattableType.of(ResolvableType) now:

  • Asserts the argument is non-null
  • Uses resolve() and maps null to the existing ? wildcard instance
  • Formats only the resolved raw type so callers (e.g. DefaultObservedModule.render) can still compose generic arguments recursively

Also adds Assert.notNull on of(Class) for consistency with of(JavaClass).

Tests

  • FormattableTypeUnitTests — unbounded wildcard / type variable → ?; Class<?> regression (Null Pointer in FormattableType.of() #1786)
  • DefaultObservedModuleUnitTests — exact signatures for List<?>, List<T>, and Class<?>
./mvnw -pl spring-modulith-core,spring-modulith-observability/spring-modulith-observability-core -am \
  test -Dtest=FormattableTypeUnitTests,DefaultObservedModuleUnitTests \
  -Dsurefire.failIfNoSpecifiedTests=false
  • FormattableTypeUnitTests: 9/9
  • DefaultObservedModuleUnitTests: 4/4
  • Temurin 21

Documentation

  • Not needed (bug fix only)

…nresolvable generics.

Rely on ResolvableType.resolve() and map null (unbounded wildcards / type
variables) to "?", instead of feeding type.toString() into package
abbreviation. That path NPEd on of(Class) when callers used resolve(), and
also double-rendered generics as List<?><?> while mangling nested types.

Signed-off-by: arimu1 <19286898+arimu1@users.noreply.github.com>
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.

Null Pointer in FormattableType.of()

1 participant