From 61177aed85432a7069afb8fbce11b722908e91ba Mon Sep 17 00:00:00 2001 From: Joe Grandja <10884212+jgrandja@users.noreply.github.com> Date: Wed, 11 Mar 2026 12:22:37 -0400 Subject: [PATCH] Remove NullAway SuppressWarnings in ClaimAccessor Issue gh-17820 --- .../security/oauth2/core/ClaimAccessor.java | 31 ++++++++++++------- .../oauth2/core/ClaimAccessorTests.java | 9 +++--- ...2TokenIntrospectionClaimAccessorTests.java | 5 ++- 3 files changed, 25 insertions(+), 20 deletions(-) diff --git a/oauth2/oauth2-core/src/main/java/org/springframework/security/oauth2/core/ClaimAccessor.java b/oauth2/oauth2-core/src/main/java/org/springframework/security/oauth2/core/ClaimAccessor.java index 84d451fb72..c22e584ff0 100644 --- a/oauth2/oauth2-core/src/main/java/org/springframework/security/oauth2/core/ClaimAccessor.java +++ b/oauth2/oauth2-core/src/main/java/org/springframework/security/oauth2/core/ClaimAccessor.java @@ -85,14 +85,15 @@ public interface ClaimAccessor { * @return the claim value or {@code null} if the claim does not exist * @throws IllegalArgumentException if the claim value cannot be converted to a * {@code Boolean} - * @throws NullPointerException if the claim value is {@code null} */ - @SuppressWarnings("NullAway") default @Nullable Boolean getClaimAsBoolean(String claim) { if (!hasClaim(claim)) { return null; } Object claimValue = getClaims().get(claim); + if (claimValue == null) { + return null; + } Boolean convertedValue = ClaimConversionService.getSharedInstance().convert(claimValue, Boolean.class); Assert.notNull(convertedValue, () -> "Unable to convert claim '" + claim + "' of type '" + claimValue.getClass() + "' to Boolean."); @@ -105,14 +106,15 @@ public interface ClaimAccessor { * @return the claim value or {@code null} if it does not exist * @throws IllegalArgumentException if the claim value cannot be converted to an * {@code Instant} - * @throws NullPointerException if the claim value is {@code null} */ - @SuppressWarnings("NullAway") default @Nullable Instant getClaimAsInstant(String claim) { if (!hasClaim(claim)) { return null; } Object claimValue = getClaims().get(claim); + if (claimValue == null) { + return null; + } Instant convertedValue = ClaimConversionService.getSharedInstance().convert(claimValue, Instant.class); Assert.notNull(convertedValue, () -> "Unable to convert claim '" + claim + "' of type '" + claimValue.getClass() + "' to Instant."); @@ -125,14 +127,15 @@ public interface ClaimAccessor { * @return the claim value or {@code null} if it does not exist * @throws IllegalArgumentException if the claim value cannot be converted to a * {@code URL} - * @throws NullPointerException if the claim value is {@code null} */ - @SuppressWarnings("NullAway") default @Nullable URL getClaimAsURL(String claim) { if (!hasClaim(claim)) { return null; } Object claimValue = getClaims().get(claim); + if (claimValue == null) { + return null; + } URL convertedValue = ClaimConversionService.getSharedInstance().convert(claimValue, URL.class); Assert.notNull(convertedValue, () -> "Unable to convert claim '" + claim + "' of type '" + claimValue.getClass() + "' to URL."); @@ -146,17 +149,19 @@ public interface ClaimAccessor { * @return the claim value or {@code null} if the claim does not exist * @throws IllegalArgumentException if the claim value cannot be converted to a * {@code Map} - * @throws NullPointerException if the claim value is {@code null} */ - @SuppressWarnings({ "unchecked", "NullAway" }) + @SuppressWarnings("unchecked") default @Nullable Map getClaimAsMap(String claim) { if (!hasClaim(claim)) { return null; } + Object claimValue = getClaims().get(claim); + if (claimValue == null) { + return null; + } final TypeDescriptor sourceDescriptor = TypeDescriptor.valueOf(Object.class); final TypeDescriptor targetDescriptor = TypeDescriptor.map(Map.class, TypeDescriptor.valueOf(String.class), TypeDescriptor.valueOf(Object.class)); - Object claimValue = getClaims().get(claim); Map convertedValue = (Map) ClaimConversionService.getSharedInstance() .convert(claimValue, sourceDescriptor, targetDescriptor); Assert.notNull(convertedValue, @@ -171,17 +176,19 @@ public interface ClaimAccessor { * @return the claim value or {@code null} if the claim does not exist * @throws IllegalArgumentException if the claim value cannot be converted to a * {@code List} - * @throws NullPointerException if the claim value is {@code null} */ - @SuppressWarnings({ "unchecked", "NullAway" }) + @SuppressWarnings("unchecked") default @Nullable List getClaimAsStringList(String claim) { if (!hasClaim(claim)) { return null; } + Object claimValue = getClaims().get(claim); + if (claimValue == null) { + return null; + } final TypeDescriptor sourceDescriptor = TypeDescriptor.valueOf(Object.class); final TypeDescriptor targetDescriptor = TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(String.class)); - Object claimValue = getClaims().get(claim); List convertedValue = (List) ClaimConversionService.getSharedInstance() .convert(claimValue, sourceDescriptor, targetDescriptor); Assert.notNull(convertedValue, diff --git a/oauth2/oauth2-core/src/test/java/org/springframework/security/oauth2/core/ClaimAccessorTests.java b/oauth2/oauth2-core/src/test/java/org/springframework/security/oauth2/core/ClaimAccessorTests.java index 73aef4a0e8..45f7669627 100644 --- a/oauth2/oauth2-core/src/test/java/org/springframework/security/oauth2/core/ClaimAccessorTests.java +++ b/oauth2/oauth2-core/src/test/java/org/springframework/security/oauth2/core/ClaimAccessorTests.java @@ -29,7 +29,6 @@ import org.junit.jupiter.api.Test; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; -import static org.assertj.core.api.Assertions.assertThatNullPointerException; import static org.assertj.core.api.Assertions.assertThatObject; /** @@ -146,10 +145,10 @@ public class ClaimAccessorTests { } @Test - public void getClaimAsMapWhenValueIsNullThenThrowNullPointerException() { + public void getClaimAsMapWhenValueIsNullThenReturnNull() { String claimName = "map"; this.claims.put(claimName, null); - assertThatNullPointerException().isThrownBy(() -> this.claimAccessor.getClaimAsMap(claimName)); + assertThat(this.claimAccessor.getClaimAsMap(claimName)).isNull(); } @Test @@ -181,10 +180,10 @@ public class ClaimAccessorTests { } @Test - public void getClaimAsStringListWhenValueIsNullThenNullPointerException() { + public void getClaimAsStringListWhenValueIsNullThenReturnNull() { String claimName = "list"; this.claims.put(claimName, null); - assertThatNullPointerException().isThrownBy(() -> this.claimAccessor.getClaimAsStringList(claimName)); + assertThat(this.claimAccessor.getClaimAsStringList(claimName)).isNull(); } @Test diff --git a/oauth2/oauth2-core/src/test/java/org/springframework/security/oauth2/core/OAuth2TokenIntrospectionClaimAccessorTests.java b/oauth2/oauth2-core/src/test/java/org/springframework/security/oauth2/core/OAuth2TokenIntrospectionClaimAccessorTests.java index c24b8798bd..8e764eb449 100644 --- a/oauth2/oauth2-core/src/test/java/org/springframework/security/oauth2/core/OAuth2TokenIntrospectionClaimAccessorTests.java +++ b/oauth2/oauth2-core/src/test/java/org/springframework/security/oauth2/core/OAuth2TokenIntrospectionClaimAccessorTests.java @@ -28,7 +28,6 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatNullPointerException; /** * Tests for {@link OAuth2TokenIntrospectionClaimAccessor}. @@ -52,9 +51,9 @@ public class OAuth2TokenIntrospectionClaimAccessorTests { } @Test - public void isActiveWhenActiveClaimValueIsNullThenThrowsNullPointerException() { + public void isActiveWhenActiveClaimValueIsNullThenReturnFalse() { this.claims.put(OAuth2TokenIntrospectionClaimNames.ACTIVE, null); - assertThatNullPointerException().isThrownBy(this.claimAccessor::isActive); + assertThat(this.claimAccessor.isActive()).isFalse(); } @Test