diff --git a/core-java-modules/core-java-concurrency-advanced-5/src/test/java/com/baeldung/exceptions_completablefuture/CompletableFutureExceptionsHandlingUnitTest.java b/core-java-modules/core-java-concurrency-advanced-5/src/test/java/com/baeldung/exceptions_completablefuture/CompletableFutureExceptionsHandlingUnitTest.java new file mode 100644 index 0000000000..afb31f7617 --- /dev/null +++ b/core-java-modules/core-java-concurrency-advanced-5/src/test/java/com/baeldung/exceptions_completablefuture/CompletableFutureExceptionsHandlingUnitTest.java @@ -0,0 +1,126 @@ +package com.baeldung.exceptions_completablefuture; + +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutionException; +import java.util.stream.Stream; + +import org.assertj.core.api.Assertions; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +public class CompletableFutureExceptionsHandlingUnitTest { + + @ParameterizedTest + @MethodSource("parametersSource_handle") + void whenCompletableFutureIsScheduled_thenHandleStageIsAlwaysInvoked(int radius, long expected) + throws ExecutionException, InterruptedException { + long actual = CompletableFuture + .supplyAsync(() -> { + if (radius <= 0) { + throw new IllegalArgumentException("Supplied with non-positive radius '%d'"); + } + return Math.round(Math.pow(radius, 2) * Math.PI); + }) + .handle((result, ex) -> { + if (ex == null) { + return result; + } else { + return -1L; + } + }) + .get(); + + Assertions.assertThat(actual).isEqualTo(expected); + } + + @ParameterizedTest + @MethodSource("parametersSource_exceptionally") + void whenCompletableFutureIsScheduled_thenExceptionallyExecutedOnlyOnFailure(int a, int b, int c, long expected) + throws ExecutionException, InterruptedException { + long actual = CompletableFuture + .supplyAsync(() -> { + if (a <= 0 || b <= 0 || c <= 0) { + throw new IllegalArgumentException(String.format("Supplied with incorrect edge length [%s]", List.of(a, b, c))); + } + return a * b * c; + }) + .exceptionally((ex) -> -1) + .get(); + + Assertions.assertThat(actual).isEqualTo(expected); + } + + @ParameterizedTest + @MethodSource("parametersSource_exceptionally") + void givenCompletableFutureIsScheduled_whenHandleIsAlreadyPresent_thenExceptionallyIsNotExecuted(int a, int b, int c, long expected) + throws ExecutionException, InterruptedException { + long actual = CompletableFuture + .supplyAsync(() -> { + if (a <= 0 || b <= 0 || c <= 0) { + throw new IllegalArgumentException(String.format("Supplied with incorrect edge length [%s]", List.of(a, b, c))); + } + return a * b * c; + }) + .handle((result, throwable) -> { + if (throwable != null) { + return -1; + } + return result; + }) + .exceptionally((ex) -> { + System.exit(1); + return 0; + }) + .get(); + + Assertions.assertThat(actual).isEqualTo(expected); + } + + @ParameterizedTest + @MethodSource("parametersSource_whenComplete") + void whenCompletableFutureIsScheduled_thenWhenCompletedExecutedAlways(Double a, long expected, Class ifAny) { + try { + CountDownLatch countDownLatch = new CountDownLatch(1); + + long actual = CompletableFuture + .supplyAsync(() -> { + if (a.isNaN()) { + throw new IllegalArgumentException("Supplied value is NaN"); + } + return Math.round(Math.pow(a, 2)); + }) + .whenComplete((result, exception) -> countDownLatch.countDown()) + .get(); + + Assertions.assertThat(countDownLatch.await(20L, java.util.concurrent.TimeUnit.SECONDS)); + Assertions.assertThat(actual).isEqualTo(expected); + } catch (Exception e) { + Assertions.assertThat(e.getClass()).isSameAs(ExecutionException.class); + Assertions.assertThat(e.getCause().getClass()).isSameAs(ifAny); + } + } + + static Stream parametersSource_handle() { + return Stream.of( + Arguments.of(1, 3), + Arguments.of(-1, -1) + ); + } + + static Stream parametersSource_exceptionally() { + return Stream.of( + Arguments.of(1, 5, 5, 25), + Arguments.of(-1, 10, 15, -1) + ); + } + + static Stream parametersSource_whenComplete() { + return Stream.of( + Arguments.of(2d, 4, null), + Arguments.of(Double.NaN, 1, IllegalArgumentException.class) + ); + } +} diff --git a/core-java-modules/core-java-datetime-conversion/src/main/java/com/baeldung/timestamptolong/TimestampToLong.java b/core-java-modules/core-java-datetime-conversion/src/main/java/com/baeldung/timestamptolong/TimestampToLong.java new file mode 100644 index 0000000000..2ebe30f4ff --- /dev/null +++ b/core-java-modules/core-java-datetime-conversion/src/main/java/com/baeldung/timestamptolong/TimestampToLong.java @@ -0,0 +1,32 @@ +package com.baeldung.timestamptolong; + +import java.sql.Timestamp; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.util.Date; + +public class TimestampToLong { + public void usingSimpleDateFormat() throws ParseException { + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + String currentDateString = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()); + long actualTimestamp = sdf.parse(currentDateString).getTime(); + } + + public void usingInstantClass() { + Instant instant = Instant.now(); + long actualTimestamp = instant.toEpochMilli(); + } + + public void usingTimestamp() { + Timestamp timestamp = new Timestamp(System.currentTimeMillis()); + long actualTimestamp = timestamp.getTime(); + } + + public void usingJava8DateTime() { + LocalDateTime localDateTime = LocalDateTime.now(); + long actualTimestamp = localDateTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli(); + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-datetime-conversion/src/test/java/com/baeldung/timestamptolong/TimestampToLongUnitTest.java b/core-java-modules/core-java-datetime-conversion/src/test/java/com/baeldung/timestamptolong/TimestampToLongUnitTest.java new file mode 100644 index 0000000000..ede8f7792d --- /dev/null +++ b/core-java-modules/core-java-datetime-conversion/src/test/java/com/baeldung/timestamptolong/TimestampToLongUnitTest.java @@ -0,0 +1,52 @@ +package com.baeldung.timestamptolong; + +import org.junit.Test; + +import java.sql.Timestamp; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.util.Date; + +import static org.junit.Assert.assertTrue; + +public class TimestampToLongUnitTest { + + private static final long TOLERANCE = 1000; + + @Test + public void givenSimpleDateFormat_whenFormattingDate_thenTConvertToLong() throws ParseException { + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + + String currentDateString = sdf.format(new Date()); + long actualTimestamp = sdf.parse(currentDateString).getTime(); + + assertTrue(Math.abs(System.currentTimeMillis() - actualTimestamp) < TOLERANCE); + } + + @Test + public void givenInstantClass_whenGettingTimestamp_thenTConvertToLong() { + Instant instant = Instant.now(); + long actualTimestamp = instant.toEpochMilli(); + + assertTrue(Math.abs(System.currentTimeMillis() - actualTimestamp) < TOLERANCE); + } + + @Test + public void givenTimestamp_whenCreatingTimestamp_thenTConvertToLong() { + Timestamp timestamp = new Timestamp(System.currentTimeMillis()); + long actualTimestamp = timestamp.getTime(); + + assertTrue(Math.abs(System.currentTimeMillis() - actualTimestamp) < TOLERANCE); + } + + @Test + public void givenJava8DateTime_whenGettingTimestamp_thenTConvertToLong() { + LocalDateTime localDateTime = LocalDateTime.now(); + long actualTimestamp = localDateTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli(); + + assertTrue(Math.abs(System.currentTimeMillis() - actualTimestamp) < TOLERANCE); + } +} diff --git a/core-java-modules/core-java-lang-6/src/main/java/com/baeldung/compressbytes/CompressByteArrayUtil.java b/core-java-modules/core-java-lang-6/src/main/java/com/baeldung/compressbytes/CompressByteArrayUtil.java new file mode 100644 index 0000000000..88e2283985 --- /dev/null +++ b/core-java-modules/core-java-lang-6/src/main/java/com/baeldung/compressbytes/CompressByteArrayUtil.java @@ -0,0 +1,58 @@ +package com.baeldung.compressbytes; + +import java.io.ByteArrayOutputStream; +import java.util.zip.DataFormatException; +import java.util.zip.Deflater; +import java.util.zip.Inflater; + +public class CompressByteArrayUtil { + + public static byte[] compress(byte[] input) { + Deflater deflater = new Deflater(); + deflater.setInput(input); + deflater.finish(); + + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + byte[] buffer = new byte[1024]; + + while (!deflater.finished()) { + int compressedSize = deflater.deflate(buffer); + outputStream.write(buffer, 0, compressedSize); + } + + return outputStream.toByteArray(); + } + + public static byte[] decompress(byte[] input) throws DataFormatException { + Inflater inflater = new Inflater(); + inflater.setInput(input); + + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + byte[] buffer = new byte[1024]; + + while (!inflater.finished()) { + int decompressedSize = inflater.inflate(buffer); + outputStream.write(buffer, 0, decompressedSize); + } + + return outputStream.toByteArray(); + } + + public static void main(String[] args) throws Exception { + String inputString = "Baeldung helps developers explore the Java ecosystem and simply be better engineers. " + + "We publish to-the-point guides and courses, with a strong focus on building web applications, Spring, " + + "Spring Security, and RESTful APIs"; + byte[] input = inputString.getBytes(); + + // Compression + byte[] compressedData = compress(input); + + // Decompression + byte[] decompressedData = decompress(compressedData); + + System.out.println("Original: " + input.length + " bytes"); + System.out.println("Compressed: " + compressedData.length + " bytes"); + System.out.println("Decompressed: " + decompressedData.length + " bytes"); + } + +} diff --git a/core-java-modules/core-java-streams-5/src/test/java/com/baeldung/nosuchelementexception/NoSuchElementExceptionStreamUnitTest.java b/core-java-modules/core-java-streams-5/src/test/java/com/baeldung/nosuchelementexception/NoSuchElementExceptionStreamUnitTest.java new file mode 100644 index 0000000000..bef834c1af --- /dev/null +++ b/core-java-modules/core-java-streams-5/src/test/java/com/baeldung/nosuchelementexception/NoSuchElementExceptionStreamUnitTest.java @@ -0,0 +1,62 @@ +package com.baeldung.nosuchelementexception; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.List; +import java.util.NoSuchElementException; +import java.util.Optional; + +import org.junit.Test; + +public class NoSuchElementExceptionStreamUnitTest { + + @Test(expected = NoSuchElementException.class) + public void givenEmptyOptional_whenCallingGetMethod_thenThrowNoSuchElementException() { + List names = List.of("William", "Amelia", "Albert", "Philip"); + Optional emptyOptional = names.stream() + .filter(name -> name.equals("Emma")) + .findFirst(); + + emptyOptional.get(); + } + + @Test + public void givenEmptyOptional_whenUsingIsPresentMethod_thenReturnDefault() { + List names = List.of("Tyler", "Amelia", "James", "Emma"); + Optional emptyOptional = names.stream() + .filter(name -> name.equals("Lucas")) + .findFirst(); + + String name = "unknown"; + if (emptyOptional.isPresent()) { + name = emptyOptional.get(); + } + + assertEquals("unknown", name); + } + + @Test + public void givenEmptyOptional_whenUsingOrElseMethod_thenReturnDefault() { + List names = List.of("Nicholas", "Justin", "James"); + Optional emptyOptional = names.stream() + .filter(name -> name.equals("Lucas")) + .findFirst(); + + String name = emptyOptional.orElse("unknown"); + + assertEquals("unknown", name); + } + + @Test + public void givenEmptyOptional_whenUsingOrElseGetMethod_thenReturnDefault() { + List names = List.of("Thomas", "Catherine", "David", "Olivia"); + Optional emptyOptional = names.stream() + .filter(name -> name.equals("Liam")) + .findFirst(); + + String name = emptyOptional.orElseGet(() -> "unknown"); + + assertEquals("unknown", name); + } + +} diff --git a/persistence-modules/redis/pom.xml b/persistence-modules/redis/pom.xml index 571487af3d..98be674a8e 100644 --- a/persistence-modules/redis/pom.xml +++ b/persistence-modules/redis/pom.xml @@ -57,7 +57,7 @@ 0.6 3.20.0 - 4.3.2 + 5.0.2 4.1.90.Final diff --git a/persistence-modules/spring-data-redis/pom.xml b/persistence-modules/spring-data-redis/pom.xml index ab133192a0..052935e215 100644 --- a/persistence-modules/spring-data-redis/pom.xml +++ b/persistence-modules/spring-data-redis/pom.xml @@ -50,6 +50,7 @@ redis.clients jedis + ${jedis.version} jar @@ -83,6 +84,7 @@ 3.2.4 0.10.0 0.6 + 5.0.2 \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-3-2/pom.xml b/spring-boot-modules/spring-boot-3-2/pom.xml index 9b5b7ea254..c85488d44b 100644 --- a/spring-boot-modules/spring-boot-3-2/pom.xml +++ b/spring-boot-modules/spring-boot-3-2/pom.xml @@ -135,6 +135,7 @@ redis.clients jedis + ${jedis.version} jar @@ -285,6 +286,7 @@ 3.0.0-M7 5.14.0 0.2.0 + 5.0.2 diff --git a/spring-boot-modules/spring-boot-keycloak/src/main/java/com/baeldung/keycloak/SecurityConfig.java b/spring-boot-modules/spring-boot-keycloak/src/main/java/com/baeldung/keycloak/SecurityConfig.java index eb7767480f..5b9ce9677a 100644 --- a/spring-boot-modules/spring-boot-keycloak/src/main/java/com/baeldung/keycloak/SecurityConfig.java +++ b/spring-boot-modules/spring-boot-keycloak/src/main/java/com/baeldung/keycloak/SecurityConfig.java @@ -4,6 +4,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.annotation.Order; import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.config.Customizer; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; @@ -53,7 +54,8 @@ class SecurityConfig { .hasRole("USER") .anyRequest() .authenticated(); - http.oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt); + http.oauth2ResourceServer((oauth2) -> oauth2 + .jwt(Customizer.withDefaults())); return http.build(); } diff --git a/spring-boot-modules/spring-boot-keycloak/src/main/java/com/baeldung/keycloaksoap/KeycloakSecurityConfig.java b/spring-boot-modules/spring-boot-keycloak/src/main/java/com/baeldung/keycloaksoap/KeycloakSecurityConfig.java index e55d307e33..ff1cf0cb42 100644 --- a/spring-boot-modules/spring-boot-keycloak/src/main/java/com/baeldung/keycloaksoap/KeycloakSecurityConfig.java +++ b/spring-boot-modules/spring-boot-keycloak/src/main/java/com/baeldung/keycloaksoap/KeycloakSecurityConfig.java @@ -3,10 +3,11 @@ package com.baeldung.keycloaksoap; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.Customizer; import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; 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.oauth2.server.resource.OAuth2ResourceServerConfigurer; +import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; import org.springframework.security.web.SecurityFilterChain; @Configuration @@ -17,11 +18,11 @@ public class KeycloakSecurityConfig { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { - http.csrf() - .disable() + http.csrf(AbstractHttpConfigurer::disable) .authorizeHttpRequests(auth -> auth.anyRequest() .authenticated()) - .oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt); + .oauth2ResourceServer((oauth2) -> oauth2 + .jwt(Customizer.withDefaults())); return http.build(); } } diff --git a/spring-reactive-modules/spring-5-reactive/pom.xml b/spring-reactive-modules/spring-5-reactive/pom.xml deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/webflux/functional/EmployeeFunctionalConfig.java b/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/webflux/functional/EmployeeFunctionalConfig.java index e6f8ba35c2..7775f61467 100644 --- a/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/webflux/functional/EmployeeFunctionalConfig.java +++ b/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/webflux/functional/EmployeeFunctionalConfig.java @@ -53,11 +53,10 @@ public class EmployeeFunctionalConfig { @Bean public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { - http.csrf() - .disable() - .authorizeExchange() - .anyExchange() - .permitAll(); + http.csrf(csrf -> csrf.disable()) + .authorizeExchange( + exchanges -> exchanges.anyExchange().permitAll() + ); return http.build(); } } \ No newline at end of file diff --git a/spring-web-modules/spring-mvc-java-2/pom.xml b/spring-web-modules/spring-mvc-java-2/pom.xml index d88a9c320a..b1b5a797f8 100644 --- a/spring-web-modules/spring-mvc-java-2/pom.xml +++ b/spring-web-modules/spring-mvc-java-2/pom.xml @@ -41,6 +41,11 @@ jaxb-runtime ${jaxb-runtime.version} + + commons-fileupload + commons-fileupload + ${commons-fileupload.version} + @@ -57,6 +62,7 @@ 4.0.1 5.2.2.RELEASE 2.3.5 + 1.5 \ No newline at end of file diff --git a/spring-web-modules/spring-mvc-java-2/src/test/java/com/baeldung/multipart/file/ConvertFileToMultipartFileUnitTest.java b/spring-web-modules/spring-mvc-java-2/src/test/java/com/baeldung/multipart/file/ConvertFileToMultipartFileUnitTest.java new file mode 100644 index 0000000000..7d99f7f9bb --- /dev/null +++ b/spring-web-modules/spring-mvc-java-2/src/test/java/com/baeldung/multipart/file/ConvertFileToMultipartFileUnitTest.java @@ -0,0 +1,45 @@ +package com.baeldung.multipart.file; + +import static org.junit.Assert.assertEquals; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.file.Files; + +import org.apache.commons.fileupload.FileItem; +import org.apache.commons.fileupload.disk.DiskFileItem; +import org.apache.commons.io.IOUtils; +import org.junit.jupiter.api.Test; +import org.springframework.web.multipart.MultipartFile; +import org.springframework.web.multipart.commons.CommonsMultipartFile; +import org.springframework.mock.web.MockMultipartFile; + +public class ConvertFileToMultipartFileUnitTest { + + @Test + public void givenFile_whenCreateMultipartFile_thenContentMatch() throws IOException { + File file = new File("src/main/resources/targetFile.tmp"); + byte[] fileBytes = Files.readAllBytes(file.toPath()); + MultipartFile multipartFile = new MockMultipartFile("file", file.getName(), "text/plain", fileBytes); + String fileContent = new String(multipartFile.getBytes()); + assertEquals("Hello World", fileContent); + assertEquals("targetFile.tmp", multipartFile.getOriginalFilename()); + } + + @Test + public void givenFile_whenCreateMultipartFileUsingCommonsMultipart_thenContentMatch() throws IOException { + File file = new File("src/main/resources/targetFile.tmp"); + FileItem fileItem = new DiskFileItem("file", Files.probeContentType(file.toPath()), false, file.getName(), (int) file.length(), file.getParentFile()); + InputStream input = new FileInputStream(file); + OutputStream outputStream = fileItem.getOutputStream(); + IOUtils.copy(input, outputStream); + MultipartFile multipartFile = new CommonsMultipartFile(fileItem); + String fileContent = new String(multipartFile.getBytes()); + assertEquals("Hello World", fileContent); + assertEquals("targetFile.tmp", multipartFile.getOriginalFilename()); + } + +} diff --git a/spring-web-modules/spring-session/spring-session-redis/pom.xml b/spring-web-modules/spring-session/spring-session-redis/pom.xml index 6824a3632d..6b1aec24e4 100644 --- a/spring-web-modules/spring-session/spring-session-redis/pom.xml +++ b/spring-web-modules/spring-session/spring-session-redis/pom.xml @@ -40,12 +40,14 @@ redis.clients jedis + ${jedis.version} jar 0.6 + 5.0.2 \ No newline at end of file