diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json
index 4e78110ba..b0a13ef47 100644
--- a/.devcontainer/devcontainer.json
+++ b/.devcontainer/devcontainer.json
@@ -34,12 +34,7 @@
"forwardPorts": [4200, 8080],
// Use 'postCreateCommand' to run commands after the container is created.
- "postCreateCommand": "bash -c 'echo \"Installing dependencies...\" && cd frontend/blog-angular-ui && npm config set legacy-peer-deps true && npm install && npm install -g @angular/cli && echo \"Verifying installations...\" && ng version && java -version'",
-
- // Add mount for ~/.m2 to cache Maven dependencies
- "mounts": [
- "source=${localEnv:HOME}${localEnv:USERPROFILE}/.m2,target=/home/vscode/.m2,type=bind,consistency=cached"
- ],
+ "postCreateCommand": "bash -c 'echo \"Installing dependencies...\" && cd frontend/blog-angular-ui && npm install && npm install -g @angular/cli && echo \"Verifying installations...\" && ng version && java -version'",
// Configure tool-specific properties.
// "customizations": {},
diff --git a/poc-algorithms/pom.xml b/poc-algorithms/pom.xml
index d5ca93085..69585ebd8 100644
--- a/poc-algorithms/pom.xml
+++ b/poc-algorithms/pom.xml
@@ -6,7 +6,7 @@
org.springframework.boot
spring-boot-starter-parent
- 3.5.8
+ 4.0.0
diff --git a/poc-reactive-learning/pom.xml b/poc-reactive-learning/pom.xml
index 21ca1a983..47ef53635 100644
--- a/poc-reactive-learning/pom.xml
+++ b/poc-reactive-learning/pom.xml
@@ -6,7 +6,7 @@
org.springframework.boot
spring-boot-starter-parent
- 3.5.8
+ 4.0.0
diff --git a/poc-rest-api/pom.xml b/poc-rest-api/pom.xml
index 081df9545..7d8609885 100644
--- a/poc-rest-api/pom.xml
+++ b/poc-rest-api/pom.xml
@@ -1,6 +1,6 @@
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/maven-v4_0_0.xsd">
4.0.0
com.example.poc
@@ -8,7 +8,7 @@
pom
Spring Boot Rest Parent
0.4.0-SNAPSHOT
- http://maven.apache.org
+ https://maven.apache.org
spring-boot-rest-webmvc
diff --git a/poc-rest-api/spring-boot-rest-webflux/pom.xml b/poc-rest-api/spring-boot-rest-webflux/pom.xml
index 824fb8144..dd53effa5 100644
--- a/poc-rest-api/spring-boot-rest-webflux/pom.xml
+++ b/poc-rest-api/spring-boot-rest-webflux/pom.xml
@@ -7,7 +7,7 @@
org.springframework.boot
spring-boot-starter-parent
- 3.5.8
+ 4.0.0
@@ -37,12 +37,8 @@
spring-boot-starter-data-r2dbc
- org.liquibase
- liquibase-core
-
-
- org.springframework
- spring-jdbc
+ org.springframework.boot
+ spring-boot-starter-liquibase
org.postgresql
@@ -59,24 +55,19 @@
mapstruct
${org.mapstruct.version}
-
- org.projectlombok
- lombok
- true
-
org.springframework.boot
- spring-boot-starter-test
+ spring-boot-starter-webflux-test
test
org.springframework.boot
- spring-boot-testcontainers
+ spring-boot-starter-data-r2dbc-test
test
- io.projectreactor
- reactor-test
+ org.springframework.boot
+ spring-boot-testcontainers
test
@@ -86,17 +77,17 @@
org.testcontainers
- junit-jupiter
+ testcontainers-junit-jupiter
test
org.testcontainers
- postgresql
+ testcontainers-postgresql
test
org.testcontainers
- r2dbc
+ testcontainers-r2dbc
test
@@ -116,14 +107,6 @@
org.springframework.boot
spring-boot-maven-plugin
-
-
-
- org.projectlombok
- lombok
-
-
-
@@ -135,28 +118,15 @@
org.apache.maven.plugins
maven-compiler-plugin
-
- ${java.version}
- ${java.version}
+
org.mapstruct
mapstruct-processor
${org.mapstruct.version}
-
-
- org.projectlombok
- lombok
- ${lombok.version}
-
-
-
- org.projectlombok
- lombok-mapstruct-binding
- 0.2.0
-
+ ${java.version}
@@ -194,7 +164,7 @@
- 1.25.2
+ 1.28.0
diff --git a/poc-rest-api/spring-boot-rest-webflux/src/main/java/com/example/poc/reactive/config/SecurityConfig.java b/poc-rest-api/spring-boot-rest-webflux/src/main/java/com/example/poc/reactive/config/SecurityConfig.java
index 977156a63..46724c25c 100644
--- a/poc-rest-api/spring-boot-rest-webflux/src/main/java/com/example/poc/reactive/config/SecurityConfig.java
+++ b/poc-rest-api/spring-boot-rest-webflux/src/main/java/com/example/poc/reactive/config/SecurityConfig.java
@@ -1,27 +1,26 @@
/* Licensed under Apache-2.0 2021-2023 */
package com.example.poc.reactive.config;
-import lombok.extern.slf4j.Slf4j;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.config.web.server.ServerHttpSecurity;
-import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.MapReactiveUserDetailsService;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.server.SecurityWebFilterChain;
-import org.springframework.security.web.server.authorization.AuthorizationContext;
import org.springframework.security.web.server.context.NoOpServerSecurityContextRepository;
-import reactor.core.publisher.Mono;
-@Configuration
-@Slf4j
+@Configuration(proxyBeanMethods = false)
class SecurityConfig {
+ private static final Logger log = LoggerFactory.getLogger(SecurityConfig.class);
+
@Bean
SecurityWebFilterChain springWebFilterChain(ServerHttpSecurity http) {
var postPath = "/posts/**";
@@ -39,19 +38,22 @@ SecurityWebFilterChain springWebFilterChain(ServerHttpSecurity http) {
.pathMatchers(postPath)
.hasRole("USER")
.pathMatchers("/users/{user}/**")
- .access(this::currentUserMatchesPath)
+ .access(
+ (authentication, context) ->
+ authentication
+ .map(
+ auth ->
+ context.getVariables()
+ .get("user")
+ .equals(
+ auth
+ .getName()))
+ .map(AuthorizationDecision::new))
.anyExchange()
.authenticated())
.build();
}
- private Mono currentUserMatchesPath(
- Mono authentication, AuthorizationContext context) {
- return authentication
- .map(a -> context.getVariables().get("user").equals(a.getName()))
- .map(AuthorizationDecision::new);
- }
-
@Bean
PasswordEncoder passwordEncoder() {
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
diff --git a/poc-rest-api/spring-boot-rest-webflux/src/main/java/com/example/poc/reactive/controller/PostClassicController.java b/poc-rest-api/spring-boot-rest-webflux/src/main/java/com/example/poc/reactive/controller/PostClassicController.java
index 3d7725f4e..81de79b6d 100644
--- a/poc-rest-api/spring-boot-rest-webflux/src/main/java/com/example/poc/reactive/controller/PostClassicController.java
+++ b/poc-rest-api/spring-boot-rest-webflux/src/main/java/com/example/poc/reactive/controller/PostClassicController.java
@@ -5,7 +5,6 @@
import com.example.poc.reactive.entity.ReactivePost;
import com.example.poc.reactive.service.PostService;
import java.net.URI;
-import lombok.RequiredArgsConstructor;
import org.reactivestreams.Publisher;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
@@ -20,11 +19,14 @@
@RestController
@RequestMapping("/posts")
-@RequiredArgsConstructor
public class PostClassicController {
private final PostService postService;
+ public PostClassicController(PostService postService) {
+ this.postService = postService;
+ }
+
@GetMapping
public Publisher all() {
return this.postService.findAllPosts();
diff --git a/poc-rest-api/spring-boot-rest-webflux/src/main/java/com/example/poc/reactive/entity/ReactivePost.java b/poc-rest-api/spring-boot-rest-webflux/src/main/java/com/example/poc/reactive/entity/ReactivePost.java
index c2ed0dc2c..260b28f83 100644
--- a/poc-rest-api/spring-boot-rest-webflux/src/main/java/com/example/poc/reactive/entity/ReactivePost.java
+++ b/poc-rest-api/spring-boot-rest-webflux/src/main/java/com/example/poc/reactive/entity/ReactivePost.java
@@ -2,11 +2,7 @@
package com.example.poc.reactive.entity;
import java.time.LocalDateTime;
-import lombok.AllArgsConstructor;
-import lombok.Builder;
-import lombok.Data;
-import lombok.NoArgsConstructor;
-import lombok.ToString;
+import java.util.Objects;
import org.springframework.data.annotation.CreatedBy;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.Id;
@@ -15,12 +11,7 @@
import org.springframework.data.relational.core.mapping.Column;
import org.springframework.data.relational.core.mapping.Table;
-@Data
-@Builder
-@NoArgsConstructor
-@AllArgsConstructor
@Table("reactive_posts")
-@ToString
public class ReactivePost {
@Id
@@ -53,4 +44,111 @@ public ReactivePost(String title, String content) {
this.title = title;
this.content = content;
}
+
+ public ReactivePost() {}
+
+ public ReactivePost(
+ Integer id,
+ String title,
+ String content,
+ LocalDateTime createdAt,
+ String createdBy,
+ LocalDateTime updatedAt,
+ String updatedBy) {
+ this.id = id;
+ this.title = title;
+ this.content = content;
+ this.createdAt = createdAt;
+ this.createdBy = createdBy;
+ this.updatedAt = updatedAt;
+ this.updatedBy = updatedBy;
+ }
+
+ public Integer getId() {
+ return id;
+ }
+
+ public ReactivePost setId(Integer id) {
+ this.id = id;
+ return this;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public ReactivePost setTitle(String title) {
+ this.title = title;
+ return this;
+ }
+
+ public String getContent() {
+ return content;
+ }
+
+ public ReactivePost setContent(String content) {
+ this.content = content;
+ return this;
+ }
+
+ public LocalDateTime getCreatedAt() {
+ return createdAt;
+ }
+
+ public ReactivePost setCreatedAt(LocalDateTime createdAt) {
+ this.createdAt = createdAt;
+ return this;
+ }
+
+ public String getCreatedBy() {
+ return createdBy;
+ }
+
+ public ReactivePost setCreatedBy(String createdBy) {
+ this.createdBy = createdBy;
+ return this;
+ }
+
+ public LocalDateTime getUpdatedAt() {
+ return updatedAt;
+ }
+
+ public ReactivePost setUpdatedAt(LocalDateTime updatedAt) {
+ this.updatedAt = updatedAt;
+ return this;
+ }
+
+ public String getUpdatedBy() {
+ return updatedBy;
+ }
+
+ public ReactivePost setUpdatedBy(String updatedBy) {
+ this.updatedBy = updatedBy;
+ return this;
+ }
+
+ @Override
+ public final boolean equals(Object o) {
+ if (!(o instanceof ReactivePost that)) return false;
+
+ return Objects.equals(getId(), that.getId())
+ && Objects.equals(getTitle(), that.getTitle())
+ && Objects.equals(getContent(), that.getContent())
+ && Objects.equals(getCreatedAt(), that.getCreatedAt())
+ && Objects.equals(getCreatedBy(), that.getCreatedBy())
+ && Objects.equals(getUpdatedAt(), that.getUpdatedAt())
+ && Objects.equals(getUpdatedBy(), that.getUpdatedBy());
+ }
+
+ @Override
+ public int hashCode() {
+ int result = Objects.hashCode(getId());
+ result = 31 * result + Objects.hashCode(getTitle());
+ result = 31 * result + Objects.hashCode(getContent());
+ result = 31 * result + Objects.hashCode(getCreatedAt());
+ result = 31 * result + Objects.hashCode(getCreatedBy());
+ result = 31 * result + Objects.hashCode(getUpdatedAt());
+ result = 31 * result + Objects.hashCode(getUpdatedBy());
+ return result;
+ }
}
diff --git a/poc-rest-api/spring-boot-rest-webflux/src/main/java/com/example/poc/reactive/exception/PostNotFoundException.java b/poc-rest-api/spring-boot-rest-webflux/src/main/java/com/example/poc/reactive/exception/PostNotFoundException.java
index 7a2f5f0e1..d141618aa 100644
--- a/poc-rest-api/spring-boot-rest-webflux/src/main/java/com/example/poc/reactive/exception/PostNotFoundException.java
+++ b/poc-rest-api/spring-boot-rest-webflux/src/main/java/com/example/poc/reactive/exception/PostNotFoundException.java
@@ -2,16 +2,20 @@
package com.example.poc.reactive.exception;
import java.io.Serial;
-import lombok.Getter;
public class PostNotFoundException extends Exception {
@Serial private static final long serialVersionUID = 1L;
- @Getter private final String message;
+ private final String message;
public PostNotFoundException(String exceptionMessage) {
super(exceptionMessage);
this.message = exceptionMessage;
}
+
+ @Override
+ public String getMessage() {
+ return message;
+ }
}
diff --git a/poc-rest-api/spring-boot-rest-webflux/src/main/java/com/example/poc/reactive/service/PostServiceImpl.java b/poc-rest-api/spring-boot-rest-webflux/src/main/java/com/example/poc/reactive/service/PostServiceImpl.java
index 46702cf50..ac90dacc9 100644
--- a/poc-rest-api/spring-boot-rest-webflux/src/main/java/com/example/poc/reactive/service/PostServiceImpl.java
+++ b/poc-rest-api/spring-boot-rest-webflux/src/main/java/com/example/poc/reactive/service/PostServiceImpl.java
@@ -7,8 +7,8 @@
import com.example.poc.reactive.exception.PostNotFoundException;
import com.example.poc.reactive.mapping.PostMapper;
import com.example.poc.reactive.repository.PostRepository;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
@@ -16,14 +16,22 @@
import reactor.core.publisher.Mono;
@Service
-@RequiredArgsConstructor
-@Slf4j
public class PostServiceImpl implements PostService {
+ private static final Logger log = LoggerFactory.getLogger(PostServiceImpl.class);
private final PostRepository postRepository;
private final ApplicationEventPublisher publisher;
private final PostMapper postMapper;
+ public PostServiceImpl(
+ PostRepository postRepository,
+ ApplicationEventPublisher publisher,
+ PostMapper postMapper) {
+ this.postRepository = postRepository;
+ this.publisher = publisher;
+ this.postMapper = postMapper;
+ }
+
@Override
public Flux findAllPosts() {
return this.postRepository.findAll();
diff --git a/poc-rest-api/spring-boot-rest-webflux/src/test/java/com/example/poc/reactive/common/AbstractIntegrationTest.java b/poc-rest-api/spring-boot-rest-webflux/src/test/java/com/example/poc/reactive/common/AbstractIntegrationTest.java
index da5899faa..88876ef13 100644
--- a/poc-rest-api/spring-boot-rest-webflux/src/test/java/com/example/poc/reactive/common/AbstractIntegrationTest.java
+++ b/poc-rest-api/spring-boot-rest-webflux/src/test/java/com/example/poc/reactive/common/AbstractIntegrationTest.java
@@ -3,8 +3,8 @@
import com.example.poc.reactive.TestApplication;
import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient;
import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.webtestclient.autoconfigure.AutoConfigureWebTestClient;
import org.springframework.test.web.reactive.server.WebTestClient;
@SpringBootTest(
diff --git a/poc-rest-api/spring-boot-rest-webflux/src/test/java/com/example/poc/reactive/common/TestContainersConfig.java b/poc-rest-api/spring-boot-rest-webflux/src/test/java/com/example/poc/reactive/common/TestContainersConfig.java
index f022eb67a..1905a2369 100644
--- a/poc-rest-api/spring-boot-rest-webflux/src/test/java/com/example/poc/reactive/common/TestContainersConfig.java
+++ b/poc-rest-api/spring-boot-rest-webflux/src/test/java/com/example/poc/reactive/common/TestContainersConfig.java
@@ -2,10 +2,10 @@
package com.example.poc.reactive.common;
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
-import org.testcontainers.containers.PostgreSQLContainer;
+import org.testcontainers.postgresql.PostgreSQLContainer;
public interface TestContainersConfig {
@ServiceConnection
- PostgreSQLContainer> postgreSQLContainer = new PostgreSQLContainer<>("postgres:18-alpine");
+ PostgreSQLContainer postgreSQLContainer = new PostgreSQLContainer("postgres:18-alpine");
}
diff --git a/poc-rest-api/spring-boot-rest-webflux/src/test/java/com/example/poc/reactive/controller/PostClassicControllerIT.java b/poc-rest-api/spring-boot-rest-webflux/src/test/java/com/example/poc/reactive/controller/PostClassicControllerIT.java
index 1d03a606c..479326ac6 100644
--- a/poc-rest-api/spring-boot-rest-webflux/src/test/java/com/example/poc/reactive/controller/PostClassicControllerIT.java
+++ b/poc-rest-api/spring-boot-rest-webflux/src/test/java/com/example/poc/reactive/controller/PostClassicControllerIT.java
@@ -26,18 +26,9 @@ void setUp() {
.deleteAll()
.thenMany(
Flux.just(
- ReactivePost.builder()
- .title("title 1")
- .content("content 1")
- .build(),
- ReactivePost.builder()
- .title("title 2")
- .content("content 2")
- .build(),
- ReactivePost.builder()
- .title("title 3")
- .content("content 3")
- .build()))
+ new ReactivePost("title 1", "content 1"),
+ new ReactivePost("title 2", "content 2"),
+ new ReactivePost("title 3", "content 3")))
.flatMap(reactivePostRepository::save)
.thenMany(reactivePostRepository.findAll());
}
diff --git a/poc-rest-api/spring-boot-rest-webflux/src/test/java/com/example/poc/reactive/controller/PostsControllerEndpointsTest.java b/poc-rest-api/spring-boot-rest-webflux/src/test/java/com/example/poc/reactive/controller/PostsControllerEndpointsTest.java
index f53286316..f9654f9c4 100644
--- a/poc-rest-api/spring-boot-rest-webflux/src/test/java/com/example/poc/reactive/controller/PostsControllerEndpointsTest.java
+++ b/poc-rest-api/spring-boot-rest-webflux/src/test/java/com/example/poc/reactive/controller/PostsControllerEndpointsTest.java
@@ -11,22 +11,20 @@
import java.util.UUID;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient;
-import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest;
-import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.boot.webflux.test.autoconfigure.WebFluxTest;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.test.context.support.WithMockUser;
+import org.springframework.test.context.bean.override.mockito.MockitoBean;
import org.springframework.test.web.reactive.server.WebTestClient;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@WebFluxTest(controllers = {PostClassicController.class})
-@AutoConfigureWebTestClient
@WithMockUser(username = "username")
class PostsControllerEndpointsTest {
- @MockBean private PostService postService;
+ @MockitoBean private PostService postService;
@Autowired private WebTestClient webTestClient;
@@ -36,8 +34,8 @@ void getAll() {
given(this.postService.findAllPosts())
.willReturn(
Flux.just(
- ReactivePost.builder().id(1).content("A").build(),
- ReactivePost.builder().id(2).content("B").build()));
+ new ReactivePost().setId(1).setContent("A"),
+ new ReactivePost().setId(2).setContent("B")));
this.webTestClient
.get()
@@ -62,7 +60,7 @@ void getAll() {
@Test
void save() {
String content = UUID.randomUUID().toString();
- ReactivePost data = ReactivePost.builder().id(123).content(content).build();
+ ReactivePost data = new ReactivePost().setId(123).setContent(content);
PostDto postDto = new PostDto("title", content);
given(this.postService.savePost(any(PostDto.class))).willReturn(Mono.just(data));
this.webTestClient
@@ -79,8 +77,8 @@ void save() {
@Test
@WithMockUser(roles = {"ADMIN"})
void delete() {
- ReactivePost data =
- ReactivePost.builder().id(123).content(UUID.randomUUID().toString()).build();
+ String content = UUID.randomUUID().toString();
+ ReactivePost data = new ReactivePost().setId(123).setContent(content);
given(this.postService.deletePostById(data.getId()))
.willReturn(Mono.just(ResponseEntity.accepted().build()));
this.webTestClient
@@ -113,7 +111,7 @@ void update() {
@Test
void getById() {
- ReactivePost data = ReactivePost.builder().id(1).content("A").build();
+ ReactivePost data = new ReactivePost().setId(1).setContent("A");
given(this.postService.findPostById(data.getId())).willReturn(Mono.just(data));
diff --git a/poc-rest-api/spring-boot-rest-webflux/src/test/java/com/example/poc/reactive/repository/ReactivePostRepositoryTest.java b/poc-rest-api/spring-boot-rest-webflux/src/test/java/com/example/poc/reactive/repository/ReactivePostRepositoryTest.java
index 4fa8505ae..52efd400d 100644
--- a/poc-rest-api/spring-boot-rest-webflux/src/test/java/com/example/poc/reactive/repository/ReactivePostRepositoryTest.java
+++ b/poc-rest-api/spring-boot-rest-webflux/src/test/java/com/example/poc/reactive/repository/ReactivePostRepositoryTest.java
@@ -9,16 +9,13 @@
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.autoconfigure.data.r2dbc.DataR2dbcTest;
+import org.springframework.boot.data.r2dbc.test.autoconfigure.DataR2dbcTest;
import org.springframework.boot.testcontainers.context.ImportTestcontainers;
import org.springframework.r2dbc.core.DatabaseClient;
import reactor.core.publisher.Hooks;
import reactor.test.StepVerifier;
-@DataR2dbcTest(
- properties = {
- "spring.test.database.replace=none",
- })
+@DataR2dbcTest
@ImportTestcontainers(TestContainersConfig.class)
class ReactivePostRepositoryTest {