Merge remote-tracking branch 'origin/PR-7005' into PR-7005

This commit is contained in:
parthiv39731
2023-10-11 14:08:42 +05:30
687 changed files with 10002 additions and 1156 deletions
+1
View File
@@ -104,6 +104,7 @@
<module>spring-boot-springdoc-2</module>
<module>spring-boot-documentation</module>
<module>spring-boot-3-url-matching</module>
<module>spring-boot-graalvm-docker</module>
</modules>
<dependencyManagement>
+65 -2
View File
@@ -41,6 +41,31 @@
<artifactId>mockserver-netty</artifactId>
<version>${mockserver.version}</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>${jupiter.version}</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>${jupiter.version}</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>${jupiter.version}</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>${jupiter.version}</version>
</dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-commons</artifactId>
<version>1.10.0</version>
</dependency>
<dependency>
<groupId>org.mock-server</groupId>
<artifactId>mockserver-client-java</artifactId>
@@ -183,12 +208,50 @@
<properties>
<java.version>19</java.version>
<mapstruct.version>1.5.2.Final</mapstruct.version>
<springdoc.version>2.0.0</springdoc.version>
<springdoc.version>2.2.0</springdoc.version>
<maven-surefire-plugin.version>3.0.0-M7</maven-surefire-plugin.version>
<start-class>com.baeldung.sample.TodoApplication</start-class>
<mockserver.version>5.14.0</mockserver.version>
<spring-boot.version>3.1.0</spring-boot.version>
<spring-boot.version>3.2.0-SNAPSHOT</spring-boot.version>
<lombok-mapstruct-binding.version>0.2.0</lombok-mapstruct-binding.version>
<jupiter.version>5.10.0</jupiter.version>
</properties>
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<releases>
<enabled>false</enabled>
</releases>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
<pluginRepository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<releases>
<enabled>false</enabled>
</releases>
</pluginRepository>
</pluginRepositories>
</project>
@@ -0,0 +1,44 @@
package com.baeldung.restclient;
import java.util.Objects;
public class Article {
Integer id;
String title;
public Article() {}
public Article(Integer id, String title) {
this.id = id;
this.title = title;
}
public Integer getId() {
return id;
}
public String getTitle() {
return title;
}
public void setId(Integer id) {
this.id = id;
}
public void setTitle(String title) {
this.title = title;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Article article = (Article) o;
return Objects.equals(id, article.id) && Objects.equals(title, article.title);
}
@Override
public int hashCode() {
return Objects.hash(id, title);
}
}
@@ -0,0 +1,54 @@
package com.baeldung.restclient;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
@RestController
@RequestMapping("/articles")
public class ArticleController {
Map<Integer, Article> database = new HashMap<>();
@GetMapping
public ResponseEntity<Collection<Article>> getArticles() {
Collection<Article> values = database.values();
if (values.isEmpty()) {
return ResponseEntity.noContent().build();
}
return ResponseEntity.ok(values);
}
@GetMapping("/{id}")
public ResponseEntity<Article> getArticle(@PathVariable("id") Integer id) {
Article article = database.get(id);
if (article == null) {
return ResponseEntity.notFound().build();
}
return ResponseEntity.ok(article);
}
@PostMapping
public void createArticle(@RequestBody Article article) {
database.put(article.getId(), article);
}
@PutMapping("/{id}")
public void updateArticle(@PathVariable("id") Integer id, @RequestBody Article article) {
assert Objects.equals(id, article.getId());
database.remove(id);
database.put(id, article);
}
@DeleteMapping("/{id}")
public void deleteArticle(@PathVariable Integer id) {
database.remove(id);
}
@DeleteMapping()
public void deleteArticles() {
database.clear();
}
}
@@ -0,0 +1,6 @@
package com.baeldung.restclient;
public class ArticleNotFoundException extends RuntimeException {
public ArticleNotFoundException() {
}
}
@@ -0,0 +1,6 @@
package com.baeldung.restclient;
public class InvalidArticleResponseException extends RuntimeException {
public InvalidArticleResponseException() {
}
}
@@ -0,0 +1,13 @@
package com.baeldung.restclient;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class RestClientApplication {
public static void main(String[] args) {
SpringApplication.run(RestClientApplication.class, args);
}
}
@@ -0,0 +1,166 @@
package com.baeldung.restclient;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.server.LocalServerPort;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestClient;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class RestClientIntegrationTest {
@LocalServerPort
private int port;
private String uriBase;
RestClient restClient = RestClient.create();
@Autowired
ObjectMapper objectMapper;
@BeforeEach
public void setup() {
uriBase = "http://localhost:" + port;
}
@AfterEach
public void teardown() {
restClient.delete()
.uri(uriBase + "/articles")
.retrieve()
.toBodilessEntity();
}
@Test
void shouldGetArticlesAndReturnString() {
String articlesAsString = restClient.get()
.uri(uriBase + "/articles")
.retrieve()
.body(String.class);
assertThat(articlesAsString).isEqualTo("");
}
@Test
void shouldPostAndGetArticles() {
Article article = new Article(1, "How to use RestClient");
restClient.post()
.uri(uriBase + "/articles")
.contentType(MediaType.APPLICATION_JSON)
.body(article)
.retrieve()
.toBodilessEntity();
List<Article> articles = restClient.get()
.uri(uriBase + "/articles")
.retrieve()
.body(new ParameterizedTypeReference<>() {});
assertThat(articles).isEqualTo(List.of(article));
}
@Test
void shouldPostAndGetArticlesWithExchange() {
assertThatThrownBy(this::getArticlesWithExchange).isInstanceOf(ArticleNotFoundException.class);
Article article = new Article(1, "How to use RestClient");
restClient.post()
.uri(uriBase + "/articles")
.contentType(MediaType.APPLICATION_JSON)
.body(article)
.retrieve()
.toBodilessEntity();
List<Article> articles = getArticlesWithExchange();
assertThat(articles).isEqualTo(List.of(article));
}
private List<Article> getArticlesWithExchange() {
return restClient.get()
.uri(uriBase + "/articles")
.exchange((request, response) -> {
if (response.getStatusCode().isSameCodeAs(HttpStatusCode.valueOf(204))) {
throw new ArticleNotFoundException();
} else if (response.getStatusCode().isSameCodeAs(HttpStatusCode.valueOf(200))) {
return objectMapper.readValue(response.getBody(), new TypeReference<>() {});
} else {
throw new InvalidArticleResponseException();
}
});
}
@Test
void shouldPostAndGetArticlesWithErrorHandling() {
assertThatThrownBy(() -> {
restClient.get()
.uri(uriBase + "/articles/1234")
.retrieve()
.onStatus(status -> status.value() == 404, (request, response) -> { throw new ArticleNotFoundException(); })
.body(new ParameterizedTypeReference<>() {});
}).isInstanceOf(ArticleNotFoundException.class);
}
@Test
void shouldPostAndPutAndGetArticles() {
Article article = new Article(1, "How to use RestClient");
restClient.post()
.uri(uriBase + "/articles")
.contentType(MediaType.APPLICATION_JSON)
.body(article)
.retrieve()
.toBodilessEntity();
Article articleChanged = new Article(1, "How to use RestClient even better");
restClient.put()
.uri(uriBase + "/articles/1")
.contentType(MediaType.APPLICATION_JSON)
.body(articleChanged)
.retrieve()
.toBodilessEntity();
List<Article> articles = restClient.get()
.uri(uriBase + "/articles")
.retrieve()
.body(new ParameterizedTypeReference<>() {});
assertThat(articles).isEqualTo(List.of(articleChanged));
}
@Test
void shouldPostAndDeleteArticles() {
Article article = new Article(1, "How to use RestClient");
restClient.post()
.uri(uriBase + "/articles")
.contentType(MediaType.APPLICATION_JSON)
.body(article)
.retrieve()
.toBodilessEntity();
restClient.delete()
.uri(uriBase + "/articles")
.retrieve()
.toBodilessEntity();
ResponseEntity<Void> entity = restClient.get()
.uri(uriBase + "/articles")
.accept(MediaType.APPLICATION_JSON)
.retrieve()
.toBodilessEntity();
assertThat(entity.getStatusCode()).isEqualTo(HttpStatusCode.valueOf(204));
}
}
@@ -9,9 +9,10 @@
<description>This is simple boot application for Spring boot actuator test</description>
<parent>
<groupId>com.baeldung.spring-boot-modules</groupId>
<artifactId>spring-boot-modules</artifactId>
<version>1.0.0-SNAPSHOT</version>
<groupId>com.baeldung</groupId>
<artifactId>parent-boot-3</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../../parent-boot-3</relativePath>
</parent>
<dependencies>
@@ -39,16 +40,6 @@
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
@@ -1,36 +1,56 @@
package com.baeldung.endpoints.enabling;
import org.springframework.boot.actuate.autoconfigure.security.servlet.EndpointRequest;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.Customizer;
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.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher;
import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Configuration
public class SecurityConfiguration {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
PasswordEncoder encoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
auth.inMemoryAuthentication()
.withUser("user")
.password(encoder.encode("password"))
.roles("USER")
.and()
.withUser("admin")
.password(encoder.encode("admin"))
.roles("USER", "ADMIN");
@Bean
MvcRequestMatcher.Builder mvc(HandlerMappingIntrospector introspector) {
return new MvcRequestMatcher.Builder(introspector);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.requestMatcher(EndpointRequest.toAnyEndpoint())
.authorizeRequests((requests) -> requests.anyRequest()
.hasRole("ADMIN"));
http.httpBasic();
@Bean
public SecurityFilterChain filterChain(HttpSecurity http, MvcRequestMatcher.Builder mvc) throws Exception {
http.httpBasic(Customizer.withDefaults());
http.securityMatcher(EndpointRequest.toAnyEndpoint());
http.authorizeHttpRequests(authz -> {
authz.requestMatchers(mvc.pattern("/actuator/**"))
.hasRole("ADMIN")
.anyRequest()
.authenticated();
});
return http.build();
}
@Bean
public InMemoryUserDetailsManager userDetailsService() {
UserDetails user = User.withDefaultPasswordEncoder()
.username("user")
.password("password")
.roles("USER")
.build();
UserDetails admin = User.withDefaultPasswordEncoder()
.username("admin")
.password("password")
.roles("USER", "ADMIN")
.build();
return new InMemoryUserDetailsManager(user, admin);
}
}
@@ -1,9 +1,9 @@
package com.baeldung.endpoints.info;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
@Entity
@Table(name = "users")
@@ -15,7 +15,7 @@ import org.springframework.context.annotation.ComponentScan;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.web.context.request.RequestContextListener;
import javax.servlet.ServletContext;
import jakarta.servlet.ServletContext;
@EnableScheduling
@ComponentScan("com.baeldung.metrics")
@@ -7,14 +7,14 @@ import org.springframework.stereotype.Component;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.FilterConfig;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
@Component
public class MetricFilter implements Filter {
@@ -13,20 +13,20 @@ import org.springframework.test.web.servlet.MockMvc;
@SpringBootTest
@AutoConfigureMockMvc
public class EndpointEnablingIntegrationTest {
class EndpointEnablingIntegrationTest {
@Autowired
private MockMvc mockMvc;
@Test
@WithMockUser(username = "user", password = "password", roles = "USER")
public void givenWrongAuthentication_whenCallingActuator_thenReturns401() throws Exception {
void givenWrongAuthentication_whenCallingActuator_thenReturns401() throws Exception {
mockMvc.perform(get("/actuator"))
.andExpect(status().isForbidden());
}
@Test
@WithMockUser(username = "admin", password = "admin", roles = "ADMIN")
public void givenProperAuthentication_whenCallingActuator_thenReturnsExpectedEndpoints() throws Exception {
void givenProperAuthentication_whenCallingActuator_thenReturnsExpectedEndpoints() throws Exception {
mockMvc.perform(get("/actuator"))
.andExpect(jsonPath("$._links").exists())
.andExpect(jsonPath("$._links.beans").exists())
@@ -10,9 +10,10 @@
<description>This is simple boot application demonstrating a custom auto-configuration</description>
<parent>
<groupId>com.baeldung.spring-boot-modules</groupId>
<artifactId>spring-boot-modules</artifactId>
<version>1.0.0-SNAPSHOT</version>
<groupId>com.baeldung</groupId>
<artifactId>parent-boot-3</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../../parent-boot-3</relativePath>
</parent>
<dependencies>
@@ -66,6 +67,13 @@
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>com.baeldung.autoconfiguration.example.AutoconfigurationApplication</mainClass>
</configuration>
</plugin>
</plugins>
</build>
@@ -3,10 +3,10 @@ package com.baeldung.autoconfiguration;
import java.util.Arrays;
import java.util.Properties;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigureOrder;
import org.springframework.boot.autoconfigure.condition.ConditionMessage;
import org.springframework.boot.autoconfigure.condition.ConditionMessage.Style;
@@ -20,7 +20,6 @@ import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.Ordered;
import org.springframework.core.env.Environment;
@@ -31,7 +30,9 @@ import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.util.ClassUtils;
@Configuration
import jakarta.persistence.EntityManagerFactory;
@AutoConfiguration
@ConditionalOnClass(DataSource.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@PropertySource("classpath:mysql.properties")
@@ -1,11 +1,13 @@
package com.baeldung.autoconfiguration.annotationprocessor;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
@Configuration
@ConfigurationProperties(prefix = "database")
public class DatabaseProperties {
@@ -1,7 +1,7 @@
package com.baeldung.autoconfiguration.example;
import javax.persistence.Entity;
import javax.persistence.Id;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
@Entity
public class MyUser {
@@ -1 +0,0 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.baeldung.autoconfiguration.MySQLAutoconfiguration
@@ -1,5 +1,5 @@
usemysql=local
mysql-hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
mysql-hibernate.dialect=org.hibernate.dialect.MySQLDialect
mysql-hibernate.show_sql=true
mysql-hibernate.hbm2ddl.auto=create-drop
@@ -9,9 +9,10 @@
<description>Demo project for Spring Boot</description>
<parent>
<groupId>com.baeldung.spring-boot-modules</groupId>
<artifactId>spring-boot-modules</artifactId>
<version>1.0.0-SNAPSHOT</version>
<groupId>com.baeldung</groupId>
<artifactId>parent-boot-3</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../../parent-boot-3</relativePath>
</parent>
<dependencies>
@@ -47,13 +48,12 @@
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<version>${rest-assured.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>${servlet.version}</version>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cloud-connectors</artifactId>
<version>${spring-boot-cloud-connectors.version}</version>
</dependency>
</dependencies>
@@ -332,6 +332,7 @@
<servlet.version>4.0.0</servlet.version>
<spring-cloud.version>Greenwich.RELEASE</spring-cloud.version>
<spring-cloud-gcp.version>1.0.0.RELEASE</spring-cloud-gcp.version>
<spring-boot-cloud-connectors.version>2.2.13.RELEASE</spring-boot-cloud-connectors.version>
</properties>
</project>
@@ -4,6 +4,7 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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.configurers.AbstractHttpConfigurer;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
@@ -12,12 +13,11 @@ public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest()
.permitAll()
.and()
.csrf()
.disable();
http.authorizeHttpRequests(expressionInterceptUrlRegistry ->
expressionInterceptUrlRegistry
.anyRequest()
.permitAll())
.csrf(AbstractHttpConfigurer::disable);
return http.build();
}
}
@@ -1,10 +1,10 @@
package com.baeldung.persistence.model;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
@Entity
public class Book {
@@ -93,8 +93,8 @@
<properties>
<swagger-core-jakarta.version>2.2.11</swagger-core-jakarta.version>
<springwolf-kafka.version>0.12.1</springwolf-kafka.version>
<springwolf-ui.version>0.8.0</springwolf-ui.version>
<springwolf-kafka.version>0.14.0</springwolf-kafka.version>
<springwolf-ui.version>0.14.0</springwolf-ui.version>
<testcontainers-kafka.version>1.18.3</testcontainers-kafka.version>
</properties>
@@ -18,7 +18,9 @@
"operationId": "incoming-topic_publish",
"description": "More details for the incoming topic",
"bindings": {
"kafka": { }
"kafka": {
"bindingVersion": "0.4.0"
}
},
"message": {
"schemaFormat": "application/vnd.oai.openapi+json;version=3.0.0",
@@ -32,7 +34,9 @@
"$ref": "#/components/schemas/SpringKafkaDefaultHeadersIncomingPayloadDto"
},
"bindings": {
"kafka": { }
"kafka": {
"bindingVersion": "0.4.0"
}
}
}
}
@@ -42,7 +46,9 @@
"operationId": "outgoing-topic_subscribe",
"description": "More details for the outgoing topic",
"bindings": {
"kafka": { }
"kafka": {
"bindingVersion": "0.4.0"
}
},
"message": {
"schemaFormat": "application/vnd.oai.openapi+json;version=3.0.0",
@@ -56,7 +62,9 @@
"$ref": "#/components/schemas/SpringKafkaDefaultHeadersOutgoingPayloadDto"
},
"bindings": {
"kafka": { }
"kafka": {
"bindingVersion": "0.4.0"
}
}
}
}
@@ -0,0 +1,3 @@
FROM ubuntu:jammy
COPY target/springboot-graalvm-docker /springboot-graalvm-docker
CMD ["/springboot-graalvm-docker"]
@@ -0,0 +1,2 @@
## Relevant Articles
- [Create a GraalVM Docker Image](https://www.baeldung.com/java-graalvm-docker-image)
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.baeldung</groupId>
<artifactId>parent-boot-3</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../../parent-boot-3</relativePath>
</parent>
<groupId>com.baeldung</groupId>
<artifactId>spring-boot-graalvm-docker</artifactId>
<version>1.0.0</version>
<name>spring-boot-graalvm-docker</name>
<description>Spring Boot GrralVM with Docker</description>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.graalvm.buildtools</groupId>
<artifactId>native-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
@@ -0,0 +1,24 @@
package com.baeldung.graalvmdockerimage;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@SpringBootApplication
public class GraalvmDockerImageApplication {
public static void main(String[] args) {
SpringApplication.run(GraalvmDockerImageApplication.class, args);
}
}
@RestController
class HelloController {
@GetMapping
public String hello() {
return "Hello GraalVM";
}
}
+2 -10
View File
@@ -27,7 +27,7 @@
</dependency>
<dependency>
<groupId>com.github.ulisesbocchio</groupId>
<artifactId>jasypt-spring-boot-starter</artifactId>
<artifactId>jasypt-spring-boot-starter</artifactId>
<version>${jasypt.version}</version>
</dependency>
<dependency>
@@ -46,15 +46,7 @@
</plugins>
</build>
<repositories>
<repository>
<id>spring-milestone</id>
<name>Spring Milestone</name>
<url>https://repo.spring.io/milestone</url>
</repository>
</repositories>
<properties>
<jasypt.version>2.0.0</jasypt.version>
<jasypt.version>3.0.5</jasypt.version>
</properties>
</project>
@@ -11,10 +11,9 @@
<description>This is a simple application demonstrating integration between Keycloak and Spring Boot.</description>
<parent>
<groupId>com.baeldung</groupId>
<artifactId>parent-boot-2</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../../parent-boot-2</relativePath>
<groupId>com.baeldung.spring-boot-modules</groupId>
<artifactId>spring-boot-modules</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<dependencies>
@@ -11,10 +11,9 @@
<description>This is a simple application demonstrating integration between Keycloak and Spring Boot.</description>
<parent>
<groupId>com.baeldung</groupId>
<artifactId>parent-boot-2</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../../parent-boot-2</relativePath>
<groupId>com.baeldung.spring-boot-modules</groupId>
<artifactId>spring-boot-modules</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<dependencies>
@@ -11,10 +11,9 @@
<description>This is a simple application demonstrating integration between Keycloak and Spring Boot.</description>
<parent>
<groupId>com.baeldung</groupId>
<artifactId>parent-boot-2</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../../parent-boot-2</relativePath>
<groupId>com.baeldung.spring-boot-modules</groupId>
<artifactId>spring-boot-modules</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<dependencies>
@@ -9,10 +9,9 @@
<description>Demo project for Spring Boot Logging with Log4J2</description>
<parent>
<groupId>com.baeldung</groupId>
<artifactId>parent-boot-2</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../../parent-boot-2</relativePath>
<groupId>com.baeldung.spring-boot-modules</groupId>
<artifactId>spring-boot-modules</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<dependencies>
@@ -9,9 +9,10 @@
<description>Module For Spring Boot MVC Web</description>
<parent>
<groupId>com.baeldung.spring-boot-modules</groupId>
<artifactId>spring-boot-modules</artifactId>
<version>1.0.0-SNAPSHOT</version>
<groupId>com.baeldung</groupId>
<artifactId>parent-boot-3</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../../parent-boot-3</relativePath>
</parent>
<dependencies>
@@ -4,10 +4,10 @@ import java.io.IOException;
import java.io.PrintWriter;
import java.util.Objects;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
public class HelloWorldServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
@@ -4,10 +4,10 @@ import java.io.IOException;
import java.io.PrintWriter;
import java.util.Objects;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
public class SpringHelloWorldServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
@@ -2,7 +2,7 @@ package com.baeldung.common.error;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import javax.servlet.Servlet;
import jakarta.servlet.Servlet;
public class SpringHelloServletRegistrationBean extends ServletRegistrationBean {
@@ -4,9 +4,9 @@ import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.context.support.XmlWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;
import jakarta.servlet.ServletContext;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRegistration;
public class WebAppInitializer implements WebApplicationInitializer {
@@ -1,9 +1,9 @@
package com.baeldung.servlets.servlets;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
@@ -1,10 +1,10 @@
package com.baeldung.servlets.servlets.javaee;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet(name = "AnnotationServlet", description = "Example Servlet Using Annotations", urlPatterns = { "/annotationservlet" })
@@ -1,9 +1,9 @@
package com.baeldung.servlets.servlets.javaee;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
@@ -1,6 +1,6 @@
package com.baeldung.utils;
import javax.annotation.security.RolesAllowed;
import jakarta.annotation.security.RolesAllowed;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@@ -1,6 +1,6 @@
package com.baeldung.utils.controller;
import javax.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
@@ -1,32 +1,34 @@
package com.baeldung.utils;
import com.baeldung.utils.controller.UtilsController;
import org.junit.Before;
import org.junit.Test;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.MockitoAnnotations;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import static org.mockito.MockitoAnnotations.openMocks;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
public class UtilsControllerIntegrationTest {
class UtilsControllerIntegrationTest {
@InjectMocks
private UtilsController utilsController;
private MockMvc mockMvc;
@Before
@BeforeEach
public void setup() {
MockitoAnnotations.initMocks(this);
openMocks(this);
this.mockMvc = MockMvcBuilders.standaloneSetup(utilsController).build();
}
@Test
public void givenParameter_setRequestParam_andSetSessionAttribute() throws Exception {
void givenParameter_setRequestParam_andSetSessionAttribute() throws Exception {
String param = "testparam";
this.mockMvc.perform(post("/setParam").param("param", param).sessionAttr("parameter", param)).andExpect(status().isOk());
}
@@ -10,10 +10,9 @@
<description>Module For Spring Boot Integration with BIRT</description>
<parent>
<groupId>com.baeldung</groupId>
<artifactId>parent-boot-2</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../../parent-boot-2</relativePath>
<groupId>com.baeldung.spring-boot-modules</groupId>
<artifactId>spring-boot-modules</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<dependencies>
@@ -11,7 +11,7 @@ This module contains articles about Spring Boot Security
- [Disable Security for a Profile in Spring Boot](https://www.baeldung.com/spring-security-disable-profile)
- [Spring @EnableWebSecurity vs. @EnableGlobalMethodSecurity](https://www.baeldung.com/spring-enablewebsecurity-vs-enableglobalmethodsecurity)
- [Spring Security Configuring Different URLs](https://www.baeldung.com/spring-security-configuring-urls)
- [Difference Between permitAll() and anonymous() in Spring Security](https://www.baeldung.com/spring-security-permitall-vs-anonymous)
### Spring Boot Security Auto-Configuration
@@ -0,0 +1,2 @@
## Relevant Articles
- [Securing Spring Boot 3 Applications With SSL Bundles](https://www.baeldung.com/spring-boot-security-ssl-bundles)
@@ -0,0 +1,56 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.baeldung</groupId>
<artifactId>parent-boot-3</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../../parent-boot-3</relativePath>
</parent>
<artifactId>springbootsslbundles</artifactId>
<name>spring-boot-ssl-bundles</name>
<packaging>jar</packaging>
<description>Module for showing usage of SSL Bundles</description>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents.client5</groupId>
<artifactId>httpclient5-fluent</artifactId>
<version>${apache.client5.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<properties>
<apache.client5.version>5.0.3</apache.client5.version>
</properties>
</project>
@@ -0,0 +1,19 @@
package com.baeldung.springbootsslbundles;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
import org.springframework.boot.ssl.SslBundles;
@SpringBootApplication
public class SSLBundlesApp {
public static void main(String[] args) {
SpringApplication.run(SSLBundlesApp.class, args);
}
@Bean
public RestTemplate restTemplate(RestTemplateBuilder restTemplateBuilder, SslBundles sslBundles) {
return restTemplateBuilder.setSslBundle(sslBundles.getBundle("secure-service")).build();
}
}
@@ -0,0 +1,38 @@
package com.baeldung.springbootsslbundles;
import org.apache.hc.client5.http.classic.HttpClient;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder;
import org.apache.hc.client5.http.io.HttpClientConnectionManager;
import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory;
import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactoryBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ssl.NoSuchSslBundleException;
import org.springframework.boot.ssl.SslBundle;
import org.springframework.boot.ssl.SslBundles;
import org.springframework.context.annotation.Bean;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import javax.net.ssl.SSLContext;
@Component
public class SecureRestTemplateConfig {
private final SSLContext sslContext;
@Autowired
public SecureRestTemplateConfig(SslBundles sslBundles) throws NoSuchSslBundleException {
SslBundle sslBundle = sslBundles.getBundle("secure-service");
this.sslContext = sslBundle.createSslContext();
}
@Bean
public RestTemplate secureRestTemplate() {
final SSLConnectionSocketFactory sslSocketFactory = SSLConnectionSocketFactoryBuilder.create().setSslContext(this.sslContext).build();
final HttpClientConnectionManager cm = PoolingHttpClientConnectionManagerBuilder.create().setSSLSocketFactory(sslSocketFactory).build();
HttpClient httpClient = HttpClients.custom().setConnectionManager(cm).evictExpiredConnections().build();
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient);
return new RestTemplate(factory);
}
}
@@ -0,0 +1,28 @@
package com.baeldung.springbootsslbundles;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
@Service
public class SecureServiceRestApi {
private final RestTemplate restTemplate;
@Autowired
public SecureServiceRestApi(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
public String fetchData(String dataId) {
ResponseEntity<String> response = restTemplate.exchange(
"https://secure-service.com/api/data/{id}",
HttpMethod.GET,
null,
String.class,
dataId
);
return response.getBody();
}
}
@@ -0,0 +1,11 @@
spring:
ssl:
bundle:
jks:
secure-service:
key:
alias: "secure-service"
keystore:
location: "classpath:keystore.p12"
password: "FooBar"
type: "PKCS12"
@@ -0,0 +1,31 @@
-----BEGIN CERTIFICATE-----
MIIFazCCA1OgAwIBAgIUCJcVMwyhLy/ln+ENMXbSWcsO0aswDQYJKoZIhvcNAQEL
BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM
GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yMzA5MDUxNjAyMzdaFw0yNDA5
MDQxNjAyMzdaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw
HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggIiMA0GCSqGSIb3DQEB
AQUAA4ICDwAwggIKAoICAQDMNn+ZmPfR4FUyG6PVGBB2rOAnIHqFqYMVyDUOtZja
9CxpgbQjHRwwWaUWcYzLPOsvN/tMC8BazAFHSI2KIeNKgjAesv9JTumqgFXdOmw8
KT7a9C1IQXnCMhlbp9J7c7CLvjAvZvZBghxFLc7xBZo9rWA67QMZoOhXvdMoKv4G
5v9qD1ZqIKlCxJQrdErVUKyZPztlIWNqzPy9BJzFlBea2ArfrASulqJuWGyO09+o
6ABNgUAicp/zfCOeKIe9cni0oZj6Buwk4eVdYESzVohBO52h95KtN17Y/Tw+U8W5
Szq9tit6Vkupbe8tih7Bkdnj22WeCLVwWdXCp1kJw2kFDJTiC3wQRa6P0OrVpPGx
Z5SmG9eSCz22alA+I521ZG85hmPDt3BleYRYlCtcW7GFT/7zLBEwlN93lY5Os1jj
PRS8o5eIg8UhTbU4QEaZRYcLzaFy0asfKfa4ZF3mH5whh/w07SEEBAKDfQPpiz3T
migd+r9qUnPWeoE8Hi7lA1KzUd4YeM2yNHqXoQiARjHkM4yrX6vVlfT+itVbrpqF
a5J7PjL26w+DsxvRt9Ad5gpOdDzuy5m2V6lphMDjeZoG4OXgBzQQ1YxK1r6wkI4U
ZwRNrb+BxmQebQHnXKEXI7jgS45uoFENwolIHm9Dou5VYGLI0z+/pDReugCcw2lO
/QIDAQABo1MwUTAdBgNVHQ4EFgQUlSkON/OM9HCXeaQ7VWQuiEwY2iAwHwYDVR0j
BBgwFoAUlSkON/OM9HCXeaQ7VWQuiEwY2iAwDwYDVR0TAQH/BAUwAwEB/zANBgkq
hkiG9w0BAQsFAAOCAgEAD+8sPSQR3+A4F9z704OOy1Mo6bvbnIuK9UdN7d4/zh+e
AoloyTFPLPZIldg9hXwCvrKjrfqS5YUKmXIp9tetX7ns13CeDFcqVwZfPnqjzdNN
ad255LEwMjIUm9hSNEV6AQBKW8E+a590SrUamEdkFm4fcUB1LaINwyJjls7C0VB2
JL50OloaUlv0IMnAPRVp0Adlt9xs69R2B8Q4i297FvHB1PI7VMLYqNnX2+tnvszO
HvWtIqm6foyReDLfC0n87cuEBV7/9304V5vgEj20TR19isd0LffJDD1ujDXvN8dS
uGOB1VLRxAPonr9Iqk358EJ1T22uEcMdKE+sMnCBjw2fYIYRfjhGN+m6U6sb4MrF
zFUI6qB7W7T/5iukiRb4pLQ0OGgKOwYxpZoxcB3Ldjo5x58uKNOTNJ5zEJ8HUofA
BNfty10D3m3DlSyYbf7m1UUM0jj2l83LBGQzhGGUZgCnCsMczLrj64Gvf2iLGmCF
gu5zrxL01dptBkvTsYJwYBA67BBS4FcgYNMGx3m1uPsVUUIguJxufXWYfbub74QV
a1SH1NjO8HR3DLDU+S92tyTKWOUzJ5qOegEsR2cutVRzDuVTsFy7kayuNv/uLRrG
3P2HnUo8PG/nmysReBk6CGycUiDTt55DoPYGoQ5l19xTlkIt7ulNg7yX5pwFMeE=
-----END CERTIFICATE-----
@@ -0,0 +1,54 @@
-----BEGIN ENCRYPTED PRIVATE KEY-----
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
7NNrMLXj3PGrZ2vzKDGSAU1LzLOUrJ4m
-----END ENCRYPTED PRIVATE KEY-----
@@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Spring SSL Bundler Demo Application</title>
</head>
<body>
<h1>Spring SSL Bundler Demo Application</h1>
<p>
This is a sample application that can be built as native executable.
</p>
</body>
</html>
@@ -0,0 +1,12 @@
package com.baeldung.springbootsslbundles;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class SpringContextTest {
@Test
void contextLoads() {
}
}
@@ -0,0 +1,6 @@
package com.baeldung.spytest;
public interface ExternalAlertService {
public boolean alert(Order order);
}
@@ -0,0 +1,18 @@
package com.baeldung.spytest;
import org.springframework.stereotype.Component;
@Component
public class NotificationService {
private ExternalAlertService externalAlertService;
public void notify(Order order) {
System.out.println(order);
}
public boolean raiseAlert(Order order) {
return externalAlertService.alert(order);
}
}
@@ -0,0 +1,49 @@
package com.baeldung.spytest;
import java.util.UUID;
public class Order {
private UUID id;
private String name;
private OrderType orderType;
private double orderQuantity;
private String address;
public Order(UUID id, String name, double orderQuantity, String address) {
this.id = id;
this.name = name;
this.orderQuantity = orderQuantity;
this.address = address;
}
public enum OrderType {
INDIVIDUAL, BULK;
}
public UUID getId() {
return id;
}
public void setId(UUID id) {
this.id = id;
}
public String getName() {
return name;
}
public double getOrderQuantity() {
return orderQuantity;
}
public String getAddress() {
return address;
}
}
@@ -0,0 +1,19 @@
package com.baeldung.spytest;
import java.util.HashMap;
import java.util.UUID;
import org.springframework.stereotype.Component;
@Component
public class OrderRepository {
public static final HashMap<UUID, Order> orders = new HashMap<>();
public Order save(Order order) {
UUID orderId = UUID.randomUUID();
order.setId(orderId);
orders.put(UUID.randomUUID(), order);
return order;
}
}
@@ -0,0 +1,25 @@
package com.baeldung.spytest;
import org.springframework.stereotype.Service;
@Service
public class OrderService {
public final OrderRepository orderRepository;
public final NotificationService notificationService;
public OrderService(OrderRepository orderRepository, NotificationService notificationService) {
this.orderRepository = orderRepository;
this.notificationService = notificationService;
}
public Order save(Order order) {
order = orderRepository.save(order);
notificationService.notify(order);
if (!notificationService.raiseAlert(order)) {
throw new RuntimeException("Alert not raised");
}
return order;
}
}
@@ -0,0 +1,13 @@
package com.baeldung.spytest;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpyTestApplication {
public static void main(String[] args) {
SpringApplication.run(SpyTestApplication.class, args);
}
}
@@ -0,0 +1,35 @@
package com.baeldung.spytest;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.verify;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.SpyBean;
@SpringBootTest
class OrderServiceIntegrationTest {
@Autowired
OrderRepository orderRepository;
@SpyBean
NotificationService notificationService;
@SpyBean
OrderService orderService;
@Test
void givenNotificationServiceIsUsingSpyBean_whenOrderServiceIsCalled_thenNotificationServiceSpyBeanShouldBeInvoked() {
Order orderInput = new Order(null, "Test", 1.0, "17 St Andrews Croft, Leeds ,LS17 7TP");
doReturn(true).when(notificationService)
.raiseAlert(any(Order.class));
Order order = orderService.save(orderInput);
Assertions.assertNotNull(order);
Assertions.assertNotNull(order.getId());
verify(notificationService).notify(any(Order.class));
}
}
@@ -0,0 +1,41 @@
package com.baeldung.spytest;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.verify;
import java.util.UUID;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Spy;
import org.springframework.test.context.junit.jupiter.SpringExtension;
@ExtendWith(SpringExtension.class)
class OrderServiceUnitTest {
@Spy
OrderRepository orderRepository;
@Spy
NotificationService notificationService;
@InjectMocks
OrderService orderService;
@Test
void givenNotificationServiceIsUsingSpy_whenOrderServiceIsCalled_thenNotificationServiceSpyShouldBeInvoked() {
UUID orderId = UUID.randomUUID();
Order orderInput = new Order(orderId, "Test", 1.0, "17 St Andrews Croft, Leeds ,LS17 7TP");
doReturn(orderInput).when(orderRepository)
.save(any());
doReturn(true).when(notificationService)
.raiseAlert(any(Order.class));
Order order = orderService.save(orderInput);
Assertions.assertNotNull(order);
Assertions.assertEquals(orderId, order.getId());
verify(notificationService).notify(any(Order.class));
}
}