Skip to content

Update to Spring Boot 4.0 (fixes #416 review comments)#418

Open
asinbow wants to merge 10 commits intoLogNet:masterfrom
asinbow:spring-boot-4-upgrade
Open

Update to Spring Boot 4.0 (fixes #416 review comments)#418
asinbow wants to merge 10 commits intoLogNet:masterfrom
asinbow:spring-boot-4-upgrade

Conversation

@asinbow
Copy link
Copy Markdown

@asinbow asinbow commented Mar 26, 2026

Summary

This PR builds on #416 (Spring Boot 4.0 upgrade) and addresses the open review comments and build issues that prevented it from being merged.

Changes on top of #416

  • Fix AOP starter dependency (grpc-spring-boot-starter-demo/build.gradle): Replace spring-boot-starter-aop:4.0.0-M2 (pinned milestone) with spring-boot-starter-aspectj per the Spring Boot 4.0 Migration Guide — addresses reviewer @tamassza's comment
  • Update Lombok 1.18.24 → 1.18.38: Required for Java 21 compatibility (JCTree$JCImport.qualid was removed in Java 21)
  • Update Kotlin 1.9.10 → 2.1.21: Spring Boot 4.0 ships Kotlin metadata 2.2.0 which is incompatible with Kotlin 1.9
  • Add spring-boot-validation dependency: Spring Boot 4 split the monolithic spring-boot-autoconfigure into smaller artifacts; ValidationAutoConfiguration moved to org.springframework.boot:spring-boot-validation and must be declared explicitly
  • Bump version 5.2.1-SNAPSHOT6.0.0-SNAPSHOT: Following the project's versioning convention, a Spring Boot major version upgrade warrants a major version bump

Spring Security Migration: legacy access-control → AuthorizationManager

The biggest change in this PR is the removal of Spring Security's legacy access-control
infrastructure (AccessDecisionVoter / AccessDecisionManager / ConfigAttribute) which
was removed in Spring Security 7 (shipped with Spring Boot 4).

What was removed and why

Old API (Spring Security ≤ 6) Replacement (Spring Security 7)
AccessDecisionVoter<T> AuthorizationManager<T>
AffirmativeBased (access decision manager) AuthorizationManagers.anyOf(...)
RoleVoter / ScopeVoter AuthorityAuthorizationManager.hasAnyAuthority(...)
AuthenticatedAttributeVoter AuthenticatedAuthorizationManager.authenticated()
PreInvocationAuthorizationAdviceVoter PreAuthorizeAuthorizationManager
ExpressionBasedPostInvocationAdvice + AfterInvocationManager PostAuthorizeAuthorizationManager
DelegatingMethodSecurityMetadataSource + PrePostAnnotationSecurityMetadataSource Pass expression handler directly to PreAuthorize/PostAuthorize managers

Behavioral equivalence

The old AffirmativeBased with allowIfAllAbstainDecisions=true semantics are preserved:

  • Grant if any manager grantsAuthorizationManagers.anyOf(new AuthorizationDecision(true), metaManager, preAuthWrapper) where the leading AuthorizationDecision(true) acts as the "all-abstain → grant" fallback.
  • @PreAuthorize argument-null guard — the old PreInvocationAuthorizationAdviceVoter returned ACCESS_ABSTAIN when method.getArguments() == null. The new code wraps PreAuthorizeAuthorizationManager in a lambda that returns null (abstain) when arguments are null, achieving the same early-exit behavior before message arguments arrive.
  • @Secured handling — still processed at startup by GrpcServiceAuthorizationConfigurer.processSecuredAnnotation() and stored in GrpcSecurityMetadataSource; no separate SecuredAuthorizationManager needed at runtime.

AuthenticatedAttributeVoter / AuthenticatedConfigAttribute

These two classes are now empty @Deprecated stubs retained for binary compatibility only. Their logic is replaced by AuthenticatedAuthorizationManager.authenticated() inside GrpcServiceAuthorizationConfigurer.Registry.mapAuthenticated().

GrpcSecurity.getOrApply()with()

Spring Security 7 replaced apply() + manual setBuilder() with a cleaner with() method
that calls setBuilder() internally. All callers updated accordingly.

Test plan

  • ./gradlew :grpc-spring-boot-starter:compileJava — passes
  • ./gradlew :grpc-spring-boot-starter:test — passes
  • ./gradlew :grpc-spring-boot-starter-demo:test — 115 tests pass, 0 failures

🤖 Generated with Claude Code

adjabaev and others added 4 commits December 9, 2025 18:54
- Replace spring-boot-starter-aop:4.0.0-M2 with spring-boot-starter-aspectj
  per Spring Boot 4.0 Migration Guide (addresses reviewer comment)
- Update Lombok from 1.18.24 to 1.18.38 for Java 21 compatibility
- Update Kotlin from 1.9.10 to 2.1.21 for Spring Boot 4.0 compatibility
- Add spring-boot-validation as compileOnly/testImplementation dependency
  since Spring Boot 4 split auto-configuration into separate artifacts and
  ValidationAutoConfiguration moved to org.springframework.boot:spring-boot-validation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix GRpcServerRunner.stop() to reset healthStatusManager to prevent
  "Only 1 single ManagedHealthStatusService" error on context restart
  (Spring Framework 7 restart() now calls stop()+start() on lifecycle beans)

- Move ConfigServerTestApplication to isolated configserver package to
  prevent component scan from picking up @GRpcService beans in the
  config server context; add @ConditionalOnBean(GRpcServicesRegistry.class)
  guards to GRpcActuateAutoConfiguration inner classes

- Replace jsonpath+Gson JSON parsing with Jackson 3.x (tools.jackson.databind)
  in ActuatorTest; fix Jackson 3.x API changes (fieldNames→propertyNames,
  elements→valueStream)

- Update application-disable-security.yml with Spring Boot 4 class names;
  add ServletWebSecurityAutoConfiguration and SecurityFilterAutoConfiguration
  exclusions to fix 401 Unauthorized on /actuator endpoints

- Spring Security 7 compatibility fixes: GrpcSecurity, SecurityInterceptor,
  GrpcServiceAuthorizationConfigurer, GrpcSecurityConfigurerAdapter and
  related security classes updated for Spring Security 7 API changes

- Add BearerTokenSecurityAutoConfiguration, Keycloak test support,
  and various Spring Boot 4 / Spring Framework 7 API migration fixes

- Fix GrpcSecurityConfiguration to import UserDetailsServiceAutoConfiguration
  from org.springframework.boot.security.autoconfigure (Spring Boot 4 location);
  add spring-boot-security as implementation dependency in demo so the class
  is available at runtime for bootRun

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@asinbow asinbow force-pushed the spring-boot-4-upgrade branch from f960372 to 7d41ddd Compare March 27, 2026 00:29
Copy link
Copy Markdown
Author

@asinbow asinbow left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey Claude, please review the comments and try simplify the pr:

  1. use better practice
  2. be consistent in code logic
  3. clean up unnecessary comments.

- ActuatorTest: replace Jackson tree-walking with JsonPath for cleaner assertions
- JwtAuthBaseTest: fix indentation to 4-space tabs per project convention
- RouteGuideDemo: use @slf4j Lombok annotation instead of manual Logger field
- ConfigServerEnvironmentBaseTest: fix OAuth2ResourceServerAutoConfiguration class name to
  correct Spring Boot 4 package
- BearerTokenSecurityAutoConfiguration: use OAuth2Error.class literal instead of string
  for @ConditionalOnClass
- GrpcSecurity: use with() instead of apply()+setBuilder() per Spring Security 7 API
- GrpcSecurityConfigurerAdapter: same with() migration

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
asinbow and others added 4 commits March 27, 2026 11:05
- Restore DocumentContext/TypeRef-based assertions for actuatorGrpcTest
  and actuatorHealthTest, matching the original test structure
- Use GsonJsonProvider/GsonMappingProvider (available in Spring Boot 4)
  instead of JacksonJsonProvider (com.fasterxml removed in Jackson 3.x)
- Restore ObjectNode + valueStream() assertion in afterGreeting for
  metrics check (valueStream() replaces elements() from Jackson 3.x)
- Keep @LocalServerPort + RestTemplate (TestRestTemplate removed in SB4)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…resttestclient

TestRestTemplate was removed from spring-boot-test in Spring Boot 4.
Replace @LocalServerPort + new RestTemplate() with @AutoConfigureTestRestTemplate
and @Autowired TestRestTemplate from the new org.springframework.boot:spring-boot-resttestclient
module. Relative paths are used directly since the base URL is pre-configured.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Use inline Configuration.builder() per test method, original variable names,
and elements().stream() as the Jackson 3 equivalent of the original
StreamSupport.stream(Spliterators.spliteratorUnknownSize(elements(), ...)) pattern.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- ActuatorTest: revert to JacksonJsonProvider/JacksonMappingProvider per original
  (Jackson 2 remains on the transitive classpath alongside Jackson 3)
- AopServiceMonitor: replace manual Logger field with @slf4j annotation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.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.

2 participants