From 957385ed009d35951ae065cff73695bc96888cee Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 18:35:17 +0000 Subject: [PATCH 1/3] feature: upgrade to Java 17 and Spring Boot 3.2.5 Co-Authored-By: Amit Manchella --- .github/workflows/gradle.yml | 4 +- README.md | 2 +- build.gradle | 39 ++++++------ gradle/wrapper/gradle-wrapper.properties | 2 +- src/main/java/io/spring/api/ArticleApi.java | 2 +- src/main/java/io/spring/api/ArticlesApi.java | 2 +- src/main/java/io/spring/api/CommentsApi.java | 4 +- .../java/io/spring/api/CurrentUserApi.java | 2 +- src/main/java/io/spring/api/UsersApi.java | 6 +- .../exception/CustomizeExceptionHandler.java | 8 +-- .../spring/api/security/JwtTokenFilter.java | 8 +-- .../api/security/WebSecurityConfig.java | 63 ++++++++++--------- .../article/ArticleCommandService.java | 2 +- .../article/DuplicatedArticleConstraint.java | 4 +- .../article/DuplicatedArticleValidator.java | 4 +- .../application/article/NewArticleParam.java | 2 +- .../user/DuplicatedEmailConstraint.java | 4 +- .../user/DuplicatedEmailValidator.java | 4 +- .../user/DuplicatedUsernameConstraint.java | 4 +- .../user/DuplicatedUsernameValidator.java | 4 +- .../application/user/RegisterParam.java | 4 +- .../application/user/UpdateUserParam.java | 2 +- .../spring/application/user/UserService.java | 8 +-- .../java/io/spring/graphql/UserMutation.java | 2 +- .../GraphQLCustomizeExceptionHandler.java | 15 +++-- 25 files changed, 103 insertions(+), 98 deletions(-) diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index fabe54421..0468aa6b5 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -17,11 +17,11 @@ jobs: steps: - uses: actions/checkout@v2 - - name: Set up JDK 11 + - name: Set up JDK 17 uses: actions/setup-java@v2 with: distribution: zulu - java-version: '11' + java-version: '17' - uses: actions/cache@v2 with: path: | diff --git a/README.md b/README.md index 09b7a08ee..f8ca4173b 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ It uses a ~~H2 in-memory database~~ sqlite database (for easy local test without # Getting started -You'll need Java 11 installed. +You'll need Java 17 installed. ./gradlew bootRun diff --git a/build.gradle b/build.gradle index da384dc69..1586fc502 100644 --- a/build.gradle +++ b/build.gradle @@ -1,20 +1,20 @@ plugins { - id 'org.springframework.boot' version '2.6.3' - id 'io.spring.dependency-management' version '1.0.11.RELEASE' + id 'org.springframework.boot' version '3.2.5' + id 'io.spring.dependency-management' version '1.1.4' id 'java' - id "com.netflix.dgs.codegen" version "5.0.6" - id "com.diffplug.spotless" version "6.2.1" + id "com.netflix.dgs.codegen" version "6.0.3" + id "com.diffplug.spotless" version "6.25.0" } version = '0.0.1-SNAPSHOT' -sourceCompatibility = '11' -targetCompatibility = '11' +sourceCompatibility = '17' +targetCompatibility = '17' spotless { java { target project.fileTree(project.rootDir) { include '**/*.java' - exclude 'build/generated/**/*.*', 'build/generated-examples/**/*.*' + exclude 'build/**', 'frontend/**' } googleJavaFormat() } @@ -35,25 +35,25 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-validation' implementation 'org.springframework.boot:spring-boot-starter-hateoas' implementation 'org.springframework.boot:spring-boot-starter-security' - implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:2.2.2' - implementation 'com.netflix.graphql.dgs:graphql-dgs-spring-boot-starter:4.9.21' + implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:3.0.3' + implementation 'com.netflix.graphql.dgs:graphql-dgs-spring-boot-starter:8.5.8' implementation 'org.flywaydb:flyway-core' - implementation 'io.jsonwebtoken:jjwt-api:0.11.2' - runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.11.2', - 'io.jsonwebtoken:jjwt-jackson:0.11.2' - implementation 'joda-time:joda-time:2.10.13' - implementation 'org.xerial:sqlite-jdbc:3.36.0.3' + implementation 'io.jsonwebtoken:jjwt-api:0.11.5' + runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.11.5', + 'io.jsonwebtoken:jjwt-jackson:0.11.5' + implementation 'joda-time:joda-time:2.12.7' + implementation 'org.xerial:sqlite-jdbc:3.45.3.0' compileOnly 'org.projectlombok:lombok' annotationProcessor 'org.projectlombok:lombok' - testImplementation 'io.rest-assured:rest-assured:4.5.1' - testImplementation 'io.rest-assured:json-path:4.5.1' - testImplementation 'io.rest-assured:xml-path:4.5.1' - testImplementation 'io.rest-assured:spring-mock-mvc:4.5.1' + testImplementation 'io.rest-assured:rest-assured:5.4.0' + testImplementation 'io.rest-assured:json-path:5.4.0' + testImplementation 'io.rest-assured:xml-path:5.4.0' + testImplementation 'io.rest-assured:spring-mock-mvc:5.4.0' testImplementation 'org.springframework.security:spring-security-test' testImplementation 'org.springframework.boot:spring-boot-starter-test' - testImplementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter-test:2.2.2' + testImplementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter-test:3.0.3' } tasks.named('test') { @@ -69,4 +69,5 @@ tasks.named('clean') { tasks.named('generateJava') { schemaPaths = ["${projectDir}/src/main/resources/schema"] // List of directories containing schema files packageName = 'io.spring.graphql' // The package name to use to generate sources + typeMapping = ["PageInfo": "graphql.relay.PageInfo"] } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 41dfb8790..48c0a02ca 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/src/main/java/io/spring/api/ArticleApi.java b/src/main/java/io/spring/api/ArticleApi.java index c80afa31d..74b8234c4 100644 --- a/src/main/java/io/spring/api/ArticleApi.java +++ b/src/main/java/io/spring/api/ArticleApi.java @@ -10,9 +10,9 @@ import io.spring.core.article.ArticleRepository; import io.spring.core.service.AuthorizationService; import io.spring.core.user.User; +import jakarta.validation.Valid; import java.util.HashMap; import java.util.Map; -import javax.validation.Valid; import lombok.AllArgsConstructor; import org.springframework.http.ResponseEntity; import org.springframework.security.core.annotation.AuthenticationPrincipal; diff --git a/src/main/java/io/spring/api/ArticlesApi.java b/src/main/java/io/spring/api/ArticlesApi.java index 50584bd6d..3f96607e9 100644 --- a/src/main/java/io/spring/api/ArticlesApi.java +++ b/src/main/java/io/spring/api/ArticlesApi.java @@ -6,8 +6,8 @@ import io.spring.application.article.NewArticleParam; import io.spring.core.article.Article; import io.spring.core.user.User; +import jakarta.validation.Valid; import java.util.HashMap; -import javax.validation.Valid; import lombok.AllArgsConstructor; import org.springframework.http.ResponseEntity; import org.springframework.security.core.annotation.AuthenticationPrincipal; diff --git a/src/main/java/io/spring/api/CommentsApi.java b/src/main/java/io/spring/api/CommentsApi.java index c5f7e77e9..ff37833ec 100644 --- a/src/main/java/io/spring/api/CommentsApi.java +++ b/src/main/java/io/spring/api/CommentsApi.java @@ -11,11 +11,11 @@ import io.spring.core.comment.CommentRepository; import io.spring.core.service.AuthorizationService; import io.spring.core.user.User; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotBlank; import java.util.HashMap; import java.util.List; import java.util.Map; -import javax.validation.Valid; -import javax.validation.constraints.NotBlank; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; diff --git a/src/main/java/io/spring/api/CurrentUserApi.java b/src/main/java/io/spring/api/CurrentUserApi.java index e096aec0b..a2ce43eb4 100644 --- a/src/main/java/io/spring/api/CurrentUserApi.java +++ b/src/main/java/io/spring/api/CurrentUserApi.java @@ -7,9 +7,9 @@ import io.spring.application.user.UpdateUserParam; import io.spring.application.user.UserService; import io.spring.core.user.User; +import jakarta.validation.Valid; import java.util.HashMap; import java.util.Map; -import javax.validation.Valid; import lombok.AllArgsConstructor; import org.springframework.http.ResponseEntity; import org.springframework.security.core.annotation.AuthenticationPrincipal; diff --git a/src/main/java/io/spring/api/UsersApi.java b/src/main/java/io/spring/api/UsersApi.java index d91321e82..71e39d4ab 100644 --- a/src/main/java/io/spring/api/UsersApi.java +++ b/src/main/java/io/spring/api/UsersApi.java @@ -12,12 +12,12 @@ import io.spring.core.service.JwtService; import io.spring.core.user.User; import io.spring.core.user.UserRepository; +import jakarta.validation.Valid; +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.NotBlank; import java.util.HashMap; import java.util.Map; import java.util.Optional; -import javax.validation.Valid; -import javax.validation.constraints.Email; -import javax.validation.constraints.NotBlank; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; diff --git a/src/main/java/io/spring/api/exception/CustomizeExceptionHandler.java b/src/main/java/io/spring/api/exception/CustomizeExceptionHandler.java index ade3ff4ff..3e7c5c908 100644 --- a/src/main/java/io/spring/api/exception/CustomizeExceptionHandler.java +++ b/src/main/java/io/spring/api/exception/CustomizeExceptionHandler.java @@ -2,15 +2,15 @@ import static org.springframework.http.HttpStatus.UNPROCESSABLE_ENTITY; +import jakarta.validation.ConstraintViolation; +import jakarta.validation.ConstraintViolationException; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.stream.Collectors; -import javax.validation.ConstraintViolation; -import javax.validation.ConstraintViolationException; import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpStatus; +import org.springframework.http.HttpStatusCode; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.MethodArgumentNotValidException; @@ -63,7 +63,7 @@ public ResponseEntity handleInvalidAuthentication( protected ResponseEntity handleMethodArgumentNotValid( MethodArgumentNotValidException e, HttpHeaders headers, - HttpStatus status, + HttpStatusCode status, WebRequest request) { List errorResources = e.getBindingResult().getFieldErrors().stream() diff --git a/src/main/java/io/spring/api/security/JwtTokenFilter.java b/src/main/java/io/spring/api/security/JwtTokenFilter.java index 1b5c50146..b03e9d143 100644 --- a/src/main/java/io/spring/api/security/JwtTokenFilter.java +++ b/src/main/java/io/spring/api/security/JwtTokenFilter.java @@ -2,13 +2,13 @@ import io.spring.core.service.JwtService; import io.spring.core.user.UserRepository; +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.Collections; import java.util.Optional; -import javax.servlet.FilterChain; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.context.SecurityContextHolder; diff --git a/src/main/java/io/spring/api/security/WebSecurityConfig.java b/src/main/java/io/spring/api/security/WebSecurityConfig.java index 3786959ef..765727978 100644 --- a/src/main/java/io/spring/api/security/WebSecurityConfig.java +++ b/src/main/java/io/spring/api/security/WebSecurityConfig.java @@ -1,6 +1,7 @@ package io.spring.api.security; import static java.util.Arrays.asList; +import static org.springframework.security.config.Customizer.withDefaults; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -8,10 +9,10 @@ import org.springframework.http.HttpStatus; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; -import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.HttpStatusEntryPoint; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.web.cors.CorsConfiguration; @@ -20,7 +21,7 @@ @Configuration @EnableWebSecurity -public class WebSecurityConfig extends WebSecurityConfigurerAdapter { +public class WebSecurityConfig { @Bean public JwtTokenFilter jwtTokenFilter() { @@ -32,36 +33,36 @@ public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } - @Override - protected void configure(HttpSecurity http) throws Exception { - - http.csrf() - .disable() - .cors() - .and() - .exceptionHandling() - .authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED)) - .and() - .sessionManagement() - .sessionCreationPolicy(SessionCreationPolicy.STATELESS) - .and() - .authorizeRequests() - .antMatchers(HttpMethod.OPTIONS) - .permitAll() - .antMatchers("/graphiql") - .permitAll() - .antMatchers("/graphql") - .permitAll() - .antMatchers(HttpMethod.GET, "/articles/feed") - .authenticated() - .antMatchers(HttpMethod.POST, "/users", "/users/login") - .permitAll() - .antMatchers(HttpMethod.GET, "/articles/**", "/profiles/**", "/tags") - .permitAll() - .anyRequest() - .authenticated(); + @Bean + public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { + http.csrf(csrf -> csrf.disable()) + .cors(withDefaults()) + .exceptionHandling( + exceptions -> + exceptions.authenticationEntryPoint( + new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED))) + .sessionManagement( + session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) + .authorizeHttpRequests( + requests -> + requests + .requestMatchers(HttpMethod.OPTIONS, "/**") + .permitAll() + .requestMatchers("/graphiql", "/graphiql/**") + .permitAll() + .requestMatchers("/graphql") + .permitAll() + .requestMatchers(HttpMethod.GET, "/articles/feed") + .authenticated() + .requestMatchers(HttpMethod.POST, "/users", "/users/login") + .permitAll() + .requestMatchers(HttpMethod.GET, "/articles/**", "/profiles/**", "/tags") + .permitAll() + .anyRequest() + .authenticated()) + .addFilterBefore(jwtTokenFilter(), UsernamePasswordAuthenticationFilter.class); - http.addFilterBefore(jwtTokenFilter(), UsernamePasswordAuthenticationFilter.class); + return http.build(); } @Bean diff --git a/src/main/java/io/spring/application/article/ArticleCommandService.java b/src/main/java/io/spring/application/article/ArticleCommandService.java index 861bc22b2..2d88441b7 100644 --- a/src/main/java/io/spring/application/article/ArticleCommandService.java +++ b/src/main/java/io/spring/application/article/ArticleCommandService.java @@ -3,7 +3,7 @@ import io.spring.core.article.Article; import io.spring.core.article.ArticleRepository; import io.spring.core.user.User; -import javax.validation.Valid; +import jakarta.validation.Valid; import lombok.AllArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; diff --git a/src/main/java/io/spring/application/article/DuplicatedArticleConstraint.java b/src/main/java/io/spring/application/article/DuplicatedArticleConstraint.java index 0eb1eda84..a18d47cac 100644 --- a/src/main/java/io/spring/application/article/DuplicatedArticleConstraint.java +++ b/src/main/java/io/spring/application/article/DuplicatedArticleConstraint.java @@ -1,12 +1,12 @@ package io.spring.application.article; +import jakarta.validation.Constraint; +import jakarta.validation.Payload; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -import javax.validation.Constraint; -import javax.validation.Payload; @Documented @Constraint(validatedBy = DuplicatedArticleValidator.class) diff --git a/src/main/java/io/spring/application/article/DuplicatedArticleValidator.java b/src/main/java/io/spring/application/article/DuplicatedArticleValidator.java index 0e3828e1e..e04853f26 100644 --- a/src/main/java/io/spring/application/article/DuplicatedArticleValidator.java +++ b/src/main/java/io/spring/application/article/DuplicatedArticleValidator.java @@ -2,8 +2,8 @@ import io.spring.application.ArticleQueryService; import io.spring.core.article.Article; -import javax.validation.ConstraintValidator; -import javax.validation.ConstraintValidatorContext; +import jakarta.validation.ConstraintValidator; +import jakarta.validation.ConstraintValidatorContext; import org.springframework.beans.factory.annotation.Autowired; class DuplicatedArticleValidator diff --git a/src/main/java/io/spring/application/article/NewArticleParam.java b/src/main/java/io/spring/application/article/NewArticleParam.java index 344d76c33..35586645d 100644 --- a/src/main/java/io/spring/application/article/NewArticleParam.java +++ b/src/main/java/io/spring/application/article/NewArticleParam.java @@ -1,8 +1,8 @@ package io.spring.application.article; import com.fasterxml.jackson.annotation.JsonRootName; +import jakarta.validation.constraints.NotBlank; import java.util.List; -import javax.validation.constraints.NotBlank; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; diff --git a/src/main/java/io/spring/application/user/DuplicatedEmailConstraint.java b/src/main/java/io/spring/application/user/DuplicatedEmailConstraint.java index e41eb009e..8e0f3d53f 100644 --- a/src/main/java/io/spring/application/user/DuplicatedEmailConstraint.java +++ b/src/main/java/io/spring/application/user/DuplicatedEmailConstraint.java @@ -1,9 +1,9 @@ package io.spring.application.user; +import jakarta.validation.Constraint; +import jakarta.validation.Payload; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; -import javax.validation.Constraint; -import javax.validation.Payload; @Constraint(validatedBy = DuplicatedEmailValidator.class) @Retention(RetentionPolicy.RUNTIME) diff --git a/src/main/java/io/spring/application/user/DuplicatedEmailValidator.java b/src/main/java/io/spring/application/user/DuplicatedEmailValidator.java index e30711465..f7543976e 100644 --- a/src/main/java/io/spring/application/user/DuplicatedEmailValidator.java +++ b/src/main/java/io/spring/application/user/DuplicatedEmailValidator.java @@ -1,8 +1,8 @@ package io.spring.application.user; import io.spring.core.user.UserRepository; -import javax.validation.ConstraintValidator; -import javax.validation.ConstraintValidatorContext; +import jakarta.validation.ConstraintValidator; +import jakarta.validation.ConstraintValidatorContext; import org.springframework.beans.factory.annotation.Autowired; public class DuplicatedEmailValidator diff --git a/src/main/java/io/spring/application/user/DuplicatedUsernameConstraint.java b/src/main/java/io/spring/application/user/DuplicatedUsernameConstraint.java index 4f365b789..0e5498804 100644 --- a/src/main/java/io/spring/application/user/DuplicatedUsernameConstraint.java +++ b/src/main/java/io/spring/application/user/DuplicatedUsernameConstraint.java @@ -1,9 +1,9 @@ package io.spring.application.user; +import jakarta.validation.Constraint; +import jakarta.validation.Payload; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; -import javax.validation.Constraint; -import javax.validation.Payload; @Constraint(validatedBy = DuplicatedUsernameValidator.class) @Retention(RetentionPolicy.RUNTIME) diff --git a/src/main/java/io/spring/application/user/DuplicatedUsernameValidator.java b/src/main/java/io/spring/application/user/DuplicatedUsernameValidator.java index ae1fd21aa..4b803bf85 100644 --- a/src/main/java/io/spring/application/user/DuplicatedUsernameValidator.java +++ b/src/main/java/io/spring/application/user/DuplicatedUsernameValidator.java @@ -1,8 +1,8 @@ package io.spring.application.user; import io.spring.core.user.UserRepository; -import javax.validation.ConstraintValidator; -import javax.validation.ConstraintValidatorContext; +import jakarta.validation.ConstraintValidator; +import jakarta.validation.ConstraintValidatorContext; import org.springframework.beans.factory.annotation.Autowired; class DuplicatedUsernameValidator diff --git a/src/main/java/io/spring/application/user/RegisterParam.java b/src/main/java/io/spring/application/user/RegisterParam.java index 3ba1234d3..d629268c6 100644 --- a/src/main/java/io/spring/application/user/RegisterParam.java +++ b/src/main/java/io/spring/application/user/RegisterParam.java @@ -1,8 +1,8 @@ package io.spring.application.user; import com.fasterxml.jackson.annotation.JsonRootName; -import javax.validation.constraints.Email; -import javax.validation.constraints.NotBlank; +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.NotBlank; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; diff --git a/src/main/java/io/spring/application/user/UpdateUserParam.java b/src/main/java/io/spring/application/user/UpdateUserParam.java index 54cd77471..f0263a0bf 100644 --- a/src/main/java/io/spring/application/user/UpdateUserParam.java +++ b/src/main/java/io/spring/application/user/UpdateUserParam.java @@ -1,7 +1,7 @@ package io.spring.application.user; import com.fasterxml.jackson.annotation.JsonRootName; -import javax.validation.constraints.Email; +import jakarta.validation.constraints.Email; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; diff --git a/src/main/java/io/spring/application/user/UserService.java b/src/main/java/io/spring/application/user/UserService.java index 48c6735b8..7772b32aa 100644 --- a/src/main/java/io/spring/application/user/UserService.java +++ b/src/main/java/io/spring/application/user/UserService.java @@ -2,12 +2,12 @@ import io.spring.core.user.User; import io.spring.core.user.UserRepository; +import jakarta.validation.Constraint; +import jakarta.validation.ConstraintValidator; +import jakarta.validation.ConstraintValidatorContext; +import jakarta.validation.Valid; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; -import javax.validation.Constraint; -import javax.validation.ConstraintValidator; -import javax.validation.ConstraintValidatorContext; -import javax.validation.Valid; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.security.crypto.password.PasswordEncoder; diff --git a/src/main/java/io/spring/graphql/UserMutation.java b/src/main/java/io/spring/graphql/UserMutation.java index 581a5b7b5..216c50f9f 100644 --- a/src/main/java/io/spring/graphql/UserMutation.java +++ b/src/main/java/io/spring/graphql/UserMutation.java @@ -17,8 +17,8 @@ import io.spring.graphql.types.UpdateUserInput; import io.spring.graphql.types.UserPayload; import io.spring.graphql.types.UserResult; +import jakarta.validation.ConstraintViolationException; import java.util.Optional; -import javax.validation.ConstraintViolationException; import lombok.AllArgsConstructor; import org.springframework.security.authentication.AnonymousAuthenticationToken; import org.springframework.security.core.Authentication; diff --git a/src/main/java/io/spring/graphql/exception/GraphQLCustomizeExceptionHandler.java b/src/main/java/io/spring/graphql/exception/GraphQLCustomizeExceptionHandler.java index bf4768b3b..a252a7261 100644 --- a/src/main/java/io/spring/graphql/exception/GraphQLCustomizeExceptionHandler.java +++ b/src/main/java/io/spring/graphql/exception/GraphQLCustomizeExceptionHandler.java @@ -11,14 +11,15 @@ import io.spring.api.exception.InvalidAuthenticationException; import io.spring.graphql.types.Error; import io.spring.graphql.types.ErrorItem; +import jakarta.validation.ConstraintViolation; +import jakarta.validation.ConstraintViolationException; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.concurrent.CompletableFuture; import java.util.stream.Collectors; -import javax.validation.ConstraintViolation; -import javax.validation.ConstraintViolationException; import org.springframework.stereotype.Component; @Component @@ -28,7 +29,7 @@ public class GraphQLCustomizeExceptionHandler implements DataFetcherExceptionHan new DefaultDataFetcherExceptionHandler(); @Override - public DataFetcherExceptionHandlerResult onException( + public CompletableFuture handleException( DataFetcherExceptionHandlerParameters handlerParameters) { if (handlerParameters.getException() instanceof InvalidAuthenticationException) { GraphQLError graphqlError = @@ -37,7 +38,8 @@ public DataFetcherExceptionHandlerResult onException( .message(handlerParameters.getException().getMessage()) .path(handlerParameters.getPath()) .build(); - return DataFetcherExceptionHandlerResult.newResult().error(graphqlError).build(); + return CompletableFuture.completedFuture( + DataFetcherExceptionHandlerResult.newResult().error(graphqlError).build()); } else if (handlerParameters.getException() instanceof ConstraintViolationException) { List errors = new ArrayList<>(); for (ConstraintViolation violation : @@ -61,9 +63,10 @@ public DataFetcherExceptionHandlerResult onException( .path(handlerParameters.getPath()) .extensions(errorsToMap(errors)) .build(); - return DataFetcherExceptionHandlerResult.newResult().error(graphqlError).build(); + return CompletableFuture.completedFuture( + DataFetcherExceptionHandlerResult.newResult().error(graphqlError).build()); } else { - return defaultHandler.onException(handlerParameters); + return defaultHandler.handleException(handlerParameters); } } From d23be51ee864ea1a4a7840f182d28f6d8274feb6 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 18:36:54 +0000 Subject: [PATCH 2/3] bug: update deprecated GitHub Actions versions to v4 Co-Authored-By: Amit Manchella --- .github/workflows/gradle.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index 0468aa6b5..1dbc33528 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -16,13 +16,13 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Set up JDK 17 - uses: actions/setup-java@v2 + uses: actions/setup-java@v4 with: distribution: zulu java-version: '17' - - uses: actions/cache@v2 + - uses: actions/cache@v4 with: path: | ~/.gradle/caches From 4a60c0d16d98362c6cb2f973216ad355f49c853b Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 18:42:32 +0000 Subject: [PATCH 3/3] bug: permit ERROR dispatch so 404s are not converted to 401 Co-Authored-By: Amit Manchella --- src/main/java/io/spring/api/security/WebSecurityConfig.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/io/spring/api/security/WebSecurityConfig.java b/src/main/java/io/spring/api/security/WebSecurityConfig.java index 765727978..40287507d 100644 --- a/src/main/java/io/spring/api/security/WebSecurityConfig.java +++ b/src/main/java/io/spring/api/security/WebSecurityConfig.java @@ -3,6 +3,7 @@ import static java.util.Arrays.asList; import static org.springframework.security.config.Customizer.withDefaults; +import jakarta.servlet.DispatcherType; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpMethod; @@ -46,6 +47,8 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { .authorizeHttpRequests( requests -> requests + .dispatcherTypeMatchers(DispatcherType.ERROR) + .permitAll() .requestMatchers(HttpMethod.OPTIONS, "/**") .permitAll() .requestMatchers("/graphiql", "/graphiql/**")