diff --git a/aws-modules/aws-s3/src/main/java/com/baeldung/s3/RenameObjectService.java b/aws-modules/aws-s3/src/main/java/com/baeldung/s3/RenameObjectService.java new file mode 100644 index 0000000000..0ca586c73b --- /dev/null +++ b/aws-modules/aws-s3/src/main/java/com/baeldung/s3/RenameObjectService.java @@ -0,0 +1,79 @@ +package com.baeldung.s3; + +import java.util.List; + +import software.amazon.awssdk.auth.credentials.ProfileCredentialsProvider; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.s3.S3Client; +import software.amazon.awssdk.services.s3.model.CopyObjectRequest; +import software.amazon.awssdk.services.s3.model.DeleteObjectRequest; +import software.amazon.awssdk.services.s3.model.ListObjectsV2Request; +import software.amazon.awssdk.services.s3.model.ListObjectsV2Response; +import software.amazon.awssdk.services.s3.model.S3Object; + +public class RenameObjectService { + + private S3Client s3Client; + + public RenameObjectService(S3Client s3Client) { + this.s3Client = s3Client; + } + + public RenameObjectService() { + init(); + } + + public void init() { + this.s3Client = S3Client.builder() + .region(Region.US_EAST_1) + .credentialsProvider(ProfileCredentialsProvider.create("default")) + .build(); + } + + public void renameFile(String bucketName, String keyName, String destinationKeyName) { + CopyObjectRequest copyObjRequest = CopyObjectRequest.builder() + .sourceBucket(bucketName) + .sourceKey(keyName) + .destinationBucket(destinationKeyName) + .destinationKey(bucketName) + .build(); + s3Client.copyObject(copyObjRequest); + DeleteObjectRequest deleteRequest = DeleteObjectRequest.builder() + .bucket(bucketName) + .key(keyName) + .build(); + s3Client.deleteObject(deleteRequest); + } + + public void renameFolder(String bucketName, String sourceFolderKey, String destinationFolderKey) { + ListObjectsV2Request listRequest = ListObjectsV2Request.builder() + .bucket(bucketName) + .prefix(sourceFolderKey) + .build(); + + ListObjectsV2Response listResponse = s3Client.listObjectsV2(listRequest); + List objects = listResponse.contents(); + + for (S3Object s3Object : objects) { + String newKey = destinationFolderKey + s3Object.key() + .substring(sourceFolderKey.length()); + + // Copy object to destination folder + CopyObjectRequest copyRequest = CopyObjectRequest.builder() + .sourceBucket(bucketName) + .sourceKey(s3Object.key()) + .destinationBucket(bucketName) + .destinationKey(newKey) + .build(); + s3Client.copyObject(copyRequest); + + // Delete object from source folder + DeleteObjectRequest deleteRequest = DeleteObjectRequest.builder() + .bucket(bucketName) + .key(s3Object.key()) + .build(); + s3Client.deleteObject(deleteRequest); + } + } + +} diff --git a/core-java-modules/core-java-collections-set-2/pom.xml b/core-java-modules/core-java-collections-set-2/pom.xml index 680c01d8ca..d1a108f8bb 100644 --- a/core-java-modules/core-java-collections-set-2/pom.xml +++ b/core-java-modules/core-java-collections-set-2/pom.xml @@ -20,6 +20,17 @@ ${junit-platform.version} test + + org.testng + testng + 7.7.0 + test + + + com.google.guava + guava + 32.1.1-jre + diff --git a/core-java-modules/core-java-collections-set-2/src/main/java/com/baeldung/cartesianproduct/CartesianProduct.java b/core-java-modules/core-java-collections-set-2/src/main/java/com/baeldung/cartesianproduct/CartesianProduct.java new file mode 100644 index 0000000000..d4725d74f1 --- /dev/null +++ b/core-java-modules/core-java-collections-set-2/src/main/java/com/baeldung/cartesianproduct/CartesianProduct.java @@ -0,0 +1,75 @@ +package com.baeldung.cartesianproduct; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import com.google.common.collect.Sets; + +public class CartesianProduct { + public List> getCartesianProductIterative(List> sets) { + List> result = new ArrayList<>(); + if(sets == null || sets.isEmpty()) { + return result; + } + int totalSets = sets.size(); + int totalCombinations = 1 << totalSets; + for(int i = 0; i < totalCombinations; i++) { + List combination = new ArrayList<>(); + for(int j = 0; j < totalSets; j++) { + if (((i >> j) & 1) == 1) { + combination.add(sets.get(j).get(0)); + } else { + combination.add(sets.get(j).get(1)); + } + } + result.add(combination); + } + return result; + } + + public List> getCartesianProductRecursive(List> sets) { + List> result = new ArrayList<>(); + getCartesianProductRecursiveHelper(sets, 0, new ArrayList<>(), result); + return result; + } + + private void getCartesianProductRecursiveHelper(List> sets, int index, List current, List> result) { + if(index == sets.size()) { + result.add(new ArrayList<>(current)); + return; + } + List currentSet = sets.get(index); + for(Object element: currentSet) { + current.add(element); + getCartesianProductRecursiveHelper(sets, index+1, current, result); + current.remove(current.size() - 1); + } + } + + public List> getCartesianProductUsingStreams(List> sets) { + return cartesianProduct(sets,0).collect(Collectors.toList()); + } + + public Stream> cartesianProduct(List> sets, int index) { + if(index == sets.size()) { + List emptyList = new ArrayList<>(); + return Stream.of(emptyList); + } + List currentSet = sets.get(index); + return currentSet.stream().flatMap(element -> cartesianProduct(sets, index+1) + .map(list -> { + List newList = new ArrayList<>(list); + newList.add(0, element); return newList; + })); + } + + public List> getCartesianProductUsingGuava(List> sets) { + Set> cartesianProduct = Sets.cartesianProduct(sets); + List> cartesianList = new ArrayList<>(cartesianProduct); + return cartesianList; + } + +} diff --git a/core-java-modules/core-java-collections-set-2/src/test/java/com/baeldung/cartesianproduct/CartesianProductUnitTest.java b/core-java-modules/core-java-collections-set-2/src/test/java/com/baeldung/cartesianproduct/CartesianProductUnitTest.java new file mode 100644 index 0000000000..cc9c01fb5f --- /dev/null +++ b/core-java-modules/core-java-collections-set-2/src/test/java/com/baeldung/cartesianproduct/CartesianProductUnitTest.java @@ -0,0 +1,93 @@ +package com.baeldung.cartesianproduct; + +import static org.testng.Assert.assertEquals; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.testng.annotations.Test; + +public class CartesianProductUnitTest { + private CartesianProduct cp = new CartesianProduct(); + List> sets = Arrays.asList( + Arrays.asList(10, 20), + Arrays.asList("John", "Jack"), + Arrays.asList('I', 'J') + ); + + @Test + public void whenUsingStreams_thenCalculateCartesianProduct() { + List> expected = Arrays.asList( + Arrays.asList(10, "John", 'I'), + Arrays.asList(10, "John", 'J'), + Arrays.asList(10, "Jack", 'I'), + Arrays.asList(10, "Jack", 'J'), + Arrays.asList(20, "John", 'I'), + Arrays.asList(20, "John", 'J'), + Arrays.asList(20, "Jack", 'I'), + Arrays.asList(20, "Jack", 'J') + ); + List> cartesianProduct = cp.getCartesianProductUsingStreams(sets); + + assertEquals(expected, cartesianProduct); + } + + @Test + public void whenUsingRecursion_thenCalculateCartesianProduct() { + List> expected = Arrays.asList( + Arrays.asList(10, "John", 'I'), + Arrays.asList(10, "John", 'J'), + Arrays.asList(10, "Jack", 'I'), + Arrays.asList(10, "Jack", 'J'), + Arrays.asList(20, "John", 'I'), + Arrays.asList(20, "John", 'J'), + Arrays.asList(20, "Jack", 'I'), + Arrays.asList(20, "Jack", 'J') + ); + List> cartesianProduct = cp.getCartesianProductRecursive(sets); + + assertEquals(expected, cartesianProduct); + } + + @Test + public void whenUsingIterativeApproach_thenCalculateCartesianProduct() { + List> expected = Arrays.asList( + Arrays.asList(20, "Jack", 'J'), + Arrays.asList(10, "Jack", 'J'), + Arrays.asList(20, "John", 'J'), + Arrays.asList(10, "John", 'J'), + Arrays.asList(20, "Jack", 'I'), + Arrays.asList(10, "Jack", 'I'), + Arrays.asList(20, "John", 'I'), + Arrays.asList(10, "John", 'I') + ); + List> cartesianProduct = cp.getCartesianProductIterative(sets); + + assertEquals(expected, cartesianProduct); + } + + @Test + public void whenUsingGuava_thenCalculateCartesianProduct() { + List> sets = new ArrayList<>(); + sets.add(new HashSet<>(Arrays.asList(10, 20))); + sets.add(new HashSet<>(Arrays.asList("John", "Jack"))); + sets.add(new HashSet<>(Arrays.asList('I', 'J'))); + + List> expected = Arrays.asList( + Arrays.asList(20, "John", 'I'), + Arrays.asList(20, "John", 'J'), + Arrays.asList(20, "Jack", 'I'), + Arrays.asList(20, "Jack", 'J'), + Arrays.asList(10, "John", 'I'), + Arrays.asList(10, "John", 'J'), + Arrays.asList(10, "Jack", 'I'), + Arrays.asList(10, "Jack", 'J') + ); + List> cartesianProduct = cp.getCartesianProductUsingGuava(sets); + + assertEquals(expected, cartesianProduct); + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-concurrency-advanced/src/main/java/com/baeldung/concurrent/phaser/LongRunningAction.java b/core-java-modules/core-java-concurrency-advanced/src/main/java/com/baeldung/concurrent/phaser/LongRunningAction.java index 44f84ad77c..093cfdbc81 100644 --- a/core-java-modules/core-java-concurrency-advanced/src/main/java/com/baeldung/concurrent/phaser/LongRunningAction.java +++ b/core-java-modules/core-java-concurrency-advanced/src/main/java/com/baeldung/concurrent/phaser/LongRunningAction.java @@ -7,31 +7,37 @@ import java.util.concurrent.Phaser; class LongRunningAction implements Runnable { - private static Logger log = LoggerFactory.getLogger(LongRunningAction.class); - private String threadName; - private Phaser ph; + private static final Logger log = LoggerFactory.getLogger(LongRunningAction.class); + private final String threadName; + private final Phaser ph; LongRunningAction(String threadName, Phaser ph) { this.threadName = threadName; this.ph = ph; + + this.randomWait(); + ph.register(); + log.info("Thread {} registered during phase {}", threadName, ph.getPhase()); } @Override public void run() { - log.info("This is phase {}", ph.getPhase()); - log.info("Thread {} before long running action", threadName); - + log.info("Thread {} BEFORE long running action in phase {}", threadName, ph.getPhase()); + ph.arriveAndAwaitAdvance(); + + randomWait(); + + log.info("Thread {} AFTER long running action in phase {}", threadName, ph.getPhase()); + ph.arriveAndDeregister(); + } + + // Simulating real work + private void randomWait() { try { - Thread.sleep(2000); + Thread.sleep((long) (Math.random() * 100)); } catch (InterruptedException e) { e.printStackTrace(); } - - log.debug("Thread {} action completed and waiting for others", threadName); - ph.arriveAndAwaitAdvance(); - log.debug("Thread {} proceeding in phase {}", threadName, ph.getPhase()); - - ph.arriveAndDeregister(); } } \ No newline at end of file diff --git a/core-java-modules/core-java-concurrency-advanced/src/test/java/com/baeldung/concurrent/phaser/PhaserUnitTest.java b/core-java-modules/core-java-concurrency-advanced/src/test/java/com/baeldung/concurrent/phaser/PhaserUnitTest.java index 384a1837c1..9cb863073e 100644 --- a/core-java-modules/core-java-concurrency-advanced/src/test/java/com/baeldung/concurrent/phaser/PhaserUnitTest.java +++ b/core-java-modules/core-java-concurrency-advanced/src/test/java/com/baeldung/concurrent/phaser/PhaserUnitTest.java @@ -7,8 +7,6 @@ import org.junit.runners.MethodSorters; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; import java.util.concurrent.Phaser; import static junit.framework.TestCase.assertEquals; @@ -16,38 +14,32 @@ import static junit.framework.TestCase.assertEquals; @FixMethodOrder(MethodSorters.NAME_ASCENDING) public class PhaserUnitTest { - private static Logger log = LoggerFactory.getLogger(PhaserUnitTest.class); + private static final Logger log = LoggerFactory.getLogger(PhaserUnitTest.class); @Test - public void givenPhaser_whenCoordinateWorksBetweenThreads_thenShouldCoordinateBetweenMultiplePhases() { - //given - ExecutorService executorService = Executors.newCachedThreadPool(); + public void givenPhaser_whenCoordinateWorksBetweenThreads_thenShouldCoordinateBetweenMultiplePhases() throws InterruptedException { Phaser ph = new Phaser(1); assertEquals(0, ph.getPhase()); - //when - executorService.submit(new LongRunningAction("thread-1", ph)); - executorService.submit(new LongRunningAction("thread-2", ph)); - executorService.submit(new LongRunningAction("thread-3", ph)); + new Thread(new LongRunningAction("thread-1", ph)).start(); + new Thread(new LongRunningAction("thread-2", ph)).start(); + new Thread(new LongRunningAction("thread-3", ph)).start(); - //then - log.debug("Thread {} waiting for others", Thread.currentThread().getName()); + log.info("Thread {} waiting for others", Thread.currentThread().getName()); ph.arriveAndAwaitAdvance(); - log.debug("Thread {} proceeding in phase {}", Thread.currentThread().getName(), ph.getPhase()); - + log.info("Thread {} proceeding in phase {}", Thread.currentThread().getName(), ph.getPhase()); assertEquals(1, ph.getPhase()); - //and - executorService.submit(new LongRunningAction("thread-4", ph)); - executorService.submit(new LongRunningAction("thread-5", ph)); + new Thread(new LongRunningAction("thread-4", ph)).start(); + new Thread(new LongRunningAction("thread-5", ph)).start(); - log.debug("Thread {} waiting for others", Thread.currentThread().getName()); + log.info("Thread {} waiting for new phase", Thread.currentThread().getName()); ph.arriveAndAwaitAdvance(); - log.debug("Thread {} proceeding in phase {}", Thread.currentThread().getName(), ph.getPhase()); - + log.info("Thread {} proceeding in phase {}", Thread.currentThread().getName(), ph.getPhase()); assertEquals(2, ph.getPhase()); - ph.arriveAndDeregister(); + Thread.sleep(1000); + assertEquals(true, ph.isTerminated()); } } diff --git a/core-java-modules/core-java-io/pom.xml b/core-java-modules/core-java-io/pom.xml index a59ac619bd..8364f36874 100644 --- a/core-java-modules/core-java-io/pom.xml +++ b/core-java-modules/core-java-io/pom.xml @@ -38,9 +38,9 @@ ${fscontext.version} - javax.activation - activation - 1.1 + org.eclipse.angus + angus-activation + ${angus-activation.version} test @@ -73,10 +73,6 @@ org.apache.maven.plugins maven-javadoc-plugin ${maven-javadoc-plugin.version} - - ${maven.compiler.source} - ${maven.compiler.target} - @@ -131,13 +127,15 @@ - 3.0.0-M1 - 2.4.0 + 3.5.0 + 2.7.1 - 1.18 + 2.8.0 0.1.5 - 3.1.0 + 3.3.0 4.4.2 + 2.1.2 + 2.0.1 \ No newline at end of file diff --git a/core-java-modules/core-java-io/src/test/java/com/baeldung/mimetype/MimeTypeUnitTest.java b/core-java-modules/core-java-io/src/test/java/com/baeldung/mimetype/MimeTypeUnitTest.java index bf916e39e7..4c382d07a6 100644 --- a/core-java-modules/core-java-io/src/test/java/com/baeldung/mimetype/MimeTypeUnitTest.java +++ b/core-java-modules/core-java-io/src/test/java/com/baeldung/mimetype/MimeTypeUnitTest.java @@ -10,7 +10,7 @@ import java.net.URLConnection; import java.nio.file.Files; import java.nio.file.Path; -import javax.activation.MimetypesFileTypeMap; +import jakarta.activation.MimetypesFileTypeMap; import org.apache.tika.Tika; import org.junit.Test; diff --git a/core-java-modules/core-java-security-3/pom.xml b/core-java-modules/core-java-security-3/pom.xml index ad9feeb36a..b979b56658 100644 --- a/core-java-modules/core-java-security-3/pom.xml +++ b/core-java-modules/core-java-security-3/pom.xml @@ -33,7 +33,7 @@ com.google.guava guava - ${google-guava.version} + ${guava.version} org.springframework.security @@ -47,7 +47,6 @@ 1.15 2.3.1 6.0.3 - 31.0.1-jre \ No newline at end of file diff --git a/core-java-modules/core-java-streams-4/pom.xml b/core-java-modules/core-java-streams-4/pom.xml index fe791ebd42..0b9b3569f1 100644 --- a/core-java-modules/core-java-streams-4/pom.xml +++ b/core-java-modules/core-java-streams-4/pom.xml @@ -39,7 +39,7 @@ org.assertj assertj-core - 3.23.1 + ${assertj.version} test @@ -55,7 +55,7 @@ org.apache.commons commons-lang3 - 3.12.0 + ${commons-lang3.version} test @@ -81,7 +81,7 @@ com.google.guava guava - ${google.guava.version} + ${guava.version} com.oath.cyclops @@ -114,6 +114,7 @@ + 3.23.1 3.1 12 12 @@ -123,7 +124,6 @@ 1.0.0-alpha-4 3.5.1 4.4 - 31.1-jre 10.4.1 diff --git a/core-java-modules/core-java-streams/pom.xml b/core-java-modules/core-java-streams/pom.xml index b0794829c2..c7282dda21 100644 --- a/core-java-modules/core-java-streams/pom.xml +++ b/core-java-modules/core-java-streams/pom.xml @@ -14,33 +14,6 @@ - - org.openjdk.jmh - jmh-core - ${jmh-core.version} - - - org.openjdk.jmh - jmh-generator-annprocess - ${jmh-generator.version} - provided - - - org.apache.commons - commons-lang3 - ${commons-lang3.version} - - - log4j - log4j - ${log4j.version} - - - org.projectlombok - lombok - ${lombok.version} - provided - com.codepoetics protonpack @@ -57,17 +30,7 @@ ${streamex.version} - org.aspectj - aspectjrt - ${asspectj.version} - - - org.aspectj - aspectjweaver - ${asspectj.version} - - - pl.touk + com.pivovarit throwing-function ${throwing-function.version} @@ -96,15 +59,13 @@ - 0.9.0 - 1.15 - 0.6.5 - 2.10 - 1.3 - 1.8.9 - 3.1 - 1.8 - 1.8 + 0.10.4 + 1.16 + 0.8.1 + 1.5.1 + + 17 + 17 \ No newline at end of file diff --git a/core-java-modules/core-java-streams/src/test/java/com/baeldung/stream/filter/StreamFilterUnitTest.java b/core-java-modules/core-java-streams/src/test/java/com/baeldung/stream/filter/StreamFilterUnitTest.java index 5ad875f61e..3f3922e015 100644 --- a/core-java-modules/core-java-streams/src/test/java/com/baeldung/stream/filter/StreamFilterUnitTest.java +++ b/core-java-modules/core-java-streams/src/test/java/com/baeldung/stream/filter/StreamFilterUnitTest.java @@ -1,8 +1,8 @@ package com.baeldung.stream.filter; import org.junit.jupiter.api.Test; -import pl.touk.throwing.ThrowingPredicate; -import pl.touk.throwing.exception.WrappedException; +import com.pivovarit.function.ThrowingPredicate; +import com.pivovarit.function.exception.WrappedException; import java.io.IOException; import java.util.Arrays; @@ -156,5 +156,4 @@ public class StreamFilterUnitTest { }) .collect(Collectors.toList())).isInstanceOf(RuntimeException.class); } - -} +} \ No newline at end of file diff --git a/core-java-modules/core-java-string-apis-2/pom.xml b/core-java-modules/core-java-string-apis-2/pom.xml index 51ab3bc1f8..814d301532 100644 --- a/core-java-modules/core-java-string-apis-2/pom.xml +++ b/core-java-modules/core-java-string-apis-2/pom.xml @@ -22,7 +22,7 @@ org.apache.commons commons-lang3 - ${commons.lang3.version} + ${commons-lang3.version} com.ibm.icu @@ -42,8 +42,6 @@ - 3.12.0 - 31.1-jre 61.1 diff --git a/docker-modules/docker-caching/multi-module-caching/pom.xml b/docker-modules/docker-caching/multi-module-caching/pom.xml index b64cf1a8b8..60f14a17e5 100644 --- a/docker-modules/docker-caching/multi-module-caching/pom.xml +++ b/docker-modules/docker-caching/multi-module-caching/pom.xml @@ -27,7 +27,7 @@ UTF-8 1.8 - 31.1-jre + 32.1.2-jre \ No newline at end of file diff --git a/docker-modules/docker-caching/single-module-caching/pom.xml b/docker-modules/docker-caching/single-module-caching/pom.xml index a388c7563f..0e5174b7ca 100644 --- a/docker-modules/docker-caching/single-module-caching/pom.xml +++ b/docker-modules/docker-caching/single-module-caching/pom.xml @@ -49,7 +49,7 @@ 8 8 UTF-8 - 31.1-jre + 32.1.2-jre \ No newline at end of file diff --git a/json-modules/json-arrays/pom.xml b/json-modules/json-arrays/pom.xml new file mode 100644 index 0000000000..0eefbc86fc --- /dev/null +++ b/json-modules/json-arrays/pom.xml @@ -0,0 +1,47 @@ + + + 4.0.0 + org.baeldung + json-arrays + json-arrays + + + com.baeldung + json-modules + 1.0.0-SNAPSHOT + + + + + org.json + json + ${json.version} + + + com.google.code.gson + gson + ${gson.version} + + + com.fasterxml.jackson.core + jackson-databind + ${jackson.version} + + + javax.json.bind + javax.json.bind-api + ${jsonb-api.version} + + + + + 1.0 + 20230227 + 2.8.5 + 1.1.2 + 2.28.0 + + + diff --git a/json-modules/json-arrays/src/test/java/com.baeldung.checkforkey/CheckForKeyUnitTest.java b/json-modules/json-arrays/src/test/java/com.baeldung.checkforkey/CheckForKeyUnitTest.java new file mode 100644 index 0000000000..6e1cbb7ab0 --- /dev/null +++ b/json-modules/json-arrays/src/test/java/com.baeldung.checkforkey/CheckForKeyUnitTest.java @@ -0,0 +1,47 @@ +package com.baeldung.checkforkey; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.Objects; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; + +import org.junit.jupiter.api.Test; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.gson.Gson; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; + +public class CheckForKeyUnitTest { + + private final String exampleJson = "[{\"colour\":\"red\"},{\"colour\":\"blue\"},{\"colour\":\"green\"}]"; + + @Test + public void givenJsonArray_whenUsingJackson_thenDetectKeyInArray() throws JsonProcessingException { + ObjectMapper objectMapper = new ObjectMapper(); + JsonNode tree = objectMapper.readTree(exampleJson); + + Stream s = StreamSupport.stream(tree.spliterator(), false); + boolean result = s.map(entry -> entry.get("colour")) + .filter(Objects::nonNull) + .anyMatch(colour -> "green".equals(colour.asText())); + assertTrue(result); + } + + @Test + public void givenJsonArray_whenUsingGson_thenDetectKeyInArray() { + Gson gson = new Gson(); + JsonArray parsed = gson.fromJson(exampleJson, JsonArray.class); + + Stream s = StreamSupport.stream(parsed.spliterator(), false); + boolean result = s.map(entry -> entry.getAsJsonObject() + .get("colour")) + .filter(Objects::nonNull) + .anyMatch(colour -> "green".equals(colour.getAsString())); + assertTrue(result); + } + +} diff --git a/json-modules/pom.xml b/json-modules/pom.xml index 82314e0edf..306b404049 100644 --- a/json-modules/pom.xml +++ b/json-modules/pom.xml @@ -16,6 +16,7 @@ json json-2 + json-arrays json-conversion json-path gson diff --git a/mapstruct/src/main/java/com/baeldung/expression/dto/LicenseDto.java b/mapstruct/src/main/java/com/baeldung/expression/dto/LicenseDto.java new file mode 100644 index 0000000000..cd6e9bad68 --- /dev/null +++ b/mapstruct/src/main/java/com/baeldung/expression/dto/LicenseDto.java @@ -0,0 +1,21 @@ +package com.baeldung.expression.dto; + +import java.time.LocalDateTime; +import java.util.UUID; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; + +@AllArgsConstructor +@Data +@Builder +public class LicenseDto { + + private UUID id; + + private LocalDateTime startDate; + + private LocalDateTime endDate; + +} diff --git a/mapstruct/src/main/java/com/baeldung/expression/mapper/LicenseMapper.java b/mapstruct/src/main/java/com/baeldung/expression/mapper/LicenseMapper.java new file mode 100644 index 0000000000..100588b45d --- /dev/null +++ b/mapstruct/src/main/java/com/baeldung/expression/mapper/LicenseMapper.java @@ -0,0 +1,43 @@ +package com.baeldung.expression.mapper; + +import java.time.Duration; +import java.time.LocalDateTime; +import java.time.OffsetDateTime; +import java.time.ZoneOffset; + +import org.mapstruct.AfterMapping; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.MappingTarget; + +import com.baeldung.expression.dto.LicenseDto; +import com.baeldung.expression.model.License; + +@Mapper +public interface LicenseMapper { + + @Mapping(target = "startDate", expression = "java(mapStartDate(licenseDto))") + @Mapping(target = "endDate", ignore = true) + @Mapping(target = "active", constant = "true") + @Mapping(target = "renewalRequired", conditionExpression = "java(isEndDateInTwoWeeks(licenseDto))", source = ".") + License toLicense(LicenseDto licenseDto); + + @AfterMapping + default void afterMapping(LicenseDto licenseDto, @MappingTarget License license) { + OffsetDateTime endDate = licenseDto.getEndDate() != null ? licenseDto.getEndDate() + .atOffset(ZoneOffset.UTC) : OffsetDateTime.now() + .plusYears(1); + license.setEndDate(endDate); + } + + default OffsetDateTime mapStartDate(LicenseDto licenseDto) { + return licenseDto.getStartDate() != null ? licenseDto.getStartDate() + .atOffset(ZoneOffset.UTC) : OffsetDateTime.now(); + } + + default boolean isEndDateInTwoWeeks(LicenseDto licenseDto) { + return licenseDto.getEndDate() != null && Duration.between(licenseDto.getEndDate(), LocalDateTime.now()) + .toDays() <= 14; + } + +} diff --git a/mapstruct/src/main/java/com/baeldung/expression/model/License.java b/mapstruct/src/main/java/com/baeldung/expression/model/License.java new file mode 100644 index 0000000000..9e87be03d4 --- /dev/null +++ b/mapstruct/src/main/java/com/baeldung/expression/model/License.java @@ -0,0 +1,21 @@ +package com.baeldung.expression.model; + +import java.time.OffsetDateTime; +import java.util.UUID; + +import lombok.Data; + +@Data +public class License { + + private UUID id; + + private OffsetDateTime startDate; + + private OffsetDateTime endDate; + + private boolean active; + + private boolean renewalRequired; + +} diff --git a/mapstruct/src/test/java/com/baeldung/expression/mapper/LicenseMapperUnitTest.java b/mapstruct/src/test/java/com/baeldung/expression/mapper/LicenseMapperUnitTest.java new file mode 100644 index 0000000000..98f704e61c --- /dev/null +++ b/mapstruct/src/test/java/com/baeldung/expression/mapper/LicenseMapperUnitTest.java @@ -0,0 +1,64 @@ +package com.baeldung.expression.mapper; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.time.LocalDate; +import java.time.LocalDateTime; + +import org.junit.jupiter.api.Test; +import org.mapstruct.factory.Mappers; + +import com.baeldung.expression.dto.LicenseDto; +import com.baeldung.expression.model.License; + +class LicenseMapperUnitTest { + + LicenseMapper licenseMapper = Mappers.getMapper(LicenseMapper.class); + + @Test + void givenLicenseDtoWithStartDateAndWithoutEndDate_WhenMapperMethodIsInvoked_ThenLicenseShouldBePopulatedWithDefaultEndDate() { + License license = licenseMapper.toLicense(LicenseDto.builder() + .startDate(LocalDateTime.now()) + .build()); + assertThat(license).isNotNull(); + assertThat(license.getEndDate() + .toLocalDate()).isEqualTo(LocalDate.now() + .plusYears(1)); + } + + @Test + void givenLicenseDtoWithEndDateAndWithoutStartDate_WhenMapperMethodIsInvoked_ThenLicenseShouldBePopulatedWithDefaultStartDate() { + License license = licenseMapper.toLicense(LicenseDto.builder() + .endDate(LocalDateTime.now() + .plusYears(2)) + .build()); + assertThat(license).isNotNull(); + assertThat(license.getStartDate() + .toLocalDate()).isEqualTo(LocalDate.now()); + } + + @Test + void givenLicenseDtoWithoutStartDateAndEndDate_WhenMapperMethodIsInvoked_ThenLicenseShouldBePopulatedWithDefaultDetails() { + License license = licenseMapper.toLicense(LicenseDto.builder() + .build()); + assertThat(license).isNotNull(); + assertThat(license.getStartDate() + .toLocalDate()).isEqualTo(LocalDate.now()); + assertThat(license.getEndDate() + .toLocalDate()).isEqualTo(LocalDate.now() + .plusYears(1)); + assertThat(license.isActive()).isTrue(); + assertThat(license.isRenewalRequired()).isFalse(); + } + + @Test + void givenLicenseDtoWithEndDateInTwoWeeks_WhenMapperMethodIsInvoked_ThenLicenseShouldBePopulatedWithRenewalRequiredSetToTrue() { + License license = licenseMapper.toLicense(LicenseDto.builder() + .endDate(LocalDateTime.now() + .plusDays(10)) + .build()); + assertThat(license).isNotNull(); + assertThat(license.isRenewalRequired()).isTrue(); + } + +} \ No newline at end of file diff --git a/pom.xml b/pom.xml index f06cd438f8..12fbc3c4f0 100644 --- a/pom.xml +++ b/pom.xml @@ -1300,7 +1300,7 @@ 3.19.0 1.18.28 2.1.214 - 31.1-jre + 32.1.2-jre 3.2.2 diff --git a/web-modules/pom.xml b/web-modules/pom.xml index c009837186..8c3d3456b6 100644 --- a/web-modules/pom.xml +++ b/web-modules/pom.xml @@ -26,7 +26,7 @@ jee-7 jooby linkrest - + ninja ratpack