diff --git a/.github/ISSUE_TEMPLATE/issue_report.md b/.github/ISSUE_TEMPLATE/issue_report.md index 725ae12064..4bc8c8121c 100644 --- a/.github/ISSUE_TEMPLATE/issue_report.md +++ b/.github/ISSUE_TEMPLATE/issue_report.md @@ -5,7 +5,7 @@ title: '[ISSUE] ' --- **Article and Module Links** -A link to the affected article and the affected module. The link to the module is the one in the "over on GitHub" standard phrase. +A link to the affected article and the affected module. You can find the link to the module in the Conclusion section in the "on Github" standard phase. **Describe the Issue** A clear and concise description of what the issue is. @@ -30,9 +30,3 @@ If applicable, add screenshots to help explain your problem. **Additional Context** Add any other context about the issue here. - -Note that, unfortunately, we can only help with issues that are specifically and directly related to the article - not with your own, custom application. - -StackOverflow is a great place to ask more general questions. - -That's primarily because we get a large number of questions and - while we do try to go through as much as everything and help wherever we can, we can't really get back to all of them. \ No newline at end of file diff --git a/algorithms-modules/algorithms-miscellaneous-7/src/main/java/com/baeldung/algorithms/rotatearray/RotateArray.java b/algorithms-modules/algorithms-miscellaneous-7/src/main/java/com/baeldung/algorithms/rotatearray/RotateArray.java new file mode 100644 index 0000000000..36490d4899 --- /dev/null +++ b/algorithms-modules/algorithms-miscellaneous-7/src/main/java/com/baeldung/algorithms/rotatearray/RotateArray.java @@ -0,0 +1,102 @@ +package com.baeldung.algorithms.rotatearray; + +/** + * To speed up the rotation, we narrow k rotations to the remainder of k divided by the array length, or k module the array length. + * Therefore, a large rotation number will be translated into the relative smallest rotation. + * All solutions replace the original array, although they might use an extra array to compute the rotation. + */ +public class RotateArray { + + private RotateArray() { + throw new IllegalStateException("Rotate array algorithm utility methods class"); + } + + /** + * + * @param arr array to apply rotation to + * @param k number of rotations + */ + public static void bruteForce(int[] arr, int k) { + checkInvalidInput(arr, k); + + k %= arr.length; + int temp; + int previous; + for (int i = 0; i < k; i++) { + previous = arr[arr.length - 1]; + for (int j = 0; j < arr.length; j++) { + temp = arr[j]; + arr[j] = previous; + previous = temp; + } + } + } + + /** + * + * @param arr array to apply rotation to + * @param k number of rotations + */ + public static void withExtraArray(int[] arr, int k) { + checkInvalidInput(arr, k); + + int[] extraArray = new int[arr.length]; + for (int i = 0; i < arr.length; i++) { + extraArray[(i + k) % arr.length] = arr[i]; + } + System.arraycopy(extraArray, 0, arr, 0, arr.length); + } + + /** + * + * @param arr array to apply rotation to + * @param k number of rotations + */ + public static void cyclicReplacement(int[] arr, int k) { + checkInvalidInput(arr, k); + + k = k % arr.length; + int count = 0; + for (int start = 0; count < arr.length; start++) { + int current = start; + int prev = arr[start]; + do { + int next = (current + k) % arr.length; + int temp = arr[next]; + arr[next] = prev; + prev = temp; + current = next; + count++; + } while (start != current); + } + } + + /** + * + * @param arr array to apply rotation to + * @param k number of rotations + */ + public static void reverse(int[] arr, int k) { + checkInvalidInput(arr, k); + + k %= arr.length; + reverse(arr, 0, arr.length - 1); + reverse(arr, 0, k - 1); + reverse(arr, k, arr.length - 1); + } + + private static void reverse(int[] nums, int start, int end) { + while (start < end) { + int temp = nums[start]; + nums[start] = nums[end]; + nums[end] = temp; + start++; + end--; + } + } + + private static void checkInvalidInput(int[] arr, int rotation) { + if (rotation < 1 || arr == null) + throw new IllegalArgumentException("Rotation must be greater than zero or array must be not null"); + } +} diff --git a/algorithms-modules/algorithms-miscellaneous-7/src/test/java/com/baeldung/algorithms/rotatearray/RotateArrayUnitTest.java b/algorithms-modules/algorithms-miscellaneous-7/src/test/java/com/baeldung/algorithms/rotatearray/RotateArrayUnitTest.java new file mode 100644 index 0000000000..4a98acdb75 --- /dev/null +++ b/algorithms-modules/algorithms-miscellaneous-7/src/test/java/com/baeldung/algorithms/rotatearray/RotateArrayUnitTest.java @@ -0,0 +1,124 @@ +package com.baeldung.algorithms.rotatearray; + +import static com.baeldung.algorithms.rotatearray.RotateArray.bruteForce; +import static com.baeldung.algorithms.rotatearray.RotateArray.cyclicReplacement; +import static com.baeldung.algorithms.rotatearray.RotateArray.reverse; +import static com.baeldung.algorithms.rotatearray.RotateArray.withExtraArray; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.junit.jupiter.api.Test; + +class RotateArrayUnitTest { + + private final int[] arr = { 1, 2, 3, 4, 5, 6 }; + private final int rotationLtArrayLength = 1; + private final int rotationGtArrayLength = arr.length + 2; + private final int[] ltArrayLengthRotation = { 6, 1, 2, 3, 4, 5 }; + private final int[] gtArrayLengthRotation = { 5, 6, 1, 2, 3, 4 }; + + @Test + void givenInputArray_whenNoRotationOrEmptyArray_thenThrowIllegalArgumentException() { + final int noRotation = 0; + final int someRotation = arr.length - 1; + + assertThrows(IllegalArgumentException.class, () -> bruteForce(arr, noRotation)); + assertThrows(IllegalArgumentException.class, () -> withExtraArray(arr, noRotation)); + assertThrows(IllegalArgumentException.class, () -> cyclicReplacement(arr, noRotation)); + assertThrows(IllegalArgumentException.class, () -> reverse(arr, noRotation)); + + assertThrows(IllegalArgumentException.class, () -> bruteForce(null, someRotation)); + assertThrows(IllegalArgumentException.class, () -> withExtraArray(null, someRotation)); + assertThrows(IllegalArgumentException.class, () -> cyclicReplacement(null, someRotation)); + assertThrows(IllegalArgumentException.class, () -> reverse(null, someRotation)); + } + + @Test + void givenInputArray_whenUseBruteForceRotationLtArrayLength_thenRotateArrayOk() { + + bruteForce(arr, rotationLtArrayLength); + assertArrayEquals(ltArrayLengthRotation, arr); + } + + @Test + void givenInputArray_whenUseBruteForceRotationGtArrayLength_thenRotateArrayOk() { + + bruteForce(arr, rotationGtArrayLength); + assertArrayEquals(gtArrayLengthRotation, arr); + } + + @Test + void givenInputArray_whenUseBruteForceRotationEqArrayLength_thenDoNothing() { + int[] expected = arr.clone(); + + bruteForce(arr, arr.length); + assertArrayEquals(expected, arr); + } + + @Test + void givenInputArray_whenUseExtraArrayRotationLtArrayLength_thenRotateArrayOk() { + + withExtraArray(arr, rotationLtArrayLength); + assertArrayEquals(ltArrayLengthRotation, arr); + } + + @Test + void givenInputArray_whenUseExtraArrayRotationGtArrayLength_thenRotateArrayOk() { + + withExtraArray(arr, rotationGtArrayLength); + assertArrayEquals(gtArrayLengthRotation, arr); + } + + @Test + void givenInputArray_whenUseExtraArrayWithRotationEqArrayLength_thenDoNothing() { + int[] clone = arr.clone(); + + withExtraArray(arr, arr.length); + assertArrayEquals(clone, arr); + } + + @Test + void givenInputArray_whenUseCyclicReplacementRotationLtArrayLength_thenRotateArrayOk() { + + cyclicReplacement(arr, rotationLtArrayLength); + assertArrayEquals(ltArrayLengthRotation, arr); + } + + @Test + void givenInputArray_whenUseCyclicReplacementRotationGtArrayLength_thenRotateArrayOk() { + + cyclicReplacement(arr, rotationGtArrayLength); + assertArrayEquals(gtArrayLengthRotation, arr); + } + + @Test + void givenInputArray_whenUseCyclicReplacementRotationEqArrayLength_thenDoNothing() { + int[] clone = arr.clone(); + + cyclicReplacement(arr, arr.length); + assertArrayEquals(clone, arr); + } + + @Test + void givenInputArray_whenUseReverseRotationLtArrayLength_thenRotateArrayOk() { + + reverse(arr, rotationLtArrayLength); + assertArrayEquals(ltArrayLengthRotation, arr); + } + + @Test + void givenInputArray_whenUseReverseRotationGtArrayLength_thenRotateArrayOk() { + + reverse(arr, rotationGtArrayLength); + assertArrayEquals(gtArrayLengthRotation, arr); + } + + @Test + void givenInputArray_whenUseReverseRotationEqArrayLength_thenDoNothing() { + + int[] clone = arr.clone(); + + reverse(arr, arr.length); + assertArrayEquals(clone, arr); + } +} diff --git a/apache-kafka-2/README.md b/apache-kafka-2/README.md index dc675a0811..40ee701be1 100644 --- a/apache-kafka-2/README.md +++ b/apache-kafka-2/README.md @@ -13,3 +13,4 @@ You can build the project from the command line using: *mvn clean install*, or i - [Read Data From the Beginning Using Kafka Consumer API](https://www.baeldung.com/java-kafka-consumer-api-read) - [Get Partition Count for a Topic in Kafka](https://www.baeldung.com/java-kafka-partition-count-topic) - [bootstrap-server in Kafka Configuration](https://www.baeldung.com/java-kafka-bootstrap-server) +- [Introduction to Apache Kafka](https://www.baeldung.com/apache-kafka) diff --git a/apache-kafka-2/src/test/java/com/baeldung/kafka/multipletopics/MultipleTopicsLiveTest.java b/apache-kafka-2/src/test/java/com/baeldung/kafka/multipletopics/MultipleTopicsLiveTest.java new file mode 100644 index 0000000000..653456a678 --- /dev/null +++ b/apache-kafka-2/src/test/java/com/baeldung/kafka/multipletopics/MultipleTopicsLiveTest.java @@ -0,0 +1,103 @@ +package com.baeldung.kafka.multipletopics; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.time.Duration; +import java.util.Arrays; +import java.util.Properties; +import java.util.concurrent.ExecutionException; + +import org.apache.kafka.clients.consumer.ConsumerConfig; +import org.apache.kafka.clients.consumer.ConsumerRecord; +import org.apache.kafka.clients.consumer.KafkaConsumer; +import org.apache.kafka.clients.producer.KafkaProducer; +import org.apache.kafka.clients.producer.ProducerConfig; +import org.apache.kafka.clients.producer.ProducerRecord; +import org.apache.kafka.common.serialization.StringDeserializer; +import org.apache.kafka.common.serialization.StringSerializer; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testcontainers.containers.KafkaContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; +import org.testcontainers.utility.DockerImageName; + +// This live test needs a Docker Daemon running so that a kafka container can be created + +@Testcontainers +public class MultipleTopicsLiveTest { + + private final Logger log = LoggerFactory.getLogger(MultipleTopicsLiveTest.class); + + private static final String CARD_PAYMENTS_TOPIC = "card-payments"; + private static final String BANK_TRANSFERS_TOPIC = "bank-transfers"; + private static KafkaProducer producer; + private static KafkaConsumer consumer; + + @Container + private static final KafkaContainer KAFKA_CONTAINER = new KafkaContainer(DockerImageName.parse("confluentinc/cp-kafka:latest")); + + @BeforeAll + static void setup() { + KAFKA_CONTAINER.addExposedPort(9092); + producer = new KafkaProducer<>(getProducerProperties()); + consumer = new KafkaConsumer<>(getConsumerProperties()); + } + + @AfterAll + static void destroy() { + KAFKA_CONTAINER.stop(); + } + + private static Properties getProducerProperties() { + Properties producerProperties = new Properties(); + producerProperties.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, KAFKA_CONTAINER.getBootstrapServers()); + producerProperties.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName()); + producerProperties.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName()); + return producerProperties; + } + + private static Properties getConsumerProperties() { + Properties consumerProperties = new Properties(); + consumerProperties.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, KAFKA_CONTAINER.getBootstrapServers()); + consumerProperties.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName()); + consumerProperties.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName()); + consumerProperties.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "earliest"); + consumerProperties.put(ConsumerConfig.GROUP_ID_CONFIG, "payments"); + return consumerProperties; + } + + @Test + void whenSendingMessagesOnTwoTopics_thenConsumerReceivesMessages() throws Exception { + publishMessages(); + + consumer.subscribe(Arrays.asList(CARD_PAYMENTS_TOPIC, BANK_TRANSFERS_TOPIC)); + + int eventsProcessed = 0; + for (ConsumerRecord record : consumer.poll(Duration.ofSeconds(10))) { + log.info("Event on topic={}, payload={}", record.topic(), record.value()); + eventsProcessed++; + } + + assertThat(eventsProcessed).isEqualTo(2); + } + + private void publishMessages() throws ExecutionException, InterruptedException { + ProducerRecord cardPayment = new ProducerRecord<>(CARD_PAYMENTS_TOPIC, createCardPayment()); + producer.send(cardPayment).get(); + + ProducerRecord bankTransfer = new ProducerRecord<>(BANK_TRANSFERS_TOPIC, createBankTransfer()); + producer.send(bankTransfer).get(); + } + + private String createCardPayment() { + return "{\"paymentReference\":\"A184028KM0013790\", \"type\":\"card\", \"amount\":\"275\", \"currency\":\"GBP\"}"; + } + + private String createBankTransfer() { + return "{\"paymentReference\":\"19ae2-18mk73-009\", \"type\":\"bank\", \"amount\":\"150\", \"currency\":\"EUR\"}"; + } +} diff --git a/apache-poi-3/README.md b/apache-poi-3/README.md new file mode 100644 index 0000000000..9e9d6a94eb --- /dev/null +++ b/apache-poi-3/README.md @@ -0,0 +1,3 @@ +## Relevant Articles +- [How To Convert Excel Data Into List Of Java Objects](https://www.baeldung.com/java-convert-excel-data-into-list) +- [Expand Columns with Apache POI](https://www.baeldung.com/java-apache-poi-expand-columns) diff --git a/aws-modules/aws-dynamodb/.gitignore b/aws-modules/aws-dynamodb/.gitignore new file mode 100644 index 0000000000..bf11a4cc38 --- /dev/null +++ b/aws-modules/aws-dynamodb/.gitignore @@ -0,0 +1,2 @@ +/target/ +.idea/ \ No newline at end of file diff --git a/aws-modules/aws-dynamodb/README.md b/aws-modules/aws-dynamodb/README.md new file mode 100644 index 0000000000..68a353e555 --- /dev/null +++ b/aws-modules/aws-dynamodb/README.md @@ -0,0 +1,7 @@ +## AWS DYNAMODB + +This module contains articles about AWS DynamoDB + +### Relevant articles +- [Integration Testing with a Local DynamoDB Instance](https://www.baeldung.com/dynamodb-local-integration-tests) + diff --git a/aws-modules/aws-dynamodb/pom.xml b/aws-modules/aws-dynamodb/pom.xml new file mode 100644 index 0000000000..37b88327f4 --- /dev/null +++ b/aws-modules/aws-dynamodb/pom.xml @@ -0,0 +1,87 @@ + + + 4.0.0 + aws-dynamodb + 0.1.0-SNAPSHOT + aws-dynamodb + jar + + + com.baeldung + aws-modules + 1.0.0-SNAPSHOT + + + + + com.amazonaws + aws-java-sdk + ${aws-java-sdk.version} + + + com.amazonaws + DynamoDBLocal + ${dynamodblocal.version} + test + + + commons-io + commons-io + ${commons-io.version} + + + com.google.code.gson + gson + ${gson.version} + + + + + + + org.apache.maven.plugins + maven-shade-plugin + ${maven-shade-plugin.version} + + false + + + + package + + shade + + + + + + org.apache.maven.plugins + maven-dependency-plugin + ${maven-plugins-version} + + + copy + compile + + copy-dependencies + + + + so,dll,dylib + native-libs + + + + + + + + + 2.8.0 + 1.21.1 + 3.1.1 + + + \ No newline at end of file diff --git a/aws-modules/aws-miscellaneous/src/main/java/com/baeldung/dynamodb/entity/ProductInfo.java b/aws-modules/aws-dynamodb/src/main/java/com/baeldung/dynamodb/entity/ProductInfo.java similarity index 100% rename from aws-modules/aws-miscellaneous/src/main/java/com/baeldung/dynamodb/entity/ProductInfo.java rename to aws-modules/aws-dynamodb/src/main/java/com/baeldung/dynamodb/entity/ProductInfo.java diff --git a/aws-modules/aws-miscellaneous/src/main/java/com/baeldung/dynamodb/repository/AbstractRepository.java b/aws-modules/aws-dynamodb/src/main/java/com/baeldung/dynamodb/repository/AbstractRepository.java similarity index 100% rename from aws-modules/aws-miscellaneous/src/main/java/com/baeldung/dynamodb/repository/AbstractRepository.java rename to aws-modules/aws-dynamodb/src/main/java/com/baeldung/dynamodb/repository/AbstractRepository.java diff --git a/aws-modules/aws-miscellaneous/src/main/java/com/baeldung/dynamodb/repository/ProductInfoRepository.java b/aws-modules/aws-dynamodb/src/main/java/com/baeldung/dynamodb/repository/ProductInfoRepository.java similarity index 100% rename from aws-modules/aws-miscellaneous/src/main/java/com/baeldung/dynamodb/repository/ProductInfoRepository.java rename to aws-modules/aws-dynamodb/src/main/java/com/baeldung/dynamodb/repository/ProductInfoRepository.java diff --git a/spring-reactive-modules/spring-reactive/src/main/resources/logback.xml b/aws-modules/aws-dynamodb/src/main/resources/logback.xml similarity index 100% rename from spring-reactive-modules/spring-reactive/src/main/resources/logback.xml rename to aws-modules/aws-dynamodb/src/main/resources/logback.xml diff --git a/aws-modules/aws-miscellaneous/src/test/java/com/baeldung/dynamodb/ProductInfoRepositoryIntegrationTest.java b/aws-modules/aws-dynamodb/src/test/java/com/baeldung/dynamodb/ProductInfoRepositoryIntegrationTest.java similarity index 91% rename from aws-modules/aws-miscellaneous/src/test/java/com/baeldung/dynamodb/ProductInfoRepositoryIntegrationTest.java rename to aws-modules/aws-dynamodb/src/test/java/com/baeldung/dynamodb/ProductInfoRepositoryIntegrationTest.java index 18f55544cd..e4dc0c65b8 100644 --- a/aws-modules/aws-miscellaneous/src/test/java/com/baeldung/dynamodb/ProductInfoRepositoryIntegrationTest.java +++ b/aws-modules/aws-dynamodb/src/test/java/com/baeldung/dynamodb/ProductInfoRepositoryIntegrationTest.java @@ -49,10 +49,10 @@ public class ProductInfoRepositoryIntegrationTest { @BeforeClass public static void setupClass() { Properties testProperties = loadFromFileInClasspath("test.properties") - .filter(properties -> !isEmpty(properties.getProperty(AWS_ACCESSKEY))) - .filter(properties -> !isEmpty(properties.getProperty(AWS_SECRETKEY))) - .filter(properties -> !isEmpty(properties.getProperty(DYNAMODB_ENDPOINT))) - .orElseThrow(() -> new RuntimeException("Unable to get all of the required test property values")); + .filter(properties -> !isEmpty(properties.getProperty(AWS_ACCESSKEY))) + .filter(properties -> !isEmpty(properties.getProperty(AWS_SECRETKEY))) + .filter(properties -> !isEmpty(properties.getProperty(DYNAMODB_ENDPOINT))) + .orElseThrow(() -> new RuntimeException("Unable to get all of the required test property values")); String amazonAWSAccessKey = testProperties.getProperty(AWS_ACCESSKEY); String amazonAWSSecretKey = testProperties.getProperty(AWS_SECRETKEY); diff --git a/aws-modules/aws-miscellaneous/src/test/java/com/baeldung/dynamodb/rule/LocalDbCreationRule.java b/aws-modules/aws-dynamodb/src/test/java/com/baeldung/dynamodb/rule/LocalDbCreationRule.java similarity index 100% rename from aws-modules/aws-miscellaneous/src/test/java/com/baeldung/dynamodb/rule/LocalDbCreationRule.java rename to aws-modules/aws-dynamodb/src/test/java/com/baeldung/dynamodb/rule/LocalDbCreationRule.java diff --git a/aws-modules/aws-miscellaneous/src/test/resources/test.properties b/aws-modules/aws-dynamodb/src/test/resources/test.properties similarity index 100% rename from aws-modules/aws-miscellaneous/src/test/resources/test.properties rename to aws-modules/aws-dynamodb/src/test/resources/test.properties diff --git a/aws-modules/aws-miscellaneous/pom.xml b/aws-modules/aws-miscellaneous/pom.xml index 2fb7e397a0..4126256fb9 100644 --- a/aws-modules/aws-miscellaneous/pom.xml +++ b/aws-modules/aws-miscellaneous/pom.xml @@ -16,31 +16,9 @@ - com.amazonaws - aws-java-sdk - ${aws-java-sdk.version} - - - com.amazonaws - aws-lambda-java-core - ${aws-lambda-java-core.version} - - - commons-logging - commons-logging - - - - - com.amazonaws - aws-lambda-java-events - ${aws-lambda-java-events.version} - - - commons-logging - commons-logging - - + software.amazon.awssdk + aws-sdk-java + ${aws-java-sdk-v2.version} commons-io @@ -52,12 +30,6 @@ gson ${gson.version} - - com.amazonaws - DynamoDBLocal - ${dynamodblocal.version} - test - @@ -101,8 +73,6 @@ - 1.3.0 - 1.1.0 2.8.0 1.21.1 1.10.L001 diff --git a/aws-modules/aws-miscellaneous/src/main/java/com/baeldung/ec2/EC2Application.java b/aws-modules/aws-miscellaneous/src/main/java/com/baeldung/ec2/EC2Application.java index 6755188fcd..e12a38e1de 100644 --- a/aws-modules/aws-miscellaneous/src/main/java/com/baeldung/ec2/EC2Application.java +++ b/aws-modules/aws-miscellaneous/src/main/java/com/baeldung/ec2/EC2Application.java @@ -2,136 +2,148 @@ package com.baeldung.ec2; import java.util.Arrays; -import com.amazonaws.auth.AWSCredentials; -import com.amazonaws.auth.AWSStaticCredentialsProvider; -import com.amazonaws.auth.BasicAWSCredentials; -import com.amazonaws.regions.Regions; -import com.amazonaws.services.ec2.AmazonEC2; -import com.amazonaws.services.ec2.AmazonEC2ClientBuilder; -import com.amazonaws.services.ec2.model.AuthorizeSecurityGroupIngressRequest; -import com.amazonaws.services.ec2.model.CreateKeyPairRequest; -import com.amazonaws.services.ec2.model.CreateKeyPairResult; -import com.amazonaws.services.ec2.model.CreateSecurityGroupRequest; -import com.amazonaws.services.ec2.model.DescribeInstancesRequest; -import com.amazonaws.services.ec2.model.DescribeInstancesResult; -import com.amazonaws.services.ec2.model.DescribeKeyPairsRequest; -import com.amazonaws.services.ec2.model.DescribeKeyPairsResult; -import com.amazonaws.services.ec2.model.IpPermission; -import com.amazonaws.services.ec2.model.IpRange; -import com.amazonaws.services.ec2.model.MonitorInstancesRequest; -import com.amazonaws.services.ec2.model.RebootInstancesRequest; -import com.amazonaws.services.ec2.model.RunInstancesRequest; -import com.amazonaws.services.ec2.model.StartInstancesRequest; -import com.amazonaws.services.ec2.model.StopInstancesRequest; -import com.amazonaws.services.ec2.model.UnmonitorInstancesRequest; +import software.amazon.awssdk.auth.credentials.ProfileCredentialsProvider; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.ec2.Ec2Client; +import software.amazon.awssdk.services.ec2.model.AuthorizeSecurityGroupIngressRequest; +import software.amazon.awssdk.services.ec2.model.CreateKeyPairRequest; +import software.amazon.awssdk.services.ec2.model.CreateKeyPairResponse; +import software.amazon.awssdk.services.ec2.model.CreateSecurityGroupRequest; +import software.amazon.awssdk.services.ec2.model.DescribeInstancesRequest; +import software.amazon.awssdk.services.ec2.model.DescribeInstancesResponse; +import software.amazon.awssdk.services.ec2.model.DescribeKeyPairsRequest; +import software.amazon.awssdk.services.ec2.model.DescribeKeyPairsResponse; +import software.amazon.awssdk.services.ec2.model.IpPermission; +import software.amazon.awssdk.services.ec2.model.IpRange; +import software.amazon.awssdk.services.ec2.model.MonitorInstancesRequest; +import software.amazon.awssdk.services.ec2.model.RebootInstancesRequest; +import software.amazon.awssdk.services.ec2.model.RunInstancesRequest; +import software.amazon.awssdk.services.ec2.model.RunInstancesResponse; +import software.amazon.awssdk.services.ec2.model.StartInstancesRequest; +import software.amazon.awssdk.services.ec2.model.StartInstancesResponse; +import software.amazon.awssdk.services.ec2.model.StopInstancesRequest; +import software.amazon.awssdk.services.ec2.model.UnmonitorInstancesRequest; public class EC2Application { - private static final AWSCredentials credentials; - - static { - // put your accesskey and secretkey here - credentials = new BasicAWSCredentials( - "", - "" - ); - } - public static void main(String[] args) { // Set up the client - AmazonEC2 ec2Client = AmazonEC2ClientBuilder.standard() - .withCredentials(new AWSStaticCredentialsProvider(credentials)) - .withRegion(Regions.US_EAST_1) + Ec2Client ec2Client = Ec2Client.builder() + .credentialsProvider(ProfileCredentialsProvider.create("default")) + .region(Region.US_EAST_1) .build(); // Create a security group - CreateSecurityGroupRequest createSecurityGroupRequest = new CreateSecurityGroupRequest().withGroupName("BaeldungSecurityGroup") - .withDescription("Baeldung Security Group"); + CreateSecurityGroupRequest createSecurityGroupRequest = CreateSecurityGroupRequest.builder() + .groupName("BaeldungSecurityGroup") + .description("Baeldung Security Group") + .build(); + ec2Client.createSecurityGroup(createSecurityGroupRequest); // Allow HTTP and SSH traffic - IpRange ipRange1 = new IpRange().withCidrIp("0.0.0.0/0"); + IpRange ipRange1 = IpRange.builder() + .cidrIp("0.0.0.0/0") + .build(); - IpPermission ipPermission1 = new IpPermission().withIpv4Ranges(Arrays.asList(new IpRange[] { ipRange1 })) - .withIpProtocol("tcp") - .withFromPort(80) - .withToPort(80); + IpPermission ipPermission1 = IpPermission.builder() + .ipRanges(Arrays.asList(ipRange1)) + .ipProtocol("tcp") + .fromPort(80) + .toPort(80) + .build(); - IpPermission ipPermission2 = new IpPermission().withIpv4Ranges(Arrays.asList(new IpRange[] { ipRange1 })) - .withIpProtocol("tcp") - .withFromPort(22) - .withToPort(22); + IpPermission ipPermission2 = IpPermission.builder() + .ipRanges(Arrays.asList(ipRange1)) + .ipProtocol("tcp") + .fromPort(22) + .toPort(22) + .build(); - AuthorizeSecurityGroupIngressRequest authorizeSecurityGroupIngressRequest = new AuthorizeSecurityGroupIngressRequest() - .withGroupName("BaeldungSecurityGroup") - .withIpPermissions(ipPermission1, ipPermission2); + AuthorizeSecurityGroupIngressRequest authorizeSecurityGroupIngressRequest = AuthorizeSecurityGroupIngressRequest + .builder() + .groupName("BaeldungSecurityGroup") + .ipPermissions(ipPermission1, ipPermission2) + .build(); ec2Client.authorizeSecurityGroupIngress(authorizeSecurityGroupIngressRequest); // Create KeyPair - CreateKeyPairRequest createKeyPairRequest = new CreateKeyPairRequest() - .withKeyName("baeldung-key-pair"); - CreateKeyPairResult createKeyPairResult = ec2Client.createKeyPair(createKeyPairRequest); - String privateKey = createKeyPairResult - .getKeyPair() - .getKeyMaterial(); // make sure you keep it, the private key, Amazon doesn't store the private key + CreateKeyPairRequest createKeyPairRequest = CreateKeyPairRequest.builder() + .keyName("baeldung-key-pair") + .build(); + + CreateKeyPairResponse createKeyPairResponse = ec2Client.createKeyPair(createKeyPairRequest); + String privateKey = createKeyPairResponse.keyMaterial(); + // make sure you keep it, the private key, Amazon doesn't store the private key // See what key-pairs you've got - DescribeKeyPairsRequest describeKeyPairsRequest = new DescribeKeyPairsRequest(); - DescribeKeyPairsResult describeKeyPairsResult = ec2Client.describeKeyPairs(describeKeyPairsRequest); + DescribeKeyPairsRequest describeKeyPairsRequest = DescribeKeyPairsRequest.builder() + .build(); + DescribeKeyPairsResponse describeKeyPairsResponse = ec2Client.describeKeyPairs(describeKeyPairsRequest); // Launch an Amazon Instance - RunInstancesRequest runInstancesRequest = new RunInstancesRequest().withImageId("ami-97785bed") // https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/AMIs.html | https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/usingsharedamis-finding.html - .withInstanceType("t2.micro") // https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instance-types.html - .withMinCount(1) - .withMaxCount(1) - .withKeyName("baeldung-key-pair") // optional - if not present, can't connect to instance - .withSecurityGroups("BaeldungSecurityGroup"); + RunInstancesRequest runInstancesRequest = RunInstancesRequest.builder() + .imageId("ami-97785bed") + .instanceType("t2.micro") // https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instance-types.html + .minCount(1) + .maxCount(1) + .keyName("baeldung-key-pair") // optional - if not present, can't connect to instance + .securityGroups("BaeldungSecurityGroup") + .build(); - String yourInstanceId = ec2Client.runInstances(runInstancesRequest).getReservation().getInstances().get(0).getInstanceId(); + RunInstancesResponse runInstancesResponse = ec2Client.runInstances(runInstancesRequest); + String yourInstanceId = runInstancesResponse.instances().get(0).instanceId(); // Start an Instance - StartInstancesRequest startInstancesRequest = new StartInstancesRequest() - .withInstanceIds(yourInstanceId); + StartInstancesRequest startInstancesRequest = StartInstancesRequest.builder() + .instanceIds(yourInstanceId) + .build(); + + StartInstancesResponse startInstancesResponse = ec2Client.startInstances(startInstancesRequest); - ec2Client.startInstances(startInstancesRequest); // Monitor Instances - MonitorInstancesRequest monitorInstancesRequest = new MonitorInstancesRequest() - .withInstanceIds(yourInstanceId); + MonitorInstancesRequest monitorInstancesRequest = MonitorInstancesRequest.builder() + .instanceIds(yourInstanceId) + .build(); + ec2Client.monitorInstances(monitorInstancesRequest); - UnmonitorInstancesRequest unmonitorInstancesRequest = new UnmonitorInstancesRequest() - .withInstanceIds(yourInstanceId); + UnmonitorInstancesRequest unmonitorInstancesRequest = UnmonitorInstancesRequest.builder() + .instanceIds(yourInstanceId) + .build(); ec2Client.unmonitorInstances(unmonitorInstancesRequest); // Reboot an Instance - - RebootInstancesRequest rebootInstancesRequest = new RebootInstancesRequest() - .withInstanceIds(yourInstanceId); + RebootInstancesRequest rebootInstancesRequest = RebootInstancesRequest.builder() + .instanceIds(yourInstanceId) + .build(); ec2Client.rebootInstances(rebootInstancesRequest); // Stop an Instance - StopInstancesRequest stopInstancesRequest = new StopInstancesRequest() - .withInstanceIds(yourInstanceId); + StopInstancesRequest stopInstancesRequest = StopInstancesRequest.builder() + .instanceIds(yourInstanceId) + .build(); + ec2Client.stopInstances(stopInstancesRequest) - .getStoppingInstances() + .stoppingInstances() .get(0) - .getPreviousState() - .getName(); + .previousState() + .name(); // Describe an Instance - DescribeInstancesRequest describeInstancesRequest = new DescribeInstancesRequest(); - DescribeInstancesResult response = ec2Client.describeInstances(describeInstancesRequest); - System.out.println(response.getReservations() + DescribeInstancesRequest describeInstancesRequest = DescribeInstancesRequest.builder().build(); + DescribeInstancesResponse response = ec2Client.describeInstances(describeInstancesRequest); + System.out.println(response.reservations() .get(0) - .getInstances() + .instances() .get(0) - .getKernelId()); + .kernelId()); } } diff --git a/aws-modules/aws-miscellaneous/src/main/java/com/baeldung/rds/AWSRDSService.java b/aws-modules/aws-miscellaneous/src/main/java/com/baeldung/rds/AWSRDSService.java index d4da92f30f..09309b92bb 100644 --- a/aws-modules/aws-miscellaneous/src/main/java/com/baeldung/rds/AWSRDSService.java +++ b/aws-modules/aws-miscellaneous/src/main/java/com/baeldung/rds/AWSRDSService.java @@ -1,13 +1,5 @@ package com.baeldung.rds; -import com.amazonaws.auth.AWSCredentialsProvider; -import com.amazonaws.auth.AWSStaticCredentialsProvider; -import com.amazonaws.auth.BasicAWSCredentials; -import com.amazonaws.regions.Regions; -import com.amazonaws.services.rds.AmazonRDS; -import com.amazonaws.services.rds.AmazonRDSClientBuilder; -import com.amazonaws.services.rds.model.*; - import java.io.IOException; import java.io.InputStream; import java.sql.*; @@ -16,12 +8,22 @@ import java.util.Properties; import java.util.UUID; import java.util.logging.Logger; +import software.amazon.awssdk.auth.credentials.ProfileCredentialsProvider; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.rds.RdsClient; +import software.amazon.awssdk.services.rds.model.CreateDbInstanceRequest; +import software.amazon.awssdk.services.rds.model.CreateDbInstanceResponse; +import software.amazon.awssdk.services.rds.model.DBInstance; +import software.amazon.awssdk.services.rds.model.DeleteDbInstanceRequest; +import software.amazon.awssdk.services.rds.model.DeleteDbInstanceResponse; +import software.amazon.awssdk.services.rds.model.DescribeDbInstancesResponse; +import software.amazon.awssdk.services.rds.model.Endpoint; + public class AWSRDSService { final static Logger logger = Logger.getLogger(AWSRDSService.class.getName()); - private AWSCredentialsProvider credentials; - private AmazonRDS amazonRDS; + private RdsClient rdsClient; private String db_username; private String db_password; private String db_database; @@ -34,22 +36,17 @@ public class AWSRDSService { * **/ public AWSRDSService() throws IOException { //Init RDS client with credentials and region. - credentials = new - AWSStaticCredentialsProvider(new - BasicAWSCredentials("", - "")); - amazonRDS = AmazonRDSClientBuilder.standard().withCredentials(credentials) - .withRegion(Regions.AP_SOUTHEAST_2).build(); Properties prop = new Properties(); InputStream input = AWSRDSService.class.getClassLoader().getResourceAsStream("db.properties"); prop.load(input); db_username = prop.getProperty("db_username"); db_password = prop.getProperty("db_password"); db_database = prop.getProperty("db_database"); - } - public AWSRDSService(AmazonRDS amazonRDS){ - this.amazonRDS = amazonRDS; + rdsClient = RdsClient.builder() + .region(Region.AP_SOUTHEAST_2) + .credentialsProvider(ProfileCredentialsProvider.create("default")) + .build(); } /** @@ -60,29 +57,29 @@ public class AWSRDSService { public String launchInstance() { String identifier = ""; - CreateDBInstanceRequest request = new CreateDBInstanceRequest(); - // RDS instance name - request.setDBInstanceIdentifier("Sydney"); - request.setEngine("postgres"); - request.setMultiAZ(false); - request.setMasterUsername(db_username); - request.setMasterUserPassword(db_password); - request.setDBName(db_database); - request.setStorageType("gp2"); - request.setAllocatedStorage(10); + CreateDbInstanceRequest instanceRequest = CreateDbInstanceRequest.builder() + .dbInstanceIdentifier("Sydney") + .engine("postgres") + .multiAZ(false) + .masterUsername(db_username) + .masterUserPassword(db_password) + .dbName(db_database) + .storageType("gp2") + .allocatedStorage(10) + .build(); - DBInstance instance = amazonRDS.createDBInstance(request); + CreateDbInstanceResponse createDbInstanceResponse = rdsClient.createDBInstance(instanceRequest); // Information about the new RDS instance - identifier = instance.getDBInstanceIdentifier(); - String status = instance.getDBInstanceStatus(); - Endpoint endpoint = instance.getEndpoint(); - String endpoint_url = "Endpoint URL not available yet."; + identifier = createDbInstanceResponse.dbInstance().dbInstanceIdentifier(); + String status = createDbInstanceResponse.dbInstance().dbInstanceStatus(); + Endpoint endpoint = createDbInstanceResponse.dbInstance().endpoint(); + String endpointUrl = "Endpoint URL not available yet."; if (endpoint != null) { - endpoint_url = endpoint.toString(); + endpointUrl = endpoint.toString(); } logger.info(identifier + "\t" + status); - logger.info(endpoint_url); + logger.info(endpointUrl); return identifier; @@ -90,44 +87,44 @@ public class AWSRDSService { // Describe DB instances public void listInstances() { - DescribeDBInstancesResult result = amazonRDS.describeDBInstances(); - List instances = result.getDBInstances(); + DescribeDbInstancesResponse response = rdsClient.describeDBInstances(); + List instances = response.dbInstances(); for (DBInstance instance : instances) { // Information about each RDS instance - String identifier = instance.getDBInstanceIdentifier(); - String engine = instance.getEngine(); - String status = instance.getDBInstanceStatus(); - Endpoint endpoint = instance.getEndpoint(); - String endpoint_url = "Endpoint URL not available yet."; + String identifier = instance.dbInstanceIdentifier(); + String engine = instance.engine(); + String status = instance.dbInstanceStatus(); + Endpoint endpoint = instance.endpoint(); + String endpointUrl = "Endpoint URL not available yet."; if (endpoint != null) { - endpoint_url = endpoint.toString(); + endpointUrl = endpoint.toString(); } logger.info(identifier + "\t" + engine + "\t" + status); - logger.info("\t" + endpoint_url); + logger.info("\t" + endpointUrl); } - } //Delete RDS instance public void terminateInstance(String identifier) { - DeleteDBInstanceRequest request = new DeleteDBInstanceRequest(); - request.setDBInstanceIdentifier(identifier); - request.setSkipFinalSnapshot(true); + DeleteDbInstanceRequest request = DeleteDbInstanceRequest.builder() + .dbInstanceIdentifier(identifier) + .skipFinalSnapshot(true) + .build(); // Delete the RDS instance - DBInstance instance = amazonRDS.deleteDBInstance(request); + DeleteDbInstanceResponse response = rdsClient.deleteDBInstance(request); // Information about the RDS instance being deleted - String status = instance.getDBInstanceStatus(); - Endpoint endpoint = instance.getEndpoint(); - String endpoint_url = "Endpoint URL not available yet."; + String status = response.dbInstance().dbInstanceStatus(); + Endpoint endpoint = response.dbInstance().endpoint(); + String endpointUrl = "Endpoint URL not available yet."; if (endpoint != null) { - endpoint_url = endpoint.toString(); + endpointUrl = endpoint.toString(); } logger.info(identifier + "\t" + status); - logger.info(endpoint_url); + logger.info(endpointUrl); } diff --git a/aws-modules/aws-miscellaneous/src/main/java/com/baeldung/sqs/SQSApplication.java b/aws-modules/aws-miscellaneous/src/main/java/com/baeldung/sqs/SQSApplication.java index 978506a24f..3b78d73f60 100644 --- a/aws-modules/aws-miscellaneous/src/main/java/com/baeldung/sqs/SQSApplication.java +++ b/aws-modules/aws-miscellaneous/src/main/java/com/baeldung/sqs/SQSApplication.java @@ -5,140 +5,190 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import com.amazonaws.auth.AWSCredentials; -import com.amazonaws.auth.AWSStaticCredentialsProvider; -import com.amazonaws.auth.BasicAWSCredentials; -import com.amazonaws.regions.Regions; -import com.amazonaws.services.sqs.AmazonSQSClientBuilder; -import com.amazonaws.services.sqs.model.CreateQueueRequest; -import com.amazonaws.services.sqs.model.DeleteMessageRequest; -import com.amazonaws.services.sqs.model.GetQueueAttributesRequest; -import com.amazonaws.services.sqs.model.GetQueueAttributesResult; -import com.amazonaws.services.sqs.model.MessageAttributeValue; -import com.amazonaws.services.sqs.model.ReceiveMessageRequest; -import com.amazonaws.services.sqs.model.SendMessageBatchRequest; -import com.amazonaws.services.sqs.model.SendMessageRequest; -import com.amazonaws.services.sqs.model.SetQueueAttributesRequest; -import com.amazonaws.services.sqs.model.SendMessageBatchRequestEntry; -import com.amazonaws.services.sqs.model.Message; -import com.amazonaws.services.sqs.AmazonSQS; +import software.amazon.awssdk.auth.credentials.ProfileCredentialsProvider; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.sqs.SqsClient; +import software.amazon.awssdk.services.sqs.model.CreateQueueRequest; +import software.amazon.awssdk.services.sqs.model.DeleteMessageRequest; +import software.amazon.awssdk.services.sqs.model.GetQueueAttributesRequest; +import software.amazon.awssdk.services.sqs.model.GetQueueAttributesResponse; +import software.amazon.awssdk.services.sqs.model.GetQueueUrlRequest; +import software.amazon.awssdk.services.sqs.model.GetQueueUrlResponse; +import software.amazon.awssdk.services.sqs.model.Message; +import software.amazon.awssdk.services.sqs.model.MessageAttributeValue; +import software.amazon.awssdk.services.sqs.model.QueueAttributeName; +import software.amazon.awssdk.services.sqs.model.ReceiveMessageRequest; +import software.amazon.awssdk.services.sqs.model.SendMessageBatchRequest; +import software.amazon.awssdk.services.sqs.model.SendMessageBatchRequestEntry; +import software.amazon.awssdk.services.sqs.model.SendMessageRequest; +import software.amazon.awssdk.services.sqs.model.SetQueueAttributesRequest; public class SQSApplication { - private static final AWSCredentials credentials; - - static { - // put your accesskey and secretkey here - credentials = new BasicAWSCredentials( - "", - "" - ); - } + private static final String STANDARD_QUEUE_NAME = "baeldung-queue"; + private static final String FIFO_QUEUE_NAME = "baeldung-queue.fifo"; + private static final String DEAD_LETTER_QUEUE_NAME = "baeldung-dead-letter-queue"; public static void main(String[] args) { // Set up the client - AmazonSQS sqs = AmazonSQSClientBuilder.standard() - .withCredentials(new AWSStaticCredentialsProvider(credentials)) - .withRegion(Regions.US_EAST_1) + SqsClient sqsClient = SqsClient.builder() + .region(Region.US_EAST_1) + .credentialsProvider(ProfileCredentialsProvider.create()) .build(); // Create a standard queue + CreateQueueRequest createStandardQueueRequest = CreateQueueRequest.builder() + .queueName(STANDARD_QUEUE_NAME) + .build(); - CreateQueueRequest createStandardQueueRequest = new CreateQueueRequest("baeldung-queue"); - String standardQueueUrl = sqs.createQueue(createStandardQueueRequest) - .getQueueUrl(); + sqsClient.createQueue(createStandardQueueRequest); + + System.out.println("\nGet queue url"); + + GetQueueUrlResponse getQueueUrlResponse = sqsClient.getQueueUrl(GetQueueUrlRequest.builder() + .queueName(STANDARD_QUEUE_NAME) + .build()); + String standardQueueUrl = getQueueUrlResponse.queueUrl(); System.out.println(standardQueueUrl); // Create a fifo queue + Map queueAttributes = new HashMap<>(); + queueAttributes.put(QueueAttributeName.FIFO_QUEUE, "true"); + queueAttributes.put(QueueAttributeName.CONTENT_BASED_DEDUPLICATION, "true"); - Map queueAttributes = new HashMap(); - queueAttributes.put("FifoQueue", "true"); - queueAttributes.put("ContentBasedDeduplication", "true"); + CreateQueueRequest createFifoQueueRequest = CreateQueueRequest.builder() + .queueName(FIFO_QUEUE_NAME) + .attributes(queueAttributes) + .build(); - CreateQueueRequest createFifoQueueRequest = new CreateQueueRequest("baeldung-queue.fifo").withAttributes(queueAttributes); - String fifoQueueUrl = sqs.createQueue(createFifoQueueRequest) - .getQueueUrl(); + sqsClient.createQueue(createFifoQueueRequest); + + GetQueueUrlResponse getFifoQueueUrlResponse = sqsClient.getQueueUrl(GetQueueUrlRequest.builder() + .queueName(FIFO_QUEUE_NAME) + .build()); + + String fifoQueueUrl = getFifoQueueUrlResponse.queueUrl(); System.out.println(fifoQueueUrl); // Set up a dead letter queue + CreateQueueRequest createDeadLetterQueueRequest = CreateQueueRequest.builder() + .queueName(DEAD_LETTER_QUEUE_NAME) + .build(); - String deadLetterQueueUrl = sqs.createQueue("baeldung-dead-letter-queue") - .getQueueUrl(); + String deadLetterQueueUrl = sqsClient.createQueue(createDeadLetterQueueRequest) + .queueUrl(); - GetQueueAttributesResult deadLetterQueueAttributes = sqs.getQueueAttributes(new GetQueueAttributesRequest(deadLetterQueueUrl).withAttributeNames("QueueArn")); + GetQueueAttributesRequest getQueueAttributesRequest = GetQueueAttributesRequest.builder() + .queueUrl(deadLetterQueueUrl) + .attributeNames(QueueAttributeName.QUEUE_ARN) + .build(); - String deadLetterQueueARN = deadLetterQueueAttributes.getAttributes() + GetQueueAttributesResponse deadLetterQueueAttributes = sqsClient.getQueueAttributes(getQueueAttributesRequest); + + String deadLetterQueueARN = deadLetterQueueAttributes.attributes() .get("QueueArn"); - SetQueueAttributesRequest queueAttributesRequest = new SetQueueAttributesRequest().withQueueUrl(standardQueueUrl) - .addAttributesEntry("RedrivePolicy", "{\"maxReceiveCount\":\"2\", " + "\"deadLetterTargetArn\":\"" + deadLetterQueueARN + "\"}"); + Map attributes = new HashMap<>(); + attributes.put(QueueAttributeName.REDRIVE_POLICY, "{\"maxReceiveCount\":\"5\", \"deadLetterTargetArn\":\"" + deadLetterQueueARN + "\"}"); - sqs.setQueueAttributes(queueAttributesRequest); + SetQueueAttributesRequest queueAttributesRequest = SetQueueAttributesRequest.builder() + .queueUrl(standardQueueUrl) + .attributes(attributes) + .build(); + + sqsClient.setQueueAttributes(queueAttributesRequest); // Send a message to a standard queue Map messageAttributes = new HashMap<>(); + MessageAttributeValue messageAttributeValue = MessageAttributeValue.builder() + .stringValue("This is an attribute") + .dataType("String") + .build(); - messageAttributes.put("AttributeOne", new MessageAttributeValue().withStringValue("This is an attribute") - .withDataType("String")); + messageAttributes.put("AttributeOne", messageAttributeValue); - SendMessageRequest sendMessageStandardQueue = new SendMessageRequest().withQueueUrl(standardQueueUrl) - .withMessageBody("A simple message.") - .withDelaySeconds(30) // Message will arrive in the queue after 30 seconds. We can use this only in standard queues - .withMessageAttributes(messageAttributes); + SendMessageRequest sendMessageStandardQueue = SendMessageRequest.builder() + .queueUrl(standardQueueUrl) + .messageBody("A simple message.") + .delaySeconds(30) // Message will arrive in the queue after 30 seconds. We can use this only in standard queues + .messageAttributes(messageAttributes) + .build(); - sqs.sendMessage(sendMessageStandardQueue); + sqsClient.sendMessage(sendMessageStandardQueue); // Send a message to a fifo queue - SendMessageRequest sendMessageFifoQueue = new SendMessageRequest().withQueueUrl(fifoQueueUrl) - .withMessageBody("FIFO Queue") - .withMessageGroupId("baeldung-group-1") - .withMessageAttributes(messageAttributes); + SendMessageRequest sendMessageFifoQueue = SendMessageRequest.builder() + .queueUrl(fifoQueueUrl) + .messageBody("FIFO Queue") + .messageGroupId("baeldung-group-1") + .messageAttributes(messageAttributes) + .build(); - sqs.sendMessage(sendMessageFifoQueue); + sqsClient.sendMessage(sendMessageFifoQueue); // Send multiple messages List messageEntries = new ArrayList<>(); - messageEntries.add(new SendMessageBatchRequestEntry().withId("id-1") - .withMessageBody("batch-1") - .withMessageGroupId("baeldung-group-1")); - messageEntries.add(new SendMessageBatchRequestEntry().withId("id-2") - .withMessageBody("batch-2") - .withMessageGroupId("baeldung-group-1")); + SendMessageBatchRequestEntry messageBatchRequestEntry1 = SendMessageBatchRequestEntry.builder() + .id("id-1") + .messageBody("batch-1") + .messageGroupId("baeldung-group-1") + .build(); - SendMessageBatchRequest sendMessageBatchRequest = new SendMessageBatchRequest(fifoQueueUrl, messageEntries); - sqs.sendMessageBatch(sendMessageBatchRequest); + SendMessageBatchRequestEntry messageBatchRequestEntry2 = SendMessageBatchRequestEntry.builder() + .id("id-2") + .messageBody("batch-2") + .messageGroupId("baeldung-group-1") + .build(); + + messageEntries.add(messageBatchRequestEntry1); + messageEntries.add(messageBatchRequestEntry2); + + SendMessageBatchRequest sendMessageBatchRequest = SendMessageBatchRequest.builder() + .queueUrl(fifoQueueUrl) + .entries(messageEntries) + .build(); + + sqsClient.sendMessageBatch(sendMessageBatchRequest); // Read a message from a queue - ReceiveMessageRequest receiveMessageRequest = new ReceiveMessageRequest(fifoQueueUrl).withWaitTimeSeconds(10) // Long polling; - .withMaxNumberOfMessages(1); // Max is 10 + ReceiveMessageRequest receiveMessageRequest = ReceiveMessageRequest.builder() + .waitTimeSeconds(10) + .maxNumberOfMessages(10) + .build(); - List sqsMessages = sqs.receiveMessage(receiveMessageRequest) - .getMessages(); + List sqsMessages = sqsClient.receiveMessage(receiveMessageRequest) + .messages(); sqsMessages.get(0) - .getAttributes(); + .attributes(); sqsMessages.get(0) - .getBody(); + .body(); // Delete a message from a queue + DeleteMessageRequest deleteMessageRequest = DeleteMessageRequest.builder() + .queueUrl(fifoQueueUrl) + .receiptHandle(sqsMessages.get(0) + .receiptHandle()) + .build(); - sqs.deleteMessage(new DeleteMessageRequest().withQueueUrl(fifoQueueUrl) - .withReceiptHandle(sqsMessages.get(0) - .getReceiptHandle())); + sqsClient.deleteMessage(deleteMessageRequest); // Monitoring - GetQueueAttributesRequest getQueueAttributesRequest = new GetQueueAttributesRequest(standardQueueUrl).withAttributeNames("All"); - GetQueueAttributesResult getQueueAttributesResult = sqs.getQueueAttributes(getQueueAttributesRequest); - System.out.println(String.format("The number of messages on the queue: %s", getQueueAttributesResult.getAttributes() + GetQueueAttributesRequest getQueueAttributesRequestForMonitoring = GetQueueAttributesRequest.builder() + .queueUrl(standardQueueUrl) + .build(); + + GetQueueAttributesResponse attributesResponse = sqsClient.getQueueAttributes(getQueueAttributesRequestForMonitoring); + System.out.println(String.format("The number of messages on the queue: %s", attributesResponse.attributes() .get("ApproximateNumberOfMessages"))); - System.out.println(String.format("The number of messages in flight: %s", getQueueAttributesResult.getAttributes() + System.out.println(String.format("The number of messages in flight: %s", attributesResponse.attributes() .get("ApproximateNumberOfMessagesNotVisible"))); } diff --git a/aws-modules/pom.xml b/aws-modules/pom.xml index b94faafa86..66fa4bffa1 100644 --- a/aws-modules/pom.xml +++ b/aws-modules/pom.xml @@ -5,6 +5,14 @@ 4.0.0 aws-modules aws-modules + + + com.amazonaws + aws-java-sdk-dynamodb + 1.12.523 + compile + + pom @@ -15,6 +23,7 @@ aws-app-sync + aws-dynamodb aws-lambda-modules aws-miscellaneous aws-reactive @@ -24,6 +33,7 @@ 1.12.331 + 2.20.147 3.0.0 diff --git a/core-java-modules/core-java-16/README.md b/core-java-modules/core-java-16/README.md index b2740d194c..11b0fba8d3 100644 --- a/core-java-modules/core-java-16/README.md +++ b/core-java-modules/core-java-16/README.md @@ -5,3 +5,4 @@ - [Collecting Stream Elements into a List in Java](https://www.baeldung.com/java-stream-to-list-collecting) - [New Features in Java 16](https://www.baeldung.com/java-16-new-features) - [Guide to Java 8 groupingBy Collector](https://www.baeldung.com/java-groupingby-collector) +- [Value-Based Classes in Java](https://www.baeldung.com/java-value-based-classes) diff --git a/core-java-modules/core-java-16/src/main/java/com/baeldung/value_based_class/Point.java b/core-java-modules/core-java-16/src/main/java/com/baeldung/value_based_class/Point.java index 13e2238274..a3055985af 100644 --- a/core-java-modules/core-java-16/src/main/java/com/baeldung/value_based_class/Point.java +++ b/core-java-modules/core-java-16/src/main/java/com/baeldung/value_based_class/Point.java @@ -30,6 +30,11 @@ public final class Point { return new Point(x, y, z); } + @Override + public String toString() { + return "Point{" + "x=" + x + ", y=" + y + ", z=" + z + '}'; + } + @Override public boolean equals(Object other) { if (other == null || getClass() != other.getClass()) diff --git a/core-java-modules/core-java-16/src/test/java/com/baeldung/value_based_class/ValueBasedClassUnitTest.java b/core-java-modules/core-java-16/src/test/java/com/baeldung/value_based_class/ValueBasedClassUnitTest.java index 781f368982..fe031a652f 100644 --- a/core-java-modules/core-java-16/src/test/java/com/baeldung/value_based_class/ValueBasedClassUnitTest.java +++ b/core-java-modules/core-java-16/src/test/java/com/baeldung/value_based_class/ValueBasedClassUnitTest.java @@ -1,14 +1,17 @@ package com.baeldung.value_based_class; +import java.util.ArrayList; +import java.util.List; + import org.junit.Assert; import org.junit.Test; public class ValueBasedClassUnitTest { @Test public void givenAutoboxedAndPrimitive_whenCompared_thenReturnEquals() { - int primitive_a = 125; - Integer obj_a = 125; // this is autoboxed - Assert.assertSame(primitive_a, obj_a); + List list = new ArrayList<>(); + list.add(1); // this is autoboxed + Assert.assertEquals(list.get(0), Integer.valueOf(1)); } @Test diff --git a/core-java-modules/core-java-17/src/test/java/com/baeldung/recordproperties/ReadRecordPropertiesByReflectionUnitTest.java b/core-java-modules/core-java-17/src/test/java/com/baeldung/recordproperties/ReadRecordPropertiesByReflectionUnitTest.java new file mode 100644 index 0000000000..4ffe3ecbeb --- /dev/null +++ b/core-java-modules/core-java-17/src/test/java/com/baeldung/recordproperties/ReadRecordPropertiesByReflectionUnitTest.java @@ -0,0 +1,89 @@ +package com.baeldung.recordproperties; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.lang.reflect.Field; +import java.lang.reflect.RecordComponent; +import java.util.ArrayList; + +import org.junit.jupiter.api.Test; + +record Player(String name, int age, Long score) { +} + +public class ReadRecordPropertiesByReflectionUnitTest { + private static final Player ERIC = new Player("Eric", 28, 4242L); + + @Test + void whenUsingRecordComponent_thenGetExpectedResult() { + var fields = new ArrayList(); + RecordComponent[] components = Player.class.getRecordComponents(); + for (var comp : components) { + try { + Field field = ERIC.getClass() + .getDeclaredField(comp.getName()); + field.setAccessible(true); + fields.add(field); + } catch (NoSuchFieldException e) { + // for simplicity, error handling is skipped + } + } + + assertEquals(3, fields.size()); + + var nameField = fields.get(0); + var ageField = fields.get(1); + var scoreField = fields.get(2); + try { + assertEquals("name", nameField.getName()); + assertEquals(String.class, nameField.getType()); + assertEquals("Eric", nameField.get(ERIC)); + + assertEquals("age", ageField.getName()); + assertEquals(int.class, ageField.getType()); + assertEquals(28, ageField.get(ERIC)); + + assertEquals("score", scoreField.getName()); + assertEquals(Long.class, scoreField.getType()); + assertEquals(4242L, scoreField.get(ERIC)); + } catch (IllegalAccessException exception) { + // for simplicity, error handling is skipped + } + + } + + @Test + void whenUsingClassGetDeclaredField_thenGetExpectedResult() { + // record has no public fields + assertEquals(0, Player.class.getFields().length); + + var fields = new ArrayList(); + for (var field : Player.class.getDeclaredFields()) { + field.setAccessible(true); + fields.add(field); + } + + assertEquals(3, fields.size()); + var nameField = fields.get(0); + var ageField = fields.get(1); + var scoreField = fields.get(2); + + try { + assertEquals("name", nameField.getName()); + assertEquals(String.class, nameField.getType()); + assertEquals("Eric", nameField.get(ERIC)); + + assertEquals("age", ageField.getName()); + assertEquals(int.class, ageField.getType()); + assertEquals(28, ageField.get(ERIC)); + + assertEquals("score", scoreField.getName()); + assertEquals(Long.class, scoreField.getType()); + assertEquals(4242L, scoreField.get(ERIC)); + } catch (IllegalAccessException ex) { + // for simplicity, error handling is skipped + } + + } + +} \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-autoconfiguration/src/main/resources/META-INF/spring.factories b/core-java-modules/core-java-18/README.md similarity index 100% rename from spring-boot-modules/spring-boot-autoconfiguration/src/main/resources/META-INF/spring.factories rename to core-java-modules/core-java-18/README.md diff --git a/core-java-modules/core-java-18/pom.xml b/core-java-modules/core-java-18/pom.xml new file mode 100644 index 0000000000..7af6258497 --- /dev/null +++ b/core-java-modules/core-java-18/pom.xml @@ -0,0 +1,55 @@ + + + 4.0.0 + core-java-18 + core-java-18 + jar + + + com.baeldung + parent-modules + 1.0.0-SNAPSHOT + ../../ + + + + + + org.apache.maven.plugins + maven-compiler-plugin + ${maven-compiler-plugin.version} + + ${maven.compiler.release} + --enable-preview + ${maven.compiler.source.version} + ${maven.compiler.target.version} + + + + org.apache.maven.plugins + maven-surefire-plugin + ${surefire.plugin.version} + + 1 + + + + org.apache.maven.surefire + surefire-api + ${surefire.plugin.version} + + + + + + + + 18 + 18 + 18 + 3.0.0-M5 + + + \ No newline at end of file diff --git a/core-java-modules/core-java-18/src/main/java/com/baeldung/finalization_closeable_cleaner/FinalizationExamples.java b/core-java-modules/core-java-18/src/main/java/com/baeldung/finalization_closeable_cleaner/FinalizationExamples.java new file mode 100644 index 0000000000..3ff77c37d6 --- /dev/null +++ b/core-java-modules/core-java-18/src/main/java/com/baeldung/finalization_closeable_cleaner/FinalizationExamples.java @@ -0,0 +1,27 @@ +package com.baeldung.finalization_closeable_cleaner; + +import java.io.FileInputStream; +import java.io.IOException; + +public class FinalizationExamples { + FileInputStream fis = null; + + public void readFileOperationWithFinalization() throws IOException { + try { + fis = new FileInputStream("input.txt"); + // perform operation on the file + System.out.println(fis.readAllBytes().length); + + } finally { + if (fis != null) + fis.close(); + } + } + + public void readFileOperationWithTryWith() throws IOException { + try (FileInputStream fis = new FileInputStream("input.txt")) { + // perform operations + System.out.println(fis.readAllBytes().length); + } + } +} diff --git a/core-java-modules/core-java-18/src/main/java/com/baeldung/finalization_closeable_cleaner/MyCleanerResourceClass.java b/core-java-modules/core-java-18/src/main/java/com/baeldung/finalization_closeable_cleaner/MyCleanerResourceClass.java new file mode 100644 index 0000000000..1dcdd216cb --- /dev/null +++ b/core-java-modules/core-java-18/src/main/java/com/baeldung/finalization_closeable_cleaner/MyCleanerResourceClass.java @@ -0,0 +1,48 @@ +package com.baeldung.finalization_closeable_cleaner; + +import java.lang.ref.Cleaner; + +public class MyCleanerResourceClass implements AutoCloseable { + private static Resource resource; + + private static final Cleaner cleaner = Cleaner.create(); + private final Cleaner.Cleanable cleanable; + + public MyCleanerResourceClass() { + resource = new Resource(); + this.cleanable = cleaner.register(this, new CleaningState()); + } + + public void useResource() { + // using the resource here + resource.use(); + } + + @Override + public void close() { + // perform actions to close all underlying resources + this.cleanable.clean(); + } + + static class CleaningState implements Runnable { + CleaningState() { + // constructor + } + + @Override + public void run() { + // some cleanup action + System.out.println("Cleanup done"); + } + } + + static class Resource { + void use() { + System.out.println("Using the resource"); + } + + void close() { + System.out.println("Cleanup done"); + } + } +} diff --git a/core-java-modules/core-java-18/src/main/java/com/baeldung/finalization_closeable_cleaner/MyCloseableResourceClass.java b/core-java-modules/core-java-18/src/main/java/com/baeldung/finalization_closeable_cleaner/MyCloseableResourceClass.java new file mode 100644 index 0000000000..b11cb4e49e --- /dev/null +++ b/core-java-modules/core-java-18/src/main/java/com/baeldung/finalization_closeable_cleaner/MyCloseableResourceClass.java @@ -0,0 +1,25 @@ +package com.baeldung.finalization_closeable_cleaner; + +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; + +public class MyCloseableResourceClass implements AutoCloseable { + + private final FileInputStream fis; + + public MyCloseableResourceClass() throws FileNotFoundException { + this.fis = new FileInputStream("src/main/resources/file.txt"); + + } + + public int getByteLength() throws IOException { + System.out.println("Some operation"); + return this.fis.readAllBytes().length; + } + @Override + public void close() throws IOException { + System.out.println("Finalized object"); + this.fis.close(); + } +} diff --git a/core-java-modules/core-java-18/src/main/java/com/baeldung/finalization_closeable_cleaner/MyFinalizableResourceClass.java b/core-java-modules/core-java-18/src/main/java/com/baeldung/finalization_closeable_cleaner/MyFinalizableResourceClass.java new file mode 100644 index 0000000000..a2c6a123b4 --- /dev/null +++ b/core-java-modules/core-java-18/src/main/java/com/baeldung/finalization_closeable_cleaner/MyFinalizableResourceClass.java @@ -0,0 +1,24 @@ +package com.baeldung.finalization_closeable_cleaner; + +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; + +public class MyFinalizableResourceClass { + private FileInputStream fis; + + public MyFinalizableResourceClass() throws FileNotFoundException { + this.fis = new FileInputStream("src/main/resources/file.txt"); + } + + public int getByteLength() throws IOException { + System.out.println("Some operation"); + return this.fis.readAllBytes().length; + } + + @Override + protected void finalize() throws Throwable { + System.out.println("Finalized object"); + this.fis.close(); + } +} diff --git a/core-java-modules/core-java-18/src/main/resources/file.txt b/core-java-modules/core-java-18/src/main/resources/file.txt new file mode 100644 index 0000000000..af27ff4986 --- /dev/null +++ b/core-java-modules/core-java-18/src/main/resources/file.txt @@ -0,0 +1 @@ +This is a test file. \ No newline at end of file diff --git a/core-java-modules/core-java-18/src/test/java/com/baeldung/finalization_closeable_cleaner/FinalizationCloseableCleanerUnitTest.java b/core-java-modules/core-java-18/src/test/java/com/baeldung/finalization_closeable_cleaner/FinalizationCloseableCleanerUnitTest.java new file mode 100644 index 0000000000..22ff228227 --- /dev/null +++ b/core-java-modules/core-java-18/src/test/java/com/baeldung/finalization_closeable_cleaner/FinalizationCloseableCleanerUnitTest.java @@ -0,0 +1,36 @@ +package com.baeldung.finalization_closeable_cleaner; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + +import java.io.IOException; + +import org.junit.Assert; +import org.junit.Test; + +public class FinalizationCloseableCleanerUnitTest { + + @Test + public void givenMyFinalizationResource_whenUsingFinalize_thenShouldClean() { + assertDoesNotThrow(() -> { + MyFinalizableResourceClass mfr = new MyFinalizableResourceClass(); + mfr.getByteLength(); + }); + } + @Test + public void givenMyCleanerResource_whenUsingCleanerAPI_thenShouldClean() { + assertDoesNotThrow(() -> { + try (MyCleanerResourceClass myCleanerResourceClass = new MyCleanerResourceClass()) { + myCleanerResourceClass.useResource(); + } + }); + } + + @Test + public void givenCloseableResource_whenUsingTryWith_thenShouldClose() throws IOException { + int length = 0; + try (MyCloseableResourceClass mcr = new MyCloseableResourceClass()) { + length = mcr.getByteLength(); + } + Assert.assertEquals(20, length); + } +} diff --git a/core-java-modules/core-java-21/README.md b/core-java-modules/core-java-21/README.md index 2e7130c906..ffb999a4ba 100644 --- a/core-java-modules/core-java-21/README.md +++ b/core-java-modules/core-java-21/README.md @@ -1,2 +1,5 @@ ## Relevant Articles - [Sequenced Collections in Java 21](https://www.baeldung.com/java-21-sequenced-collections) +- [String Templates in Java 21](https://www.baeldung.com/java-21-string-templates) +- [Unnamed Classes and Instance Main Methods in Java 21](https://www.baeldung.com/java-21-unnamed-class-instance-main) +- [Unnamed Patterns and Variables in Java 21](https://www.baeldung.com/java-unnamed-patterns-variables) diff --git a/core-java-modules/core-java-21/pom.xml b/core-java-modules/core-java-21/pom.xml index 0504f787c6..7b8fa9063f 100644 --- a/core-java-modules/core-java-21/pom.xml +++ b/core-java-modules/core-java-21/pom.xml @@ -12,6 +12,12 @@ 0.0.1-SNAPSHOT + + 21 + 21 + UTF-8 + + @@ -20,14 +26,22 @@ 21 21 - --enable-preview + + false + + --enable-preview + + + org.apache.maven.plugins + maven-surefire-plugin + + --enable-preview + + + - - 21 - 21 - UTF-8 - + \ No newline at end of file diff --git a/core-java-modules/core-java-21/src/main/java/com/baeldung/unnamed/variables/Car.java b/core-java-modules/core-java-21/src/main/java/com/baeldung/unnamed/variables/Car.java new file mode 100644 index 0000000000..8f51c03539 --- /dev/null +++ b/core-java-modules/core-java-21/src/main/java/com/baeldung/unnamed/variables/Car.java @@ -0,0 +1,11 @@ +package com.baeldung.unnamed.variables; + +public record Car(String name, String color, T engine) { } + +abstract class Engine { } + +class GasEngine extends Engine { } + +class ElectricEngine extends Engine { } + +class HybridEngine extends Engine { } \ No newline at end of file diff --git a/core-java-modules/core-java-21/src/main/java/com/baeldung/unnamed/variables/UnnamedPatterns.java b/core-java-modules/core-java-21/src/main/java/com/baeldung/unnamed/variables/UnnamedPatterns.java new file mode 100644 index 0000000000..310ce621f9 --- /dev/null +++ b/core-java-modules/core-java-21/src/main/java/com/baeldung/unnamed/variables/UnnamedPatterns.java @@ -0,0 +1,50 @@ +package com.baeldung.unnamed.variables; + +public class UnnamedPatterns { + + static String getObjectsColorWithNamedPattern(Object object) { + if (object instanceof Car(String name, String color, Engine engine)) { + return color; + } + return "No color!"; + } + + static String getObjectsColorWithUnnamedPattern(Object object) { + if (object instanceof Car(_, String color, _)) { + return color; + } + return "No color!"; + } + + static String getObjectsColorWithSwitchAndNamedPattern(Object object) { + return switch (object) { + case Car(String name, String color, Engine engine) -> color; + default -> "No color!"; + }; + } + + static String getObjectsColorWithSwitchAndUnnamedPattern(Object object) { + return switch (object) { + case Car(_, String color, _) -> color; + default -> "No color!"; + }; + } + + static String getEngineTypeWithNamedPattern(Car car) { + return switch (car) { + case Car(String name, String color, GasEngine engine) -> "gas"; + case Car(String name, String color, ElectricEngine engine) -> "electric"; + case Car(String name, String color, HybridEngine engine) -> "hybrid"; + default -> "none"; + }; + } + + static String getEngineTypeWithUnnamedPattern(Car car) { + return switch (car) { + case Car(_, _, GasEngine _) -> "gas"; + case Car(_, _, ElectricEngine _) -> "electric"; + case Car(_, _, HybridEngine _) -> "hybrid"; + default -> "none"; + }; + } +} diff --git a/core-java-modules/core-java-21/src/main/java/com/baeldung/unnamed/variables/UnnamedVariables.java b/core-java-modules/core-java-21/src/main/java/com/baeldung/unnamed/variables/UnnamedVariables.java new file mode 100644 index 0000000000..82e76b40a4 --- /dev/null +++ b/core-java-modules/core-java-21/src/main/java/com/baeldung/unnamed/variables/UnnamedVariables.java @@ -0,0 +1,134 @@ +package com.baeldung.unnamed.variables; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Queue; + +class Transaction implements AutoCloseable { + + @Override + public void close() { + System.out.println("Closed!"); + } +} + +public class UnnamedVariables { + + static int countCarsOverLimitWithNamedVariable(Collection> cars, int limit) { + var total = 0; + var totalOverLimit = 0; + for (var car : cars) { + total++; + if (total > limit) { + totalOverLimit++; + // side effect + } + } + return totalOverLimit; + } + + static int countCarsOverLimitWithUnnamedVariable(Collection> cars, int limit) { + var total = 0; + var totalOverLimit = 0; + for (var _ : cars) { + total++; + if (total > limit) { + totalOverLimit++; + // side effect + } + } + return totalOverLimit; + } + + static void sendNotificationToCarsWithNamedVariable(Collection> cars) { + sendOneTimeNotification(); + for (int i = 0; i < cars.size(); i++) { + // Notify car + } + } + + static void sendNotificationToCarsWithUnnamedVariable(Collection> cars) { + for (int i = 0, _ = sendOneTimeNotification(); i < cars.size(); i++) { + // Notify car + } + } + + private static int sendOneTimeNotification() { + System.out.println("Sending one time notification!"); + return 1; + } + + static Car removeThreeCarsAndReturnFirstRemovedWithNamedVariables(Queue> cars) { + var x = cars.poll(); + var y = cars.poll(); + var z = cars.poll(); + return x; + } + + static Car removeThreeCarsAndReturnFirstRemovedWithUnnamedVariables(Queue> cars) { + var car = cars.poll(); + var _ = cars.poll(); + var _ = cars.poll(); + return car; + } + + static void handleCarExceptionWithNamedVariables(Car car) { + try { + someOperationThatFails(car); + } catch (IllegalStateException ex) { + System.out.println("Got an illegal state exception for: " + car.name()); + } catch (RuntimeException ex) { + System.out.println("Got a runtime exception!"); + } + } + + static void handleCarExceptionWithUnnamedVariables(Car car) { + try { + someOperationThatFails(car); + } catch (IllegalStateException | NumberFormatException _) { + System.out.println("Got an illegal state exception for: " + car.name()); + } catch (RuntimeException _) { + System.out.println("Got a runtime exception!"); + } + } + + static void obtainTransactionAndUpdateCarWithNamedVariables(Car car) { + try (var transaction = new Transaction()) { + updateCar(car); + } + } + + static void obtainTransactionAndUpdateCarWithUnnamedVariables(Car car) { + try (var _ = new Transaction()) { + updateCar(car); + } + } + + static void updateCar(Car car) { + // Some update logic + System.out.println("Car updated!"); + } + + static Map>> getCarsByFirstLetterWithNamedVariables(List> cars) { + Map>> carMap = new HashMap<>(); + cars.forEach(car -> + carMap.computeIfAbsent(car.name().substring(0, 1), firstLetter -> new ArrayList<>()).add(car) + ); + return carMap; + } + + static Map>> getCarsByFirstLetterWithUnnamedVariables(List> cars) { + Map>> carMap = new HashMap<>(); + cars.forEach(car -> + carMap.computeIfAbsent(car.name().substring(0, 1), _ -> new ArrayList<>()).add(car) + ); + return carMap; + } + + private static void someOperationThatFails(Car car) { + throw new IllegalStateException("Triggered exception for: " + car.name()); + } +} diff --git a/core-java-modules/core-java-21/src/main/java/com/baeldung/unnamedclasses/HelloWorld.java b/core-java-modules/core-java-21/src/main/java/com/baeldung/unnamedclasses/HelloWorld.java new file mode 100644 index 0000000000..bf0e2c96c2 --- /dev/null +++ b/core-java-modules/core-java-21/src/main/java/com/baeldung/unnamedclasses/HelloWorld.java @@ -0,0 +1,3 @@ +void main() { + System.out.println("Hello, World!"); +} diff --git a/core-java-modules/core-java-21/src/main/java/com/baeldung/unnamedclasses/HelloWorldChild.java b/core-java-modules/core-java-21/src/main/java/com/baeldung/unnamedclasses/HelloWorldChild.java new file mode 100644 index 0000000000..827be7c788 --- /dev/null +++ b/core-java-modules/core-java-21/src/main/java/com/baeldung/unnamedclasses/HelloWorldChild.java @@ -0,0 +1,7 @@ +package com.baeldung.unnamedclasses; + +public class HelloWorldChild extends HelloWorldSuper { + void main() { + System.out.println("Hello, World!"); + } +} diff --git a/core-java-modules/core-java-21/src/main/java/com/baeldung/unnamedclasses/HelloWorldSuper.java b/core-java-modules/core-java-21/src/main/java/com/baeldung/unnamedclasses/HelloWorldSuper.java new file mode 100644 index 0000000000..59c88716a4 --- /dev/null +++ b/core-java-modules/core-java-21/src/main/java/com/baeldung/unnamedclasses/HelloWorldSuper.java @@ -0,0 +1,7 @@ +package com.baeldung.unnamedclasses; + +public class HelloWorldSuper { + public static void main(String[] args) { + System.out.println("Hello from the superclass"); + } +} diff --git a/core-java-modules/core-java-21/src/main/java/com/baeldung/unnamedclasses/HelloWorldWithMethod.java b/core-java-modules/core-java-21/src/main/java/com/baeldung/unnamedclasses/HelloWorldWithMethod.java new file mode 100644 index 0000000000..698516544e --- /dev/null +++ b/core-java-modules/core-java-21/src/main/java/com/baeldung/unnamedclasses/HelloWorldWithMethod.java @@ -0,0 +1,6 @@ +private String getMessage() { + return "Hello, World!"; +} +void main() { + System.out.println(getMessage()); +} diff --git a/core-java-modules/core-java-21/src/test/java/com/baeldung/unnamed/variables/CarScenario.java b/core-java-modules/core-java-21/src/test/java/com/baeldung/unnamed/variables/CarScenario.java new file mode 100644 index 0000000000..2acb83cdef --- /dev/null +++ b/core-java-modules/core-java-21/src/test/java/com/baeldung/unnamed/variables/CarScenario.java @@ -0,0 +1,13 @@ +package com.baeldung.unnamed.variables; + +import java.util.List; + +class CarScenario { + + protected final List> cars = List.of( + new Car<>("Mitsubishi", "blue", new GasEngine()), + new Car<>("Toyota", "red", new ElectricEngine()), + new Car<>("Jaguar", "white", new HybridEngine()) + ); + +} diff --git a/core-java-modules/core-java-21/src/test/java/com/baeldung/unnamed/variables/UnnamedPatternsUnitTest.java b/core-java-modules/core-java-21/src/test/java/com/baeldung/unnamed/variables/UnnamedPatternsUnitTest.java new file mode 100644 index 0000000000..9d860a201a --- /dev/null +++ b/core-java-modules/core-java-21/src/test/java/com/baeldung/unnamed/variables/UnnamedPatternsUnitTest.java @@ -0,0 +1,44 @@ +package com.baeldung.unnamed.variables; + +import static com.baeldung.unnamed.variables.UnnamedPatterns.getEngineTypeWithNamedPattern; +import static com.baeldung.unnamed.variables.UnnamedPatterns.getEngineTypeWithUnnamedPattern; +import static com.baeldung.unnamed.variables.UnnamedPatterns.getObjectsColorWithNamedPattern; +import static com.baeldung.unnamed.variables.UnnamedPatterns.getObjectsColorWithSwitchAndNamedPattern; +import static com.baeldung.unnamed.variables.UnnamedPatterns.getObjectsColorWithSwitchAndUnnamedPattern; +import static com.baeldung.unnamed.variables.UnnamedPatterns.getObjectsColorWithUnnamedPattern; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; + +public class UnnamedPatternsUnitTest extends CarScenario { + + @Test + public void whenExtractingColorWithNamedPatterns_thenReturnBlue() { + assertEquals("blue", getObjectsColorWithNamedPattern(cars.get(0))); + } + + @Test + public void whenExtractingColorWithUnnamedPatterns_thenReturnBlue() { + assertEquals("blue", getObjectsColorWithUnnamedPattern(cars.get(0))); + } + + @Test + public void whenExtractingColorWithSwitchAndNamedPatterns_thenReturnBlue() { + assertEquals("blue", getObjectsColorWithSwitchAndNamedPattern(cars.get(0))); + } + + @Test + public void whenExtractingColorWithSwitchAndUnnamedPatterns_thenReturnBlue() { + assertEquals("blue", getObjectsColorWithSwitchAndUnnamedPattern(cars.get(0))); + } + + @Test + public void whenExtractingEngineTypeWithNamedPatterns_thenReturnGas() { + assertEquals("gas", getEngineTypeWithNamedPattern(cars.get(0))); + } + + @Test + public void whenExtractingEngineTypeWithUnnamedPatterns_thenReturnGas() { + assertEquals("gas", getEngineTypeWithUnnamedPattern(cars.get(0))); + } +} diff --git a/core-java-modules/core-java-21/src/test/java/com/baeldung/unnamed/variables/UnnamedVariablesUnitTest.java b/core-java-modules/core-java-21/src/test/java/com/baeldung/unnamed/variables/UnnamedVariablesUnitTest.java new file mode 100644 index 0000000000..094879c277 --- /dev/null +++ b/core-java-modules/core-java-21/src/test/java/com/baeldung/unnamed/variables/UnnamedVariablesUnitTest.java @@ -0,0 +1,93 @@ +package com.baeldung.unnamed.variables; + +import static com.baeldung.unnamed.variables.UnnamedVariables.countCarsOverLimitWithNamedVariable; +import static com.baeldung.unnamed.variables.UnnamedVariables.countCarsOverLimitWithUnnamedVariable; +import static com.baeldung.unnamed.variables.UnnamedVariables.getCarsByFirstLetterWithNamedVariables; +import static com.baeldung.unnamed.variables.UnnamedVariables.getCarsByFirstLetterWithUnnamedVariables; +import static com.baeldung.unnamed.variables.UnnamedVariables.handleCarExceptionWithNamedVariables; +import static com.baeldung.unnamed.variables.UnnamedVariables.handleCarExceptionWithUnnamedVariables; +import static com.baeldung.unnamed.variables.UnnamedVariables.obtainTransactionAndUpdateCarWithNamedVariables; +import static com.baeldung.unnamed.variables.UnnamedVariables.obtainTransactionAndUpdateCarWithUnnamedVariables; +import static com.baeldung.unnamed.variables.UnnamedVariables.removeThreeCarsAndReturnFirstRemovedWithNamedVariables; +import static com.baeldung.unnamed.variables.UnnamedVariables.removeThreeCarsAndReturnFirstRemovedWithUnnamedVariables; +import static com.baeldung.unnamed.variables.UnnamedVariables.sendNotificationToCarsWithNamedVariable; +import static com.baeldung.unnamed.variables.UnnamedVariables.sendNotificationToCarsWithUnnamedVariable; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.LinkedList; + +import org.junit.jupiter.api.Test; + +public class UnnamedVariablesUnitTest extends CarScenario { + + @Test + public void whenCountingCarsOverLimitWithNamedVariables_thenShouldReturnOne() { + assertEquals(1, countCarsOverLimitWithNamedVariable(cars, 2)); + } + + @Test + public void whenCountingCarsOverLimitWithUnnamedVariables_thenShouldReturnOne() { + assertEquals(1, countCarsOverLimitWithUnnamedVariable(cars, 2)); + } + + @Test + public void whenNotifyingCarsWithNamedVariables_thenShouldNotFail() { + assertDoesNotThrow(() -> sendNotificationToCarsWithNamedVariable(cars)); + } + + @Test + public void whenNotifyingCarsWithUnnamedVariables_thenShouldNotFail() { + assertDoesNotThrow(() -> sendNotificationToCarsWithUnnamedVariable(cars)); + } + + @Test + public void whenPollingCarsWithNamedVariables_thenReturnFirstOneAndEmptyQueue() { + var carQueue = new LinkedList<>(cars); + assertEquals("Mitsubishi", removeThreeCarsAndReturnFirstRemovedWithNamedVariables(carQueue).name()); + assertEquals(0, carQueue.size()); + } + + @Test + public void whenPollingCarsWithUnnamedVariables_thenReturnFirstOneAndEmptyQueue() { + var carQueue = new LinkedList<>(cars); + assertEquals("Mitsubishi", removeThreeCarsAndReturnFirstRemovedWithUnnamedVariables(carQueue).name()); + assertEquals(0, carQueue.size()); + } + + @Test + public void whenHandlingExceptionWithNamedVariables_thenNoExceptionIsThrown() { + assertDoesNotThrow(() -> handleCarExceptionWithNamedVariables(cars.get(0))); + } + + @Test + public void whenHandlingExceptionWithUnnamedVariables_thenNoExceptionIsThrown() { + assertDoesNotThrow(() -> handleCarExceptionWithUnnamedVariables(cars.get(0))); + } + + @Test + public void whenHandlingTransactionUpdateWithNamedVariables_thenNoExceptionIsThrown() { + assertDoesNotThrow(() -> obtainTransactionAndUpdateCarWithNamedVariables(cars.get(0))); + } + + @Test + public void whenHandlingTransactionUpdateWithUnnamedVariables_thenNoExceptionIsThrown() { + assertDoesNotThrow(() -> obtainTransactionAndUpdateCarWithUnnamedVariables(cars.get(0))); + } + + @Test + public void whenGettingCarsByFirstLetterWithNamedVariables_thenHaveThreeKeys() { + var carsByLetter = getCarsByFirstLetterWithNamedVariables(cars); + assertEquals(1, carsByLetter.get("M").size()); + assertEquals(1, carsByLetter.get("T").size()); + assertEquals(1, carsByLetter.get("J").size()); + } + + @Test + public void whenGettingCarsByFirstLetterWithUnnamedVariables_thenHaveThreeKeys() { + var carsByLetter = getCarsByFirstLetterWithUnnamedVariables(cars); + assertEquals(1, carsByLetter.get("M").size()); + assertEquals(1, carsByLetter.get("T").size()); + assertEquals(1, carsByLetter.get("J").size()); + } +} diff --git a/core-java-modules/core-java-9-streams/README.md b/core-java-modules/core-java-9-streams/README.md index 0ad8500689..d9663e0858 100644 --- a/core-java-modules/core-java-9-streams/README.md +++ b/core-java-modules/core-java-9-streams/README.md @@ -4,3 +4,4 @@ This module contains articles about Java 9 streams ### Relevant Articles: - [How to Break from Java Stream forEach](https://www.baeldung.com/java-break-stream-foreach) +- [Creating Stream of Regex Matches](https://www.baeldung.com/java-stream-regex-matches) diff --git a/core-java-modules/core-java-arrays-convert/README.md b/core-java-modules/core-java-arrays-convert/README.md index dcaaaac12e..2e34829525 100644 --- a/core-java-modules/core-java-arrays-convert/README.md +++ b/core-java-modules/core-java-arrays-convert/README.md @@ -10,3 +10,4 @@ This module contains articles about arrays conversion in Java - [Convert Java Array to Iterable](https://www.baeldung.com/java-array-convert-to-iterable) - [Converting an int[] to HashSet in Java](https://www.baeldung.com/java-converting-int-array-to-hashset) - [Convert an ArrayList of String to a String Array in Java](https://www.baeldung.com/java-convert-string-arraylist-array) +- [Convert Char Array to Int Array in Java](https://www.baeldung.com/java-convert-char-int-array) diff --git a/core-java-modules/core-java-arrays-convert/src/main/java/com/baeldung/array/conversions/CharArrayToIntArrayUtils.java b/core-java-modules/core-java-arrays-convert/src/main/java/com/baeldung/array/conversions/CharArrayToIntArrayUtils.java new file mode 100644 index 0000000000..fbd76a0113 --- /dev/null +++ b/core-java-modules/core-java-arrays-convert/src/main/java/com/baeldung/array/conversions/CharArrayToIntArrayUtils.java @@ -0,0 +1,67 @@ +package com.baeldung.array.conversions; + +import java.util.Arrays; + +public class CharArrayToIntArrayUtils { + + static int[] usingGetNumericValueMethod(char[] chars) { + if (chars == null) { + return null; + } + + int[] ints = new int[chars.length]; + for (int i = 0; i < chars.length; i++) { + ints[i] = Character.getNumericValue(chars[i]); + } + + return ints; + } + + static int[] usingDigitMethod(char[] chars) { + if (chars == null) { + return null; + } + + int[] ints = new int[chars.length]; + for (int i = 0; i < chars.length; i++) { + ints[i] = Character.digit(chars[i], 10); + } + + return ints; + } + + static int[] usingStreamApiMethod(char[] chars) { + if (chars == null) { + return null; + } + + return new String(chars).chars() + .map(c -> c - 48) + .toArray(); + } + + static int[] usingParseIntMethod(char[] chars) { + if (chars == null) { + return null; + } + + int[] ints = new int[chars.length]; + for (int i = 0; i < chars.length; i++) { + ints[i] = Integer.parseInt(String.valueOf(chars[i])); + } + + return ints; + } + + static int[] usingArraysSetAllMethod(char[] chars) { + if (chars == null) { + return null; + } + + int[] ints = new int[chars.length]; + Arrays.setAll(ints, i -> Character.getNumericValue(chars[i])); + + return ints; + } + +} diff --git a/core-java-modules/core-java-arrays-convert/src/test/java/com/baeldung/array/conversions/CharArrayToIntArrayUtilsUnitTest.java b/core-java-modules/core-java-arrays-convert/src/test/java/com/baeldung/array/conversions/CharArrayToIntArrayUtilsUnitTest.java new file mode 100644 index 0000000000..534dc3893f --- /dev/null +++ b/core-java-modules/core-java-arrays-convert/src/test/java/com/baeldung/array/conversions/CharArrayToIntArrayUtilsUnitTest.java @@ -0,0 +1,54 @@ +package com.baeldung.array.conversions; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; + +import org.junit.jupiter.api.Test; + +class CharArrayToIntArrayUtilsUnitTest { + + @Test + void givenCharArray_whenUsingGetNumericValueMethod_shouldGetIntArray() { + int[] expected = { 2, 3, 4, 5 }; + char[] chars = { '2', '3', '4', '5' }; + int[] result = CharArrayToIntArrayUtils.usingGetNumericValueMethod(chars); + + assertArrayEquals(expected, result); + } + + @Test + void givenCharArray_whenUsingDigitMethod_shouldGetIntArray() { + int[] expected = { 1, 2, 3, 6 }; + char[] chars = { '1', '2', '3', '6' }; + int[] result = CharArrayToIntArrayUtils.usingDigitMethod(chars); + + assertArrayEquals(expected, result); + } + + @Test + void givenCharArray_whenUsingStreamApi_shouldGetIntArray() { + int[] expected = { 9, 8, 7, 6 }; + char[] chars = { '9', '8', '7', '6' }; + int[] result = CharArrayToIntArrayUtils.usingStreamApiMethod(chars); + + assertArrayEquals(expected, result); + } + + @Test + void givenCharArray_whenUsingParseIntMethod_shouldGetIntArray() { + int[] expected = { 9, 8, 7, 6 }; + char[] chars = { '9', '8', '7', '6' }; + int[] result = CharArrayToIntArrayUtils.usingParseIntMethod(chars); + + assertArrayEquals(expected, result); + } + + @Test + void givenCharArray_whenUsingArraysSetAllMethod_shouldGetIntArray() { + int[] expected = { 4, 9, 2, 3 }; + char[] chars = { '4', '9', '2', '3' }; + int[] result = CharArrayToIntArrayUtils.usingArraysSetAllMethod(chars); + + assertArrayEquals(expected, result); + } + +} diff --git a/core-java-modules/core-java-arrays-guides/README.md b/core-java-modules/core-java-arrays-guides/README.md index 0af77980af..d8b0d126a1 100644 --- a/core-java-modules/core-java-arrays-guides/README.md +++ b/core-java-modules/core-java-arrays-guides/README.md @@ -9,3 +9,4 @@ This module contains complete guides about arrays in Java - [Guide to ArrayStoreException](https://www.baeldung.com/java-arraystoreexception) - [Creating a Generic Array in Java](https://www.baeldung.com/java-generic-array) - [Maximum Size of Java Arrays](https://www.baeldung.com/java-arrays-max-size) +- [Merge Two Arrays and Remove Duplicates in Java](https://www.baeldung.com/java-merge-two-arrays-delete-duplicates) diff --git a/core-java-modules/core-java-arrays-operations-advanced-2/README.md b/core-java-modules/core-java-arrays-operations-advanced-2/README.md new file mode 100644 index 0000000000..17ffa2562d --- /dev/null +++ b/core-java-modules/core-java-arrays-operations-advanced-2/README.md @@ -0,0 +1,2 @@ +## Relevant Articles +- [Find the Middle Element of an Array in Java](https://www.baeldung.com/java-array-middle-item) diff --git a/core-java-modules/core-java-arrays-operations-advanced/README.md b/core-java-modules/core-java-arrays-operations-advanced/README.md index 0647d89d16..b379958f37 100644 --- a/core-java-modules/core-java-arrays-operations-advanced/README.md +++ b/core-java-modules/core-java-arrays-operations-advanced/README.md @@ -14,4 +14,3 @@ This module contains articles about advanced operations on arrays in Java. They - [Slicing Arrays in Java](https://www.baeldung.com/java-slicing-arrays) - [Combining Two or More Byte Arrays](https://www.baeldung.com/java-concatenate-byte-arrays) - [Calculating the Sum of Two Arrays in Java](https://www.baeldung.com/java-sum-arrays-element-wise) -- [Find the Middle Element of an Array in Java](https://www.baeldung.com/java-array-middle-item) diff --git a/core-java-modules/core-java-char/README.md b/core-java-modules/core-java-char/README.md index e4af3121c5..56040a3ea5 100644 --- a/core-java-modules/core-java-char/README.md +++ b/core-java-modules/core-java-char/README.md @@ -5,3 +5,4 @@ This module contains articles about Java Character Class ### Relevant Articles: - [Character#isAlphabetic vs. Character#isLetter](https://www.baeldung.com/java-character-isletter-isalphabetic) - [Difference Between Java’s “char” and “String”](https://www.baeldung.com/java-char-vs-string) +- [Increment Character in Java](https://www.baeldung.com/java-char-sequence) diff --git a/core-java-modules/core-java-char/src/test/java/com/baeldung/incrementchar/IncrementCharUnitTest.java b/core-java-modules/core-java-char/src/test/java/com/baeldung/incrementchar/IncrementCharUnitTest.java new file mode 100644 index 0000000000..7621e85762 --- /dev/null +++ b/core-java-modules/core-java-char/src/test/java/com/baeldung/incrementchar/IncrementCharUnitTest.java @@ -0,0 +1,29 @@ +package com.baeldung.incrementchar; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +class IncrementCharUnitTest { + @Test + void whenUsingForLoop_thenGenerateCharacters(){ + final List allCapitalCharacters = Arrays.asList('A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'); + List characters = new ArrayList<>(); + for (char character = 'A'; character <= 'Z'; character++) { + characters.add(character); + } + Assertions.assertEquals(characters, allCapitalCharacters); + } + + @Test + void whenUsingStreams_thenGenerateCharacters() { + final List allCapitalCharacters = Arrays.asList('A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'); + final List characters = IntStream.rangeClosed('A', 'Z').mapToObj(c -> (char) c).collect(Collectors.toList()); + Assertions.assertEquals(characters, allCapitalCharacters); + } +} diff --git a/core-java-modules/core-java-collections-5/README.md b/core-java-modules/core-java-collections-5/README.md index 1769d11686..e478d87ad0 100644 --- a/core-java-modules/core-java-collections-5/README.md +++ b/core-java-modules/core-java-collections-5/README.md @@ -5,4 +5,6 @@ ### Relevant Articles: - [Introduction to Roaring Bitmap](https://www.baeldung.com/java-roaring-bitmap-intro) - [Creating Custom Iterator in Java](https://www.baeldung.com/java-creating-custom-iterator) +- [Difference Between Arrays.sort() and Collections.sort()](https://www.baeldung.com/java-arrays-collections-sort-methods) +- [Skipping the First Iteration in Java](https://www.baeldung.com/java-skip-first-iteration) - More articles: [[<-- prev]](/core-java-modules/core-java-collections-4) diff --git a/core-java-modules/core-java-collections-5/src/main/java/com/baeldung/skippingfirstelement/SkipFirstElementExample.java b/core-java-modules/core-java-collections-5/src/main/java/com/baeldung/skippingfirstelement/SkipFirstElementExample.java new file mode 100644 index 0000000000..86982486fa --- /dev/null +++ b/core-java-modules/core-java-collections-5/src/main/java/com/baeldung/skippingfirstelement/SkipFirstElementExample.java @@ -0,0 +1,126 @@ +package com.baeldung.skippingfirstelement; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +public class SkipFirstElementExample { + + private final List stringList = new ArrayList<>(); + private final Set stringSet = new HashSet<>(); + private final Map stringMap = new HashMap<>(); + + public SkipFirstElementExample() { + // Initializing a List + stringList.add("Monday"); + stringList.add("Tuesday"); + stringList.add("Wednesday"); + stringList.add("Thursday"); + stringList.add("Friday"); + stringList.add("Saturday"); + stringList.add("Sunday"); + // Initializing a Set + stringSet.add("Monday"); + stringSet.add("Tuesday"); + stringSet.add("Wednesday"); + stringSet.add("Thursday"); + stringSet.add("Friday"); + stringSet.add("Saturday"); + stringSet.add("Sunday"); + // Initializing a Map + stringMap.put("Monday", "The day when coffee is a life support system."); + stringMap.put("Tuesday", "The day you realize that Monday's optimism was a lie."); + stringMap.put("Wednesday", "Hump Day, or as it's known, the 'Is it Friday yet?' day."); + stringMap.put("Thursday", "The day that says, 'Hold my beer, Friday is coming!'"); + stringMap.put("Friday", "The golden child of the weekdays. The superhero of the workweek."); + stringMap.put("Saturday", "The day of rest? More like the day of 'What can I binge-watch next?'"); + stringMap.put("Sunday", "The day before you have to adult again."); + } + + void skippingFirstElementInListWithForLoop(List stringList) { + for (int i = 1; i < stringList.size(); i++) { + process(stringList.get(i)); + } + } + + void skippingFirstElementInListWithWhileLoop(List stringList) { + final Iterator iterator = stringList.iterator(); + if (iterator.hasNext()) { + iterator.next(); + } + while (iterator.hasNext()) { + process(iterator.next()); + } + } + + void skippingFirstElementInSetWithWhileLoop(Set stringSet) { + final Iterator iterator = stringSet.iterator(); + if (iterator.hasNext()) { + iterator.next(); + } + while (iterator.hasNext()) { + process(iterator.next()); + } + } + + void skippingFirstElementInListWithWhileLoopStoringFirstElement(List stringList) { + final Iterator iterator = stringList.iterator(); + String firstElement = null; + if (iterator.hasNext()) { + firstElement = iterator.next(); + } + while (iterator.hasNext()) { + process(iterator.next()); + // additional logic using fistElement + } + } + + void skippingFirstElementInMapWithStreamSkip(Map stringMap) { + stringMap.entrySet().stream().skip(1).forEach(this::process); + } + + void skippingFirstElementInListWithSubList(List stringList) { + for (final String element : stringList.subList(1, stringList.size())) { + process(element); + } + } + + void skippingFirstElementInListWithForLoopWithAdditionalCheck(List stringList) { + for (int i = 0; i < stringList.size(); i++) { + if (i == 0) { + // do something else + } else { + process(stringList.get(i)); + } + } + } + + void skippingFirstElementInListWithWhileLoopWithCounter(List stringList) { + int counter = 0; + while (counter < stringList.size()) { + if (counter != 0) { + process(stringList.get(counter)); + } + ++counter; + } + } + + void skippingFirstElementInListWithReduce(List stringList) { + stringList.stream().reduce((skip, element) -> { + process(element); + return element; + }); + } + + protected void process(String string) { + System.out.println(string); + } + protected void process(Entry mapEntry) { + System.out.println(mapEntry); + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-collections-5/src/test/java/com/baeldung/skippingfirstelement/SkipFirstElementExampleUnitTest.java b/core-java-modules/core-java-collections-5/src/test/java/com/baeldung/skippingfirstelement/SkipFirstElementExampleUnitTest.java new file mode 100644 index 0000000000..9821b22ac7 --- /dev/null +++ b/core-java-modules/core-java-collections-5/src/test/java/com/baeldung/skippingfirstelement/SkipFirstElementExampleUnitTest.java @@ -0,0 +1,122 @@ +package com.baeldung.skippingfirstelement; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Stream; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.condition.EnabledForJreRange; +import org.junit.jupiter.api.condition.JRE; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +@EnabledForJreRange(min = JRE.JAVA_9) +class SkipFirstElementExampleUnitTest { + + private static TestableSkipFirstElement testableSkip = new TestableSkipFirstElement(); + + @BeforeEach + void setup() { + testableSkip.reset(); + } + + private static Stream listProvider() { + return Stream.of( + Arguments.of( + List.of("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"), + List.of("Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday")) + ); + } + + private static Stream mapProvider() { + return Stream.of( + Arguments.of( + Map.of( + "Monday", "The day when coffee is a life support system.", + "Tuesday", "The day you realize that Monday's optimism was a lie.", + "Wednesday", "Hump Day, or as it's known, the 'Is it Friday yet?' day.", + "Thursday", "The day that says, 'Hold my beer, Friday is coming!'", + "Friday", "The golden child of the weekdays. The superhero of the workweek.", + "Saturday", "The day of rest? More like the day of 'What can I binge-watch next?'", + "Sunday", "The day before you have to adult again." + ) + ) + ); + } + + @ParameterizedTest + @MethodSource("listProvider") + void skippingFirstElementInListWithForLoop(List input, List expected) { + testableSkip.skippingFirstElementInListWithForLoop(input); + List actual = testableSkip.getResult(); + assertEquals(actual, expected); + } + + @ParameterizedTest + @MethodSource("listProvider") + void skippingFirstElementInListWithWhileLoop(List input, List expected) { + testableSkip.skippingFirstElementInListWithWhileLoop(input); + List actual = testableSkip.getResult(); + assertEquals(actual, expected); + } + + @ParameterizedTest + @MethodSource("listProvider") + void skippingFirstElementInSetWithWhileLoop(List input) { + testableSkip.skippingFirstElementInSetWithWhileLoop(new HashSet<>(input)); + Set actual = new HashSet<>(testableSkip.getResult()); + assertEquals(actual.size(), input.size() - 1); + } + + @ParameterizedTest + @MethodSource("listProvider") + void skippingFirstElementInListWithWhileLoopStoringFirstElement(List input, List expected) { + testableSkip.skippingFirstElementInListWithWhileLoopStoringFirstElement(input); + List actual = testableSkip.getResult(); + assertEquals(actual, expected); + } + + @ParameterizedTest + @MethodSource("mapProvider") + void skippingFirstElementInMapWithStreamSkip(Map input) { + testableSkip.skippingFirstElementInMapWithStreamSkip(input); + List actual = testableSkip.getResult(); + assertEquals(actual.size(), input.size() - 1); + } + + @ParameterizedTest + @MethodSource("listProvider") + void skippingFirstElementInListWithSubList(List input, List expected) { + testableSkip.skippingFirstElementInListWithSubList(input); + List actual = testableSkip.getResult(); + assertEquals(actual, expected); + } + + @ParameterizedTest + @MethodSource("listProvider") + void skippingFirstElementInListWithForLoopWithAdditionalCheck(List input, List expected) { + testableSkip.skippingFirstElementInListWithForLoopWithAdditionalCheck(input); + List actual = testableSkip.getResult(); + assertEquals(actual, expected); + } + + @ParameterizedTest + @MethodSource("listProvider") + void skippingFirstElementInListWithWhileLoopWithCounter(List input, List expected) { + testableSkip.skippingFirstElementInListWithWhileLoopWithCounter(input); + List actual = testableSkip.getResult(); + assertEquals(actual, expected); + } + + @ParameterizedTest + @MethodSource("listProvider") + void skippingFirstElementInListWithReduce(List input, List expected) { + testableSkip.skippingFirstElementInListWithReduce(input); + List actual = testableSkip.getResult(); + assertEquals(actual, expected); + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-collections-5/src/test/java/com/baeldung/skippingfirstelement/TestableSkip.java b/core-java-modules/core-java-collections-5/src/test/java/com/baeldung/skippingfirstelement/TestableSkip.java new file mode 100644 index 0000000000..0e2f340485 --- /dev/null +++ b/core-java-modules/core-java-collections-5/src/test/java/com/baeldung/skippingfirstelement/TestableSkip.java @@ -0,0 +1,10 @@ +package com.baeldung.skippingfirstelement; + +import java.util.List; + +public interface TestableSkip { + + void reset(); + + List getResult(); +} diff --git a/core-java-modules/core-java-collections-5/src/test/java/com/baeldung/skippingfirstelement/TestableSkipFirstElement.java b/core-java-modules/core-java-collections-5/src/test/java/com/baeldung/skippingfirstelement/TestableSkipFirstElement.java new file mode 100644 index 0000000000..99facb73ad --- /dev/null +++ b/core-java-modules/core-java-collections-5/src/test/java/com/baeldung/skippingfirstelement/TestableSkipFirstElement.java @@ -0,0 +1,37 @@ +package com.baeldung.skippingfirstelement; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map.Entry; + +public class TestableSkipFirstElement extends SkipFirstElementExample implements TestableSkip { + + + private List processedList = new ArrayList<>(); + private List> processedEntryList = new ArrayList<>(); + + @Override + public void process(String string) { + processedList.add(string); + } + + @Override + public void process(Entry stringEntry) { + processedEntryList.add(stringEntry); + } + + @Override + public void reset() { + processedList.clear(); + processedEntryList.clear(); + } + + @Override + public List getResult() { + if (!processedList.isEmpty()) + return processedList; + return processedEntryList; + } + + +} diff --git a/core-java-modules/core-java-collections-array-list-2/README.md b/core-java-modules/core-java-collections-array-list-2/README.md new file mode 100644 index 0000000000..575e0dbb07 --- /dev/null +++ b/core-java-modules/core-java-collections-array-list-2/README.md @@ -0,0 +1,6 @@ +## Core Java Collections ArrayList + +This module contains articles about the Java ArrayList collection + +### Relevant Articles: +- [Create an ArrayList with Multiple Object Types](https://www.baeldung.com/java-arraylist-multiple-object-types) diff --git a/core-java-modules/core-java-collections-array-list-2/pom.xml b/core-java-modules/core-java-collections-array-list-2/pom.xml new file mode 100644 index 0000000000..042f6e5bb5 --- /dev/null +++ b/core-java-modules/core-java-collections-array-list-2/pom.xml @@ -0,0 +1,32 @@ + + 4.0.0 + core-java-collections-array-list-2 + core-java-collections-array-list-2 + jar + + com.baeldung.core-java-modules + core-java-modules + 0.0.1-SNAPSHOT + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + ${maven-compiler-plugin.source} + ${maven-compiler-plugin.target} + + + + + + + 17 + 17 + + diff --git a/core-java-modules/core-java-collections-array-list-2/src/main/java/com/baeldung/list/multipleobjecttypes/AlternativeMultipeTypeList.java b/core-java-modules/core-java-collections-array-list-2/src/main/java/com/baeldung/list/multipleobjecttypes/AlternativeMultipeTypeList.java new file mode 100644 index 0000000000..5315147dff --- /dev/null +++ b/core-java-modules/core-java-collections-array-list-2/src/main/java/com/baeldung/list/multipleobjecttypes/AlternativeMultipeTypeList.java @@ -0,0 +1,51 @@ +package com.baeldung.list.multipleobjecttypes; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; +import java.util.function.Predicate; + +public class AlternativeMultipeTypeList { + + public static void main(String[] args) { + // List of Parent Class + ArrayList myList = new ArrayList<>(); + myList.add(1.2); + myList.add(2); + myList.add(-3.5); + + // List of Interface type + ArrayList diffMapList = new ArrayList<>(); + diffMapList.add(new HashMap<>()); + diffMapList.add(new TreeMap<>()); + diffMapList.add(new LinkedHashMap<>()); + + // List of Custom Object + ArrayList objList = new ArrayList<>(); + objList.add(new CustomObject("String")); + objList.add(new CustomObject(2)); + + // List via Functional Interface + List dataList = new ArrayList<>(); + + Predicate myPredicate = inputData -> (inputData instanceof String || inputData instanceof Integer); + + UserFunctionalInterface myInterface = (listObj, data) -> { + if (myPredicate.test(data)) + listObj.add(data); + else + System.out.println("Skipping input as data not allowed for class: " + data.getClass() + .getSimpleName()); + return listObj; + }; + + myInterface.addToList(dataList, Integer.valueOf(2)); + myInterface.addToList(dataList, Double.valueOf(3.33)); + myInterface.addToList(dataList, "String Value"); + myInterface.printList(dataList); + } + +} diff --git a/core-java-modules/core-java-collections-array-list-2/src/main/java/com/baeldung/list/multipleobjecttypes/CustomObject.java b/core-java-modules/core-java-collections-array-list-2/src/main/java/com/baeldung/list/multipleobjecttypes/CustomObject.java new file mode 100644 index 0000000000..b3ac4ffddb --- /dev/null +++ b/core-java-modules/core-java-collections-array-list-2/src/main/java/com/baeldung/list/multipleobjecttypes/CustomObject.java @@ -0,0 +1,22 @@ +package com.baeldung.list.multipleobjecttypes; + +public class CustomObject { + String classData; + Integer intData; + + CustomObject(String classData) { + this.classData = classData; + } + + CustomObject(Integer intData) { + this.intData = intData; + } + + public String getClassData() { + return this.classData; + } + + public Integer getIntData() { + return this.intData; + } +} diff --git a/core-java-modules/core-java-collections-array-list-2/src/main/java/com/baeldung/list/multipleobjecttypes/MultipleObjectTypeArrayList.java b/core-java-modules/core-java-collections-array-list-2/src/main/java/com/baeldung/list/multipleobjecttypes/MultipleObjectTypeArrayList.java new file mode 100644 index 0000000000..c5740c5cf8 --- /dev/null +++ b/core-java-modules/core-java-collections-array-list-2/src/main/java/com/baeldung/list/multipleobjecttypes/MultipleObjectTypeArrayList.java @@ -0,0 +1,40 @@ +package com.baeldung.list.multipleobjecttypes; + +import java.math.BigInteger; +import java.time.LocalDate; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class MultipleObjectTypeArrayList { + + public static void main(String[] args) { + + ArrayList multiTypeList = new ArrayList<>(); + + multiTypeList.add(Integer.valueOf(10)); + multiTypeList.add(Double.valueOf(11.5)); + multiTypeList.add("String Data"); + multiTypeList.add(Arrays.asList(1, 2, 3)); + multiTypeList.add(new CustomObject("Class Data")); + multiTypeList.add(BigInteger.valueOf(123456789)); + multiTypeList.add(LocalDate.of(2023, 9, 19)); + + for (Object dataObj : multiTypeList) { + if (dataObj instanceof Integer intData) + System.out.println("Integer Data : " + intData); + else if (dataObj instanceof Double doubleData) + System.out.println("Double Data : " + doubleData); + else if (dataObj instanceof String stringData) + System.out.println("String Data : " + stringData); + else if (dataObj instanceof List intList) + System.out.println("List Data : " + intList); + else if (dataObj instanceof CustomObject customObj) + System.out.println("CustomObject Data : " + customObj.getClassData()); + else if (dataObj instanceof BigInteger bigIntData) + System.out.println("BigInteger Data : " + bigIntData); + else if (dataObj instanceof LocalDate localDate) + System.out.println("LocalDate Data : " + localDate.toString()); + } + } +} diff --git a/core-java-modules/core-java-collections-array-list-2/src/main/java/com/baeldung/list/multipleobjecttypes/UserFunctionalInterface.java b/core-java-modules/core-java-collections-array-list-2/src/main/java/com/baeldung/list/multipleobjecttypes/UserFunctionalInterface.java new file mode 100644 index 0000000000..6c0f8451da --- /dev/null +++ b/core-java-modules/core-java-collections-array-list-2/src/main/java/com/baeldung/list/multipleobjecttypes/UserFunctionalInterface.java @@ -0,0 +1,18 @@ +package com.baeldung.list.multipleobjecttypes; + +import java.util.List; + +@FunctionalInterface +public interface UserFunctionalInterface { + + List addToList(List list, Object data); + + default void printList(List dataList) { + for (Object data : dataList) { + if (data instanceof String stringData) + System.out.println("String Data: " + stringData); + if (data instanceof Integer intData) + System.out.println("Integer Data: " + intData); + } + } +} diff --git a/core-java-modules/core-java-collections-conversions-3/README.md b/core-java-modules/core-java-collections-conversions-3/README.md index f89cd199ff..653f518840 100644 --- a/core-java-modules/core-java-collections-conversions-3/README.md +++ b/core-java-modules/core-java-collections-conversions-3/README.md @@ -3,3 +3,4 @@ This module contains articles about conversions among Collection types in Java. ### Relevant Articles: +- [Converting HashMap Values to an ArrayList in Java](https://www.baeldung.com/java-hashmap-arraylist) diff --git a/core-java-modules/core-java-collections-list-6/README.md b/core-java-modules/core-java-collections-list-6/README.md new file mode 100644 index 0000000000..fd162743dc --- /dev/null +++ b/core-java-modules/core-java-collections-list-6/README.md @@ -0,0 +1,2 @@ +## Relevant Articles +- [Check if a List Contains a String Element While Ignoring Case](https://www.baeldung.com/java-list-search-case-insensitive) diff --git a/core-java-modules/core-java-collections-list-6/pom.xml b/core-java-modules/core-java-collections-list-6/pom.xml new file mode 100644 index 0000000000..9bea6358c4 --- /dev/null +++ b/core-java-modules/core-java-collections-list-6/pom.xml @@ -0,0 +1,15 @@ + + + 4.0.0 + core-java-collections-list-6 + core-java-collections-list-6 + jar + + + com.baeldung.core-java-modules + core-java-modules + 0.0.1-SNAPSHOT + + \ No newline at end of file diff --git a/core-java-modules/core-java-collections-list-6/src/test/java/com/baeldung/lists/StringListCaseInsensitiveContainsUnitTest.java b/core-java-modules/core-java-collections-list-6/src/test/java/com/baeldung/lists/StringListCaseInsensitiveContainsUnitTest.java new file mode 100644 index 0000000000..51fafcca6b --- /dev/null +++ b/core-java-modules/core-java-collections-list-6/src/test/java/com/baeldung/lists/StringListCaseInsensitiveContainsUnitTest.java @@ -0,0 +1,44 @@ +package com.baeldung.lists; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.List; + +import org.junit.jupiter.api.Test; + +public class StringListCaseInsensitiveContainsUnitTest { + private final static List THE_LIST = List.of("Game of Thrones", "Forrest Gump", "American Beauty", "Pretty Woman", "Catch Me If You Can"); + + @Test + void whenUsingContains_thenGetExpectedResult() { + assertFalse(THE_LIST.contains("catch me if you can")); + } + + boolean ignoreCaseContainsForLoop(List list, String value) { + for (String e : list) { + if (value.equalsIgnoreCase(e)) + return true; + } + return false; + } + + @Test + void whenUsingIgnoreCaseContainsForLoop_thenGetExpectedResult() { + assertTrue(ignoreCaseContainsForLoop(THE_LIST, "CATCH me if you CAN")); + assertTrue(ignoreCaseContainsForLoop(THE_LIST, "game of thrones")); + assertFalse(ignoreCaseContainsForLoop(THE_LIST, "The Godfather")); + } + + @Test + void whenUsingIgnoreCaseContainsStream_thenGetExpectedResult() { + assertTrue(THE_LIST.stream() + .anyMatch(e -> e.equalsIgnoreCase("CATCH me if you CAN"))); + + assertTrue(THE_LIST.stream() + .anyMatch("game of thrones"::equalsIgnoreCase)); + + assertFalse(THE_LIST.stream() + .anyMatch("The Godfather"::equalsIgnoreCase)); + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-collections-maps-6/src/test/com/baeldung/objecttomap/ObjectToMapUnitTest.java b/core-java-modules/core-java-collections-maps-6/src/test/com/baeldung/objecttomap/ObjectToMapUnitTest.java deleted file mode 100644 index 52c2fb2bea..0000000000 --- a/core-java-modules/core-java-collections-maps-6/src/test/com/baeldung/objecttomap/ObjectToMapUnitTest.java +++ /dev/null @@ -1,76 +0,0 @@ -package java.com.baeldung.objecttomap; -import com.google.gson.Gson; -import org.junit.Assert; -import org.junit.Test; -import wiremock.com.fasterxml.jackson.core.type.TypeReference; -import wiremock.com.fasterxml.jackson.databind.ObjectMapper; -import wiremock.com.google.common.reflect.TypeToken; -import java.lang.reflect.Field; -import java.util.HashMap; -import java.util.Map; - -public class ObjectToMapUnitTest { - Employee employee = new Employee("John", 3000.0); - - @Test - public void givenJavaObject_whenUsingReflection_thenConvertToMap() throws IllegalAccessException { - Map map = convertUsingReflection(employee); - Assert.assertEquals(employee.getName(), map.get("name")); - Assert.assertEquals(employee.getSalary(), map.get("salary")); - } - - private Map convertUsingReflection(Object object) throws IllegalAccessException { - Map map = new HashMap<>(); - Field[] fields = object.getClass().getDeclaredFields(); - - for (Field field : fields) { - field.setAccessible(true); - map.put(field.getName(), field.get(object)); - } - - return map; - } - - @Test - public void givenJavaObject_whenUsingJackson_thenConvertToMap() { - ObjectMapper objectMapper = new ObjectMapper(); - Map map = objectMapper.convertValue(employee, new TypeReference>() {}); - Assert.assertEquals(employee.getName(), map.get("name")); - Assert.assertEquals(employee.getSalary(), map.get("salary")); - } - - @Test - public void givenJavaObject_whenUsingGson_thenConvertToMap() { - Gson gson = new Gson(); - String json = gson.toJson(employee); - Map map = gson.fromJson(json, new TypeToken>() {}.getType()); - Assert.assertEquals(employee.getName(), map.get("name")); - Assert.assertEquals(employee.getSalary(), map.get("salary")); - } - - private static class Employee { - private String name; - private Double salary; - - public Employee(String name, Double salary) { - this.name = name; - this.salary = salary; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public Double getSalary() { - return salary; - } - - public void setSalary(Double age) { - this.salary = salary; - } - } -} diff --git a/core-java-modules/core-java-collections-maps-6/src/test/java/com/baeldung/objecttomap/ObjectToMapUnitTest.java b/core-java-modules/core-java-collections-maps-6/src/test/java/com/baeldung/objecttomap/ObjectToMapUnitTest.java new file mode 100644 index 0000000000..e232121048 --- /dev/null +++ b/core-java-modules/core-java-collections-maps-6/src/test/java/com/baeldung/objecttomap/ObjectToMapUnitTest.java @@ -0,0 +1,128 @@ +package com.baeldung.objecttomap; + +import static org.junit.Assert.assertEquals; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.common.reflect.TypeToken; +import com.google.gson.Gson; +import org.junit.Test; +import java.lang.reflect.Field; +import java.util.Comparator; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.SortedMap; +import java.util.TreeMap; +import java.util.stream.Collectors; + +public class ObjectToMapUnitTest { + Employee employee = new Employee("John", 3000.0); + + @Test + public void givenJavaObject_whenUsingReflection_thenConvertToMap() throws IllegalAccessException { + Map map = convertUsingReflection(employee); + assertEquals(employee.getName(), map.get("name")); + assertEquals(employee.getSalary(), map.get("salary")); + } + + private Map convertUsingReflection(Object object) throws IllegalAccessException { + Map map = new HashMap<>(); + Field[] fields = object.getClass().getDeclaredFields(); + + for (Field field : fields) { + field.setAccessible(true); + map.put(field.getName(), field.get(object)); + } + + return map; + } + + @Test + public void givenJavaObject_whenUsingJackson_thenConvertToMap() { + ObjectMapper objectMapper = new ObjectMapper(); + Map map = objectMapper.convertValue(employee, new TypeReference>() {}); + assertEquals(employee.getName(), map.get("name")); + assertEquals(employee.getSalary(), map.get("salary")); + } + + @Test + public void givenJavaObject_whenUsingGson_thenConvertToMap() { + Gson gson = new Gson(); + String json = gson.toJson(employee); + Map map = gson.fromJson(json, new TypeToken>() {}.getType()); + assertEquals(employee.getName(), map.get("name")); + assertEquals(employee.getSalary(), map.get("salary")); + } + + @Test + public void given_UnsortedMap_whenSortingByValueDescending_thenValuesAreInDescendingOrder() { + Map unsortedMap = new HashMap<>(); + unsortedMap.put("one", 1); + unsortedMap.put("three", 3); + unsortedMap.put("five", 5); + unsortedMap.put("two", 2); + unsortedMap.put("four", 4); + + Map sortedMap = sortMapByValueDescending(unsortedMap); + + assertEquals(5, sortedMap.size()); + final Iterator iterator = sortedMap.values().iterator(); + assertEquals(5, (int) iterator.next()); + assertEquals(4, (int) iterator.next()); + assertEquals(3, (int) iterator.next()); + assertEquals(2, (int) iterator.next()); + assertEquals(1, (int) iterator.next()); + } + + @Test + public void given_UnsortedMap_whenUsingTreeMap_thenKeysAreInDescendingOrder() { + SortedMap treeMap = new TreeMap<>(Comparator.reverseOrder()); + treeMap.put("one", 1); + treeMap.put("three", 3); + treeMap.put("five", 5); + treeMap.put("two", 2); + treeMap.put("four", 4); + + assertEquals(5, treeMap.size()); + final Iterator iterator = treeMap.keySet().iterator(); + assertEquals("two", iterator.next()); + assertEquals("three", iterator.next()); + assertEquals("one", iterator.next()); + assertEquals("four", iterator.next()); + assertEquals("five", iterator.next()); + } + + private static class Employee { + private String name; + private Double salary; + + public Employee(String name, Double salary) { + this.name = name; + this.salary = salary; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Double getSalary() { + return salary; + } + + public void setSalary(Double age) { + this.salary = salary; + } + } + + public static > Map sortMapByValueDescending(Map map) { + return map.entrySet().stream() + .sorted(Map.Entry.comparingByValue().reversed()) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new)); + } +} diff --git a/core-java-modules/core-java-collections-maps-7/README.md b/core-java-modules/core-java-collections-maps-7/README.md new file mode 100644 index 0000000000..c63f3b360b --- /dev/null +++ b/core-java-modules/core-java-collections-maps-7/README.md @@ -0,0 +1 @@ +## Relevant Articles \ No newline at end of file diff --git a/core-java-modules/core-java-collections-maps-7/pom.xml b/core-java-modules/core-java-collections-maps-7/pom.xml new file mode 100644 index 0000000000..bb7c6e9fb5 --- /dev/null +++ b/core-java-modules/core-java-collections-maps-7/pom.xml @@ -0,0 +1,78 @@ + + + 4.0.0 + core-java-collections-maps-7 + core-java-collections-maps-7 + jar + + + core-java-modules + com.baeldung.core-java-modules + 0.0.1-SNAPSHOT + + + + 5.2.5.RELEASE + + + + com.fasterxml.jackson.core + jackson-databind + 2.12.4 + + + org.openjdk.jmh + jmh-core + 1.36 + + + com.google.code.gson + gson + 2.8.9 + + + org.json + json + 20230227 + + + junit + junit + 4.13.1 + test + + + org.junit.jupiter + junit-jupiter + 5.8.1 + test + + + org.junit.jupiter + junit-jupiter + 5.8.1 + test + + + junit + junit + 4.13.1 + test + + + org.junit.jupiter + junit-jupiter + 5.8.1 + test + + + junit + junit + 4.13.1 + test + + + + \ No newline at end of file diff --git a/core-java-modules/core-java-collections-maps-7/src/main/java/com/baeldung/map/ConvertHashMapStringToHashMapObjectUsingtoString.java b/core-java-modules/core-java-collections-maps-7/src/main/java/com/baeldung/map/ConvertHashMapStringToHashMapObjectUsingtoString.java new file mode 100644 index 0000000000..2b3d6db89c --- /dev/null +++ b/core-java-modules/core-java-collections-maps-7/src/main/java/com/baeldung/map/ConvertHashMapStringToHashMapObjectUsingtoString.java @@ -0,0 +1,60 @@ +package com.baeldung.map; + +import java.util.HashMap; +import java.util.Map; + +public class ConvertHashMapStringToHashMapObjectUsingtoString { + public String name; + public int age; + + public ConvertHashMapStringToHashMapObjectUsingtoString(String name, int age) { + this.name = name; + this.age = age; + } + + public static ConvertHashMapStringToHashMapObjectUsingtoString deserializeCustomObject(String valueString) { + if (valueString.startsWith("{") && valueString.endsWith("}")) { + valueString = valueString.substring(1, valueString.length() - 1); + String[] parts = valueString.split(","); + String name = null; + int age = -1; + for (String part : parts) { + String[] keyValue = part.split("="); + if (keyValue.length == 2) { + String key = keyValue[0].trim(); + String val = keyValue[1].trim(); + if (key.equals("name")) { + name = val; + } else if (key.equals("age")) { + age = Integer.parseInt(val); + } + } + } + if (name != null && age >= 0) { + return new ConvertHashMapStringToHashMapObjectUsingtoString(name, age); + } + } + return new ConvertHashMapStringToHashMapObjectUsingtoString("", -1); + } + + public static void main(String[] args) { + String hashMapString = "{key1={name=John, age=30}, key2={name=Alice, age=25}}"; + String keyValuePairs = hashMapString.replaceAll("[{}\\s]", ""); + String[] pairs = keyValuePairs.split(","); + Map actualHashMap = new HashMap<>(); + for (String pair : pairs) { + String[] keyValue = pair.split("="); + if (keyValue.length == 2) { + String key = keyValue[0]; + ConvertHashMapStringToHashMapObjectUsingtoString value = deserializeCustomObject(keyValue[1]); + actualHashMap.put(key, value); + } + } + System.out.println(actualHashMap); + } + + @Override + public String toString() { + return "{name=" + name + ", age=" + age + "}"; + } +} diff --git a/core-java-modules/core-java-collections-maps-7/src/test/java/com/baeldung/map/ConvertHashMapStringToHashMapObjectUsingtoStringUnitTest.java b/core-java-modules/core-java-collections-maps-7/src/test/java/com/baeldung/map/ConvertHashMapStringToHashMapObjectUsingtoStringUnitTest.java new file mode 100644 index 0000000000..7d31402131 --- /dev/null +++ b/core-java-modules/core-java-collections-maps-7/src/test/java/com/baeldung/map/ConvertHashMapStringToHashMapObjectUsingtoStringUnitTest.java @@ -0,0 +1,31 @@ +package com.baeldung.map; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class ConvertHashMapStringToHashMapObjectUsingtoStringUnitTest { + + @Test + void givenValidCustomObject_whenSerializing_thenSerializedStringIsCorrect() { + ConvertHashMapStringToHashMapObjectUsingtoString customObject = new ConvertHashMapStringToHashMapObjectUsingtoString("John", 30); + String expectedSerializedString = "{name=John, age=30}"; + assertEquals(expectedSerializedString, customObject.toString()); + } + + @Test + void givenValidSerializedString_whenDeserializing_thenCustomObjectIsCorrect() { + String serializedString = "{name=Alice, age=25}"; + ConvertHashMapStringToHashMapObjectUsingtoString customObject = ConvertHashMapStringToHashMapObjectUsingtoString.deserializeCustomObject(serializedString); + assertEquals("Alice", customObject.name); + assertEquals(25, customObject.age); + } + + @Test + void givenInvalidSerializedString_whenDeserializing_thenDefaultCustomObjectIsCreated() { + String invalidSerializedString = "{invalidString}"; + ConvertHashMapStringToHashMapObjectUsingtoString customObject = ConvertHashMapStringToHashMapObjectUsingtoString.deserializeCustomObject(invalidSerializedString); + assertEquals("", customObject.name); + assertEquals(-1, customObject.age); + } +} diff --git a/core-java-modules/core-java-datetime-conversion/src/test/java/com/baeldung/epochtolocaldate/EpochTimeToLocalDateTimeConverterUnitTest.java b/core-java-modules/core-java-datetime-conversion/src/test/java/com/baeldung/epochtolocaldate/EpochTimeToLocalDateTimeConverterUnitTest.java index 6e3b250938..80c403bb4e 100644 --- a/core-java-modules/core-java-datetime-conversion/src/test/java/com/baeldung/epochtolocaldate/EpochTimeToLocalDateTimeConverterUnitTest.java +++ b/core-java-modules/core-java-datetime-conversion/src/test/java/com/baeldung/epochtolocaldate/EpochTimeToLocalDateTimeConverterUnitTest.java @@ -12,10 +12,10 @@ public class EpochTimeToLocalDateTimeConverterUnitTest { @Test public void testConvertEpochTimeToLocalDateTime() { long epochTimeMillis = 1624962431000L; // Example epoch time in milliseconds - LocalDateTime expectedDateTime = LocalDateTime.of(2021, 6, 29, 12, 13, 51); + LocalDateTime expectedDateTime = LocalDateTime.of(2021, 6, 29, 10, 27, 11); Instant instant = Instant.ofEpochMilli(epochTimeMillis); - ZoneId zoneId = ZoneId.systemDefault(); + ZoneId zoneId = ZoneId.of("UTC"); LocalDateTime actualDateTime = instant.atZone(zoneId).toLocalDateTime(); assertEquals(expectedDateTime, actualDateTime); diff --git a/core-java-modules/core-java-documentation/README.md b/core-java-modules/core-java-documentation/README.md index b66b9e8c05..972e76c165 100644 --- a/core-java-modules/core-java-documentation/README.md +++ b/core-java-modules/core-java-documentation/README.md @@ -3,4 +3,4 @@ ### Relevant Articles: - [Introduction to Javadoc](http://www.baeldung.com/javadoc) - +- [Code Snippets in Java API Documentation](https://www.baeldung.com/java-doc-code-snippets) diff --git a/core-java-modules/core-java-documentation/src/main/java/com/baeldung/snippettag/GreetingsExternalSnippet.java b/core-java-modules/core-java-documentation/src/main/java/com/baeldung/snippettag/GreetingsExternalSnippet.java new file mode 100644 index 0000000000..6cf27b7acc --- /dev/null +++ b/core-java-modules/core-java-documentation/src/main/java/com/baeldung/snippettag/GreetingsExternalSnippet.java @@ -0,0 +1,18 @@ +package com.baeldung.snippettag; + +/** + * + * External code snippet showing the loop process in binary search method. + * {@snippet class="BinarySearch" region="binary"} + * + * Time Zone + * {@snippet file="application.properties" region="zone"} + * + */ + +public class GreetingsExternalSnippet { + public void helloBinarySearch() { + System.out.println("Hi, it's great knowing that binary search uses a loop under the hood"); + } + +} diff --git a/core-java-modules/core-java-documentation/src/main/java/com/baeldung/snippettag/GreetingsHighlightTag.java b/core-java-modules/core-java-documentation/src/main/java/com/baeldung/snippettag/GreetingsHighlightTag.java new file mode 100644 index 0000000000..03f30e1ad2 --- /dev/null +++ b/core-java-modules/core-java-documentation/src/main/java/com/baeldung/snippettag/GreetingsHighlightTag.java @@ -0,0 +1,35 @@ +package com.baeldung.snippettag; + + +/** + * The code below shows a full highlighted line + * {@snippet : + * public void helloBaeldung() { + * System.out.println("Hello From Team Baeldung"); // @highlight + * } + * } + * + * highlighting a substring + * {@snippet : + * public void helloBaeldung() { + * System.out.println("Hello From Team Baeldung"); // @highlight substring="println" + * } + * } + * + * highlighting texts on multiple lines + * {@snippet : + * public void helloBaeldung() { + * System.out.println("Hello From Team Baeldung"); // @highlight region substring="println" + * String country = "USA"; + * System.out.println("Hello From Team " + country); // @end + * } + * } + * + */ + +public class GreetingsHighlightTag { + public void helloBaeldung() { + System.out.println("Hello From Team Baeldung"); + } + +} diff --git a/core-java-modules/core-java-documentation/src/main/java/com/baeldung/snippettag/GreetingsInlineSnippet.java b/core-java-modules/core-java-documentation/src/main/java/com/baeldung/snippettag/GreetingsInlineSnippet.java new file mode 100644 index 0000000000..71876eecf6 --- /dev/null +++ b/core-java-modules/core-java-documentation/src/main/java/com/baeldung/snippettag/GreetingsInlineSnippet.java @@ -0,0 +1,17 @@ +package com.baeldung.snippettag; + +/** + * The code below shows the content of {@code helloBaeldung()} method + * {@snippet : + * public void helloBaeldung() { + * System.out.println("Hello From Team Baeldung"); + * } + * } + */ + +public class GreetingsInlineSnippet { + public void helloBaeldung() { + System.out.println("Hello From Team Baeldung"); + } + +} diff --git a/core-java-modules/core-java-documentation/src/main/java/com/baeldung/snippettag/GreetingsReplaceAndLinkTag.java b/core-java-modules/core-java-documentation/src/main/java/com/baeldung/snippettag/GreetingsReplaceAndLinkTag.java new file mode 100644 index 0000000000..7f6f1b72f7 --- /dev/null +++ b/core-java-modules/core-java-documentation/src/main/java/com/baeldung/snippettag/GreetingsReplaceAndLinkTag.java @@ -0,0 +1,24 @@ +package com.baeldung.snippettag; + +/** + * + * Using the replace tag + * {@snippet : + * public void helloBaeldung() { + * System.out.println("Hello From Team Baeldung"); // @replace regex='".*"' replacement="..." + * } + * } + * Using the link tag + * {@snippet : + * public void helloBaeldung() { + * System.out.println("Hello From Team Baeldung"); // @link substring="System.out" target="System#out" + * } + * } + * + */ + +public class GreetingsReplaceAndLinkTag { + public void helloBaeldung() { + System.out.println("Hello From Team Baeldung"); + } +} diff --git a/core-java-modules/core-java-documentation/src/main/java/snippet-files/BinarySearch.java b/core-java-modules/core-java-documentation/src/main/java/snippet-files/BinarySearch.java new file mode 100644 index 0000000000..a5f6e565ac --- /dev/null +++ b/core-java-modules/core-java-documentation/src/main/java/snippet-files/BinarySearch.java @@ -0,0 +1,27 @@ + +public class BinarySearch { + + public int search(int[] list, int item) { + int index = Integer.MAX_VALUE; + int low = 0; + int high = list.length - 1; + // @start region="binary" + while (low <= high) { + int mid = high - low; + int guess = list[mid]; + if (guess == item) { + index = mid; + break; + } else if (guess > item) { + low = mid - 1; + } else { + low = mid + 1; + } + low++; + } + // @end region="binary" + + return index; + } + +} diff --git a/core-java-modules/core-java-documentation/src/main/java/snippet-files/application.properties b/core-java-modules/core-java-documentation/src/main/java/snippet-files/application.properties new file mode 100644 index 0000000000..a2aeefdb89 --- /dev/null +++ b/core-java-modules/core-java-documentation/src/main/java/snippet-files/application.properties @@ -0,0 +1,4 @@ +# @start region="zone" +local.timezone = GMT+1 +local.zip = 94123 +# @end region="zone" \ No newline at end of file diff --git a/core-java-modules/core-java-io-5/.gitignore b/core-java-modules/core-java-io-5/.gitignore new file mode 100644 index 0000000000..0c0cd871c5 --- /dev/null +++ b/core-java-modules/core-java-io-5/.gitignore @@ -0,0 +1,2 @@ +test-link* +0.* \ No newline at end of file diff --git a/core-java-modules/core-java-io-5/README.md b/core-java-modules/core-java-io-5/README.md new file mode 100644 index 0000000000..9fb4b967a4 --- /dev/null +++ b/core-java-modules/core-java-io-5/README.md @@ -0,0 +1,8 @@ +## Core Java IO + +This module contains articles about core Java input and output (IO) + +### Relevant Articles: +- [Get File Extension From MIME Type in Java](https://www.baeldung.com/java-mime-type-file-extension) +- [[<-- Prev]](/core-java-modules/core-java-io-4) + diff --git a/core-java-modules/core-java-io-5/pom.xml b/core-java-modules/core-java-io-5/pom.xml new file mode 100644 index 0000000000..11116b071c --- /dev/null +++ b/core-java-modules/core-java-io-5/pom.xml @@ -0,0 +1,66 @@ + + + 4.0.0 + core-java-io-5 + core-java-io-5 + jar + + + com.baeldung.core-java-modules + core-java-modules + 0.0.1-SNAPSHOT + + + + + + org.apache.tika + tika-core + ${tika.version} + + + net.sf.jmimemagic + jmimemagic + ${jmime-magic.version} + + + org.jodd + jodd-util + ${jodd-util.version} + + + com.j256.simplemagic + simplemagic + ${simplemagic.version} + + + + + core-java-io-5 + + + src/main/resources + true + + + + + maven-compiler-plugin + + 11 + 11 + + + + + + + + 2.8.0 + 0.1.5 + 6.2.1 + 1.17 + + \ No newline at end of file diff --git a/core-java-modules/core-java-io/src/test/java/com/baeldung/extension/ExtensionFromMimeTypeUnitTest.java b/core-java-modules/core-java-io-5/src/test/java/com/baeldung/extension/ExtensionFromMimeTypeUnitTest.java similarity index 94% rename from core-java-modules/core-java-io/src/test/java/com/baeldung/extension/ExtensionFromMimeTypeUnitTest.java rename to core-java-modules/core-java-io-5/src/test/java/com/baeldung/extension/ExtensionFromMimeTypeUnitTest.java index 2238cfcafa..6b1fd490a8 100644 --- a/core-java-modules/core-java-io/src/test/java/com/baeldung/extension/ExtensionFromMimeTypeUnitTest.java +++ b/core-java-modules/core-java-io-5/src/test/java/com/baeldung/extension/ExtensionFromMimeTypeUnitTest.java @@ -11,10 +11,8 @@ import java.util.Map; import java.util.Set; import org.apache.tika.mime.MimeTypeException; - -import org.junit.Test; - import com.j256.simplemagic.ContentType; +import org.junit.Test; public class ExtensionFromMimeTypeUnitTest { private static final String IMAGE_JPEG_MIME_TYPE = "image/jpeg"; @@ -37,14 +35,14 @@ public class ExtensionFromMimeTypeUnitTest { } @Test - public void whenUsingMimetypesFileTypeMap_thenGetFileExtension() { + public void whenUsingSimpleMagic_thenGetFileExtension() { List expectedExtensions = Arrays.asList("jpeg", "jpg", "jpe"); String[] detectedExtensions = ContentType.fromMimeType(IMAGE_JPEG_MIME_TYPE).getFileExtensions(); assertThat(detectedExtensions).containsExactlyElementsOf(expectedExtensions); } @Test - public void whenUsingCustomLogic_thenGetFileExtension() { + public void whenUsingCustomMap_thenGetFileExtension() { Map> mimeExtensionsMap = new HashMap<>(); List expectedExtensions = Arrays.asList(".jpg", ".jpe", ".jpeg"); addMimeExtensions(mimeExtensionsMap, "image/jpeg", ".jpg"); diff --git a/core-java-modules/core-java-io-5/src/test/java/com/baeldung/rmlinebreaks/RemoveLinebreaksUnitTest.java b/core-java-modules/core-java-io-5/src/test/java/com/baeldung/rmlinebreaks/RemoveLinebreaksUnitTest.java new file mode 100644 index 0000000000..7cfc7ede79 --- /dev/null +++ b/core-java-modules/core-java-io-5/src/test/java/com/baeldung/rmlinebreaks/RemoveLinebreaksUnitTest.java @@ -0,0 +1,72 @@ +package com.baeldung.rmlinebreaks; + +import org.junit.jupiter.api.Test; + +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; + +public class RemoveLinebreaksUnitTest { + + private Path file1Path() throws Exception { + return Paths.get(this.getClass().getClassLoader().getResource("multiple-line-1.txt").toURI()); + } + + private Path file2Path() throws Exception { + return Paths.get(this.getClass().getClassLoader().getResource("multiple-line-2.txt").toURI()); + } + + @Test + void whenRemovingLineSeparatorFromFile1_thenGetTheExpectedResult() throws Exception { + String content = Files.readString(file1Path(), StandardCharsets.UTF_8); + + String result = content.replace(System.getProperty("line.separator"), ""); + assertEquals("A, B, C, D, E, F", result); + } + + @Test + void whenRemovingLineSeparatorFromFile2_thenNotGetTheExpectedResult() throws Exception { + String content = Files.readString(file2Path(), StandardCharsets.UTF_8); + + String result = content.replace(System.getProperty("line.separator"), ""); + assertNotEquals("A, B, C, D, E, F", result); // <-- NOT equals assertion! + } + + @Test + void whenRemovingAllLinebreaks_thenGetTheExpectedResult() throws Exception { + String content1 = Files.readString(file1Path(), StandardCharsets.UTF_8); + + // file contains CRLF + String content2 = Files.readString(file2Path(), StandardCharsets.UTF_8); + + String result1 = content1.replace("\r", "").replace("\n", ""); + String result2 = content2.replace("\r", "").replace("\n", ""); + + assertEquals("A, B, C, D, E, F", result1); + assertEquals("A, B, C, D, E, F", result2); + + String resultReplaceAll = content2.replaceAll("[\\n\\r]", ""); + assertEquals("A, B, C, D, E, F", resultReplaceAll); + + } + + @Test + void whenUsingReadAllLinesAndJoin_thenGetExpectedResult() throws Exception { + List lines1 = Files.readAllLines(file1Path(), StandardCharsets.UTF_8); + + // file contains CRLF + List lines2 = Files.readAllLines(file2Path(), StandardCharsets.UTF_8); + + String result1 = String.join("", lines1); + String result2 = String.join("", lines2); + + assertEquals("A, B, C, D, E, F", result1); + assertEquals("A, B, C, D, E, F", result2); + } + +} \ No newline at end of file diff --git a/core-java-modules/core-java-io-5/src/test/resources/multiple-line-1.txt b/core-java-modules/core-java-io-5/src/test/resources/multiple-line-1.txt new file mode 100644 index 0000000000..42e87e734e --- /dev/null +++ b/core-java-modules/core-java-io-5/src/test/resources/multiple-line-1.txt @@ -0,0 +1,6 @@ +A, + B, + C, + D, + E, + F diff --git a/core-java-modules/core-java-io-5/src/test/resources/multiple-line-2.txt b/core-java-modules/core-java-io-5/src/test/resources/multiple-line-2.txt new file mode 100644 index 0000000000..4fe5d5f4ed --- /dev/null +++ b/core-java-modules/core-java-io-5/src/test/resources/multiple-line-2.txt @@ -0,0 +1,4 @@ +A, B, + C, + D, E, + F diff --git a/core-java-modules/core-java-io-apis-2/README.md b/core-java-modules/core-java-io-apis-2/README.md index cc3c351afc..3ec3220424 100644 --- a/core-java-modules/core-java-io-apis-2/README.md +++ b/core-java-modules/core-java-io-apis-2/README.md @@ -7,3 +7,4 @@ This module contains articles about core Java input/output(IO) APIs. - [Get the Desktop Path in Java](https://www.baeldung.com/java-desktop-path) - [Check if a File Is Empty in Java](https://www.baeldung.com/java-check-file-empty) - [Converting Relative to Absolute Paths in Java](https://www.baeldung.com/java-from-relative-to-absolute-paths) +- [Detect EOF in Java](https://www.baeldung.com/java-file-detect-end-of-file) diff --git a/core-java-modules/core-java-io/pom.xml b/core-java-modules/core-java-io/pom.xml index 12e957a3ba..faeddafd81 100644 --- a/core-java-modules/core-java-io/pom.xml +++ b/core-java-modules/core-java-io/pom.xml @@ -43,17 +43,6 @@ ${angus-activation.version} test - - org.jodd - jodd-util - ${jodd-util.version} - - - com.j256.simplemagic - simplemagic - ${simplemagic.version} - - @@ -153,8 +142,6 @@ 4.4.2 2.1.2 2.0.1 - 6.2.1 - 1.17 \ No newline at end of file diff --git a/core-java-modules/core-java-lang-6/pom.xml b/core-java-modules/core-java-lang-6/pom.xml index 53ef36a898..6561c4fdcc 100644 --- a/core-java-modules/core-java-lang-6/pom.xml +++ b/core-java-modules/core-java-lang-6/pom.xml @@ -18,7 +18,11 @@ mapstruct ${mapstruct.version} - + + org.apache.commons + commons-lang3 + ${commons-lang3.version} + diff --git a/core-java-modules/core-java-lang-6/src/main/java/com/baeldung/compareobjects/Address.java b/core-java-modules/core-java-lang-6/src/main/java/com/baeldung/compareobjects/Address.java new file mode 100644 index 0000000000..e82a1018ce --- /dev/null +++ b/core-java-modules/core-java-lang-6/src/main/java/com/baeldung/compareobjects/Address.java @@ -0,0 +1,47 @@ +package com.baeldung.compareobjects; + +import java.util.Objects; + +public class Address { + private String streetAddress; + private String city; + private String postalCode; + + public Address(String streetAddress, String city, String postalCode) { + this.streetAddress = streetAddress; + this.city = city; + this.postalCode = postalCode; + } + + public String getStreetAddress() { + return streetAddress; + } + + public String getCity() { + return city; + } + + public String getPostalCode() { + return postalCode; + } + + @Override + public String toString() { + return "Address{" + "streetAddress='" + streetAddress + '\'' + ", city='" + city + '\'' + ", postalCode='" + postalCode + '\'' + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + Address address = (Address) o; + return Objects.equals(streetAddress, address.streetAddress) && Objects.equals(city, address.city) && Objects.equals(postalCode, address.postalCode); + } + + @Override + public int hashCode() { + return Objects.hash(streetAddress, city, postalCode); + } +} diff --git a/core-java-modules/core-java-lang-6/src/main/java/com/baeldung/compareobjects/Person.java b/core-java-modules/core-java-lang-6/src/main/java/com/baeldung/compareobjects/Person.java new file mode 100644 index 0000000000..6ba244ff17 --- /dev/null +++ b/core-java-modules/core-java-lang-6/src/main/java/com/baeldung/compareobjects/Person.java @@ -0,0 +1,58 @@ +package com.baeldung.compareobjects; + +import java.util.List; +import java.util.Objects; + +import org.apache.commons.lang3.builder.DiffExclude; + +public class Person { + private String firstName; + private String lastName; + private int age; + private List phoneNumbers; + @DiffExclude + private Address address; + + public Person(String firstName, String lastName, int age, List phoneNumbers, Address address) { + this.firstName = firstName; + this.lastName = lastName; + this.age = age; + this.phoneNumbers = phoneNumbers; + this.address = address; + } + + public String getFirstName() { + return firstName; + } + + public String getLastName() { + return lastName; + } + + public int getAge() { + return age; + } + + public List getPhoneNumbers() { + return phoneNumbers; + } + + public Address getAddress() { + return address; + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + Person person = (Person) o; + return age == person.age && Objects.equals(firstName, person.firstName) && Objects.equals(lastName, person.lastName) && Objects.equals(phoneNumbers, person.phoneNumbers) && Objects.equals(address, person.address); + } + + @Override + public int hashCode() { + return Objects.hash(firstName, lastName, age, phoneNumbers, address); + } +} diff --git a/core-java-modules/core-java-lang-6/src/main/java/com/baeldung/compareobjects/PersonDiffBuilder.java b/core-java-modules/core-java-lang-6/src/main/java/com/baeldung/compareobjects/PersonDiffBuilder.java new file mode 100644 index 0000000000..9e21f5d7c3 --- /dev/null +++ b/core-java-modules/core-java-lang-6/src/main/java/com/baeldung/compareobjects/PersonDiffBuilder.java @@ -0,0 +1,32 @@ +package com.baeldung.compareobjects; + +import org.apache.commons.lang3.builder.DiffBuilder; +import org.apache.commons.lang3.builder.DiffResult; +import org.apache.commons.lang3.builder.ToStringStyle; + +public class PersonDiffBuilder { + public static DiffResult compare(Person first, Person second) { + DiffBuilder diffBuilder = new DiffBuilder(first, second, ToStringStyle.DEFAULT_STYLE).append("person", first.getFirstName(), second.getFirstName()) + .append("lastName", first.getLastName(), second.getLastName()) + .append("streetAddress", first.getAddress() + .getStreetAddress(), second.getAddress() + .getStreetAddress()) + .append("city", first.getAddress() + .getCity(), second.getAddress() + .getCity()) + .append("postalCode", first.getAddress() + .getPostalCode(), second.getAddress() + .getPostalCode()) + .append("age", first.getAge(), second.getAge()); + + for (int i = 0; i < first.getPhoneNumbers() + .size(); i++) { + diffBuilder.append("phoneNumbers[" + i + "].number", first.getPhoneNumbers() + .get(i) + .getNumber(), second.getPhoneNumbers() + .get(i) + .getNumber()); + } + return diffBuilder.build(); + } +} diff --git a/core-java-modules/core-java-lang-6/src/main/java/com/baeldung/compareobjects/PersonReflectionDiffBuilder.java b/core-java-modules/core-java-lang-6/src/main/java/com/baeldung/compareobjects/PersonReflectionDiffBuilder.java new file mode 100644 index 0000000000..82081e7282 --- /dev/null +++ b/core-java-modules/core-java-lang-6/src/main/java/com/baeldung/compareobjects/PersonReflectionDiffBuilder.java @@ -0,0 +1,11 @@ +package com.baeldung.compareobjects; + +import org.apache.commons.lang3.builder.DiffResult; +import org.apache.commons.lang3.builder.ReflectionDiffBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +public class PersonReflectionDiffBuilder { + public static DiffResult compare(Person first, Person second) { + return new ReflectionDiffBuilder<>(first, second, ToStringStyle.SHORT_PREFIX_STYLE).build(); + } +} diff --git a/core-java-modules/core-java-lang-6/src/main/java/com/baeldung/compareobjects/PhoneNumber.java b/core-java-modules/core-java-lang-6/src/main/java/com/baeldung/compareobjects/PhoneNumber.java new file mode 100644 index 0000000000..4ab2b4a4bd --- /dev/null +++ b/core-java-modules/core-java-lang-6/src/main/java/com/baeldung/compareobjects/PhoneNumber.java @@ -0,0 +1,43 @@ +package com.baeldung.compareobjects; + +import java.util.Objects; + +import org.apache.commons.lang3.builder.DiffExclude; + +public class PhoneNumber { + private String type; + private String number; + + public PhoneNumber(String type, String number) { + this.type = type; + this.number = number; + } + + public String getType() { + return type; + } + + public String getNumber() { + return number; + } + + @Override + public String toString() { + return "PhoneNumber{" + "type='" + type + '\'' + ", number='" + number + '\'' + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + PhoneNumber that = (PhoneNumber) o; + return Objects.equals(number, that.number); + } + + @Override + public int hashCode() { + return Objects.hash(number); + } +} diff --git a/core-java-modules/core-java-lang-6/src/test/java/com/baeldung/compareobjects/PersonDiffBuilderUnitTest.java b/core-java-modules/core-java-lang-6/src/test/java/com/baeldung/compareobjects/PersonDiffBuilderUnitTest.java new file mode 100644 index 0000000000..417e9da0ea --- /dev/null +++ b/core-java-modules/core-java-lang-6/src/test/java/com/baeldung/compareobjects/PersonDiffBuilderUnitTest.java @@ -0,0 +1,38 @@ +package com.baeldung.compareobjects; + +import static org.junit.jupiter.api.Assertions.assertFalse; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.lang3.builder.Diff; +import org.apache.commons.lang3.builder.DiffResult; +import org.junit.jupiter.api.Test; + +public class PersonDiffBuilderUnitTest { + + @Test + void givenTwoPeopleDifferent_whenComparingWithDiffBuilder_thenDifferencesFound() { + List phoneNumbers1 = new ArrayList<>(); + phoneNumbers1.add(new PhoneNumber("home", "123-456-7890")); + phoneNumbers1.add(new PhoneNumber("work", "987-654-3210")); + + List phoneNumbers2 = new ArrayList<>(); + phoneNumbers2.add(new PhoneNumber("mobile1", "123-456-7890")); + phoneNumbers2.add(new PhoneNumber("mobile2", "987-654-3210")); + + Address address1 = new Address("123 Main St", "London", "12345"); + Address address2 = new Address("123 Main St", "Paris", "54321"); + + Person person1 = new Person("John", "Doe", 30, phoneNumbers1, address1); + Person person2 = new Person("Jane", "Smith", 28, phoneNumbers2, address2); + + DiffResult diff = PersonDiffBuilder.compare(person1, person2); + for (Diff d : diff.getDiffs()) { + System.out.println(d.getFieldName() + ": " + d.getLeft() + " != " + d.getRight()); + } + + assertFalse(diff.getDiffs() + .isEmpty()); + } +} diff --git a/core-java-modules/core-java-lang-6/src/test/java/com/baeldung/compareobjects/PersonReflectionDiffBuilderUnitTest.java b/core-java-modules/core-java-lang-6/src/test/java/com/baeldung/compareobjects/PersonReflectionDiffBuilderUnitTest.java new file mode 100644 index 0000000000..fffa56dccc --- /dev/null +++ b/core-java-modules/core-java-lang-6/src/test/java/com/baeldung/compareobjects/PersonReflectionDiffBuilderUnitTest.java @@ -0,0 +1,37 @@ +package com.baeldung.compareobjects; + +import static org.junit.jupiter.api.Assertions.assertFalse; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.lang3.builder.Diff; +import org.apache.commons.lang3.builder.DiffResult; +import org.junit.jupiter.api.Test; + +public class PersonReflectionDiffBuilderUnitTest { + @Test + void givenTwoPeopleDifferent_whenComparingWithReflectionDiffBuilder_thenDifferencesFound() { + List phoneNumbers1 = new ArrayList<>(); + phoneNumbers1.add(new PhoneNumber("home", "123-456-7890")); + phoneNumbers1.add(new PhoneNumber("work", "987-654-3210")); + + List phoneNumbers2 = new ArrayList<>(); + phoneNumbers2.add(new PhoneNumber("mobile1", "123-456-7890")); + phoneNumbers2.add(new PhoneNumber("mobile2", "987-654-3210")); + + Address address1 = new Address("123 Main St", "London", "12345"); + Address address2 = new Address("123 Main St", "Paris", "54321"); + + Person person1 = new Person("John", "Doe", 30, phoneNumbers1, address1); + Person person2 = new Person("Jane", "Smith", 28, phoneNumbers2, address2); + + DiffResult diff = PersonReflectionDiffBuilder.compare(person1, person2); + for (Diff d : diff.getDiffs()) { + System.out.println(d.getFieldName() + ": " + d.getLeft() + " != " + d.getRight()); + } + + assertFalse(diff.getDiffs() + .isEmpty()); + } +} diff --git a/core-java-modules/core-java-networking/src/test/java/com/baeldung/networking/url/UrlUnitTest.java b/core-java-modules/core-java-networking/src/test/java/com/baeldung/networking/url/UrlUnitTest.java index 87d9d7a620..ca04263689 100644 --- a/core-java-modules/core-java-networking/src/test/java/com/baeldung/networking/url/UrlUnitTest.java +++ b/core-java-modules/core-java-networking/src/test/java/com/baeldung/networking/url/UrlUnitTest.java @@ -2,10 +2,15 @@ package com.baeldung.networking.url; import static java.util.stream.Collectors.toList; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import java.io.IOException; import java.net.MalformedURLException; +import java.net.URI; import java.net.URISyntaxException; import java.net.URL; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.Map; import org.apache.http.client.utils.URIBuilder; @@ -149,4 +154,24 @@ public class UrlUnitTest { assertEquals("http://baeldung.com:9090/articles?topic=java&version=8", url.toString()); } + @Test + public void givenURI_whenConvertingToURL_thenCorrect() throws IOException, URISyntaxException { + String aURIString = "http://courses.baeldung.com"; + URI uri = new URI(aURIString); + URL url = uri.toURL(); + assertNotNull(url); + assertEquals(aURIString, url.toString()); + } + + @Test + public void givenPath_whenConvertingToURIAndThenURL_thenCorrect() throws IOException, URISyntaxException { + String finalPath = "file:/D:/baeldung/java-url"; + Path path = Paths.get("/baeldung/java-url"); + URI uri = path.toUri(); + URL url = uri.toURL(); + assertNotNull(url); + // Adapt the finalPath value to match your own path + // assertEquals(finalPath, url.toString()); + } + } \ No newline at end of file diff --git a/core-java-modules/core-java-numbers-3/src/test/java/com/baeldung/integerToBinary/IntegerToBinaryUnitTest.java b/core-java-modules/core-java-numbers-3/src/test/java/com/baeldung/integerToBinary/IntegerToBinaryUnitTest.java index 38ae79f2f5..9439f012e3 100644 --- a/core-java-modules/core-java-numbers-3/src/test/java/com/baeldung/integerToBinary/IntegerToBinaryUnitTest.java +++ b/core-java-modules/core-java-numbers-3/src/test/java/com/baeldung/integerToBinary/IntegerToBinaryUnitTest.java @@ -1,6 +1,8 @@ package com.baeldung.integerToBinary; +import org.apache.commons.lang3.StringUtils; import org.junit.Test; + import static org.junit.Assert.assertEquals; public class IntegerToBinaryUnitTest { @@ -24,4 +26,18 @@ public class IntegerToBinaryUnitTest { String binaryString = Integer.toString(n, 2); assertEquals("111", binaryString); } -} + + @Test + public void givenAnInteger_whenFormatAndReplaceCalled_thenZeroPaddedBinaryString() { + int n = 7; + String binaryString = String.format("%8s", Integer.toBinaryString(n)).replace(" ", "0"); + assertEquals("00000111", binaryString); + } + + @Test + public void givenAnInteger_whenUsingApacheStringUtils_thenZeroPaddedBinaryString() { + int n = 7; + String binaryString = StringUtils.leftPad(Integer.toBinaryString(n), 8, "0"); + assertEquals("00000111", binaryString); + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-numbers-6/README.md b/core-java-modules/core-java-numbers-6/README.md index 254b2b58d7..e3d5454d60 100644 --- a/core-java-modules/core-java-numbers-6/README.md +++ b/core-java-modules/core-java-numbers-6/README.md @@ -4,4 +4,6 @@ - [Integer.class vs Integer.TYPE vs int.class](https://www.baeldung.com/java-integer-class-vs-type-vs-int) - [Does Java Read Integers in Little Endian or Big Endian?](https://www.baeldung.com/java-integers-little-big-endian) - [How to Split an Integer Number Into Digits in Java](https://www.baeldung.com/java-integer-individual-digits) +- [Java Double vs. BigDecimal](https://www.baeldung.com/java-double-vs-bigdecimal) +- [Finding the Square Root of a BigInteger in Java](https://www.baeldung.com/java-find-square-root-biginteger) - More articles: [[<-- prev]](../core-java-numbers-5) diff --git a/core-java-modules/core-java-numbers-6/pom.xml b/core-java-modules/core-java-numbers-6/pom.xml index 531f1293d1..7a3b3d4426 100644 --- a/core-java-modules/core-java-numbers-6/pom.xml +++ b/core-java-modules/core-java-numbers-6/pom.xml @@ -25,8 +25,12 @@ ${commons-codec} test + + com.google.guava + guava + ${guava.version} + - core-java-numbers-6 @@ -39,5 +43,6 @@ 1.15 + 32.1.2-jre \ No newline at end of file diff --git a/core-java-modules/core-java-numbers-6/src/main/java/com/baeldung/bigintegerroot/BenchmarkRunner.java b/core-java-modules/core-java-numbers-6/src/main/java/com/baeldung/bigintegerroot/BenchmarkRunner.java new file mode 100644 index 0000000000..2ac57a9c0c --- /dev/null +++ b/core-java-modules/core-java-numbers-6/src/main/java/com/baeldung/bigintegerroot/BenchmarkRunner.java @@ -0,0 +1,8 @@ +package com.baeldung.bigintegerroot; + +public class BenchmarkRunner { + public static void main(String[] args) throws Exception { + org.openjdk.jmh.Main.main(args); + } +} + diff --git a/core-java-modules/core-java-numbers-6/src/main/java/com/baeldung/bigintegerroot/BigIntegerHolder.java b/core-java-modules/core-java-numbers-6/src/main/java/com/baeldung/bigintegerroot/BigIntegerHolder.java new file mode 100644 index 0000000000..c2d2f30827 --- /dev/null +++ b/core-java-modules/core-java-numbers-6/src/main/java/com/baeldung/bigintegerroot/BigIntegerHolder.java @@ -0,0 +1,10 @@ +package com.baeldung.bigintegerroot; + +public class BigIntegerHolder { + + private BigIntegerHolder() { + } + public static final String BIG_NUMBER = "179769313000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"; + public static final String VERY_BIG_NUMBER = "32473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834"; + public static final String INSANELY_BIG_NUMBER = "3247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834324739274923749279342847923749237492374987230480128343247392749237492793428479237492374923749872304801283432473927492374927934284792374923749237498723048012834"; +} diff --git a/core-java-modules/core-java-numbers-6/src/main/java/com/baeldung/bigintegerroot/BigIntegerSquareRootBenchmark.java b/core-java-modules/core-java-numbers-6/src/main/java/com/baeldung/bigintegerroot/BigIntegerSquareRootBenchmark.java new file mode 100644 index 0000000000..645e4eb2dd --- /dev/null +++ b/core-java-modules/core-java-numbers-6/src/main/java/com/baeldung/bigintegerroot/BigIntegerSquareRootBenchmark.java @@ -0,0 +1,60 @@ +package com.baeldung.bigintegerroot; + +import static com.baeldung.bigintegerroot.BigIntegerHolder.*; + +import com.baeldung.bigintegerroot.algorithms.Newton; +import com.baeldung.bigintegerroot.algorithms.NewtonPlus; +import com.google.common.math.BigIntegerMath; +import java.math.BigInteger; +import java.math.RoundingMode; +import java.util.concurrent.TimeUnit; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.infra.Blackhole; + +@Warmup(iterations = 1) +@Measurement(iterations = 1, time = 1, timeUnit = TimeUnit.MINUTES) +@Fork(1) +@State(Scope.Benchmark) +public class BigIntegerSquareRootBenchmark { + + @Param({BIG_NUMBER, VERY_BIG_NUMBER, INSANELY_BIG_NUMBER}) + public String number; + @Benchmark + @BenchmarkMode(Mode.Throughput) + public void calculateRootWithJava(Blackhole blackhole) { + final BigInteger integer = new BigInteger(number); + final BigInteger root = integer.sqrt(); + blackhole.consume(root); + } + + @Benchmark + @BenchmarkMode(Mode.Throughput) + public void calculateRootWithGuava(Blackhole blackhole) { + final BigInteger integer = new BigInteger(number); + final BigInteger root = BigIntegerMath.sqrt(integer, RoundingMode.DOWN); + blackhole.consume(root); + } + + @Benchmark + @BenchmarkMode(Mode.Throughput) + public void calculateRootWithNewtonPlus(Blackhole blackhole) { + final BigInteger integer = new BigInteger(number); + final BigInteger root = NewtonPlus.sqrt(integer); + blackhole.consume(root); + } + @Benchmark + @BenchmarkMode(Mode.Throughput) + public void calculateRootWithNewton(Blackhole blackhole) { + final BigInteger integer = new BigInteger(number); + final BigInteger root = Newton.sqrt(integer); + blackhole.consume(root); + } +} diff --git a/core-java-modules/core-java-numbers-6/src/main/java/com/baeldung/bigintegerroot/algorithms/Newton.java b/core-java-modules/core-java-numbers-6/src/main/java/com/baeldung/bigintegerroot/algorithms/Newton.java new file mode 100644 index 0000000000..07acba7537 --- /dev/null +++ b/core-java-modules/core-java-numbers-6/src/main/java/com/baeldung/bigintegerroot/algorithms/Newton.java @@ -0,0 +1,29 @@ +package com.baeldung.bigintegerroot.algorithms; + +import java.math.BigInteger; + +public class Newton { + + private Newton() { + } + + public static BigInteger sqrt(BigInteger n) { + // Initial approximation + BigInteger x = n.divide(BigInteger.TWO); + + // Tolerance level (small positive integer) + BigInteger tolerance = BigInteger.ONE; + + while (true) { + // x_new = 0.5 * (x + n / x) + BigInteger xNew = x.add(n.divide(x)).divide(BigInteger.TWO); + + // Check for convergence within tolerance + if (x.subtract(xNew).abs().compareTo(tolerance) <= 0) { + return xNew; + } + + x = xNew; + } + } +} diff --git a/core-java-modules/core-java-numbers-6/src/main/java/com/baeldung/bigintegerroot/algorithms/NewtonPlus.java b/core-java-modules/core-java-numbers-6/src/main/java/com/baeldung/bigintegerroot/algorithms/NewtonPlus.java new file mode 100644 index 0000000000..80d50c0ca5 --- /dev/null +++ b/core-java-modules/core-java-numbers-6/src/main/java/com/baeldung/bigintegerroot/algorithms/NewtonPlus.java @@ -0,0 +1,108 @@ +package com.baeldung.bigintegerroot.algorithms; + +import java.math.BigInteger; + +public class NewtonPlus { + + private NewtonPlus() { + } + + // A fast square root by Ryan Scott White. + public static BigInteger sqrt(BigInteger x) { + if (x.compareTo(BigInteger.valueOf(144838757784765629L)) < 0) { + long xAsLong = x.longValue(); + long vInt = (long)Math.sqrt(xAsLong); + if (vInt * vInt > xAsLong) + vInt--; + return BigInteger.valueOf(vInt); } + + double xAsDub = x.doubleValue(); + BigInteger val; + if (xAsDub < 2.1267e37) // 2.12e37 largest here + // since sqrt(long.max*long.max) > long.max + { + long vInt = (long)Math.sqrt(xAsDub); + val = BigInteger.valueOf + ((vInt + x.divide(BigInteger.valueOf(vInt)).longValue()) >> 1); + } + else if (xAsDub < 4.3322e127) { + // Convert a double to a BigInteger + long bits = Double.doubleToLongBits(Math.sqrt(xAsDub)); + int exp = ((int) (bits >> 52) & 0x7ff) - 1075; + val = BigInteger.valueOf((bits & ((1L << 52)) - 1) | (1L << 52)).shiftLeft(exp); + + val = x.divide(val).add(val).shiftRight(1); + if (xAsDub > 2e63) { + val = x.divide(val).add(val).shiftRight(1); } + } + else // handle large numbers over 4.3322e127 + { + int xLen = x.bitLength(); + int wantedPrecision = ((xLen + 1) / 2); + int xLenMod = xLen + (xLen & 1) + 1; + + //////// Do the first Sqrt on Hardware //////// + long tempX = x.shiftRight(xLenMod - 63).longValue(); + double tempSqrt1 = Math.sqrt(tempX); + long valLong = Double.doubleToLongBits(tempSqrt1) & 0x1fffffffffffffL; + + if (valLong == 0) + valLong = 1L << 53; + + //////// Classic Newton Iterations //////// + val = BigInteger.valueOf(valLong).shiftLeft(53 - 1) + .add((x.shiftRight(xLenMod - + (3 * 53))).divide(BigInteger.valueOf(valLong))); + + int size = 106; + for (; size < 256; size <<= 1) { + val = val.shiftLeft(size - 1).add(x.shiftRight + (xLenMod - (3*size)).divide(val));} + + if (xAsDub > 4e254) { // 4e254 = 1<<845.77 + int numOfNewtonSteps = 31 - + Integer.numberOfLeadingZeros(wantedPrecision / size)+1; + + ////// Apply Starting Size //////// + int wantedSize = (wantedPrecision >> numOfNewtonSteps) + 2; + int needToShiftBy = size - wantedSize; + val = val.shiftRight(needToShiftBy); + + size = wantedSize; + do { + //////// Newton Plus Iteration //////// + int shiftX = xLenMod - (3 * size); + BigInteger valSqrd = val.multiply(val).shiftLeft(size - 1); + BigInteger valSU = x.shiftRight(shiftX).subtract(valSqrd); + val = val.shiftLeft(size).add(valSU.divide(val)); + size *= 2; + } while (size < wantedPrecision); + } + val = val.shiftRight(size - wantedPrecision); + } + + // Detect a round ups. This function can be further optimized - see article. + // For a ~7% speed bump the following line can be removed but round-ups will occur. + if (val.multiply(val).compareTo(x) > 0) + val = val.subtract(BigInteger.ONE); + + // Enabling the below will guarantee an error is stopped for larger numbers. + // Note: As of this writing, there are no known errors. + BigInteger tmp = val.multiply(val); + if (tmp.compareTo(x) > 0) { + System.out.println("val^2(" + val.multiply(val).toString() + + ") ≥ x(" + x.toString()+")"); + System.console().readLine(); + //throw new Exception("Sqrt function had internal error - value too high"); + } + if (tmp.add(val.shiftLeft(1)).add(BigInteger.ONE).compareTo(x) <= 0) { + System.out.println("(val+1)^2(" + + val.add(BigInteger.ONE).multiply(val.add(BigInteger.ONE)).toString() + + ") ≥ x(" + x.toString() + ")"); + System.console().readLine(); + //throw new Exception("Sqrt function had internal error - value too low"); + } + + return val; + } +} diff --git a/core-java-modules/core-java-numbers-6/src/test/java/com/baeldung/bigintegerroot/BigIntegerSquareRootUnitTest.java b/core-java-modules/core-java-numbers-6/src/test/java/com/baeldung/bigintegerroot/BigIntegerSquareRootUnitTest.java new file mode 100644 index 0000000000..edb75b16ef --- /dev/null +++ b/core-java-modules/core-java-numbers-6/src/test/java/com/baeldung/bigintegerroot/BigIntegerSquareRootUnitTest.java @@ -0,0 +1,39 @@ +package com.baeldung.bigintegerroot; + + +import static org.junit.jupiter.api.Assertions.assertTrue; + +import com.baeldung.bigintegerroot.algorithms.Newton; +import com.baeldung.bigintegerroot.algorithms.NewtonPlus; +import com.google.common.math.BigIntegerMath; +import java.math.BigInteger; +import java.math.RoundingMode; +import java.util.stream.Stream; +import org.apache.commons.math3.util.Pair; +import org.junit.jupiter.api.condition.EnabledForJreRange; +import org.junit.jupiter.api.condition.JRE; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +class BigIntegerSquareRootUnitTest { + + @ParameterizedTest + @ValueSource(strings = { + BigIntegerHolder.BIG_NUMBER, + BigIntegerHolder.VERY_BIG_NUMBER, + BigIntegerHolder.VERY_BIG_NUMBER + }) + void squareRootTest(String number) { + final BigInteger bigInteger = new BigInteger(number); + final BigInteger javaRoot = bigInteger.sqrt(); + final BigInteger guavaRoot = BigIntegerMath.sqrt(bigInteger, RoundingMode.DOWN); + final BigInteger newtonRoot = Newton.sqrt(bigInteger); + final BigInteger newtonPlusRoot = NewtonPlus.sqrt(bigInteger); + + assertTrue(Stream.of( + new Pair<>(javaRoot, guavaRoot), + new Pair<>(guavaRoot, newtonRoot), + new Pair<>(newtonRoot, newtonPlusRoot) + ).allMatch(pair -> pair.getFirst().equals(pair.getSecond()))); + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-numbers-6/src/test/java/com/baeldung/javadoublevsbigdecimal/BigDecimalConversionUnitTest.java b/core-java-modules/core-java-numbers-6/src/test/java/com/baeldung/javadoublevsbigdecimal/BigDecimalConversionUnitTest.java new file mode 100644 index 0000000000..76c218d85f --- /dev/null +++ b/core-java-modules/core-java-numbers-6/src/test/java/com/baeldung/javadoublevsbigdecimal/BigDecimalConversionUnitTest.java @@ -0,0 +1,28 @@ +package com.baeldung.javadoublevsbigdecimal; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; + +import java.math.BigDecimal; +import java.math.RoundingMode; + +import org.junit.jupiter.api.Test; + +public class BigDecimalConversionUnitTest { + + @Test + void whenConvertingDoubleToBigDecimal_thenConversionIsCorrect() { + double doubleValue = 123.456; + BigDecimal bigDecimalValue = BigDecimal.valueOf(doubleValue); + BigDecimal expected = new BigDecimal("123.456").setScale(3, RoundingMode.HALF_UP); + assertEquals(expected, bigDecimalValue.setScale(3, RoundingMode.HALF_UP)); + } + + @Test + void givenDecimalPlacesGreaterThan15_whenConvertingBigDecimalToDouble_thenPrecisionIsLost() { + BigDecimal bigDecimalValue = new BigDecimal("789.1234567890123456"); + double doubleValue = bigDecimalValue.doubleValue(); + BigDecimal convertedBackToBigDecimal = BigDecimal.valueOf(doubleValue); + assertNotEquals(bigDecimalValue, convertedBackToBigDecimal); + } +} diff --git a/core-java-modules/core-java-numbers-6/src/test/java/com/baeldung/javadoublevsbigdecimal/BigDecimalUnitTest.java b/core-java-modules/core-java-numbers-6/src/test/java/com/baeldung/javadoublevsbigdecimal/BigDecimalUnitTest.java new file mode 100644 index 0000000000..3ee611f315 --- /dev/null +++ b/core-java-modules/core-java-numbers-6/src/test/java/com/baeldung/javadoublevsbigdecimal/BigDecimalUnitTest.java @@ -0,0 +1,42 @@ +package com.baeldung.javadoublevsbigdecimal; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.math.BigDecimal; +import java.math.RoundingMode; + +import org.junit.jupiter.api.Test; + +public class BigDecimalUnitTest { + + private BigDecimal bigDecimal1 = new BigDecimal("124567890.0987654321"); + private BigDecimal bigDecimal2 = new BigDecimal("987654321.123456789"); + + @Test + public void givenTwoBigDecimals_whenAdd_thenCorrect() { + BigDecimal expected = new BigDecimal("1112222211.2222222211"); + BigDecimal actual = bigDecimal1.add(bigDecimal2); + assertEquals(expected, actual); + } + + @Test + public void givenTwoBigDecimals_whenMultiply_thenCorrect() { + BigDecimal expected = new BigDecimal("123030014929277547.5030955772112635269"); + BigDecimal actual = bigDecimal1.multiply(bigDecimal2); + assertEquals(expected, actual); + } + + @Test + public void givenTwoBigDecimals_whenSubtract_thenCorrect() { + BigDecimal expected = new BigDecimal("-863086431.0246913569"); + BigDecimal actual = bigDecimal1.subtract(bigDecimal2); + assertEquals(expected, actual); + } + + @Test + public void givenTwoBigDecimals_whenDivide_thenCorrect() { + BigDecimal expected = new BigDecimal("0.13"); + BigDecimal actual = bigDecimal1.divide(bigDecimal2, 2, RoundingMode.HALF_UP); + assertEquals(expected, actual); + } +} diff --git a/core-java-modules/core-java-numbers-6/src/test/java/com/baeldung/javadoublevsbigdecimal/JavaDoubleUnitTest.java b/core-java-modules/core-java-numbers-6/src/test/java/com/baeldung/javadoublevsbigdecimal/JavaDoubleUnitTest.java new file mode 100644 index 0000000000..8697e1bfce --- /dev/null +++ b/core-java-modules/core-java-numbers-6/src/test/java/com/baeldung/javadoublevsbigdecimal/JavaDoubleUnitTest.java @@ -0,0 +1,15 @@ +package com.baeldung.javadoublevsbigdecimal; + +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +public class JavaDoubleUnitTest { + + @Test + public void givenDoubleLiteral_whenAssigningToDoubleVariable_thenValueIsNotExactlyEqual() { + double doubleValue = 0.1; + double epsilon = 0.0000000000000001; + assertEquals(0.1, doubleValue, epsilon); + } +} diff --git a/core-java-modules/core-java-numbers-conversions/pom.xml b/core-java-modules/core-java-numbers-conversions/pom.xml index f745b83f8a..d014675ead 100644 --- a/core-java-modules/core-java-numbers-conversions/pom.xml +++ b/core-java-modules/core-java-numbers-conversions/pom.xml @@ -18,6 +18,18 @@ commons-lang3 ${commons-lang3.version} + + org.testng + testng + RELEASE + test + + + junit + junit + 4.13.2 + test + diff --git a/core-java-modules/core-java-numbers-conversions/src/main/java/com/baeldung/floatdoubleconversions/FloatAndDoubleConversions.java b/core-java-modules/core-java-numbers-conversions/src/main/java/com/baeldung/floatdoubleconversions/FloatAndDoubleConversions.java new file mode 100644 index 0000000000..f4fd68550c --- /dev/null +++ b/core-java-modules/core-java-numbers-conversions/src/main/java/com/baeldung/floatdoubleconversions/FloatAndDoubleConversions.java @@ -0,0 +1,15 @@ +package com.baeldung.floatdoubleconversions; + +public class FloatAndDoubleConversions { + public static void main(String args[]){ + float vatRate = 14.432511f; + System.out.println("vatRate:"+vatRate); + Float localTaxRate = 20.12434f; + System.out.println("localTaxRate:"+localTaxRate); + + double shootingAverage = 56.00000000000001; + System.out.println("shootingAverage:"+shootingAverage); + Double assistAverage = 81.123000000045; + System.out.println("assistAverage:"+assistAverage); + } +} diff --git a/core-java-modules/core-java-numbers-conversions/src/test/java/com/baeldung/floatdoubleconversions/FloatDoubleConversionsTest.java b/core-java-modules/core-java-numbers-conversions/src/test/java/com/baeldung/floatdoubleconversions/FloatDoubleConversionsTest.java new file mode 100644 index 0000000000..9c6b01e9de --- /dev/null +++ b/core-java-modules/core-java-numbers-conversions/src/test/java/com/baeldung/floatdoubleconversions/FloatDoubleConversionsTest.java @@ -0,0 +1,29 @@ +package com.baeldung.floatdoubleconversions; + +import org.junit.Assert; +import org.junit.Test; + +public class FloatDoubleConversionsTest { + + @Test + public void whenDoubleType_thenFloatTypeSuccess(){ + double interestRatesYearly = 13.333333333333334; + float interest = (float) interestRatesYearly; + Assert.assertEquals(13.333333f, interest, 0.000004f); + + Double monthlyRates = 2.111111111111112; + float rates = monthlyRates.floatValue(); + Assert.assertEquals(2.1111112f, rates, 0.00000013); + } + @Test + public void whenFloatType_thenDoubleTypeSuccess(){ + float gradeAverage =2.05f; + double average = gradeAverage; + Assert.assertEquals(2.05, average, 0.06); + + Float monthlyRates = 2.1111112f; + Double rates = monthlyRates.doubleValue(); + Assert.assertEquals(2.11111112, rates, 0.0000002);//true + } + +} diff --git a/core-java-modules/core-java-numbers-conversions/src/test/java/com/baeldung/floattobigdecimal/FloatToBigDecimalUnitTest.java b/core-java-modules/core-java-numbers-conversions/src/test/java/com/baeldung/floattobigdecimal/FloatToBigDecimalUnitTest.java new file mode 100644 index 0000000000..f783d00976 --- /dev/null +++ b/core-java-modules/core-java-numbers-conversions/src/test/java/com/baeldung/floattobigdecimal/FloatToBigDecimalUnitTest.java @@ -0,0 +1,49 @@ +package com.baeldung.floattobigdecimal; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; + +import java.math.BigDecimal; + +import org.junit.jupiter.api.Test; + +class FloatToBigDecimalUnitTest { + + @Test + public void whenFloatComparedWithDifferentValues_thenCouldMatch() { + assertNotEquals(1.1f, 1.09f); + assertEquals(1.1f, 1.09999999f); + } + + @Test + public void whenCreatedFromFloat_thenMatchesInternallyStoredValue() { + float floatToConvert = 1.10000002384185791015625f; + BigDecimal bdFromFloat = new BigDecimal(floatToConvert); + assertEquals("1.10000002384185791015625", bdFromFloat.toString()); + } + + @Test + public void whenCreatedFromString_thenPreservesTheOriginal() { + BigDecimal bdFromString = new BigDecimal("1.1"); + assertEquals("1.1", bdFromString.toString()); + } + + @Test + public void whenCreatedFromFloatConvertedToString_thenFloatInternalValueGetsTruncated() { + String floatValue = Float.toString(1.10000002384185791015625f); + BigDecimal bdFromString = new BigDecimal(floatValue); + assertEquals("1.1", floatValue); + assertEquals("1.1", bdFromString.toString()); + } + + @Test + public void whenCreatedByValueOf_thenFloatValueGetsTruncated() { + assertEquals("1.100000023841858", BigDecimal.valueOf(1.10000002384185791015625f).toString()); + } + + @Test + public void whenDoubleConvertsFloatToString_thenFloatValueGetsTruncated() { + assertEquals("1.100000023841858", Double.toString(1.10000002384185791015625f)); + } + +} \ No newline at end of file diff --git a/core-java-modules/core-java-os-2/.gitignore b/core-java-modules/core-java-os-2/.gitignore new file mode 100644 index 0000000000..3de4cc647e --- /dev/null +++ b/core-java-modules/core-java-os-2/.gitignore @@ -0,0 +1,26 @@ +*.class + +0.* + +#folders# +/target +/neoDb* +/data +/src/main/webapp/WEB-INF/classes +*/META-INF/* +.resourceCache + +# Packaged files # +*.jar +*.war +*.ear + +# Files generated by integration tests +*.txt +backup-pom.xml +/bin/ +/temp + +#IntelliJ specific +.idea/ +*.iml \ No newline at end of file diff --git a/core-java-modules/core-java-os-2/README.md b/core-java-modules/core-java-os-2/README.md new file mode 100644 index 0000000000..fa9f504184 --- /dev/null +++ b/core-java-modules/core-java-os-2/README.md @@ -0,0 +1,7 @@ +## Core Java OS + +This module contains articles about working with the operating system (OS) in Java + +### Relevant Articles: + + diff --git a/core-java-modules/core-java-os-2/pom.xml b/core-java-modules/core-java-os-2/pom.xml new file mode 100644 index 0000000000..53fdafa7d4 --- /dev/null +++ b/core-java-modules/core-java-os-2/pom.xml @@ -0,0 +1,42 @@ + + + 4.0.0 + core-java-os + core-java-os + jar + + + com.baeldung.core-java-modules + core-java-modules + 0.0.1-SNAPSHOT + + + + core-java-os + + + src/main/resources + true + + + + + org.apache.maven.plugins + maven-compiler-plugin + ${maven-compiler-plugin.version} + + ${maven.compiler.source} + ${maven.compiler.target} + + + + + + + 1.9 + 1.9 + + + \ No newline at end of file diff --git a/core-java-modules/core-java-os-2/src/main/java/com/baeldung/system/EnvironmentExample.java b/core-java-modules/core-java-os-2/src/main/java/com/baeldung/system/EnvironmentExample.java new file mode 100644 index 0000000000..2557c0cfa8 --- /dev/null +++ b/core-java-modules/core-java-os-2/src/main/java/com/baeldung/system/EnvironmentExample.java @@ -0,0 +1,9 @@ +package com.baeldung.system; + +public class EnvironmentExample { + public void getUserName() { + String username = System.getenv("USERNAME"); + System.out.println("User: " + username); + } + +} diff --git a/core-java-modules/core-java-os-2/src/main/java/com/baeldung/system/PropertiesExample.java b/core-java-modules/core-java-os-2/src/main/java/com/baeldung/system/PropertiesExample.java new file mode 100644 index 0000000000..cb203c40c6 --- /dev/null +++ b/core-java-modules/core-java-os-2/src/main/java/com/baeldung/system/PropertiesExample.java @@ -0,0 +1,19 @@ +package com.baeldung.system; + +public class PropertiesExample { + public void getUserName() { + String username = System.getProperty("user.name"); + System.out.println("User: " + username); + } + + public void getCustomProp() { + String customProperty = System.getProperty("custom.prop"); + System.out.println("Custom property: " + customProperty); + } + + public void getCustomPropWithFallback() { + String customProperty = System.getProperty("non-existent-property", "default value"); + System.out.println("Custom property: " + customProperty); + } + +} diff --git a/core-java-modules/core-java-os/README.md b/core-java-modules/core-java-os/README.md index 6d477de70a..81e67e4663 100644 --- a/core-java-modules/core-java-os/README.md +++ b/core-java-modules/core-java-os/README.md @@ -14,5 +14,6 @@ This module contains articles about working with the operating system (OS) in Ja - [How to Run a Shell Command in Java](http://www.baeldung.com/run-shell-command-in-java) - [Taking Screenshots Using Java](https://www.baeldung.com/java-taking-screenshots) - [Java Sound API – Capturing Microphone](https://www.baeldung.com/java-sound-api-capture-mic) +- [How to Detect the Username Using Java](https://www.baeldung.com/java-get-username) This module uses Java 9, so make sure to have the JDK 9 installed to run it. diff --git a/core-java-modules/core-java-os/src/test/java/com/baeldung/system/WhenDetectingOSUnitTest.java b/core-java-modules/core-java-os/src/test/java/com/baeldung/system/WhenDetectingOSUnitTest.java deleted file mode 100644 index 27a6dd43c6..0000000000 --- a/core-java-modules/core-java-os/src/test/java/com/baeldung/system/WhenDetectingOSUnitTest.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.baeldung.system; - -import org.junit.Assert; -import org.junit.Ignore; -import org.junit.Test; - -@Ignore -public class WhenDetectingOSUnitTest { - - private DetectOS os = new DetectOS(); - - @Test - public void whenUsingSystemProperty_shouldReturnOS() { - String expected = "Windows 10"; - String actual = os.getOperatingSystem(); - Assert.assertEquals(expected, actual); - } - - @Test - public void whenUsingSystemUtils_shouldReturnOS() { - String expected = "Windows 10"; - String actual = os.getOperatingSystemSystemUtils(); - Assert.assertEquals(expected, actual); - } -} diff --git a/core-java-modules/core-java-os/src/test/java/com/baeldung/system/exit/SystemExitUnitTest.java b/core-java-modules/core-java-os/src/test/java/com/baeldung/system/exit/SystemExitUnitTest.java deleted file mode 100644 index 8ad3f75623..0000000000 --- a/core-java-modules/core-java-os/src/test/java/com/baeldung/system/exit/SystemExitUnitTest.java +++ /dev/null @@ -1,64 +0,0 @@ -package com.baeldung.system.exit; - -import org.junit.After; -import org.junit.Before; -import org.junit.Ignore; -import org.junit.Test; - -import java.security.Permission; - -import static org.junit.Assert.assertEquals; - -@Ignore("This test is ignored because it tests deprecated code") -public class SystemExitUnitTest { - - private SecurityManager securityManager; - private SystemExitExample example; - - @Before - public void setUp() { - example = new SystemExitExample(); - securityManager = System.getSecurityManager(); - System.setSecurityManager(new NoExitSecurityManager()); - } - - @After - public void tearDown() throws Exception { - System.setSecurityManager(securityManager); - } - - @Test - public void testExit() throws Exception { - try { - example.readFile(); - } catch (ExitException e) { - assertEquals("Exit status", 2, e.status); - } - } - - protected static class ExitException extends SecurityException { - - private static final long serialVersionUID = 1L; - public final int status; - - public ExitException(int status) { - this.status = status; - } - } - - private static class NoExitSecurityManager extends SecurityManager { - @Override - public void checkPermission(Permission perm) { - } - - @Override - public void checkPermission(Permission perm, Object context) { - } - - @Override - public void checkExit(int status) { - super.checkExit(status); - throw new ExitException(status); - } - } -} \ No newline at end of file diff --git a/core-java-modules/core-java-reflection-3/README.md b/core-java-modules/core-java-reflection-3/README.md new file mode 100644 index 0000000000..d997aa22f1 --- /dev/null +++ b/core-java-modules/core-java-reflection-3/README.md @@ -0,0 +1,2 @@ +### Relevant Articles: +- [Is Java Reflection Bad Practice?](https://www.baeldung.com/java-reflection-bad-practice) diff --git a/core-java-modules/core-java-reflection-3/pom.xml b/core-java-modules/core-java-reflection-3/pom.xml new file mode 100644 index 0000000000..fa5fe897e0 --- /dev/null +++ b/core-java-modules/core-java-reflection-3/pom.xml @@ -0,0 +1,78 @@ + + + 4.0.0 + core-java-reflection-3 + core-java-reflection-3 + jar + + + com.baeldung.core-java-modules + core-java-modules + 0.0.1-SNAPSHOT + + + + + org.springframework + spring-test + ${spring.version} + test + + + org.reflections + reflections + ${reflections.version} + + + + + core-java-reflection-3 + + + src/main/resources + true + + + + + org.apache.maven.plugins + maven-compiler-plugin + ${maven-compiler-plugin.version} + + ${source.version} + ${target.version} + -parameters + + + + org.jacoco + jacoco-maven-plugin + 0.8.8 + + + + prepare-agent + + + + report + prepare-package + + report + + + + + + + + + 0.9.12 + 1.8 + 1.8 + 5.3.4 + + + \ No newline at end of file diff --git a/core-java-modules/core-java-reflection-3/src/main/java/com/baeldung/reflection/disadvantages/encapsulation/MyClass.java b/core-java-modules/core-java-reflection-3/src/main/java/com/baeldung/reflection/disadvantages/encapsulation/MyClass.java new file mode 100644 index 0000000000..680079adea --- /dev/null +++ b/core-java-modules/core-java-reflection-3/src/main/java/com/baeldung/reflection/disadvantages/encapsulation/MyClass.java @@ -0,0 +1,11 @@ +package com.baeldung.reflection.disadvantages.encapsulation; + +public class MyClass { + + private String veryPrivateField; + + public MyClass() { + + this.veryPrivateField = "Secret Information"; + } +} diff --git a/core-java-modules/core-java-reflection-3/src/main/java/com/baeldung/reflection/disadvantages/performance/BenchmarkRunner.java b/core-java-modules/core-java-reflection-3/src/main/java/com/baeldung/reflection/disadvantages/performance/BenchmarkRunner.java new file mode 100644 index 0000000000..1de026f796 --- /dev/null +++ b/core-java-modules/core-java-reflection-3/src/main/java/com/baeldung/reflection/disadvantages/performance/BenchmarkRunner.java @@ -0,0 +1,7 @@ +package com.baeldung.reflection.disadvantages.performance; + +public class BenchmarkRunner { + public static void main(String[] args) throws Exception { + org.openjdk.jmh.Main.main(args); + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-reflection-3/src/main/java/com/baeldung/reflection/disadvantages/performance/InitializationBenchmark.java b/core-java-modules/core-java-reflection-3/src/main/java/com/baeldung/reflection/disadvantages/performance/InitializationBenchmark.java new file mode 100644 index 0000000000..e6c0c3daea --- /dev/null +++ b/core-java-modules/core-java-reflection-3/src/main/java/com/baeldung/reflection/disadvantages/performance/InitializationBenchmark.java @@ -0,0 +1,29 @@ +package com.baeldung.reflection.disadvantages.performance; + +import org.openjdk.jmh.annotations.*; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.util.concurrent.TimeUnit; + +public class InitializationBenchmark { + + @Benchmark + @Fork(value = 1, warmups = 1) + @OutputTimeUnit(TimeUnit.NANOSECONDS) + @BenchmarkMode(Mode.AverageTime) + public void directInit() { + + Person person = new Person("John", "Doe", 50); + } + + @Benchmark + @Fork(value = 1, warmups = 1) + @OutputTimeUnit(TimeUnit.NANOSECONDS) + @BenchmarkMode(Mode.AverageTime) + public void reflectiveInit() throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException { + + Constructor constructor = Person.class.getDeclaredConstructor(String.class, String.class, Integer.class); + Person person = constructor.newInstance("John", "Doe", 50); + } +} diff --git a/core-java-modules/core-java-reflection-3/src/main/java/com/baeldung/reflection/disadvantages/performance/MethodInvocationBenchmark.java b/core-java-modules/core-java-reflection-3/src/main/java/com/baeldung/reflection/disadvantages/performance/MethodInvocationBenchmark.java new file mode 100644 index 0000000000..1128cf8f33 --- /dev/null +++ b/core-java-modules/core-java-reflection-3/src/main/java/com/baeldung/reflection/disadvantages/performance/MethodInvocationBenchmark.java @@ -0,0 +1,48 @@ +package com.baeldung.reflection.disadvantages.performance; + +import org.openjdk.jmh.annotations.*; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.concurrent.TimeUnit; + +public class MethodInvocationBenchmark { + + @Benchmark + @Fork(value = 1, warmups = 1) + @OutputTimeUnit(TimeUnit.NANOSECONDS) + @BenchmarkMode(Mode.AverageTime) + public void directCall() { + + directCall(new Person("John", "Doe", 50)); + } + + @Benchmark + @Fork(value = 1, warmups = 1) + @OutputTimeUnit(TimeUnit.NANOSECONDS) + @BenchmarkMode(Mode.AverageTime) + public void reflectiveCall() throws InvocationTargetException, NoSuchMethodException, IllegalAccessException { + + reflectiveCall(new Person("John", "Doe", 50)); + } + + + private void directCall(Person person) { + + person.getFirstName(); + person.getLastName(); + person.getAge(); + } + + private void reflectiveCall(Person person) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + + Method getFirstNameMethod = Person.class.getMethod("getFirstName"); + getFirstNameMethod.invoke(person); + + Method getLastNameMethod = Person.class.getMethod("getLastName"); + getLastNameMethod.invoke(person); + + Method getAgeMethod = Person.class.getMethod("getAge"); + getAgeMethod.invoke(person); + } +} diff --git a/core-java-modules/core-java-reflection-3/src/main/java/com/baeldung/reflection/disadvantages/performance/Person.java b/core-java-modules/core-java-reflection-3/src/main/java/com/baeldung/reflection/disadvantages/performance/Person.java new file mode 100644 index 0000000000..014c82ba45 --- /dev/null +++ b/core-java-modules/core-java-reflection-3/src/main/java/com/baeldung/reflection/disadvantages/performance/Person.java @@ -0,0 +1,38 @@ +package com.baeldung.reflection.disadvantages.performance; + +public class Person { + + private String firstName; + private String lastName; + private Integer age; + + public Person(String firstName, String lastName, Integer age) { + this.firstName = firstName; + this.lastName = lastName; + this.age = age; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + public Integer getAge() { + return age; + } + + public void setAge(Integer age) { + this.age = age; + } +} diff --git a/core-java-modules/core-java-reflection-3/src/test/java/com/baeldung/reflection/disadvantages/encapsulation/ReflectionEncapsulationUnitTest.java b/core-java-modules/core-java-reflection-3/src/test/java/com/baeldung/reflection/disadvantages/encapsulation/ReflectionEncapsulationUnitTest.java new file mode 100644 index 0000000000..efb0a7da31 --- /dev/null +++ b/core-java-modules/core-java-reflection-3/src/test/java/com/baeldung/reflection/disadvantages/encapsulation/ReflectionEncapsulationUnitTest.java @@ -0,0 +1,21 @@ +package com.baeldung.reflection.disadvantages.encapsulation; + +import org.junit.jupiter.api.Test; + +import java.lang.reflect.Field; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class ReflectionEncapsulationUnitTest { + + @Test + public void givenPrivateField_whenUsingReflection_thenIsAccessible() throws IllegalAccessException, NoSuchFieldException { + MyClass myClassInstance = new MyClass(); + + Field privateField = MyClass.class.getDeclaredField("veryPrivateField"); + privateField.setAccessible(true); + + String accessedField = privateField.get(myClassInstance).toString(); + assertEquals(accessedField, "Secret Information"); + } +} diff --git a/core-java-modules/core-java-regex-2/README.md b/core-java-modules/core-java-regex-2/README.md index 02e470cce5..404b33b65f 100644 --- a/core-java-modules/core-java-regex-2/README.md +++ b/core-java-modules/core-java-regex-2/README.md @@ -9,4 +9,5 @@ - [Regular Expression: \z vs \Z Anchors in Java](https://www.baeldung.com/java-regular-expression-z-vs-z-anchors) - [Extract Text Between Square Brackets](https://www.baeldung.com/java-get-content-between-square-brackets) - [Get the Indexes of Regex Pattern Matches in Java](https://www.baeldung.com/java-indexes-regex-pattern-matches) +- [Check if a String is Strictly Alphanumeric With Java](https://www.baeldung.com/java-check-string-contains-only-letters-numbers) - More articles: [[<-- prev]](/core-java-modules/core-java-regex) diff --git a/core-java-modules/core-java-regex-2/src/main/java/com/baeldung/alphanumeric/AlphanumericPerformanceBenchmark.java b/core-java-modules/core-java-regex-2/src/main/java/com/baeldung/alphanumeric/AlphanumericPerformanceBenchmark.java new file mode 100644 index 0000000000..4b2ecc4c4d --- /dev/null +++ b/core-java-modules/core-java-regex-2/src/main/java/com/baeldung/alphanumeric/AlphanumericPerformanceBenchmark.java @@ -0,0 +1,91 @@ +package com.baeldung.alphanumeric; + +import java.util.concurrent.TimeUnit; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.infra.Blackhole; + +@Warmup(iterations = 1) +@Measurement(iterations = 1, time = 1, timeUnit = TimeUnit.MINUTES) +@Fork(1) +public class AlphanumericPerformanceBenchmark { + + private static final String TEST_STRING = "ABC123abc123"; + private static final String REGEX = "[^[a-zA-Z0-9]*$]"; + private static final Pattern PATTERN = Pattern.compile(REGEX); + + @Benchmark + @BenchmarkMode(Mode.Throughput) + public void alphanumericRegex(Blackhole blackhole) { + final Matcher matcher = PATTERN.matcher(TEST_STRING); + boolean result = matcher.matches(); + blackhole.consume(result); + } + + @Benchmark + @BenchmarkMode(Mode.Throughput) + public void alphanumericRegexDirectlyOnString(Blackhole blackhole) { + boolean result = TEST_STRING.matches(REGEX); + blackhole.consume(result); + } + + @Benchmark + @BenchmarkMode(Mode.Throughput) + public void alphanumericIteration(Blackhole blackhole) { + boolean result = true; + for (int i = 0; i < TEST_STRING.length(); ++i) { + final int codePoint = TEST_STRING.codePointAt(i); + if (!isAlphanumeric(codePoint)) { + result = false; + break; + } + } + blackhole.consume(result); + } + + @Benchmark + @BenchmarkMode(Mode.Throughput) + public void alphanumericIterationWithCharacterChecks(Blackhole blackhole) { + boolean result = true; + for (int i = 0; i < TEST_STRING.length(); ++i) { + final int codePoint = TEST_STRING.codePointAt(i); + if (!Character.isAlphabetic(codePoint) || !Character.isDigit(codePoint)) { + result = false; + break; + } + } + blackhole.consume(result); + } + + @Benchmark + @BenchmarkMode(Mode.Throughput) + public void alphanumericIterationWithCopy(Blackhole blackhole) { + boolean result = true; + for (final char c : TEST_STRING.toCharArray()) { + if (!isAlphanumeric(c)) { + result = false; + break; + } + } + blackhole.consume(result); + } + + @Benchmark + @BenchmarkMode(Mode.Throughput) + public void alphanumericIterationWithStream(Blackhole blackhole) { + boolean result = TEST_STRING.chars().allMatch(this::isAlphanumeric); + blackhole.consume(result); + } + + public boolean isAlphanumeric(final int codePoint) { + return (codePoint >= 65 && codePoint <= 90) || + (codePoint >= 97 && codePoint <= 172) || + (codePoint >= 48 && codePoint <= 57); + } +} diff --git a/core-java-modules/core-java-regex-2/src/test/java/com/baeldung/alphanumeric/AlphanumericUnitTest.java b/core-java-modules/core-java-regex-2/src/test/java/com/baeldung/alphanumeric/AlphanumericUnitTest.java new file mode 100644 index 0000000000..b00bf7c4e3 --- /dev/null +++ b/core-java-modules/core-java-regex-2/src/test/java/com/baeldung/alphanumeric/AlphanumericUnitTest.java @@ -0,0 +1,30 @@ +package com.baeldung.alphanumeric; + +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +class AlphanumericUnitTest { + + private AlphanumericPerformanceBenchmark alphanumericPerformanceBenchmark = new AlphanumericPerformanceBenchmark(); + + @ParameterizedTest + @CsvSource({ + "A,true", + "B,true", + "C,true", + "1,true", + "2,true", + "3,true", + "!,false", + "@,false", + "#,false", + "$,false", + "%,false" + }) + void shouldCorrectlyIdentifyAlphanumericCharacterTest(char character, boolean result) { + boolean actual = alphanumericPerformanceBenchmark.isAlphanumeric(character); + assertEquals(actual, result); + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-security/src/main/java/com/baeldung/ssl/SecureConnection.java b/core-java-modules/core-java-security/src/main/java/com/baeldung/ssl/SecureConnection.java index 36dee603eb..6f2e3250fc 100644 --- a/core-java-modules/core-java-security/src/main/java/com/baeldung/ssl/SecureConnection.java +++ b/core-java-modules/core-java-security/src/main/java/com/baeldung/ssl/SecureConnection.java @@ -7,7 +7,7 @@ import javax.net.ssl.SSLSocket; import javax.net.ssl.SSLSocketFactory; public class SecureConnection { - + public static void main(String[] args) { if (args.length != 2) { System.out.println("Use: SecureConnection host port"); @@ -20,20 +20,20 @@ public class SecureConnection { SSLSocket sslsocket = (SSLSocket) sslsocketfactory.createSocket(host, port); InputStream in = sslsocket.getInputStream(); OutputStream out = sslsocket.getOutputStream(); - + out.write(1); - + while (in.available() > 0) { System.out.print(in.read()); } - + System.out.println("Secured connection performed successfully"); - + } catch (Exception exception) { exception.printStackTrace(); } } - + /** * Get the host from arguments * @param args the arguments @@ -42,7 +42,7 @@ public class SecureConnection { private static String getHost(String[] args) { return args[0]; } - + /** * Get the port from arguments * @param args the arguments diff --git a/core-java-modules/core-java-security/src/main/java/com/baeldung/ssl/example/SimpleClient.java b/core-java-modules/core-java-security/src/main/java/com/baeldung/ssl/example/SimpleClient.java index d6efc34c3e..cf9a76b39a 100644 --- a/core-java-modules/core-java-security/src/main/java/com/baeldung/ssl/example/SimpleClient.java +++ b/core-java-modules/core-java-security/src/main/java/com/baeldung/ssl/example/SimpleClient.java @@ -15,10 +15,8 @@ public class SimpleClient { SocketFactory factory = SSLSocketFactory.getDefault(); try (Socket connection = factory.createSocket(host, port)) { - ((SSLSocket) connection).setEnabledCipherSuites( - new String[] { "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256"}); - ((SSLSocket) connection).setEnabledProtocols( - new String[] { "TLSv1.2"}); + ((SSLSocket) connection).setEnabledCipherSuites(new String[] { "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256" }); + ((SSLSocket) connection).setEnabledProtocols(new String[] { "TLSv1.2" }); SSLParameters sslParams = new SSLParameters(); sslParams.setEndpointIdentificationAlgorithm("HTTPS"); ((SSLSocket) connection).setSSLParameters(sslParams); @@ -28,6 +26,7 @@ public class SimpleClient { } public static void main(String[] args) throws IOException { + System.setProperty("javax.net.debug", "ssl:handshake"); System.out.println(startClient("localhost", 8443)); } } diff --git a/core-java-modules/core-java-security/src/main/java/com/baeldung/ssl/example/SimpleServer.java b/core-java-modules/core-java-security/src/main/java/com/baeldung/ssl/example/SimpleServer.java index 27d15d04d7..83946ccc1f 100644 --- a/core-java-modules/core-java-security/src/main/java/com/baeldung/ssl/example/SimpleServer.java +++ b/core-java-modules/core-java-security/src/main/java/com/baeldung/ssl/example/SimpleServer.java @@ -14,11 +14,10 @@ public class SimpleServer { ServerSocketFactory factory = SSLServerSocketFactory.getDefault(); try (ServerSocket listener = factory.createServerSocket(port)) { + System.setProperty("javax.net.debug", "ssl:handshake"); ((SSLServerSocket) listener).setNeedClientAuth(true); - ((SSLServerSocket) listener).setEnabledCipherSuites( - new String[] { "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256"}); - ((SSLServerSocket) listener).setEnabledProtocols( - new String[] { "TLSv1.2"}); + ((SSLServerSocket) listener).setEnabledCipherSuites(new String[] { "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256" }); + ((SSLServerSocket) listener).setEnabledProtocols(new String[] { "TLSv1.2" }); while (true) { try (Socket socket = listener.accept()) { PrintWriter out = new PrintWriter(socket.getOutputStream(), true); @@ -29,6 +28,7 @@ public class SimpleServer { } public static void main(String[] args) throws IOException { + System.setProperty("javax.net.debug", "ssl:handshake"); startServer(8443); } } \ No newline at end of file diff --git a/core-java-modules/core-java-streams-5/README.md b/core-java-modules/core-java-streams-5/README.md index dec4a7a0cb..e7c58a0eb2 100644 --- a/core-java-modules/core-java-streams-5/README.md +++ b/core-java-modules/core-java-streams-5/README.md @@ -3,3 +3,4 @@ - [Working With Empty Stream in Java](https://www.baeldung.com/java-empty-stream) - [Aggregate Runtime Exceptions in Java Streams](https://www.baeldung.com/java-streams-aggregate-exceptions) - [Streams vs. Loops in Java](https://www.baeldung.com/java-streams-vs-loops) +- [Partition a Stream in Java](https://www.baeldung.com/java-partition-stream) diff --git a/core-java-modules/core-java-streams-5/pom.xml b/core-java-modules/core-java-streams-5/pom.xml index dc97d81b3d..d7baf84d30 100644 --- a/core-java-modules/core-java-streams-5/pom.xml +++ b/core-java-modules/core-java-streams-5/pom.xml @@ -43,6 +43,11 @@ vavr ${vavr.version} + + com.google.guava + guava + ${guava.version} + @@ -72,6 +77,7 @@ 12 12 0.10.2 + 32.1.2-jre \ No newline at end of file diff --git a/core-java-modules/core-java-streams-5/src/main/java/com/baeldung/streams/partitioning/PartitionStream.java b/core-java-modules/core-java-streams-5/src/main/java/com/baeldung/streams/partitioning/PartitionStream.java new file mode 100644 index 0000000000..1ef3fa7707 --- /dev/null +++ b/core-java-modules/core-java-streams-5/src/main/java/com/baeldung/streams/partitioning/PartitionStream.java @@ -0,0 +1,90 @@ +package com.baeldung.streams.partitioning; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.BiConsumer; +import java.util.function.BinaryOperator; +import java.util.function.Function; +import java.util.function.Supplier; +import java.util.stream.Collector; +import java.util.stream.Collectors; +import java.util.stream.IntStream; +import java.util.stream.Stream; + +import com.google.common.collect.Iterables; + +public class PartitionStream { + + public static Stream> partitionList(List source, int batchSize) { + if (batchSize <= 0) { + throw new IllegalArgumentException(String.format("Expected the batchSize to be greater than ZERO, actual value was: %s", batchSize)); + } + if (source.isEmpty()) { + return Stream.empty(); + } + int nrOfFullBatches = (source.size() - 1) / batchSize; + return IntStream.rangeClosed(0, nrOfFullBatches) + .mapToObj(batch -> { + int startIndex = batch * batchSize; + int endIndex = (batch == nrOfFullBatches) ? source.size() : (batch + 1) * batchSize; + return source.subList(startIndex, endIndex); + }); + } + + public static Iterable> partitionUsingGuava(Stream source, int batchSize) { + return Iterables.partition(source::iterator, batchSize); + } + + public static List> partitionStream(Stream source, int batchSize) { + return source.collect(partitionBySize(batchSize, Collectors.toList())); + } + + public static Collector partitionBySize(int batchSize, Collector, A, R> downstream) { + Supplier> supplier = () -> new Accumulator<>( + batchSize, + downstream.supplier().get(), + downstream.accumulator()::accept + ); + + BiConsumer, T> accumulator = (acc, value) -> acc.add(value); + + BinaryOperator> combiner = (acc1, acc2) -> acc1.combine(acc2, downstream.combiner()); + + Function, R> finisher = acc -> { + if (!acc.values.isEmpty()) { + downstream.accumulator().accept(acc.downstreamAccumulator, acc.values); + } + return downstream.finisher().apply(acc.downstreamAccumulator); + }; + + return Collector.of(supplier, accumulator, combiner, finisher, Collector.Characteristics.UNORDERED); + } + + static class Accumulator { + private final List values = new ArrayList<>(); + private final int batchSize; + private A downstreamAccumulator; + private final BiConsumer> batchFullListener; + + Accumulator(int batchSize, A accumulator, BiConsumer> onBatchFull) { + this.batchSize = batchSize; + this.downstreamAccumulator = accumulator; + this.batchFullListener = onBatchFull; + } + + void add(T value) { + values.add(value); + if (values.size() == batchSize) { + batchFullListener.accept(downstreamAccumulator, new ArrayList<>(values)); + values.clear(); + } + } + + Accumulator combine(Accumulator other, BinaryOperator accumulatorCombiner) { + this.downstreamAccumulator = accumulatorCombiner.apply(downstreamAccumulator, other.downstreamAccumulator); + other.values.forEach(this::add); + return this; + } + } + +} diff --git a/core-java-modules/core-java-streams-5/src/test/java/com/baeldung/partitioning/PartitionStreamsUnitTest.java b/core-java-modules/core-java-streams-5/src/test/java/com/baeldung/partitioning/PartitionStreamsUnitTest.java new file mode 100644 index 0000000000..df75e69783 --- /dev/null +++ b/core-java-modules/core-java-streams-5/src/test/java/com/baeldung/partitioning/PartitionStreamsUnitTest.java @@ -0,0 +1,82 @@ +package com.baeldung.partitioning; + +import static com.baeldung.streams.partitioning.PartitionStream.partitionList; +import static com.baeldung.streams.partitioning.PartitionStream.partitionStream; +import static com.baeldung.streams.partitioning.PartitionStream.partitionUsingGuava; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.assertj.core.api.Assertions.atIndex; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.stream.Stream; + +import org.junit.jupiter.api.Test; + +public class PartitionStreamsUnitTest { + + @Test + void whenPartitionList_thenReturnThreeSubLists() { + List source = List.of(1, 2, 3, 4, 5, 6, 7, 8); + + Stream> result = partitionList(source, 3); + + assertThat(result) + .containsExactlyInAnyOrder( + List.of(1, 2, 3), + List.of(4, 5, 6), + List.of(7, 8) + ); + } + + @Test + void whenPartitionEmptyList_thenReturnEmptyStream() { + Stream> result = partitionList(Collections.emptyList(), 3); + + assertThat(result).isEmpty(); + } + + @Test + void whenPartitionListWithNegativeBatchSize_thenThrowException() { + assertThatThrownBy(() -> partitionList(List.of(1,2,3), -1)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("Expected the batchSize to be greater than ZERO, actual value was: -1"); + } + + @Test + void whenPartitionParallelStream_thenReturnThreeSubLists() { + Stream source = Stream.of(1, 2, 3, 4, 5, 6, 7, 8).parallel(); + + List> result = partitionStream(source, 3); + + assertThat(result) + .hasSize(3) + .satisfies(batch -> assertThat(batch).hasSize(3), atIndex(0)) + .satisfies(batch -> assertThat(batch).hasSize(3), atIndex(1)) + .satisfies(batch -> assertThat(batch).hasSize(2), atIndex(2)); + } + + @Test + void whenPartitionEmptyParallelStream_thenReturnEmptyList() { + Stream source = Stream.empty().parallel(); + + List> result = partitionStream(source, 3); + + assertThat(result).isEmpty(); + } + + @Test + void whenPartitionParallelStreamWithGuava_thenReturnThreeSubLists() { + Stream source = Stream.of(1, 2, 3, 4, 5, 6, 7, 8).parallel(); + + Iterable> result = partitionUsingGuava(source, 3); + + assertThat(result) + .map(ArrayList::new) + .hasSize(3) + .satisfies(batch -> assertThat(batch).asList().hasSize(3), atIndex(0)) + .satisfies(batch -> assertThat(batch).asList().hasSize(3), atIndex(1)) + .satisfies(batch -> assertThat(batch).asList().hasSize(2), atIndex(2)); + } +} diff --git a/core-java-modules/core-java-string-algorithms-3/README.md b/core-java-modules/core-java-string-algorithms-3/README.md index 2bb70f5c97..3ef07129ed 100644 --- a/core-java-modules/core-java-string-algorithms-3/README.md +++ b/core-java-modules/core-java-string-algorithms-3/README.md @@ -11,4 +11,5 @@ This module contains articles about string-related algorithms. - [Find the First Non Repeating Character in a String in Java](https://www.baeldung.com/java-find-the-first-non-repeating-character) - [Find the First Embedded Occurrence of an Integer in a Java String](https://www.baeldung.com/java-string-find-embedded-integer) - [Find the Most Frequent Characters in a String](https://www.baeldung.com/java-string-find-most-frequent-characters) -- [Checking If a String Is a Repeated Substring](https://www.baeldung.com/java-repeated-substring) \ No newline at end of file +- [Checking If a String Is a Repeated Substring](https://www.baeldung.com/java-repeated-substring) +- [Check if Letter Is Emoji With Java](https://www.baeldung.com/java-check-letter-emoji) diff --git a/core-java-modules/core-java-string-apis/src/test/java/com/baeldung/charsequence/CharSequenceVsStringUnitTest.java b/core-java-modules/core-java-string-apis/src/test/java/com/baeldung/charsequence/CharSequenceVsStringUnitTest.java index aa15345bcb..13a0407a98 100644 --- a/core-java-modules/core-java-string-apis/src/test/java/com/baeldung/charsequence/CharSequenceVsStringUnitTest.java +++ b/core-java-modules/core-java-string-apis/src/test/java/com/baeldung/charsequence/CharSequenceVsStringUnitTest.java @@ -1,11 +1,11 @@ package com.baeldung.charsequence; -import org.junit.Test; - import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertTrue; +import org.junit.Test; + public class CharSequenceVsStringUnitTest { @Test @@ -44,4 +44,43 @@ public class CharSequenceVsStringUnitTest { assertEquals(firstAddressOfTest, secondAddressOfTest); } + + @Test + public void givenCharSequenceAsString_whenConvertingUsingCasting_thenCorrect() { + String expected = "baeldung"; + CharSequence charSequence = "baeldung"; + String explicitCastedString = (String) charSequence; + + assertEquals(expected, charSequence); + assertEquals(expected, explicitCastedString); + } + + @Test(expected = ClassCastException.class) + public void givenCharSequenceAsStringBuiler_whenConvertingUsingCasting_thenThrowException() { + CharSequence charSequence = new StringBuilder("baeldung"); + String castedString = (String) charSequence; + } + + @Test + public void givenCharSequence_whenConvertingUsingToString_thenCorrect() { + String expected = "baeldung"; + CharSequence charSequence1 = "baeldung"; + CharSequence charSequence2 = new StringBuilder("baeldung"); + + assertEquals(expected, charSequence1.toString()); + assertEquals(expected, charSequence2.toString()); + } + + @Test + public void givenCharSequence_whenConvertingUsingValueOf_thenCorrect() { + String expected = "baeldung"; + CharSequence charSequence1 = "baeldung"; + CharSequence charSequence2 = new StringBuilder("baeldung"); + CharSequence charSequence3 = null; + + assertEquals(expected, String.valueOf(charSequence1)); + assertEquals(expected, String.valueOf(charSequence2)); + assertEquals("null", String.valueOf(charSequence3)); + } + } diff --git a/core-java-modules/core-java-string-conversions-3/src/test/java/com/baeldung/stringsplitkeyvalue/StringSplitKeyValueUnitTest.java b/core-java-modules/core-java-string-conversions-3/src/test/java/com/baeldung/stringsplitkeyvalue/StringSplitKeyValueUnitTest.java new file mode 100644 index 0000000000..25f68ff373 --- /dev/null +++ b/core-java-modules/core-java-string-conversions-3/src/test/java/com/baeldung/stringsplitkeyvalue/StringSplitKeyValueUnitTest.java @@ -0,0 +1,80 @@ +package com.baeldung.stringsplitkeyvalue; + +import org.junit.jupiter.api.Test; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.StringTokenizer; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class StringSplitKeyValueUnitTest { + +@Test +public void givenStringData_whenUsingTokenizer_thenTokenizeAndValidate() { + String data = "name=John age=30 city=NewYork"; + StringTokenizer tokenizer = new StringTokenizer(data); + + // Create a map to store key-value pairs + Map keyValueMap = new HashMap<>(); + + while (tokenizer.hasMoreTokens()) { + String token = tokenizer.nextToken(); + String[] keyValue = token.split("="); + + if (keyValue.length == 2) { + String key = keyValue[0]; + String value = keyValue[1]; + + // Store key-value pairs in the map + keyValueMap.put(key, value); + } + } + + // Use assertions to validate the key-value pairs in the map + assertEquals("John", keyValueMap.get("name")); + assertEquals("30", keyValueMap.get("age")); + assertEquals("NewYork", keyValueMap.get("city")); +} + + +@Test +public void givenDataWithPattern_whenUsingMatcher_thenPerformPatternMatching() { + String data = "name=John,age=30;city=NewYork"; + Pattern pattern = Pattern.compile("\\b(\\w+)=(\\w+)\\b"); + Matcher matcher = pattern.matcher(data); + + // Create a map to store key-value pairs + Map keyValueMap = new HashMap<>(); + + while (matcher.find()) { + String key = matcher.group(1); + String value = matcher.group(2); + + // Store key-value pairs in the map + keyValueMap.put(key, value); + } + + // Use assertions to validate the key-value pairs in the map + assertEquals("John", keyValueMap.get("name")); + assertEquals("30", keyValueMap.get("age")); + assertEquals("NewYork", keyValueMap.get("city")); +} + + @Test + public void givenStringData_whenUsingJavaMap_thenSplitAndValidate() { + String data = "name=John age=30 city=NewYork"; + Map keyValueMap = Arrays.stream(data.split(" ")) + .map(kv -> kv.split("=")) + .filter(kvArray -> kvArray.length == 2) + .collect(Collectors.toMap(kv -> kv[0], kv -> kv[1])); + + assertEquals("John", keyValueMap.get("name")); + assertEquals("30", keyValueMap.get("age")); + assertEquals("NewYork", keyValueMap.get("city")); + } +} diff --git a/core-java-modules/core-java-string-operations-5/README.md b/core-java-modules/core-java-string-operations-5/README.md index fda7f39654..dffd3c1ab6 100644 --- a/core-java-modules/core-java-string-operations-5/README.md +++ b/core-java-modules/core-java-string-operations-5/README.md @@ -11,4 +11,3 @@ - [Check if the First Letter of a String Is a Number](https://www.baeldung.com/java-check-if-string-starts-with-number) - [Print “” Quotes Around a String in Java](https://www.baeldung.com/java-string-print-quotes) - [Remove Punctuation From a String in Java](https://www.baeldung.com/java-remove-punctuation-from-string) -- [Replacing Single Quote with \’ in Java String](https://www.baeldung.com/java-replacing-single-quote-string) diff --git a/core-java-modules/core-java-string-operations-6/README.md b/core-java-modules/core-java-string-operations-6/README.md index 853d58287d..b4b78d1ad7 100644 --- a/core-java-modules/core-java-string-operations-6/README.md +++ b/core-java-modules/core-java-string-operations-6/README.md @@ -10,3 +10,5 @@ - [Check if a String Contains Non-Alphanumeric Characters](https://www.baeldung.com/java-string-test-special-characters) - [Check if a String Has All Unique Characters in Java](https://www.baeldung.com/java-check-string-all-unique-chars) - [Performance Comparison Between Different Java String Concatenation Methods](https://www.baeldung.com/java-string-concatenation-methods) +- [Replacing Single Quote with \’ in Java String](https://www.baeldung.com/java-replacing-single-quote-string) + diff --git a/core-java-modules/core-java-string-operations-5/src/test/java/com/baeldung/replace/ReplaceStringUnitTest.java b/core-java-modules/core-java-string-operations-6/src/test/java/com/baeldung/replace/ReplaceStringUnitTest.java similarity index 100% rename from core-java-modules/core-java-string-operations-5/src/test/java/com/baeldung/replace/ReplaceStringUnitTest.java rename to core-java-modules/core-java-string-operations-6/src/test/java/com/baeldung/replace/ReplaceStringUnitTest.java diff --git a/core-java-modules/pom.xml b/core-java-modules/pom.xml index 34e5204868..5b5255daa1 100644 --- a/core-java-modules/pom.xml +++ b/core-java-modules/pom.xml @@ -28,13 +28,14 @@ core-java-9-improvements - core-java-collections-array-list core-java-9-streams core-java-9 core-java-10 core-java-11 core-java-11-2 core-java-11-3 + core-java-collections-array-list + core-java-collections-array-list-2 core-java-collections-list-4 core-java-collections-list-5 core-java-collections-maps-4 @@ -78,9 +79,11 @@ core-java-collections-list core-java-collections-list-2 core-java-collections-list-3 + core-java-collections-list-6 core-java-collections-maps core-java-collections-maps-2 core-java-collections-maps-3 + core-java-collections-maps-7 core-java-compiler core-java-concurrency-2 core-java-concurrency-advanced @@ -108,6 +111,7 @@ core-java-io-2 core-java-io-3 core-java-io-4 + core-java-io-5 core-java-io-apis core-java-io-apis-2 core-java-io-conversions @@ -154,6 +158,7 @@ core-java-properties core-java-reflection core-java-reflection-2 + core-java-reflection-3 core-java-scanner core-java-security-2 core-java-security-3 diff --git a/jenkins-modules/plugins/pom.xml b/jenkins-modules/plugins/pom.xml index 42add1664e..c2b1408556 100644 --- a/jenkins-modules/plugins/pom.xml +++ b/jenkins-modules/plugins/pom.xml @@ -12,6 +12,7 @@ org.jenkins-ci.plugins plugin 2.33 + diff --git a/jersey/pom.xml b/jersey/pom.xml index c2b37f7118..d279406e9a 100644 --- a/jersey/pom.xml +++ b/jersey/pom.xml @@ -76,6 +76,11 @@ jersey-apache-connector ${jersey.version} + + org.glassfish.jersey.media + jersey-media-multipart + ${jersey.version} + @@ -102,4 +107,4 @@ 3.1.1 - \ No newline at end of file + diff --git a/jersey/src/main/java/com/baeldung/jersey/server/form/FormExampleResource.java b/jersey/src/main/java/com/baeldung/jersey/server/form/FormExampleResource.java new file mode 100644 index 0000000000..15e82679ef --- /dev/null +++ b/jersey/src/main/java/com/baeldung/jersey/server/form/FormExampleResource.java @@ -0,0 +1,61 @@ +package com.baeldung.jersey.server.form; + +import jakarta.ws.rs.*; +import jakarta.ws.rs.core.MediaType; +import org.glassfish.jersey.media.multipart.FormDataParam; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; + +@Path("form") +public class FormExampleResource +{ + @GET + @Path("/example1") + @Produces({MediaType.TEXT_HTML}) + public InputStream getExample1() throws Exception + { + File f = new File("src/main/resources/html/example1.html"); + return new FileInputStream(f); + } + + @GET + @Path("/example2") + @Produces({MediaType.TEXT_HTML}) + public InputStream getExample2() throws Exception + { + File f = new File("src/main/resources/html/example2.html"); + return new FileInputStream(f); + } + + @POST + @Path("/example1") + public String example1(@FormParam("first_name") String firstName, + @FormParam("last_name") String lastName, + @FormParam("age") String age) + { + return "Got: First = " + firstName + ", Last = " + lastName + ", Age = " + age; + } + + @POST + @Path("/example2") + @Consumes(MediaType.MULTIPART_FORM_DATA) + public String example2(@FormDataParam("first_name") String firstName, + @FormDataParam("last_name") String lastName, + @FormDataParam("age") String age, + @FormDataParam("photo") InputStream photo) + throws Exception + { + int len; + int size = 1024; + byte[] buf; + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + buf = new byte[size]; + while ((len = photo.read(buf, 0, size)) != -1) + bos.write(buf, 0, len); + buf = bos.toByteArray(); + return "Got: First = " + firstName + ", Last = " + lastName + ", Age = " + age + ", Photo (# of bytes) = " + buf.length; + } +} diff --git a/jersey/src/main/resources/formexamples/example1.html b/jersey/src/main/resources/formexamples/example1.html new file mode 100644 index 0000000000..6335dcce08 --- /dev/null +++ b/jersey/src/main/resources/formexamples/example1.html @@ -0,0 +1,16 @@ + + + Example 1 using @FormParam + + +
+ + + + + + + +
+ + diff --git a/jersey/src/main/resources/formexamples/example2.html b/jersey/src/main/resources/formexamples/example2.html new file mode 100644 index 0000000000..4875c652a4 --- /dev/null +++ b/jersey/src/main/resources/formexamples/example2.html @@ -0,0 +1,18 @@ + + + Example 2 using @FormDataParam + + +
+ + + + + + + + + +
+ + diff --git a/libraries-apache-commons-2/pom.xml b/libraries-apache-commons-2/pom.xml index d771aac9ab..ee9b51e6cc 100644 --- a/libraries-apache-commons-2/pom.xml +++ b/libraries-apache-commons-2/pom.xml @@ -28,12 +28,18 @@ commons-vfs2 ${commons-vfs2.version} + + org.apache.commons + commons-text + ${apache-commons-text.version} + 1.23.0 1.10.13 2.9.0 + 1.10.0 \ No newline at end of file diff --git a/libraries-apache-commons-2/src/main/java/com/baeldung/commons/convertunicode/UnicodeConverterUtil.java b/libraries-apache-commons-2/src/main/java/com/baeldung/commons/convertunicode/UnicodeConverterUtil.java new file mode 100644 index 0000000000..c788f6ee61 --- /dev/null +++ b/libraries-apache-commons-2/src/main/java/com/baeldung/commons/convertunicode/UnicodeConverterUtil.java @@ -0,0 +1,29 @@ +package com.baeldung.commons.convertunicode; + +import org.apache.commons.text.StringEscapeUtils; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class UnicodeConverterUtil { + + public static String decodeWithApacheCommons(String input) { + return StringEscapeUtils.unescapeJava(input); + } + + public static String decodeWithPlainJava(String input) { + Pattern pattern = Pattern.compile("\\\\u[0-9a-fA-F]{4}"); + Matcher matcher = pattern.matcher(input); + + StringBuilder decodedString = new StringBuilder(); + + while (matcher.find()) { + String unicodeSequence = matcher.group(); + char unicodeChar = (char) Integer.parseInt(unicodeSequence.substring(2), 16); + matcher.appendReplacement(decodedString, Character.toString(unicodeChar)); + } + + matcher.appendTail(decodedString); + return decodedString.toString(); + } +} diff --git a/libraries-apache-commons-2/src/test/java/com/baeldung/commons/convertunicode/UnicodeConverterUnitTest.java b/libraries-apache-commons-2/src/test/java/com/baeldung/commons/convertunicode/UnicodeConverterUnitTest.java new file mode 100644 index 0000000000..f4a9bbcb77 --- /dev/null +++ b/libraries-apache-commons-2/src/test/java/com/baeldung/commons/convertunicode/UnicodeConverterUnitTest.java @@ -0,0 +1,39 @@ +package com.baeldung.commons.convertunicode; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class UnicodeConverterUnitTest { + + @Test + public void whenInputHaveUnicodeSequences_ThenDecode() { + String encodedString = "\\u0048\\u0065\\u006C\\u006C\\u006F World"; + String expectedDecodedString = "Hello World"; + assertEquals(expectedDecodedString, UnicodeConverterUtil.decodeWithApacheCommons(encodedString)); + assertEquals(expectedDecodedString, UnicodeConverterUtil.decodeWithPlainJava(encodedString)); + } + + @Test + public void whenInputHaveNoUnicodeSequences_ThenDoNothing() { + String inputString = "Hello World"; + assertEquals(inputString, UnicodeConverterUtil.decodeWithApacheCommons(inputString)); + assertEquals(inputString, UnicodeConverterUtil.decodeWithPlainJava(inputString)); + } + + @Test + public void whenInputHaveUnicodeSequencesInMiddle_ThenDecode() { + String encodedString = "This is a test \\u0069\\u006E the middle."; + String expectedDecodedString = "This is a test in the middle."; + assertEquals(expectedDecodedString, UnicodeConverterUtil.decodeWithApacheCommons(encodedString)); + assertEquals(expectedDecodedString, UnicodeConverterUtil.decodeWithPlainJava(encodedString)); + } + + @Test + public void whenInputHaveMultipleUnicodeSequences_ThenDecode() { + String encodedString = "Unicode: \\u0048\\u0065\\u006C\\u006C\\u006F \\u0057\\u006F\\u0072\\u006C\\u0064"; + String expectedDecodedString = "Unicode: Hello World"; + assertEquals(expectedDecodedString, UnicodeConverterUtil.decodeWithApacheCommons(encodedString)); + assertEquals(expectedDecodedString, UnicodeConverterUtil.decodeWithPlainJava(encodedString)); + } +} diff --git a/libraries-io/pom.xml b/libraries-io/pom.xml index e92f6e11e1..fa89ebeabe 100644 --- a/libraries-io/pom.xml +++ b/libraries-io/pom.xml @@ -5,6 +5,18 @@ 4.0.0 libraries-io libraries-io + + + + org.apache.maven.plugins + maven-compiler-plugin + + 17 + 17 + + + + com.baeldung @@ -34,6 +46,11 @@ zip4j ${zip4j.version} + + com.opencsv + opencsv + ${opencsv.version} + @@ -42,6 +59,10 @@ 0.27.0 2.4 2.9.0 + 5.7.1 + 17 + 17 + UTF-8 \ No newline at end of file diff --git a/libraries-io/src/main/java/com/baeldung/java/io/pojotocsv/Application.java b/libraries-io/src/main/java/com/baeldung/java/io/pojotocsv/Application.java new file mode 100644 index 0000000000..b84da6229b --- /dev/null +++ b/libraries-io/src/main/java/com/baeldung/java/io/pojotocsv/Application.java @@ -0,0 +1,4 @@ +package com.baeldung.java.io.pojotocsv; + +public record Application(String id, String name, Integer age, String created_at) { +} diff --git a/libraries-io/src/main/java/com/baeldung/java/io/pojotocsv/ApplicationWithAnnotation.java b/libraries-io/src/main/java/com/baeldung/java/io/pojotocsv/ApplicationWithAnnotation.java new file mode 100644 index 0000000000..a0cd158843 --- /dev/null +++ b/libraries-io/src/main/java/com/baeldung/java/io/pojotocsv/ApplicationWithAnnotation.java @@ -0,0 +1,8 @@ +package com.baeldung.java.io.pojotocsv; + +import com.opencsv.bean.CsvBindByName; +import com.opencsv.bean.CsvBindByPosition; + +public record ApplicationWithAnnotation(@CsvBindByName(column = "id", required = true) @CsvBindByPosition(position = 1) String id, @CsvBindByName(column = "name", required = true) @CsvBindByPosition(position = 0) String name, + @CsvBindByName(column = "age", required = true) @CsvBindByPosition(position = 2) Integer age, @CsvBindByName(column = "position", required = true) @CsvBindByPosition(position = 3) String created_at) { +} \ No newline at end of file diff --git a/libraries-io/src/main/java/com/baeldung/java/io/pojotocsv/BeanToCsv.java b/libraries-io/src/main/java/com/baeldung/java/io/pojotocsv/BeanToCsv.java new file mode 100644 index 0000000000..f66c16beda --- /dev/null +++ b/libraries-io/src/main/java/com/baeldung/java/io/pojotocsv/BeanToCsv.java @@ -0,0 +1,55 @@ +package com.baeldung.java.io.pojotocsv; + +import java.io.FileWriter; +import java.io.IOException; +import java.util.List; + +import com.opencsv.CSVWriter; +import com.opencsv.bean.StatefulBeanToCsvBuilder; +import com.opencsv.exceptions.CsvDataTypeMismatchException; +import com.opencsv.exceptions.CsvRequiredFieldEmptyException; + +public class BeanToCsv { + + public void beanToCSVWithDefault(List applications) throws Exception { + try (FileWriter writer = new FileWriter("src/main/resources/application.csv")) { + var builder = new StatefulBeanToCsvBuilder(writer).withQuotechar(CSVWriter.NO_QUOTE_CHARACTER) + .withSeparator(',') + .build(); + builder.write(applications); + } + } + + public void beanToCSVWithCustomHeaderStrategy(List applications) throws IOException, CsvRequiredFieldEmptyException, CsvDataTypeMismatchException { + try (FileWriter writer = new FileWriter("src/main/resources/application2.csv")) { + var mappingStrategy = new CustomHeaderStrategy(); + mappingStrategy.setType(Application.class); + + var builder = new StatefulBeanToCsvBuilder(writer).withQuotechar(CSVWriter.NO_QUOTE_CHARACTER) + .withMappingStrategy(mappingStrategy) + .build(); + builder.write(applications); + } + } + + public void beanToCSVWithCustomPositionStrategy(List applications) throws Exception { + try (FileWriter writer = new FileWriter("src/main/resources/application3.csv")) { + var builder = new StatefulBeanToCsvBuilder(writer).withQuotechar(CSVWriter.NO_QUOTE_CHARACTER) + .build(); + builder.write(applications); + } + } + + public void beanToCSVWithCustomHeaderAndPositionStrategy(List applications) throws IOException, CsvRequiredFieldEmptyException, CsvDataTypeMismatchException { + try (FileWriter writer = new FileWriter("src/main/resources/application4.csv")) { + var mappingStrategy = new CustomColumnPositionStrategy(); + mappingStrategy.setType(ApplicationWithAnnotation.class); + + var builder = new StatefulBeanToCsvBuilder(writer).withQuotechar(CSVWriter.NO_QUOTE_CHARACTER) + .withMappingStrategy(mappingStrategy) + .build(); + builder.write(applications); + } + } + +} diff --git a/libraries-io/src/main/java/com/baeldung/java/io/pojotocsv/CustomColumnPositionStrategy.java b/libraries-io/src/main/java/com/baeldung/java/io/pojotocsv/CustomColumnPositionStrategy.java new file mode 100644 index 0000000000..204bf3f917 --- /dev/null +++ b/libraries-io/src/main/java/com/baeldung/java/io/pojotocsv/CustomColumnPositionStrategy.java @@ -0,0 +1,12 @@ +package com.baeldung.java.io.pojotocsv; + +import com.opencsv.bean.ColumnPositionMappingStrategy; +import com.opencsv.exceptions.CsvRequiredFieldEmptyException; + +public class CustomColumnPositionStrategy extends ColumnPositionMappingStrategy { + @Override + public String[] generateHeader(T bean) throws CsvRequiredFieldEmptyException { + super.generateHeader(bean); + return super.getColumnMapping(); + } +} diff --git a/libraries-io/src/main/java/com/baeldung/java/io/pojotocsv/CustomHeaderStrategy.java b/libraries-io/src/main/java/com/baeldung/java/io/pojotocsv/CustomHeaderStrategy.java new file mode 100644 index 0000000000..8e81c8ec28 --- /dev/null +++ b/libraries-io/src/main/java/com/baeldung/java/io/pojotocsv/CustomHeaderStrategy.java @@ -0,0 +1,16 @@ +package com.baeldung.java.io.pojotocsv; + +import java.util.Arrays; + +import com.opencsv.bean.HeaderColumnNameMappingStrategy; +import com.opencsv.exceptions.CsvRequiredFieldEmptyException; + +public class CustomHeaderStrategy extends HeaderColumnNameMappingStrategy { + @Override + public String[] generateHeader(T bean) throws CsvRequiredFieldEmptyException { + String[] header = super.generateHeader(bean); + return Arrays.stream(header) + .map(String::toLowerCase) + .toArray(String[]::new); + } +} diff --git a/libraries-io/src/main/resources/application.csv b/libraries-io/src/main/resources/application.csv new file mode 100644 index 0000000000..d4040e18e1 --- /dev/null +++ b/libraries-io/src/main/resources/application.csv @@ -0,0 +1,4 @@ +AGE,CREATED_AT,ID,NAME +34,2023-08-11,123,Sam +44,2023-02-11,456,Tam +54,2023-03-11,890,Jam diff --git a/libraries-io/src/main/resources/application2.csv b/libraries-io/src/main/resources/application2.csv new file mode 100644 index 0000000000..92bbced703 --- /dev/null +++ b/libraries-io/src/main/resources/application2.csv @@ -0,0 +1,4 @@ +age,created_at,id,name +34,2023-08-11,123,Sam +44,2023-02-11,456,Tam +54,2023-03-11,890,Jam diff --git a/libraries-io/src/main/resources/application3.csv b/libraries-io/src/main/resources/application3.csv new file mode 100644 index 0000000000..165107b103 --- /dev/null +++ b/libraries-io/src/main/resources/application3.csv @@ -0,0 +1,3 @@ +Sam,123,34,2023-08-11 +Tam,456,44,2023-02-11 +Jam,789,54,2023-03-11 diff --git a/libraries-io/src/main/resources/application4.csv b/libraries-io/src/main/resources/application4.csv new file mode 100644 index 0000000000..b7999ae227 --- /dev/null +++ b/libraries-io/src/main/resources/application4.csv @@ -0,0 +1,4 @@ +name,id,age,created_at +Sam,123,34,2023-08-11 +Tam,456,44,2023-02-11 +Jam,789,54,2023-03-11 diff --git a/libraries-io/src/test/java/com/baeldung/java/io/pojotocsv/BeanToCsvUnitTest.java b/libraries-io/src/test/java/com/baeldung/java/io/pojotocsv/BeanToCsvUnitTest.java new file mode 100644 index 0000000000..50cd1b1e0e --- /dev/null +++ b/libraries-io/src/test/java/com/baeldung/java/io/pojotocsv/BeanToCsvUnitTest.java @@ -0,0 +1,80 @@ +package com.baeldung.java.io.pojotocsv; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +import java.io.BufferedReader; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public class BeanToCsvUnitTest { + + List applications = new ArrayList<>(); + List applicationsWithAnnotation = new ArrayList<>(); + + @BeforeEach + public void beforeEach() { + applications = List.of(new Application("123", "Sam", 34, "2023-08-11"), new Application("456", "Tam", 44, "2023-02-11"), new Application("890", "Jam", 54, "2023-03-11")); + + applicationsWithAnnotation = List.of(new ApplicationWithAnnotation("123", "Sam", 34, "2023-08-11"), new ApplicationWithAnnotation("456", "Tam", 44, "2023-02-11"), new ApplicationWithAnnotation("789", "Jam", 54, "2023-03-11")); + } + + @Test + public void givenApplicationPOJO_whenUsingDefaultStrategy_thenReceiveCSVFormatWithAscendingOrderOfField() throws Exception { + BeanToCsv beanToCsv = new BeanToCsv(); + beanToCsv.beanToCSVWithDefault(applications); + try (BufferedReader bufferedReader = Files.newBufferedReader(Path.of("src/main/resources/application.csv"))) { + List content = bufferedReader.lines() + .toList(); + assertThat(content.get(0)).isEqualTo("AGE,CREATED_AT,ID,NAME"); + assertThat(content.get(1)).isEqualTo("34,2023-08-11,123,Sam"); + assertThat(content.get(2)).isEqualTo("44,2023-02-11,456,Tam"); + assertThat(content.get(3)).isEqualTo("54,2023-03-11,890,Jam"); + } + } + + @Test + public void givenApplicationPOJO_whenUsingCustomHeaderStrategy_thenReceiveCSVFormatWithCustomHeaders() throws Exception { + BeanToCsv beanToCsv = new BeanToCsv(); + beanToCsv.beanToCSVWithCustomHeaderStrategy(applications); + try (BufferedReader bufferedReader = Files.newBufferedReader(Path.of("src/main/resources/application2.csv"))) { + List content = bufferedReader.lines() + .toList(); + assertThat(content.get(0)).isEqualTo("age,created_at,id,name"); + assertThat(content.get(1)).isEqualTo("34,2023-08-11,123,Sam"); + assertThat(content.get(2)).isEqualTo("44,2023-02-11,456,Tam"); + assertThat(content.get(3)).isEqualTo("54,2023-03-11,890,Jam"); + } + } + + @Test + public void givenApplicationPOJOWithAnnotation_whenUsingCustomPositionStrategy_thenReceiveCSVFormatWithCustomPosition() throws Exception { + BeanToCsv beanToCsv = new BeanToCsv(); + beanToCsv.beanToCSVWithCustomPositionStrategy(applicationsWithAnnotation); + try (BufferedReader bufferedReader = Files.newBufferedReader(Path.of("src/main/resources/application3.csv"))) { + List content = bufferedReader.lines() + .toList(); + assertThat(content.get(0)).isEqualTo("Sam,123,34,2023-08-11"); + assertThat(content.get(1)).isEqualTo("Tam,456,44,2023-02-11"); + assertThat(content.get(2)).isEqualTo("Jam,789,54,2023-03-11"); + } + } + + @Test + public void givenApplicationPOJOWithAnnotation_whenUsingCustomHeaderPositionStrategy_thenReceiveCSVFormatWithCustomHeaderPosition() throws Exception { + BeanToCsv beanToCsv = new BeanToCsv(); + beanToCsv.beanToCSVWithCustomHeaderAndPositionStrategy(applicationsWithAnnotation); + try (BufferedReader bufferedReader = Files.newBufferedReader(Path.of("src/main/resources/application4.csv"))) { + List content = bufferedReader.lines() + .toList(); + assertThat(content.get(0)).isEqualTo("name,id,age,created_at"); + assertThat(content.get(1)).isEqualTo("Sam,123,34,2023-08-11"); + assertThat(content.get(2)).isEqualTo("Tam,456,44,2023-02-11"); + assertThat(content.get(3)).isEqualTo("Jam,789,54,2023-03-11"); + } + } +} diff --git a/logging-modules/log4j/README.md b/logging-modules/log4j/README.md index a47d0ae89b..32ea358369 100644 --- a/logging-modules/log4j/README.md +++ b/logging-modules/log4j/README.md @@ -4,3 +4,4 @@ - [A Guide to Rolling File Appenders](http://www.baeldung.com/java-logging-rolling-file-appenders) - [Logging Exceptions Using SLF4J](https://www.baeldung.com/slf4j-log-exceptions) - [Log4j Warning: “No Appenders Could Be Found for Logger”](https://www.baeldung.com/log4j-no-appenders-found) +- [A Guide to Log4j and the log4j.properties File in Java](https://www.baeldung.com/java-log4j-properties-guide) diff --git a/logging-modules/log4j2/README.md b/logging-modules/log4j2/README.md index 87e92e0d48..fa7133ffdd 100644 --- a/logging-modules/log4j2/README.md +++ b/logging-modules/log4j2/README.md @@ -9,3 +9,4 @@ - [Log4j 2 Plugins](https://www.baeldung.com/log4j2-plugins) - [Printing Thread Info in Log File Using Log4j2](https://www.baeldung.com/log4j2-print-thread-info) - [Log4j2 – Logging to Both File and Console](https://www.baeldung.com/java-log4j2-file-and-console) +- [Log4j 2 Configuration Using a Properties File](https://www.baeldung.com/java-log4j2-config-with-prop-file) diff --git a/mapstruct/src/main/java/com/baeldung/expression/dto/LicenseDto.java b/mapstruct/src/main/java/com/baeldung/expression/dto/LicenseDto.java index 025df1a4f6..1d7cacaead 100644 --- a/mapstruct/src/main/java/com/baeldung/expression/dto/LicenseDto.java +++ b/mapstruct/src/main/java/com/baeldung/expression/dto/LicenseDto.java @@ -11,6 +11,8 @@ public class LicenseDto { private LocalDateTime endDate; + private String licenseType; + public UUID getId() { return id; } @@ -35,4 +37,12 @@ public class LicenseDto { this.endDate = endDate; } + public String getLicenseType() { + return licenseType; + } + + public void setLicenseType(String licenseType) { + this.licenseType = licenseType; + } + } diff --git a/mapstruct/src/main/java/com/baeldung/expression/mapper/LicenseMapper.java b/mapstruct/src/main/java/com/baeldung/expression/mapper/LicenseMapper.java index 100588b45d..0d8904e220 100644 --- a/mapstruct/src/main/java/com/baeldung/expression/mapper/LicenseMapper.java +++ b/mapstruct/src/main/java/com/baeldung/expression/mapper/LicenseMapper.java @@ -6,6 +6,7 @@ import java.time.OffsetDateTime; import java.time.ZoneOffset; import org.mapstruct.AfterMapping; +import org.mapstruct.Condition; import org.mapstruct.Mapper; import org.mapstruct.Mapping; import org.mapstruct.MappingTarget; @@ -40,4 +41,13 @@ public interface LicenseMapper { .toDays() <= 14; } -} + @Condition + default boolean mapsToExpectedLicenseType(String licenseType) { + try { + return licenseType != null && License.LicenseType.valueOf(licenseType) != null; + } catch (IllegalArgumentException e) { + return false; + } + } + +} \ No newline at end of file diff --git a/mapstruct/src/main/java/com/baeldung/expression/model/License.java b/mapstruct/src/main/java/com/baeldung/expression/model/License.java index 71e4f086c0..e36e278a57 100644 --- a/mapstruct/src/main/java/com/baeldung/expression/model/License.java +++ b/mapstruct/src/main/java/com/baeldung/expression/model/License.java @@ -3,7 +3,6 @@ package com.baeldung.expression.model; import java.time.OffsetDateTime; import java.util.UUID; - public class License { private UUID id; @@ -16,6 +15,8 @@ public class License { private boolean renewalRequired; + private LicenseType licenseType; + public UUID getId() { return id; } @@ -55,4 +56,16 @@ public class License { public void setRenewalRequired(boolean renewalRequired) { this.renewalRequired = renewalRequired; } -} + + public enum LicenseType { + INDIVIDUAL, FAMILY + } + + public LicenseType getLicenseType() { + return licenseType; + } + + public void setLicenseType(LicenseType licenseType) { + this.licenseType = licenseType; + } +} \ No newline at end of file diff --git a/mapstruct/src/test/java/com/baeldung/expression/mapper/LicenseMapperUnitTest.java b/mapstruct/src/test/java/com/baeldung/expression/mapper/LicenseMapperUnitTest.java index dcdda5c1ac..d7521e81f5 100644 --- a/mapstruct/src/test/java/com/baeldung/expression/mapper/LicenseMapperUnitTest.java +++ b/mapstruct/src/test/java/com/baeldung/expression/mapper/LicenseMapperUnitTest.java @@ -6,6 +6,7 @@ import java.time.LocalDate; import java.time.LocalDateTime; import java.util.UUID; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.mapstruct.factory.Mappers; @@ -74,4 +75,31 @@ class LicenseMapperUnitTest { assertThat(license.getId()).isSameAs(id); } + @Test + void givenLicenseDtoWithoutLicenseTypeString_whenMapperMethodIsInvoked_thenLicenseShouldBePopulatedWithoutLicenseType() { + LicenseDto licenseDto = new LicenseDto(); + License license = licenseMapper.toLicense(licenseDto); + assertThat(license).isNotNull(); + Assertions.assertNull(license.getLicenseType()); + } + + @Test + void givenLicenseDtoWithInvalidLicenseTypeString_whenMapperMethodIsInvoked_thenLicenseShouldBePopulatedWithoutLicenseType() { + LicenseDto licenseDto = new LicenseDto(); + licenseDto.setLicenseType("invalid_license_type"); + License license = licenseMapper.toLicense(licenseDto); + assertThat(license).isNotNull(); + Assertions.assertNull(license.getLicenseType()); + } + + @Test + void givenLicenseDtoWithValidLicenseTypeString_whenMapperMethodIsInvoked_thenLicenseShouldBePopulatedWithMatchingLicenseType() { + LicenseDto licenseDto = new LicenseDto(); + licenseDto.setLicenseType("INDIVIDUAL"); + License license = licenseMapper.toLicense(licenseDto); + assertThat(license).isNotNull(); + Assertions.assertNotNull(license.getLicenseType()); + assertThat(license.getLicenseType()).isEqualTo(License.LicenseType.INDIVIDUAL); + } + } \ No newline at end of file diff --git a/messaging-modules/apache-camel/pom.xml b/messaging-modules/apache-camel/pom.xml index bb20f178aa..8b49ad4893 100644 --- a/messaging-modules/apache-camel/pom.xml +++ b/messaging-modules/apache-camel/pom.xml @@ -17,30 +17,39 @@ - org.apache.camel - camel-core - ${env.camel.version} + org.apache.camel.springboot + camel-spring-boot-starter + ${camel.version} + + + org.apache.camel.springboot + camel-jackson-starter + ${camel.version} org.apache.camel - camel-spring-javaconfig - ${env.camel.version} + camel-test-spring-junit5 + ${camel.version} + test - org.apache.camel - camel-jackson - ${env.camel.version} + org.junit.platform + junit-platform-launcher + test - org.apache.camel - camel-test - ${env.camel.version} + org.springframework.boot + spring-boot-starter-web + + + org.awaitility + awaitility test - 3.14.7 + 3.21.0 \ No newline at end of file diff --git a/messaging-modules/apache-camel/src/main/java/com/baeldung/camel/apache/Application.java b/messaging-modules/apache-camel/src/main/java/com/baeldung/camel/apache/Application.java new file mode 100755 index 0000000000..51b2540aa8 --- /dev/null +++ b/messaging-modules/apache-camel/src/main/java/com/baeldung/camel/apache/Application.java @@ -0,0 +1,11 @@ +package com.baeldung.camel.apache; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class Application { + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } +} \ No newline at end of file diff --git a/messaging-modules/apache-camel/src/main/java/com/baeldung/camel/apache/file/FileProcessor.java b/messaging-modules/apache-camel/src/main/java/com/baeldung/camel/apache/file/FileProcessor.java index ce4d92e8ab..a0571e7083 100644 --- a/messaging-modules/apache-camel/src/main/java/com/baeldung/camel/apache/file/FileProcessor.java +++ b/messaging-modules/apache-camel/src/main/java/com/baeldung/camel/apache/file/FileProcessor.java @@ -5,14 +5,17 @@ import java.util.Date; import org.apache.camel.Exchange; import org.apache.camel.Processor; +import org.springframework.stereotype.Component; +@Component public class FileProcessor implements Processor { + @Override public void process(Exchange exchange) throws Exception { String originalFileName = (String) exchange.getIn().getHeader(Exchange.FILE_NAME, String.class); Date date = new Date(); - SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH-mm-ss"); + SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); String changedFileName = dateFormat.format(date) + originalFileName; exchange.getIn().setHeader(Exchange.FILE_NAME, changedFileName); } diff --git a/messaging-modules/apache-camel/src/main/java/com/baeldung/camel/apache/file/FileRouter.java b/messaging-modules/apache-camel/src/main/java/com/baeldung/camel/apache/file/FileRouter.java index 760f37677b..b57232d41e 100644 --- a/messaging-modules/apache-camel/src/main/java/com/baeldung/camel/apache/file/FileRouter.java +++ b/messaging-modules/apache-camel/src/main/java/com/baeldung/camel/apache/file/FileRouter.java @@ -1,7 +1,9 @@ package com.baeldung.camel.apache.file; import org.apache.camel.builder.RouteBuilder; +import org.springframework.stereotype.Component; +@Component public class FileRouter extends RouteBuilder { private static final String SOURCE_FOLDER = "src/test/source-folder"; diff --git a/messaging-modules/apache-camel/src/main/resources/camel-context-test.xml b/messaging-modules/apache-camel/src/main/resources/camel-context-test.xml index f306574868..f6177c69b5 100644 --- a/messaging-modules/apache-camel/src/main/resources/camel-context-test.xml +++ b/messaging-modules/apache-camel/src/main/resources/camel-context-test.xml @@ -1,11 +1,12 @@ + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:context="http://www.springframework.org/schema/context" + xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd + http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> - - + + diff --git a/messaging-modules/apache-camel/src/test/java/com/apache/baeldung/camel/jackson/FruitArrayJacksonUnmarshalUnitTest.java b/messaging-modules/apache-camel/src/test/java/com/apache/baeldung/camel/jackson/FruitArrayJacksonUnmarshalUnitTest.java index bc0025b263..ab5993d816 100644 --- a/messaging-modules/apache-camel/src/test/java/com/apache/baeldung/camel/jackson/FruitArrayJacksonUnmarshalUnitTest.java +++ b/messaging-modules/apache-camel/src/test/java/com/apache/baeldung/camel/jackson/FruitArrayJacksonUnmarshalUnitTest.java @@ -1,31 +1,65 @@ package com.apache.baeldung.camel.jackson; +import com.baeldung.camel.apache.Application; +import com.baeldung.camel.apache.jackson.Fruit; +import org.apache.camel.Configuration; +import org.apache.camel.EndpointInject; +import org.apache.camel.ProducerTemplate; +import org.apache.camel.RoutesBuilder; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.jackson.ListJacksonDataFormat; +import org.apache.camel.component.mock.MockEndpoint; +import org.apache.camel.test.spring.junit5.CamelSpringBootTest; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.Bean; +import org.springframework.test.annotation.DirtiesContext; + import java.io.IOException; import java.net.URISyntaxException; import java.net.URL; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Paths; import java.util.List; -import org.apache.camel.builder.RouteBuilder; -import org.apache.camel.component.jackson.ListJacksonDataFormat; -import org.apache.camel.component.mock.MockEndpoint; -import org.apache.camel.test.junit4.CamelTestSupport; -import org.junit.Test; +import static org.springframework.test.util.AssertionErrors.assertEquals; +import static org.springframework.test.util.AssertionErrors.assertNotNull; -import com.baeldung.camel.apache.jackson.Fruit; +@CamelSpringBootTest +@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD) +@SpringBootTest(classes = {Application.class, FruitArrayJacksonUnmarshalUnitTest.TestConfig.class}) +public class FruitArrayJacksonUnmarshalUnitTest { -public class FruitArrayJacksonUnmarshalUnitTest extends CamelTestSupport { + @Autowired + private ProducerTemplate template; + + @EndpointInject("mock:marshalledObject") + private MockEndpoint mock; + + @Configuration + static class TestConfig { + @Bean + RoutesBuilder route() { + return new RouteBuilder() { + @Override + public void configure() throws Exception { + from("direct:jsonInput").unmarshal(new ListJacksonDataFormat(Fruit.class)) + .to("mock:marshalledObject"); + } + }; + } + } @Test public void givenJsonFruitArray_whenUnmarshalled_thenSuccess() throws Exception { - MockEndpoint mock = getMockEndpoint("mock:marshalledObject"); - mock.expectedMessageCount(1); + mock.setExpectedMessageCount(1); mock.message(0).body().isInstanceOf(List.class); String json = readJsonFromFile("/json/fruit-array.json"); template.sendBody("direct:jsonInput", json); - assertMockEndpointsSatisfied(); + mock.assertIsSatisfied(); @SuppressWarnings("unchecked") List fruitList = mock.getReceivedExchanges().get(0).getIn().getBody(List.class); @@ -41,22 +75,10 @@ public class FruitArrayJacksonUnmarshalUnitTest extends CamelTestSupport { assertEquals("Fruit name", "Apple", fruit.getName()); assertEquals("Fruit id", 101, fruit.getId()); } - - @Override - protected RouteBuilder createRouteBuilder() throws Exception { - return new RouteBuilder() { - @Override - public void configure() throws Exception { - - from("direct:jsonInput").unmarshal(new ListJacksonDataFormat(Fruit.class)) - .to("mock:marshalledObject"); - } - }; - } private String readJsonFromFile(String path) throws URISyntaxException, IOException { URL resource = FruitArrayJacksonUnmarshalUnitTest.class.getResource(path); - return new String(Files.readAllBytes(Paths.get(resource.toURI()))); + return new String(Files.readAllBytes(Paths.get(resource.toURI())), StandardCharsets.UTF_8); } } diff --git a/messaging-modules/apache-camel/src/test/java/com/apache/baeldung/camel/jackson/FruitListJacksonUnmarshalUnitTest.java b/messaging-modules/apache-camel/src/test/java/com/apache/baeldung/camel/jackson/FruitListJacksonUnmarshalUnitTest.java index 2d15ebf46b..8120eeffec 100644 --- a/messaging-modules/apache-camel/src/test/java/com/apache/baeldung/camel/jackson/FruitListJacksonUnmarshalUnitTest.java +++ b/messaging-modules/apache-camel/src/test/java/com/apache/baeldung/camel/jackson/FruitListJacksonUnmarshalUnitTest.java @@ -1,32 +1,64 @@ package com.apache.baeldung.camel.jackson; +import com.baeldung.camel.apache.Application; +import com.baeldung.camel.apache.jackson.Fruit; +import com.baeldung.camel.apache.jackson.FruitList; +import org.apache.camel.Configuration; +import org.apache.camel.EndpointInject; +import org.apache.camel.ProducerTemplate; +import org.apache.camel.RoutesBuilder; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.jackson.JacksonDataFormat; +import org.apache.camel.component.mock.MockEndpoint; +import org.apache.camel.test.spring.junit5.CamelSpringBootTest; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.Bean; + import java.io.IOException; import java.net.URISyntaxException; import java.net.URL; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Paths; import java.util.List; -import org.apache.camel.builder.RouteBuilder; -import org.apache.camel.component.jackson.JacksonDataFormat; -import org.apache.camel.component.mock.MockEndpoint; -import org.apache.camel.test.junit4.CamelTestSupport; -import org.junit.Test; +import static org.springframework.test.util.AssertionErrors.assertEquals; +import static org.springframework.test.util.AssertionErrors.assertNotNull; -import com.baeldung.camel.apache.jackson.Fruit; -import com.baeldung.camel.apache.jackson.FruitList; +@CamelSpringBootTest +@SpringBootTest(classes = {Application.class, FruitListJacksonUnmarshalUnitTest.TestConfig.class}) +public class FruitListJacksonUnmarshalUnitTest { -public class FruitListJacksonUnmarshalUnitTest extends CamelTestSupport { + @Autowired + private ProducerTemplate template; + + @EndpointInject("mock:marshalledObject") + private MockEndpoint mock; + + @Configuration + static class TestConfig { + @Bean + RoutesBuilder route() { + return new RouteBuilder() { + @Override + public void configure() throws Exception { + from("direct:jsonInput").unmarshal(new JacksonDataFormat(FruitList.class)) + .to("mock:marshalledObject"); + } + }; + } + } @Test public void givenJsonFruitList_whenUnmarshalled_thenSuccess() throws Exception { - MockEndpoint mock = getMockEndpoint("mock:marshalledObject"); - mock.expectedMessageCount(1); + mock.setExpectedMessageCount(1); mock.message(0).body().isInstanceOf(FruitList.class); String json = readJsonFromFile("/json/fruit-list.json"); template.sendBody("direct:jsonInput", json); - assertMockEndpointsSatisfied(); + mock.assertIsSatisfied(); FruitList fruitList = mock.getReceivedExchanges().get(0).getIn().getBody(FruitList.class); assertNotNull("Fruit lists should not be null", fruitList); @@ -43,20 +75,9 @@ public class FruitListJacksonUnmarshalUnitTest extends CamelTestSupport { assertEquals("Fruit id", 101, fruit.getId()); } - @Override - protected RouteBuilder createRouteBuilder() throws Exception { - return new RouteBuilder() { - @Override - public void configure() throws Exception { - from("direct:jsonInput").unmarshal(new JacksonDataFormat(FruitList.class)) - .to("mock:marshalledObject"); - } - }; - } - private String readJsonFromFile(String path) throws URISyntaxException, IOException { URL resource = FruitListJacksonUnmarshalUnitTest.class.getResource(path); - return new String(Files.readAllBytes(Paths.get(resource.toURI()))); + return new String(Files.readAllBytes(Paths.get(resource.toURI())), StandardCharsets.UTF_8); } } diff --git a/messaging-modules/apache-camel/src/test/java/com/apache/camel/file/processor/FileProcessorIntegrationTest.java b/messaging-modules/apache-camel/src/test/java/com/apache/camel/file/processor/FileProcessorIntegrationTest.java index e4390a95e5..5003021d20 100644 --- a/messaging-modules/apache-camel/src/test/java/com/apache/camel/file/processor/FileProcessorIntegrationTest.java +++ b/messaging-modules/apache-camel/src/test/java/com/apache/camel/file/processor/FileProcessorIntegrationTest.java @@ -1,16 +1,21 @@ package com.apache.camel.file.processor; -import java.io.File; - +import com.baeldung.camel.apache.file.FileProcessor; import org.apache.camel.CamelContext; import org.apache.camel.builder.RouteBuilder; import org.apache.camel.impl.DefaultCamelContext; +import org.awaitility.Awaitility; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.springframework.context.support.ClassPathXmlApplicationContext; -import com.baeldung.camel.apache.file.FileProcessor; +import java.io.File; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.concurrent.TimeUnit; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; public class FileProcessorIntegrationTest { @@ -52,7 +57,7 @@ public class FileProcessorIntegrationTest { } @Test - public void moveFolderContentJavaDSLTest() throws Exception { + public void givenJavaDSLRoute_whenCamelStart_thenMoveFolderContent() throws Exception { final CamelContext camelContext = new DefaultCamelContext(); camelContext.addRoutes(new RouteBuilder() { @Override @@ -61,15 +66,26 @@ public class FileProcessorIntegrationTest { } }); camelContext.start(); - Thread.sleep(DURATION_MILIS); + verifyFolderContent(); camelContext.stop(); } @Test - public void moveFolderContentSpringDSLTest() throws InterruptedException { + public void givenSpringDSLRoute_whenCamelStart_thenMoveFolderContent() throws InterruptedException { ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("camel-context-test.xml"); - Thread.sleep(DURATION_MILIS); + verifyFolderContent(); applicationContext.close(); + } + private void verifyFolderContent() { + Date date = new Date(); + SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); + File destinationFile1 = new File(DESTINATION_FOLDER + "/" + dateFormat.format(date) + "File1.txt"); + File destinationFile2 = new File(DESTINATION_FOLDER + "/" + dateFormat.format(date) + "File2.txt"); + + Awaitility.await().atMost(DURATION_MILIS, TimeUnit.MILLISECONDS).untilAsserted(() -> { + assertThat(destinationFile1.exists()).isTrue(); + assertThat(destinationFile2.exists()).isTrue(); + }); } } \ No newline at end of file diff --git a/microservices-modules/micronaut/README.md b/microservices-modules/micronaut/README.md index 1ab31d0c0c..f784f8ad70 100644 --- a/microservices-modules/micronaut/README.md +++ b/microservices-modules/micronaut/README.md @@ -5,3 +5,4 @@ This module contains articles about Micronaut. ### Relevant Articles: - [Introduction to Micronaut Framework](https://www.baeldung.com/micronaut) - [Micronaut vs. Spring Boot](https://www.baeldung.com/micronaut-vs-spring-boot) +- [API Versioning in Micronaut](https://www.baeldung.com/java-api-versioning-micronaut) diff --git a/microservices-modules/micronaut/pom.xml b/microservices-modules/micronaut/pom.xml index 716b5497d8..d3f4326a85 100644 --- a/microservices-modules/micronaut/pom.xml +++ b/microservices-modules/micronaut/pom.xml @@ -7,6 +7,7 @@ micronaut 0.1 micronaut + ${packaging} com.baeldung @@ -18,7 +19,7 @@ io.micronaut - bom + micronaut-bom ${micronaut.version} pom import @@ -29,120 +30,136 @@ io.micronaut - http-client + micronaut-runtime + compile + + + io.micronaut + micronaut-jackson-databind + + + + + io.micronaut + micronaut-http-client compile io.micronaut - http-server-netty + micronaut-http-server-netty + compile + + + jakarta.annotation + jakarta.annotation-api compile io.micronaut - inject + micronaut-inject compile io.micronaut - runtime + micronaut-validation compile - - javax.annotation - javax.annotation-api - ${annotation.api.version} - compile - - - io.micronaut - inject-java - provided - ch.qos.logback logback-classic - ${logback.version} runtime - io.projectreactor - reactor-core - ${reactor.version} + io.micronaut.rxjava3 + micronaut-rxjava3 + compile + + + io.micronaut.rxjava3 + micronaut-rxjava3-http-client + compile + + + io.micronaut.serde + micronaut-serde-jackson + compile + + + org.junit.jupiter + junit-jupiter-engine + test + + + org.assertj + assertj-core + test + + + io.micronaut.test + micronaut-test-junit5 + test + + io.micronaut.build + micronaut-maven-plugin + + + org.apache.maven.plugins + maven-compiler-plugin + + ${jdk.version} + ${jdk.version} + + -parameters + + + + + + + + io.micronaut + micronaut-inject-java + ${micronaut.version} + + + + io.micronaut + micronaut-http-validation + ${micronaut.version} + + + + + org.apache.maven.plugins maven-shade-plugin ${shade.plugin.version} - package - - shade - - - - - ${exec.mainClass} - - - - + default-shade + none - - org.codehaus.mojo - exec-maven-plugin - - java - - -classpath - - ${exec.mainClass} - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - ${compiler.plugin.version} - - ${jdk.version} - ${jdk.version} - - -parameters - - - - io.micronaut - inject-java - ${micronaut.version} - - - - - - com.baeldung.micronaut.vs.springboot.CompareApplication - 1.0.0.RC2 + 3.10.1 17 - 1.3.2 - 3.1.6.RELEASE + 17 + jar 3.7.0 - 3.1.0 + netty + 3.2.0 \ No newline at end of file diff --git a/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/custom/client/BirdCountClient.java b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/custom/client/BirdCountClient.java new file mode 100644 index 0000000000..d9e09b1c6e --- /dev/null +++ b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/custom/client/BirdCountClient.java @@ -0,0 +1,42 @@ +package com.baeldung.micronaut.apiversioning.custom.client; + +import io.micronaut.core.annotation.Nullable; +import io.micronaut.core.async.annotation.SingleResult; +import io.micronaut.http.HttpHeaders; +import io.micronaut.http.annotation.Get; +import io.micronaut.http.annotation.Header; +import io.micronaut.http.annotation.QueryValue; +import io.micronaut.http.client.annotation.Client; +import io.reactivex.rxjava3.core.Flowable; + +@Client("/") +@Header(name = HttpHeaders.ACCEPT, value = "application/json") +public interface BirdCountClient { + + @Get( + uri = "/bird/count", + consumes = {"application/json"}, + produces = {"application/json"} + ) + @Header(name = "api-key", value = "11") + @SingleResult + Flowable countV1(@QueryValue("max") @Nullable Integer max); + + @Get( + uri = "/bird/count", + consumes = {"application/json"}, + produces = {"application/json"} + ) + @Header(name = "api-key", value = "10") + @SingleResult + Flowable countV2(@QueryValue("max") @Nullable Integer max); + + @Get( + uri = "/bird/count", + consumes = {"application/json"}, + produces = {"application/json"} + ) + @Header(name = "api-key", value = "") + @SingleResult + Flowable countDefault(@QueryValue("max") @Nullable Integer max); +} diff --git a/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/custom/server/BirdCountController.java b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/custom/server/BirdCountController.java new file mode 100644 index 0000000000..c836761266 --- /dev/null +++ b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/custom/server/BirdCountController.java @@ -0,0 +1,36 @@ +package com.baeldung.micronaut.apiversioning.custom.server; + +import io.micronaut.core.annotation.NonNull; +import io.micronaut.core.annotation.Nullable; +import io.micronaut.core.version.annotation.Version; +import io.micronaut.http.annotation.Controller; +import io.micronaut.http.annotation.Get; +import io.micronaut.http.annotation.QueryValue; +import io.reactivex.rxjava3.core.Flowable; + +import java.util.stream.Stream; + +@Controller("/bird") +public class BirdCountController { + + @Get(value = "/count", produces = {"application/json"}) + @Version("1") + public Flowable countV1(@QueryValue("max") @Nullable Integer max) { + return Flowable.fromStream( + Stream.iterate(0, i -> i + 1) + .map(index -> "Bird " + index) + .limit(max == null ? 10 : max) + ); + } + + @Get(value = "/count", produces = {"application/json"}) + @Version("2") + public Flowable countV2(@QueryValue("max") @NonNull Integer max) { + return Flowable.fromStream( + Stream.iterate(0, i -> i + 1) + .map(index -> "Bird " + index) + .limit(max) + ); + } + +} diff --git a/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/custom/server/CustomVersionResolver.java b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/custom/server/CustomVersionResolver.java new file mode 100644 index 0000000000..3075a135c8 --- /dev/null +++ b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/custom/server/CustomVersionResolver.java @@ -0,0 +1,31 @@ +package com.baeldung.micronaut.apiversioning.custom.server; + +import io.micronaut.context.annotation.Requires; +import io.micronaut.context.annotation.Value; +import io.micronaut.http.HttpRequest; +import io.micronaut.web.router.version.resolution.RequestVersionResolver; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; + +import java.util.Optional; + +@Singleton +@Requires(property = "my.router.versioning.enabled", value = "true") +public class CustomVersionResolver implements RequestVersionResolver { + + @Inject + @Value("${micronaut.router.versioning.default-version}") + private String defaultVersion; + + @Override + public Optional resolve(HttpRequest request) { + var apiKey = Optional.ofNullable(request.getHeaders().get("api-key")); + + if (apiKey.isPresent() && !apiKey.get().isEmpty()) { + return Optional.of(Integer.parseInt(apiKey.get()) % 2 == 0 ? "2" : "1"); + } + + return Optional.of(defaultVersion); + } + +} diff --git a/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/header/client/DogCountClient.java b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/header/client/DogCountClient.java new file mode 100644 index 0000000000..487bff4d57 --- /dev/null +++ b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/header/client/DogCountClient.java @@ -0,0 +1,42 @@ +package com.baeldung.micronaut.apiversioning.header.client; + +import io.micronaut.core.annotation.Nullable; +import io.micronaut.core.async.annotation.SingleResult; +import io.micronaut.core.version.annotation.Version; +import io.micronaut.http.HttpHeaders; +import io.micronaut.http.annotation.Get; +import io.micronaut.http.annotation.Header; +import io.micronaut.http.annotation.QueryValue; +import io.micronaut.http.client.annotation.Client; +import io.reactivex.rxjava3.core.Flowable; + +@Client("/") +@Header(name = HttpHeaders.ACCEPT, value = "application/json") +public interface DogCountClient { + + @Get( + uri = "/dog/count", + consumes = {"application/json"}, + produces = {"application/json"} + ) + @Version("1") + @SingleResult + Flowable countV1(@QueryValue("max") @Nullable Integer max); + + @Get( + uri = "/dog/count", + consumes = {"application/json"}, + produces = {"application/json"} + ) + @Version("2") + @SingleResult + Flowable countV2(@QueryValue("max") @Nullable Integer max); + + @Get( + uri = "/dog/count", + consumes = {"application/json"}, + produces = {"application/json"} + ) + @SingleResult + Flowable countDefault(@QueryValue("max") @Nullable Integer max); +} diff --git a/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/header/server/DogCountController.java b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/header/server/DogCountController.java new file mode 100644 index 0000000000..de0f6788cf --- /dev/null +++ b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/header/server/DogCountController.java @@ -0,0 +1,36 @@ +package com.baeldung.micronaut.apiversioning.header.server; + +import io.micronaut.core.annotation.NonNull; +import io.micronaut.core.annotation.Nullable; +import io.micronaut.core.version.annotation.Version; +import io.micronaut.http.annotation.Controller; +import io.micronaut.http.annotation.Get; +import io.micronaut.http.annotation.QueryValue; +import io.reactivex.rxjava3.core.Flowable; + +import java.util.stream.Stream; + +@Controller("/dog") +public class DogCountController { + + @Get(value = "/count", produces = {"application/json"}) + @Version("1") + public Flowable countV1(@QueryValue("max") @Nullable Integer max) { + return Flowable.fromStream( + Stream.iterate(0, i -> i + 1) + .map(index -> "Dog " + index) + .limit(max == null ? 10 : max) + ); + } + + @Get(value = "/count", produces = {"application/json"}) + @Version("2") + public Flowable countV2(@QueryValue("max") @NonNull Integer max) { + return Flowable.fromStream( + Stream.iterate(0, i -> i + 1) + .map(index -> "Dog " + index) + .limit(max) + ); + } + +} diff --git a/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/param/client/CatCountClient.java b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/param/client/CatCountClient.java new file mode 100644 index 0000000000..2332ade98e --- /dev/null +++ b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/param/client/CatCountClient.java @@ -0,0 +1,23 @@ +package com.baeldung.micronaut.apiversioning.param.client; + +import io.micronaut.core.annotation.Nullable; +import io.micronaut.core.async.annotation.SingleResult; +import io.micronaut.http.HttpHeaders; +import io.micronaut.http.annotation.Get; +import io.micronaut.http.annotation.Header; +import io.micronaut.http.annotation.QueryValue; +import io.micronaut.http.client.annotation.Client; +import io.reactivex.rxjava3.core.Flowable; + +@Client("/") +@Header(name = HttpHeaders.ACCEPT, value = "application/json") +public interface CatCountClient { + + @Get( + uri = "/cat/count", + consumes = {"application/json"}, + produces = {"application/json"} + ) + @SingleResult + Flowable count(@QueryValue("max") @Nullable Integer max, @QueryValue(value = "v", defaultValue = "1") @Nullable Integer version); +} diff --git a/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/param/server/CatCountController.java b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/param/server/CatCountController.java new file mode 100644 index 0000000000..43a34a2272 --- /dev/null +++ b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/param/server/CatCountController.java @@ -0,0 +1,37 @@ +package com.baeldung.micronaut.apiversioning.param.server; + +import io.micronaut.core.annotation.NonNull; +import io.micronaut.core.annotation.Nullable; +import io.micronaut.core.version.annotation.Version; +import io.micronaut.http.annotation.Controller; +import io.micronaut.http.annotation.Get; +import io.micronaut.http.annotation.QueryValue; +import io.reactivex.rxjava3.core.Flowable; + +import java.util.stream.Stream; + +@Controller("/cat") +public class CatCountController { + + @Get(value = "/count", produces = {"application/json"}) + @Version("1") + public Flowable countV1(@QueryValue("max") @Nullable Integer max) { + return Flowable.fromStream( + Stream.iterate(0, i -> i + 1) + .map(index -> "Cat " + index) + .limit(max == null ? 10 : max) + ); + } + + + @Get(value = "/count", produces = {"application/json"}) + @Version("2") + public Flowable countV2(@QueryValue("max") @NonNull Integer max) { + return Flowable.fromStream( + Stream.iterate(0, i -> i + 1) + .map(index -> "Cat " + index) + .limit(max) + ); + } + +} diff --git a/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/url/client/SheepCountClient.java b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/url/client/SheepCountClient.java new file mode 100644 index 0000000000..cdb344b4e5 --- /dev/null +++ b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/url/client/SheepCountClient.java @@ -0,0 +1,39 @@ +package com.baeldung.micronaut.apiversioning.url.client; + +import io.micronaut.core.annotation.Nullable; +import io.micronaut.core.async.annotation.SingleResult; +import io.micronaut.http.HttpHeaders; +import io.micronaut.http.annotation.Get; +import io.micronaut.http.annotation.Header; +import io.micronaut.http.annotation.QueryValue; +import io.micronaut.http.client.annotation.Client; +import io.reactivex.rxjava3.core.Flowable; + +@Client("/") +@Header(name = HttpHeaders.ACCEPT, value = "application/json") +public interface SheepCountClient { + + @Get( + uri = "/v1/sheep/count", + consumes = {"application/json"}, + produces = {"application/json"} + ) + @SingleResult + Flowable countV1(@QueryValue("max") @Nullable Integer max); + + @Get( + uri = "/v2/sheep/count", + consumes = {"application/json"}, + produces = {"application/json"} + ) + @SingleResult + Flowable countV2(@QueryValue("max") @Nullable Integer max); + + @Get( + uri = "/sheep/count", + consumes = {"application/json"}, + produces = {"application/json"} + ) + @SingleResult + Flowable countDefault(@QueryValue("max") @Nullable Integer max); +} diff --git a/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/url/server/SheepCountControllerV1.java b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/url/server/SheepCountControllerV1.java new file mode 100644 index 0000000000..5ee6a2a57d --- /dev/null +++ b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/url/server/SheepCountControllerV1.java @@ -0,0 +1,26 @@ +package com.baeldung.micronaut.apiversioning.url.server; + +import io.micronaut.core.annotation.Nullable; +import io.micronaut.http.annotation.Controller; +import io.micronaut.http.annotation.Get; +import io.reactivex.rxjava3.core.Flowable; + +import java.util.stream.Stream; + +@Controller("/v1/sheep/count") +public class SheepCountControllerV1 { + + @Get( + uri = "{?max}", + consumes = {"application/json"}, + produces = {"application/json"} + ) + Flowable countV1(@Nullable Integer max) { + return Flowable.fromStream( + Stream.iterate(0, i -> i + 1) + .map(index -> "Sheep " + index) + .limit(max == null ? 10 : max) + ); + } + +} diff --git a/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/url/server/SheepCountControllerV2.java b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/url/server/SheepCountControllerV2.java new file mode 100644 index 0000000000..d95f4a3cca --- /dev/null +++ b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/apiversioning/url/server/SheepCountControllerV2.java @@ -0,0 +1,27 @@ +package com.baeldung.micronaut.apiversioning.url.server; + +import io.micronaut.core.annotation.NonNull; +import io.micronaut.http.annotation.Controller; +import io.micronaut.http.annotation.Get; +import io.micronaut.http.annotation.QueryValue; +import io.reactivex.rxjava3.core.Flowable; + +import java.util.stream.Stream; + +@Controller +public class SheepCountControllerV2 { + + @Get( + uris = {"/v2/sheep/count", "/sheep/count"}, + consumes = {"application/json"}, + produces = {"application/json"} + ) + Flowable countV2(@QueryValue("max") @NonNull Integer max) { + return Flowable.fromStream( + Stream.iterate(0, i -> i + 1) + .map(index -> "Sheep " + index) + .limit(max) + ); + } + +} diff --git a/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/helloworld/client/ConcreteGreetingClient.java b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/helloworld/client/ConcreteGreetingClient.java index 96bc51f235..943b2f703e 100644 --- a/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/helloworld/client/ConcreteGreetingClient.java +++ b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/helloworld/client/ConcreteGreetingClient.java @@ -1,28 +1,27 @@ package com.baeldung.micronaut.helloworld.client; import io.micronaut.http.HttpRequest; +import io.micronaut.http.client.HttpClient; import io.micronaut.http.client.annotation.Client; -import io.micronaut.http.client.RxHttpClient; -import io.reactivex.Single; - -import javax.inject.Singleton; +import io.reactivex.rxjava3.core.Single; +import jakarta.inject.Singleton; @Singleton public class ConcreteGreetingClient { - private RxHttpClient httpClient; + private HttpClient httpClient; - public ConcreteGreetingClient(@Client("/") RxHttpClient httpClient) { + public ConcreteGreetingClient(@Client("/") HttpClient httpClient) { this.httpClient = httpClient; } public String greet(String name) { HttpRequest req = HttpRequest.GET("/greet/" + name); - return httpClient.retrieve(req).blockingFirst(); + return Single.fromPublisher(httpClient.retrieve(req)).blockingGet(); } public Single greetAsync(String name) { HttpRequest req = HttpRequest.GET("/async/greet/" + name); - return httpClient.retrieve(req).first("An error as occurred"); + return Single.fromPublisher(httpClient.retrieve(req)); } } diff --git a/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/helloworld/server/controller/AsyncGreetController.java b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/helloworld/server/controller/AsyncGreetController.java index 4d86b9dfed..862a822573 100644 --- a/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/helloworld/server/controller/AsyncGreetController.java +++ b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/helloworld/server/controller/AsyncGreetController.java @@ -3,9 +3,9 @@ package com.baeldung.micronaut.helloworld.server.controller; import com.baeldung.micronaut.helloworld.server.service.GreetingService; import io.micronaut.http.annotation.Controller; import io.micronaut.http.annotation.Get; -import io.reactivex.Single; -import javax.inject.Inject; +import io.reactivex.rxjava3.core.Single; +import jakarta.inject.Inject; @Controller("/async/greet") public class AsyncGreetController { diff --git a/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/helloworld/server/controller/GreetController.java b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/helloworld/server/controller/GreetController.java index c890c037e4..ba3b6197d8 100644 --- a/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/helloworld/server/controller/GreetController.java +++ b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/helloworld/server/controller/GreetController.java @@ -7,7 +7,7 @@ import io.micronaut.http.annotation.Controller; import io.micronaut.http.annotation.Get; import io.micronaut.http.annotation.Post; -import javax.inject.Inject; +import jakarta.inject.Inject; @Controller("/greet") public class GreetController { diff --git a/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/helloworld/server/service/EnglishGreetingService.java b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/helloworld/server/service/EnglishGreetingService.java index 8ea5172cf6..865ee0b639 100644 --- a/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/helloworld/server/service/EnglishGreetingService.java +++ b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/helloworld/server/service/EnglishGreetingService.java @@ -2,7 +2,7 @@ package com.baeldung.micronaut.helloworld.server.service; import io.micronaut.context.annotation.Primary; -import javax.inject.Singleton; +import jakarta.inject.Singleton; @Primary @Singleton diff --git a/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/helloworld/server/service/SpanishGreetingService.java b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/helloworld/server/service/SpanishGreetingService.java index 1ec53d8b2d..e426c2911e 100644 --- a/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/helloworld/server/service/SpanishGreetingService.java +++ b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/helloworld/server/service/SpanishGreetingService.java @@ -1,6 +1,6 @@ package com.baeldung.micronaut.helloworld.server.service; -import javax.inject.Singleton; +import jakarta.inject.Singleton; @Singleton public class SpanishGreetingService implements GreetingService { diff --git a/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/vs/springboot/CompareApplication.java b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/vs/springboot/CompareApplication.java index 4654526b28..0fea9f970b 100644 --- a/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/vs/springboot/CompareApplication.java +++ b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/vs/springboot/CompareApplication.java @@ -1,9 +1,11 @@ package com.baeldung.micronaut.vs.springboot; + import io.micronaut.runtime.Micronaut; public class CompareApplication { + public static void main(String[] args) { - Micronaut.run(CompareApplication.class); + Micronaut.run(CompareApplication.class, args); } -} +} \ No newline at end of file diff --git a/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/vs/springboot/client/ArithmeticClientImpl.java b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/vs/springboot/client/ArithmeticClientImpl.java index 6b7ae900be..95e3157bfe 100644 --- a/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/vs/springboot/client/ArithmeticClientImpl.java +++ b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/vs/springboot/client/ArithmeticClientImpl.java @@ -1,46 +1,46 @@ package com.baeldung.micronaut.vs.springboot.client; -import javax.inject.Singleton; - import io.micronaut.http.HttpRequest; -import io.micronaut.http.client.RxHttpClient; +import io.micronaut.http.client.HttpClient; import io.micronaut.http.client.annotation.Client; +import io.reactivex.rxjava3.core.Single; +import jakarta.inject.Singleton; @Singleton public class ArithmeticClientImpl { - private RxHttpClient httpClient; + private HttpClient httpClient; - public ArithmeticClientImpl(@Client("/") RxHttpClient httpClient) { + public ArithmeticClientImpl(@Client("/") HttpClient httpClient) { this.httpClient = httpClient; } public String sum(float number1, float number2) { HttpRequest req = HttpRequest.GET("/math/sum/" + number1 + "/" + number2); - return httpClient.retrieve(req) - .blockingFirst(); + return Single.fromPublisher(httpClient.retrieve(req)) + .blockingGet(); } public String subtract(float number1, float number2) { HttpRequest req = HttpRequest.GET("/math/subtract/" + number1 + "/" + number2); - return httpClient.retrieve(req) - .blockingFirst(); + return Single.fromPublisher(httpClient.retrieve(req)) + .blockingGet(); } public String multiply(float number1, float number2) { HttpRequest req = HttpRequest.GET("/math/multiply/" + number1 + "/" + number2); - return httpClient.retrieve(req) - .blockingFirst(); + return Single.fromPublisher(httpClient.retrieve(req)) + .blockingGet(); } public String divide(float number1, float number2) { HttpRequest req = HttpRequest.GET("/math/divide/" + number1 + "/" + number2); - return httpClient.retrieve(req) - .blockingFirst(); + return Single.fromPublisher(httpClient.retrieve(req)) + .blockingGet(); } public String memory() { HttpRequest req = HttpRequest.GET("/math/memory"); - return httpClient.retrieve(req) - .blockingFirst(); + return Single.fromPublisher(httpClient.retrieve(req)) + .blockingGet(); } } diff --git a/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/vs/springboot/controller/ArithmeticController.java b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/vs/springboot/controller/ArithmeticController.java index 5bc0e865e1..b774556ece 100644 --- a/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/vs/springboot/controller/ArithmeticController.java +++ b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/vs/springboot/controller/ArithmeticController.java @@ -3,7 +3,7 @@ package com.baeldung.micronaut.vs.springboot.controller; import java.lang.management.ManagementFactory; import java.lang.management.MemoryMXBean; -import javax.inject.Inject; +import jakarta.inject.Inject; import com.baeldung.micronaut.vs.springboot.service.ArithmeticService; diff --git a/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/vs/springboot/service/ArithmeticService.java b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/vs/springboot/service/ArithmeticService.java index e0e4680495..599a6ee4cf 100644 --- a/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/vs/springboot/service/ArithmeticService.java +++ b/microservices-modules/micronaut/src/main/java/com/baeldung/micronaut/vs/springboot/service/ArithmeticService.java @@ -1,6 +1,6 @@ package com.baeldung.micronaut.vs.springboot.service; -import javax.inject.Singleton; +import jakarta.inject.Singleton; @Singleton public class ArithmeticService { diff --git a/microservices-modules/micronaut/src/main/resources/application.yml b/microservices-modules/micronaut/src/main/resources/application.yml index 32daacd4aa..b265d245aa 100644 --- a/microservices-modules/micronaut/src/main/resources/application.yml +++ b/microservices-modules/micronaut/src/main/resources/application.yml @@ -1,5 +1,19 @@ +context-path: / + micronaut: - application: - name: hello-world-server - server: - port: ${random.port} \ No newline at end of file + router: + versioning: + enabled: true + default-version: 2 + parameter: + enabled: true + names: 'v,api-version' + header: + enabled: true + names: + - 'X-API-VERSION' + + application: + name: hello-world-server + server: + port: ${random.port} diff --git a/microservices-modules/micronaut/src/main/resources/logback.xml b/microservices-modules/micronaut/src/main/resources/logback.xml index afaebf8e17..4db42a7916 100644 --- a/microservices-modules/micronaut/src/main/resources/logback.xml +++ b/microservices-modules/micronaut/src/main/resources/logback.xml @@ -8,6 +8,12 @@ + + + diff --git a/microservices-modules/micronaut/src/test/java/com/baeldung/micronaut/apiversioning/custom/client/BirdCountClientUnitTest.java b/microservices-modules/micronaut/src/test/java/com/baeldung/micronaut/apiversioning/custom/client/BirdCountClientUnitTest.java new file mode 100644 index 0000000000..a3a547f9e2 --- /dev/null +++ b/microservices-modules/micronaut/src/test/java/com/baeldung/micronaut/apiversioning/custom/client/BirdCountClientUnitTest.java @@ -0,0 +1,42 @@ +package com.baeldung.micronaut.apiversioning.custom.client; + +import io.micronaut.context.annotation.Property; +import io.micronaut.http.client.exceptions.HttpClientResponseException; +import io.micronaut.runtime.EmbeddedApplication; +import io.micronaut.test.extensions.junit5.annotation.MicronautTest; +import jakarta.inject.Inject; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +@MicronautTest +@Property(name = "my.router.versioning.enabled", value = "true") +class BirdCountClientUnitTest { + + @Inject + private EmbeddedApplication application; + + @Inject + private BirdCountClient client; + + @Test + void givenTheCountApi_whenUsingV1ViaCustomStrategy_shouldRouteToProperHandler() { + Assertions.assertEquals(10, client.countV1(null).blockingSingle().split(",").length); + Assertions.assertEquals(4, client.countV1(4).blockingSingle().split(",").length); + } + + @Test + void givenTheCountApi_whenUsingV2ViaCustomStrategy_shouldRouteToProperHandler() { + Assertions.assertThrows(HttpClientResponseException.class, + () -> client.countV2(null).count().blockingGet()); + + Assertions.assertEquals(6, client.countV2(6).blockingSingle().split(",").length); + } + + @Test + void givenTheCountApi_whenUsingDefaultVersionViaCustomStrategy_shouldRouteToProperHandler() { + Assertions.assertThrows(HttpClientResponseException.class, + () -> client.countDefault(null).count().blockingGet()); + + Assertions.assertEquals(6, client.countDefault(6).blockingSingle().split(",").length); + } +} \ No newline at end of file diff --git a/microservices-modules/micronaut/src/test/java/com/baeldung/micronaut/apiversioning/header/client/DogCountClientUnitTest.java b/microservices-modules/micronaut/src/test/java/com/baeldung/micronaut/apiversioning/header/client/DogCountClientUnitTest.java new file mode 100644 index 0000000000..4a47c76943 --- /dev/null +++ b/microservices-modules/micronaut/src/test/java/com/baeldung/micronaut/apiversioning/header/client/DogCountClientUnitTest.java @@ -0,0 +1,40 @@ +package com.baeldung.micronaut.apiversioning.header.client; + +import io.micronaut.http.client.exceptions.HttpClientResponseException; +import io.micronaut.runtime.EmbeddedApplication; +import io.micronaut.test.extensions.junit5.annotation.MicronautTest; +import jakarta.inject.Inject; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +@MicronautTest +class DogCountClientUnitTest { + + @Inject + private EmbeddedApplication application; + + @Inject + private DogCountClient dogCountClient; + + @Test + void givenTheCountApi_whenUsingV1ViaHeaderStrategy_shouldRouteToProperHandler() { + Assertions.assertEquals(10, dogCountClient.countV1(null).blockingSingle().split(",").length); + Assertions.assertEquals(4, dogCountClient.countV1(4).blockingSingle().split(",").length); + } + + @Test + void givenTheCountApi_whenUsingV2ViaHeaderStrategy_shouldRouteToProperHandler() { + Assertions.assertThrows(HttpClientResponseException.class, + () -> dogCountClient.countV2(null).count().blockingGet()); + + Assertions.assertEquals(6, dogCountClient.countV2(6).blockingSingle().split(",").length); + } + + @Test + void givenTheCountApi_whenUsingDefaultVersionViaHeaderStrategy_shouldRouteToProperHandler() { + Assertions.assertThrows(HttpClientResponseException.class, + () -> dogCountClient.countDefault(null).count().blockingGet()); + + Assertions.assertEquals(6, dogCountClient.countDefault(6).blockingSingle().split(",").length); + } +} \ No newline at end of file diff --git a/microservices-modules/micronaut/src/test/java/com/baeldung/micronaut/apiversioning/param/client/CatCountClientUnitTest.java b/microservices-modules/micronaut/src/test/java/com/baeldung/micronaut/apiversioning/param/client/CatCountClientUnitTest.java new file mode 100644 index 0000000000..266f72eed8 --- /dev/null +++ b/microservices-modules/micronaut/src/test/java/com/baeldung/micronaut/apiversioning/param/client/CatCountClientUnitTest.java @@ -0,0 +1,38 @@ +package com.baeldung.micronaut.apiversioning.param.client; + +import io.micronaut.http.client.exceptions.HttpClientResponseException; +import io.micronaut.runtime.EmbeddedApplication; +import io.micronaut.test.extensions.junit5.annotation.MicronautTest; +import jakarta.inject.Inject; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +@MicronautTest +class CatCountClientUnitTest { + + @Inject + private EmbeddedApplication application; + + @Inject + private CatCountClient client; + + @Test + void givenTheCountApi_whenUsingV1ViaParameterStrategy_shouldRouteToProperHandler() { + Assertions.assertEquals(10, client.count(null, 1).blockingSingle().split(",").length); + Assertions.assertEquals(5, client.count(5, 1).blockingSingle().split(",").length); + } + + @Test + void givenTheCountApi_whenUsingV2ViaParameterStrategy_shouldRouteToProperHandler() { + Assertions.assertThrows(HttpClientResponseException.class, + () -> client.count(null, 2).count().blockingGet()); + + Assertions.assertEquals(6, client.count(6, 2).blockingSingle().split(",").length); + } + + @Test + void givenTheCountApi_whenUsingDefaultVersionViaParameterStrategy_shouldRouteToProperHandler() { + Assertions.assertEquals(10, client.count(null, null).blockingSingle().split(",").length); + Assertions.assertEquals(6, client.count(6, null).blockingSingle().split(",").length); + } +} \ No newline at end of file diff --git a/microservices-modules/micronaut/src/test/java/com/baeldung/micronaut/apiversioning/url/client/SheepCountClientUnitTest.java b/microservices-modules/micronaut/src/test/java/com/baeldung/micronaut/apiversioning/url/client/SheepCountClientUnitTest.java new file mode 100644 index 0000000000..e082793fe1 --- /dev/null +++ b/microservices-modules/micronaut/src/test/java/com/baeldung/micronaut/apiversioning/url/client/SheepCountClientUnitTest.java @@ -0,0 +1,44 @@ +package com.baeldung.micronaut.apiversioning.url.client; + +import io.micronaut.http.client.exceptions.HttpClientResponseException; +import io.micronaut.runtime.EmbeddedApplication; +import io.micronaut.test.extensions.junit5.annotation.MicronautTest; +import jakarta.inject.Inject; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.util.List; +import java.util.stream.Collectors; + +@MicronautTest +class SheepCountClientUnitTest { + + @Inject + private EmbeddedApplication application; + @Inject + private SheepCountClient client; + + @Test + void givenTheCountApi_whenUsingV1ViaUrlStrategy_shouldRouteToProperHandler() { + Assertions.assertEquals(10, client.countV1(null).blockingSingle().split(",").length); + Assertions.assertEquals(4, client.countV1(4).blockingSingle().split(",").length); + } + + @Test + void givenTheCountApi_whenUsingV2ViaUrlStrategy_shouldRouteToProperHandler() { + Assertions.assertThrows(HttpClientResponseException.class, + () -> client.countV2(null).count().blockingGet()); + + final var actual = client.countV2(4).blockingSingle().split(",").length; + Assertions.assertEquals(4, actual); + } + + @Test + void givenTheCountApi_whenUsingDefaultVersionViaUrlStrategy_shouldRouteToProperHandler() { + Assertions.assertThrows(HttpClientResponseException.class, + () -> client.countDefault(null).count().blockingGet()); + + final var actual = client.countDefault(4).blockingSingle().split(",").length; + Assertions.assertEquals(4, actual); + } +} \ No newline at end of file diff --git a/microservices-modules/micronaut/src/test/java/com/baeldung/micronaut/helloworld/client/ConcreteGreetingClientUnitTest.java b/microservices-modules/micronaut/src/test/java/com/baeldung/micronaut/helloworld/client/ConcreteGreetingClientUnitTest.java index 336374d5a6..88a9782074 100644 --- a/microservices-modules/micronaut/src/test/java/com/baeldung/micronaut/helloworld/client/ConcreteGreetingClientUnitTest.java +++ b/microservices-modules/micronaut/src/test/java/com/baeldung/micronaut/helloworld/client/ConcreteGreetingClientUnitTest.java @@ -1,31 +1,19 @@ package com.baeldung.micronaut.helloworld.client; -import io.micronaut.context.ApplicationContext; -import io.micronaut.runtime.server.EmbeddedServer; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; +import io.micronaut.runtime.EmbeddedApplication; +import io.micronaut.test.extensions.junit5.annotation.MicronautTest; +import jakarta.inject.Inject; +import org.junit.jupiter.api.Test; -import static junit.framework.TestCase.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; -public class ConcreteGreetingClientUnitTest -{ - private EmbeddedServer server; +@MicronautTest +public class ConcreteGreetingClientUnitTest { + @Inject + private EmbeddedApplication application; + @Inject private ConcreteGreetingClient client; - @Before - public void setup() - { - server = ApplicationContext.run(EmbeddedServer.class); - client = server.getApplicationContext().getBean(ConcreteGreetingClient.class); - } - - @After - public void cleanup() - { - server.stop(); - } - @Test public void testGreeting() { assertEquals(client.greet("Mike"), "Hello Mike"); diff --git a/microservices-modules/micronaut/src/test/java/com/baeldung/micronaut/helloworld/client/GreetingClientUnitTest.java b/microservices-modules/micronaut/src/test/java/com/baeldung/micronaut/helloworld/client/GreetingClientUnitTest.java index c47fb3a31d..5b269531e7 100644 --- a/microservices-modules/micronaut/src/test/java/com/baeldung/micronaut/helloworld/client/GreetingClientUnitTest.java +++ b/microservices-modules/micronaut/src/test/java/com/baeldung/micronaut/helloworld/client/GreetingClientUnitTest.java @@ -1,30 +1,21 @@ package com.baeldung.micronaut.helloworld.client; -import io.micronaut.context.ApplicationContext; -import io.micronaut.runtime.server.EmbeddedServer; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; +import io.micronaut.runtime.EmbeddedApplication; +import io.micronaut.test.extensions.junit5.annotation.MicronautTest; +import jakarta.inject.Inject; +import org.junit.jupiter.api.Test; -import static junit.framework.TestCase.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +@MicronautTest public class GreetingClientUnitTest { - private EmbeddedServer server; + + @Inject + private EmbeddedApplication application; + + @Inject private GreetingClient client; - @Before - public void setup() - { - server = ApplicationContext.run(EmbeddedServer.class); - client = server.getApplicationContext().getBean(GreetingClient.class); - } - - @After - public void cleanup() - { - server.stop(); - } - @Test public void testGreeting() { assertEquals(client.greet("Mike"), "Hello Mike"); diff --git a/microservices-modules/micronaut/src/test/java/com/baeldung/micronaut/vs/springboot/ArithmeticClientUnitTest.java b/microservices-modules/micronaut/src/test/java/com/baeldung/micronaut/vs/springboot/ArithmeticClientUnitTest.java index 9a1b095d22..fa191778f5 100644 --- a/microservices-modules/micronaut/src/test/java/com/baeldung/micronaut/vs/springboot/ArithmeticClientUnitTest.java +++ b/microservices-modules/micronaut/src/test/java/com/baeldung/micronaut/vs/springboot/ArithmeticClientUnitTest.java @@ -1,34 +1,21 @@ package com.baeldung.micronaut.vs.springboot; -import static org.junit.Assert.assertEquals; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.containsString; - -import io.micronaut.context.ApplicationContext; -import io.micronaut.runtime.server.EmbeddedServer; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - import com.baeldung.micronaut.vs.springboot.client.ArithmeticClientImpl; +import io.micronaut.runtime.EmbeddedApplication; +import io.micronaut.test.extensions.junit5.annotation.MicronautTest; +import jakarta.inject.Inject; +import org.junit.jupiter.api.Test; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; + +@MicronautTest public class ArithmeticClientUnitTest { - private EmbeddedServer server; + @Inject + private EmbeddedApplication server; + @Inject private ArithmeticClientImpl client; - @Before - public void setup() { - server = ApplicationContext.run(EmbeddedServer.class); - client = server.getApplicationContext() - .getBean(ArithmeticClientImpl.class); - } - - @After - public void cleanup() { - server.stop(); - } - @Test public void givenTwoNumbers_whenAdd_thenCorrectAnswerReturned() { String expected = Float.valueOf(10 + 20).toString(); @@ -56,6 +43,6 @@ public class ArithmeticClientUnitTest { @Test public void whenMemory_thenCorrectAnswerReturned() { String expected = "Initial:"; - assertThat(client.memory(), containsString(expected)); + assertThat(client.memory()).contains(expected); } } diff --git a/parent-spring-6/pom.xml b/parent-spring-6/pom.xml index 77afe2072a..7b28afc9b1 100644 --- a/parent-spring-6/pom.xml +++ b/parent-spring-6/pom.xml @@ -1,7 +1,7 @@ + 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"> 4.0.0 parent-spring-6 0.0.1-SNAPSHOT @@ -35,7 +35,7 @@ - 6.0.10 + 6.0.12 diff --git a/persistence-modules/pom.xml b/persistence-modules/pom.xml index ec63d5c56e..f35b22a19d 100644 --- a/persistence-modules/pom.xml +++ b/persistence-modules/pom.xml @@ -115,7 +115,7 @@ java-mongodb questdb neo4j - + rethinkdb scylladb spring-data-cassandra-2 spring-data-jpa-repo-3 diff --git a/persistence-modules/rethinkdb/src/test/java/com/baeldung/rethinkdb/InsertIntegrationTest.java b/persistence-modules/rethinkdb/src/test/java/com/baeldung/rethinkdb/InsertIntegrationLiveTest.java similarity index 96% rename from persistence-modules/rethinkdb/src/test/java/com/baeldung/rethinkdb/InsertIntegrationTest.java rename to persistence-modules/rethinkdb/src/test/java/com/baeldung/rethinkdb/InsertIntegrationLiveTest.java index 244959d854..0e6cdae2b4 100644 --- a/persistence-modules/rethinkdb/src/test/java/com/baeldung/rethinkdb/InsertIntegrationTest.java +++ b/persistence-modules/rethinkdb/src/test/java/com/baeldung/rethinkdb/InsertIntegrationLiveTest.java @@ -10,7 +10,7 @@ import static com.rethinkdb.RethinkDB.r; /** * Some tests demonstrating inserting data. */ -public class InsertIntegrationTest extends TestBase { +public class InsertIntegrationLiveTest extends TestBase { /** * Create a table for the tests. */ diff --git a/persistence-modules/rethinkdb/src/test/java/com/baeldung/rethinkdb/QueryIntegrationTest.java b/persistence-modules/rethinkdb/src/test/java/com/baeldung/rethinkdb/QueryIntegrationLiveTest.java similarity index 97% rename from persistence-modules/rethinkdb/src/test/java/com/baeldung/rethinkdb/QueryIntegrationTest.java rename to persistence-modules/rethinkdb/src/test/java/com/baeldung/rethinkdb/QueryIntegrationLiveTest.java index 263dda9bc6..626d15bcb6 100644 --- a/persistence-modules/rethinkdb/src/test/java/com/baeldung/rethinkdb/QueryIntegrationTest.java +++ b/persistence-modules/rethinkdb/src/test/java/com/baeldung/rethinkdb/QueryIntegrationLiveTest.java @@ -16,7 +16,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue; /** * Some tests demonstrating querying data. */ -public class QueryIntegrationTest extends TestBase { +public class QueryIntegrationLiveTest extends TestBase { /** * Create a table for the tests. */ diff --git a/persistence-modules/rethinkdb/src/test/java/com/baeldung/rethinkdb/StreamingIntegrationTest.java b/persistence-modules/rethinkdb/src/test/java/com/baeldung/rethinkdb/StreamingIntegrationLiveTest.java similarity index 98% rename from persistence-modules/rethinkdb/src/test/java/com/baeldung/rethinkdb/StreamingIntegrationTest.java rename to persistence-modules/rethinkdb/src/test/java/com/baeldung/rethinkdb/StreamingIntegrationLiveTest.java index 4ca147cf68..bc105d2e4f 100644 --- a/persistence-modules/rethinkdb/src/test/java/com/baeldung/rethinkdb/StreamingIntegrationTest.java +++ b/persistence-modules/rethinkdb/src/test/java/com/baeldung/rethinkdb/StreamingIntegrationLiveTest.java @@ -13,7 +13,7 @@ import static com.rethinkdb.RethinkDB.r; /** * Some tests demonstrating streaming live changes to data. */ -public class StreamingIntegrationTest extends TestBase { +public class StreamingIntegrationLiveTest extends TestBase { @Test public void getLiveInserts() throws InterruptedException { ExecutorService executorService = Executors.newCachedThreadPool(); diff --git a/persistence-modules/rethinkdb/src/test/java/com/baeldung/rethinkdb/TablesIntegrationTest.java b/persistence-modules/rethinkdb/src/test/java/com/baeldung/rethinkdb/TablesIntegrationLiveTest.java similarity index 94% rename from persistence-modules/rethinkdb/src/test/java/com/baeldung/rethinkdb/TablesIntegrationTest.java rename to persistence-modules/rethinkdb/src/test/java/com/baeldung/rethinkdb/TablesIntegrationLiveTest.java index d60e500373..7bffb189b3 100644 --- a/persistence-modules/rethinkdb/src/test/java/com/baeldung/rethinkdb/TablesIntegrationTest.java +++ b/persistence-modules/rethinkdb/src/test/java/com/baeldung/rethinkdb/TablesIntegrationLiveTest.java @@ -12,7 +12,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue; /** * Some tests demonstrating working with tables. */ -public class TablesIntegrationTest extends TestBase { +public class TablesIntegrationLiveTest extends TestBase { @Test public void createTable() { diff --git a/persistence-modules/rethinkdb/src/test/java/com/baeldung/rethinkdb/UpdateIntegrationTest.java b/persistence-modules/rethinkdb/src/test/java/com/baeldung/rethinkdb/UpdateIntegrationLiveTest.java similarity index 96% rename from persistence-modules/rethinkdb/src/test/java/com/baeldung/rethinkdb/UpdateIntegrationTest.java rename to persistence-modules/rethinkdb/src/test/java/com/baeldung/rethinkdb/UpdateIntegrationLiveTest.java index 39fad3a878..d47caa0b5e 100644 --- a/persistence-modules/rethinkdb/src/test/java/com/baeldung/rethinkdb/UpdateIntegrationTest.java +++ b/persistence-modules/rethinkdb/src/test/java/com/baeldung/rethinkdb/UpdateIntegrationLiveTest.java @@ -8,7 +8,7 @@ import static com.rethinkdb.RethinkDB.r; /** * Some tests demonstrating updating data. */ -public class UpdateIntegrationTest extends TestBase { +public class UpdateIntegrationLiveTest extends TestBase { /** * Create a table for the tests. */ diff --git a/persistence-modules/spring-boot-persistence-mongodb-3/pom.xml b/persistence-modules/spring-boot-persistence-mongodb-3/pom.xml index c48525673a..3f144bae54 100644 --- a/persistence-modules/spring-boot-persistence-mongodb-3/pom.xml +++ b/persistence-modules/spring-boot-persistence-mongodb-3/pom.xml @@ -9,27 +9,12 @@ com.baeldung - parent-boot-2 + parent-boot-3 0.0.1-SNAPSHOT - ../../parent-boot-2 + ../../parent-boot-3 - - org.mongodb - mongodb-driver-sync - ${mongodb-driver.version} - - - org.mongodb - mongodb-driver-core - ${mongodb-driver.version} - - - org.mongodb - bson - ${mongodb-driver.version} - org.springframework.boot spring-boot-starter-web @@ -37,16 +22,6 @@ org.springframework.boot spring-boot-starter-data-mongodb - - - org.mongodb - mongodb-driver-sync - - - org.mongodb - mongodb-driver-core - - org.mongodb @@ -57,12 +32,13 @@ de.flapdoodle.embed de.flapdoodle.embed.mongo test + ${de.flapdoodle.embed.mongo.version} - 1.7.3 - 4.9.1 + com.baeldung.boot.atlassearch.MongoDbAtlasSearchApplication + 1.8.0 + 4.9.2 - diff --git a/persistence-modules/spring-boot-persistence-mongodb-3/src/main/java/com/baeldung/boot/atlassearch/MongoDbAtlasSearchApplication.java b/persistence-modules/spring-boot-persistence-mongodb-3/src/main/java/com/baeldung/boot/atlassearch/MongoDbAtlasSearchApplication.java new file mode 100644 index 0000000000..afaf524829 --- /dev/null +++ b/persistence-modules/spring-boot-persistence-mongodb-3/src/main/java/com/baeldung/boot/atlassearch/MongoDbAtlasSearchApplication.java @@ -0,0 +1,12 @@ +package com.baeldung.boot.atlassearch; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class MongoDbAtlasSearchApplication { + + public static void main(String... args) { + SpringApplication.run(MongoDbAtlasSearchApplication.class, args); + } +} diff --git a/persistence-modules/spring-boot-persistence-mongodb-3/src/main/java/com/baeldung/boot/atlassearch/config/IndexConfig.java b/persistence-modules/spring-boot-persistence-mongodb-3/src/main/java/com/baeldung/boot/atlassearch/config/IndexConfig.java new file mode 100644 index 0000000000..cb4fae89e4 --- /dev/null +++ b/persistence-modules/spring-boot-persistence-mongodb-3/src/main/java/com/baeldung/boot/atlassearch/config/IndexConfig.java @@ -0,0 +1,22 @@ +package com.baeldung.boot.atlassearch.config; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class IndexConfig { + + @Value("${com.baeldung.atlas-search.index.query}") + private String queryIndex; + + @Value("${com.baeldung.atlas-search.index.facet}") + private String facetIndex; + + public String getFacetIndex() { + return facetIndex; + } + + public String getQueryIndex() { + return queryIndex; + } +} diff --git a/persistence-modules/spring-boot-persistence-mongodb-3/src/main/java/com/baeldung/boot/atlassearch/service/MovieAtlasSearchService.java b/persistence-modules/spring-boot-persistence-mongodb-3/src/main/java/com/baeldung/boot/atlassearch/service/MovieAtlasSearchService.java new file mode 100644 index 0000000000..55d47759d5 --- /dev/null +++ b/persistence-modules/spring-boot-persistence-mongodb-3/src/main/java/com/baeldung/boot/atlassearch/service/MovieAtlasSearchService.java @@ -0,0 +1,183 @@ +package com.baeldung.boot.atlassearch.service; + +import static com.mongodb.client.model.Aggregates.facet; +import static com.mongodb.client.model.Aggregates.limit; +import static com.mongodb.client.model.Aggregates.project; +import static com.mongodb.client.model.Aggregates.replaceWith; +import static com.mongodb.client.model.Aggregates.search; +import static com.mongodb.client.model.Aggregates.searchMeta; +import static com.mongodb.client.model.Aggregates.skip; +import static com.mongodb.client.model.Projections.excludeId; +import static com.mongodb.client.model.Projections.fields; +import static com.mongodb.client.model.Projections.include; +import static com.mongodb.client.model.Projections.metaSearchScore; +import static com.mongodb.client.model.search.SearchCount.total; +import static com.mongodb.client.model.search.SearchFacet.combineToBson; +import static com.mongodb.client.model.search.SearchFacet.numberFacet; +import static com.mongodb.client.model.search.SearchFacet.stringFacet; +import static com.mongodb.client.model.search.SearchOperator.compound; +import static com.mongodb.client.model.search.SearchOperator.numberRange; +import static com.mongodb.client.model.search.SearchOperator.of; +import static com.mongodb.client.model.search.SearchOperator.text; +import static com.mongodb.client.model.search.SearchOptions.searchOptions; +import static com.mongodb.client.model.search.SearchPath.fieldPath; +import static java.util.Arrays.asList; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; + +import org.apache.logging.log4j.LogManager; +import org.bson.Document; +import org.bson.conversions.Bson; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.stereotype.Service; + +import com.baeldung.boot.atlassearch.config.IndexConfig; +import com.mongodb.client.MongoCollection; +import com.mongodb.client.MongoDatabase; +import com.mongodb.client.model.Facet; +import com.mongodb.client.model.search.SearchScore; + +@Service +public class MovieAtlasSearchService { + + @Autowired + private IndexConfig config; + + private final MongoCollection collection; + + public MovieAtlasSearchService(MongoTemplate mongoTemplate) { + MongoDatabase database = mongoTemplate.getDb(); + this.collection = database.getCollection("movies"); + } + + public static void debug(List pipeline) { + StringBuilder builder = new StringBuilder("["); + final AtomicBoolean first = new AtomicBoolean(true); + pipeline.forEach(stage -> { + builder.append((first.get() ? "" : ",") + + stage.toBsonDocument() + ); + + first.set(false); + }); + builder.append("]"); + + LogManager.getLogger(MovieAtlasSearchService.class) + .debug(builder.toString()); + } + + public Document late90sMovies(int skip, int limit, String keywords, SearchScore modifier) { + List pipeline = asList( + search( + compound() + .must(asList( + numberRange( + fieldPath("year")) + .gteLt(1995, 2000) + )) + .should(asList( + text( + fieldPath("fullplot"), keywords + ) + .score(modifier) + )), + searchOptions() + .index(config.getQueryIndex()) + ), + project(fields( + excludeId(), + include("title", "year", "fullplot", "imdb.rating"), + metaSearchScore("score") + )), + facet( + new Facet("rows", + skip(skip), + limit(limit) + ), + new Facet("totalRows", + replaceWith("$$SEARCH_META"), + limit(1) + ) + ) + ); + + debug(pipeline); + return collection.aggregate(pipeline) + .first(); + } + + public Document countLate90sMovies(String keywords) { + List pipeline = asList( + searchMeta( + compound() + .must(asList( + numberRange( + fieldPath("year")) + .gteLt(1995, 2000), + text( + fieldPath("fullplot"), keywords + ) + )), + searchOptions() + .index(config.getQueryIndex()) + .count(total()) + ) + ); + + debug(pipeline); + return collection.aggregate(pipeline) + .first(); + } + + public Collection moviesByKeywords(String keywords) { + List pipeline = asList( + search( + text( + fieldPath("fullplot"), keywords + ), + searchOptions() + .index(config.getQueryIndex()) + ), + project(fields( + excludeId(), + include("title", "year", "fullplot", "imdb.rating") + )) + ); + + debug(pipeline); + return collection.aggregate(pipeline) + .into(new ArrayList()); + } + + public Document genresThroughTheDecades(String genre) { + List pipeline = asList( + searchMeta(of( + new Document("facet", + new Document("operator", + text( + fieldPath("genres"), genre + ) + ).append("facets", combineToBson(asList( + stringFacet("genresFacet", + fieldPath("genres") + ).numBuckets(5), + numberFacet("yearFacet", + fieldPath("year"), + asList(1900, 1930, 1960, 1990, 2020) + ) + ))) + )), + searchOptions() + .index(config.getFacetIndex()) + ) + ); + + debug(pipeline); + return collection.aggregate(pipeline) + .first(); + } +} diff --git a/persistence-modules/spring-boot-persistence-mongodb-3/src/main/java/com/baeldung/boot/atlassearch/web/MovieAtlasSearchController.java b/persistence-modules/spring-boot-persistence-mongodb-3/src/main/java/com/baeldung/boot/atlassearch/web/MovieAtlasSearchController.java new file mode 100644 index 0000000000..4c41915347 --- /dev/null +++ b/persistence-modules/spring-boot-persistence-mongodb-3/src/main/java/com/baeldung/boot/atlassearch/web/MovieAtlasSearchController.java @@ -0,0 +1,48 @@ +package com.baeldung.boot.atlassearch.web; + +import java.util.Collection; + +import org.bson.Document; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.baeldung.boot.atlassearch.service.MovieAtlasSearchService; +import com.mongodb.client.model.search.SearchScore; + +@RestController +@RequestMapping("/movies") +public class MovieAtlasSearchController { + + @Autowired + private MovieAtlasSearchService service; + + @GetMapping("with/{keywords}") + Collection getMoviesWithKeywords(@PathVariable String keywords) { + return service.moviesByKeywords(keywords); + } + + @GetMapping("90s/with/{keywords}/count") + Document getCount90sMoviesWithKeywords(@PathVariable String keywords) { + return service.countLate90sMovies(keywords); + } + + @GetMapping("90s/{skip}/{limit}/with/{keywords}") + Document getMoviesUsingScoreBoost(@PathVariable int skip, @PathVariable int limit, @PathVariable String keywords) { + return service.late90sMovies(skip, limit, keywords, SearchScore.boost(2)); + } + + @PostMapping("90s/{skip}/{limit}/with/{keywords}") + Document getMoviesUsingScoringFunction(@RequestBody String jsonFunction, @PathVariable int skip, @PathVariable int limit, @PathVariable String keywords) { + return service.late90sMovies(skip, limit, keywords, SearchScore.of(new Document("function", Document.parse(jsonFunction)))); + } + + @GetMapping("by-genre/{genre}") + Document getMoviesWithFacets(@PathVariable String genre) { + return service.genresThroughTheDecades(genre); + } +} diff --git a/persistence-modules/spring-boot-persistence-mongodb-3/src/main/resources/application.properties b/persistence-modules/spring-boot-persistence-mongodb-3/src/main/resources/application.properties index 8309c4461f..02ba79e336 100644 --- a/persistence-modules/spring-boot-persistence-mongodb-3/src/main/resources/application.properties +++ b/persistence-modules/spring-boot-persistence-mongodb-3/src/main/resources/application.properties @@ -1 +1,4 @@ spring.application.name=spring-boot-persistence-mongodb-3 + +com.baeldung.atlas-search.index.query=idx-queries +com.baeldung.atlas-search.index.facet=idx-facets \ No newline at end of file diff --git a/persistence-modules/spring-boot-persistence-mongodb-3/src/test/java/com/baeldung/boot/atlassearch/MovieAtlasSearchServiceLiveTest.java b/persistence-modules/spring-boot-persistence-mongodb-3/src/test/java/com/baeldung/boot/atlassearch/MovieAtlasSearchServiceLiveTest.java new file mode 100644 index 0000000000..190ebc19d9 --- /dev/null +++ b/persistence-modules/spring-boot-persistence-mongodb-3/src/test/java/com/baeldung/boot/atlassearch/MovieAtlasSearchServiceLiveTest.java @@ -0,0 +1,67 @@ +package com.baeldung.boot.atlassearch; + +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.bson.Document; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit4.SpringRunner; + +import com.baeldung.boot.atlassearch.service.MovieAtlasSearchService; +import com.mongodb.client.model.search.SearchScore; + +@DirtiesContext +@RunWith(SpringRunner.class) +@TestPropertySource("/embedded.properties") +@SpringBootTest(classes = MongoDbAtlasSearchApplication.class) +public class MovieAtlasSearchServiceLiveTest { + + @Autowired + private MovieAtlasSearchService service; + + @Test + public void givenScoreBoost_thenFirstItemContainsPlot() { + final String plot = "space"; + + Document movies = service.late90sMovies(0, 1, plot, SearchScore.boost(2)); + + assertTrue(movies.getList("rows", Document.class) + .iterator() + .next() + .getString("fullplot") + .contains(plot)); + } + + @Test + public void givenFacetOperator_thenCorrespondingBucketsReturned() { + final String genre = "Sci-Fi"; + + Document meta = service.genresThroughTheDecades(genre); + + Long lowerBound = meta + .get("count", Document.class) + .getLong("lowerBound"); + + Document genresFacetFirstBucket = meta.get("facet", Document.class) + .get("genresFacet", Document.class) + .getList("buckets", Document.class) + .iterator() + .next(); + + Document yearFacetFirstBucket = meta.get("facet", Document.class) + .get("yearFacet", Document.class) + .getList("buckets", Document.class) + .iterator() + .next(); + + assertEquals(lowerBound, genresFacetFirstBucket.getLong("count")); + assertEquals(genre, genresFacetFirstBucket.getString("_id")); + assertNotNull(yearFacetFirstBucket); + } +} diff --git a/persistence-modules/spring-boot-persistence-mongodb-3/src/test/resources/embedded.properties b/persistence-modules/spring-boot-persistence-mongodb-3/src/test/resources/embedded.properties index cd1c1d43c7..f47eca5023 100644 --- a/persistence-modules/spring-boot-persistence-mongodb-3/src/test/resources/embedded.properties +++ b/persistence-modules/spring-boot-persistence-mongodb-3/src/test/resources/embedded.properties @@ -1,4 +1,4 @@ -spring.mongodb.embedded.version=4.4.9 +spring.mongodb.embedded.version=4.9.2 #spring.data.mongodb.uri=changeit #spring.data.mongodb.database=changeit diff --git a/persistence-modules/spring-data-cassandra-2/src/test/java/org/baeldung/cassandra/inquery/ProductRepositoryNestedLiveTest.java b/persistence-modules/spring-data-cassandra-2/src/test/java/org/baeldung/cassandra/inquery/ProductRepositoryNestedLiveTest.java index 3d2433814e..3592c8b80d 100644 --- a/persistence-modules/spring-data-cassandra-2/src/test/java/org/baeldung/cassandra/inquery/ProductRepositoryNestedLiveTest.java +++ b/persistence-modules/spring-data-cassandra-2/src/test/java/org/baeldung/cassandra/inquery/ProductRepositoryNestedLiveTest.java @@ -23,7 +23,7 @@ import static org.junit.jupiter.api.Assertions.*; @Testcontainers @SpringBootTest -class ProductRepositoryIntegrationTest { +class ProductRepositoryNestedLiveTest { private static final String KEYSPACE_NAME = "mynamespace"; diff --git a/persistence-modules/spring-data-cassandra-2/src/test/java/org/baeldung/objectmapper/MapperLiveTest.java b/persistence-modules/spring-data-cassandra-2/src/test/java/org/baeldung/objectmapper/MapperLiveTest.java index b61663d622..50681d36c5 100644 --- a/persistence-modules/spring-data-cassandra-2/src/test/java/org/baeldung/objectmapper/MapperLiveTest.java +++ b/persistence-modules/spring-data-cassandra-2/src/test/java/org/baeldung/objectmapper/MapperLiveTest.java @@ -1,7 +1,8 @@ package org.baeldung.objectmapper; -import com.datastax.oss.driver.api.core.CqlIdentifier; -import com.datastax.oss.driver.api.core.CqlSession; +import java.net.InetSocketAddress; +import java.util.List; + import org.baeldung.objectmapper.dao.CounterDao; import org.baeldung.objectmapper.dao.UserDao; import org.baeldung.objectmapper.entity.Counter; @@ -14,7 +15,8 @@ import org.testcontainers.containers.CassandraContainer; import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Testcontainers; -import java.util.List; +import com.datastax.oss.driver.api.core.CqlIdentifier; +import com.datastax.oss.driver.api.core.CqlSession; @Testcontainers @SpringBootTest @@ -23,35 +25,30 @@ public class MapperLiveTest { private static final String KEYSPACE_NAME = "baeldung"; @Container - private static final CassandraContainer cassandra = (CassandraContainer) new CassandraContainer("cassandra:3.11.2") - .withExposedPorts(9042); + private static final CassandraContainer cassandra = (CassandraContainer) new CassandraContainer("cassandra:3.11.2").withExposedPorts(9042); + @BeforeAll static void setupCassandraConnectionProperties() { System.setProperty("spring.data.cassandra.keyspace-name", KEYSPACE_NAME); - System.setProperty("spring.data.cassandra.contact-points", cassandra.getContainerIpAddress()); + System.setProperty("spring.data.cassandra.contact-points", cassandra.getHost()); System.setProperty("spring.data.cassandra.port", String.valueOf(cassandra.getMappedPort(9042))); + setupCassandra(new InetSocketAddress(cassandra.getHost(), cassandra.getMappedPort(9042)), cassandra.getLocalDatacenter()); } static UserDao userDao; static CounterDao counterDao; - @BeforeAll - static void setup() { - setupCassandraConnectionProperties(); - CqlSession session = CqlSession.builder().build(); + static void setupCassandra(InetSocketAddress cassandraEndpoint, String localDataCenter) { + CqlSession session = CqlSession.builder() + .withLocalDatacenter(localDataCenter) + .addContactPoint(cassandraEndpoint) + .build(); - String createKeyspace = "CREATE KEYSPACE IF NOT EXISTS baeldung " + - "WITH replication = {'class':'SimpleStrategy', 'replication_factor':1};"; + String createKeyspace = "CREATE KEYSPACE IF NOT EXISTS baeldung " + "WITH replication = {'class':'SimpleStrategy', 'replication_factor':1};"; String useKeyspace = "USE baeldung;"; - String createUserTable = "CREATE TABLE IF NOT EXISTS user_profile " + - "(id int, username text, user_age int, writetime bigint, PRIMARY KEY (id, user_age)) " + - "WITH CLUSTERING ORDER BY (user_age DESC);"; - String createAdminTable = "CREATE TABLE IF NOT EXISTS admin_profile " + - "(id int, username text, user_age int, role text, writetime bigint, department text, " + - "PRIMARY KEY (id, user_age)) " + - "WITH CLUSTERING ORDER BY (user_age DESC);"; - String createCounter = "CREATE TABLE IF NOT EXISTS counter " + - "(id text, count counter, PRIMARY KEY (id));"; + String createUserTable = "CREATE TABLE IF NOT EXISTS user_profile " + "(id int, username text, user_age int, writetime bigint, PRIMARY KEY (id, user_age)) " + "WITH CLUSTERING ORDER BY (user_age DESC);"; + String createAdminTable = "CREATE TABLE IF NOT EXISTS admin_profile " + "(id int, username text, user_age int, role text, writetime bigint, department text, " + "PRIMARY KEY (id, user_age)) " + "WITH CLUSTERING ORDER BY (user_age DESC);"; + String createCounter = "CREATE TABLE IF NOT EXISTS counter " + "(id text, count counter, PRIMARY KEY (id));"; session.execute(createKeyspace); session.execute(useKeyspace); @@ -75,22 +72,25 @@ public class MapperLiveTest { @Test void givenCounter_whenIncrement_thenIncremented() { Counter users = counterDao.getCounterById("users"); - long initialCount = users != null ? users.getCount(): 0; + long initialCount = users != null ? users.getCount() : 0; counterDao.incrementCounter("users", 1); users = counterDao.getCounterById("users"); - long finalCount = users != null ? users.getCount(): 0; + long finalCount = users != null ? users.getCount() : 0; Assertions.assertEquals(finalCount - initialCount, 1); } @Test void givenUser_whenGetUsersOlderThan_thenRetrieved() { - User user = new User(2, "JaneDoe", 20); + User user = new User(2, "JaneDoe", 32); + User userTwo = new User(3, "JohnDoe", 20); userDao.insertUser(user); - List retrievedUsers = userDao.getUsersOlderThanAge(30).all(); - Assertions.assertEquals(retrievedUsers.size(), 1); + userDao.insertUser(userTwo); + List retrievedUsers = userDao.getUsersOlderThanAge(30) + .all(); + Assertions.assertEquals(1, retrievedUsers.size()); } } \ No newline at end of file diff --git a/persistence-modules/spring-data-jpa-enterprise/pom.xml b/persistence-modules/spring-data-jpa-enterprise/pom.xml index 16294cd3cc..6bd89032fa 100644 --- a/persistence-modules/spring-data-jpa-enterprise/pom.xml +++ b/persistence-modules/spring-data-jpa-enterprise/pom.xml @@ -54,6 +54,11 @@ spring-security-test test + + org.postgresql + postgresql + runtime + org.testcontainers @@ -61,6 +66,12 @@ ${testcontainers.version} test + + org.testcontainers + junit-jupiter + ${testcontainers.version} + test + @@ -87,7 +98,7 @@ 1.3.1.Final - 1.17.3 + 1.19.1 \ No newline at end of file diff --git a/persistence-modules/spring-data-jpa-enterprise/src/main/resources/application.properties b/persistence-modules/spring-data-jpa-enterprise/src/main/resources/application.properties index 0ca1872207..875253c79e 100644 --- a/persistence-modules/spring-data-jpa-enterprise/src/main/resources/application.properties +++ b/persistence-modules/spring-data-jpa-enterprise/src/main/resources/application.properties @@ -12,4 +12,5 @@ spring.datasource.url=jdbc:h2:mem:baeldung spring.jpa.show-sql=false #hibernate.dialect=org.hibernate.dialect.H2Dialect +spring.jpa.hibernate.ddl-auto=create spring.jpa.properties.hibernate.id.new_generator_mappings=false \ No newline at end of file diff --git a/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/boot/daos/UserRepositoryCommon.java b/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/boot/daos/UserRepositoryCommon.java index e8841d921c..45be598153 100644 --- a/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/boot/daos/UserRepositoryCommon.java +++ b/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/boot/daos/UserRepositoryCommon.java @@ -1,8 +1,9 @@ package com.baeldung.boot.daos; -import org.junit.After; -import org.junit.Test; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; import org.springframework.dao.InvalidDataAccessApiUsageException; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; @@ -25,6 +26,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.junit.Assert.*; +@SpringBootTest public class UserRepositoryCommon { final String USER_EMAIL = "email@example.com"; @@ -274,7 +276,7 @@ public class UserRepositoryCommon { .getName()).isEqualTo(USER_NAME_ADAM); } - @Test(expected = PropertyReferenceException.class) + @Test public void givenUsersInDB_WhenFindAllSortWithFunction_ThenThrowException() { userRepository.save(new User(USER_NAME_ADAM, LocalDate.now(), USER_EMAIL, ACTIVE_STATUS)); userRepository.save(new User(USER_NAME_PETER, LocalDate.now(), USER_EMAIL2, ACTIVE_STATUS)); @@ -282,10 +284,7 @@ public class UserRepositoryCommon { userRepository.findAll(Sort.by(Sort.Direction.ASC, "name")); - List usersSortByNameLength = userRepository.findAll(Sort.by("LENGTH(name)")); - - assertThat(usersSortByNameLength.get(0) - .getName()).isEqualTo(USER_NAME_ADAM); + assertThrows(PropertyReferenceException.class, () -> userRepository.findAll(Sort.by("LENGTH(name)"))); } @Test @@ -556,7 +555,7 @@ public class UserRepositoryCommon { assertEquals(0, nativeQuery.getResultList().get(0)); } - @After + @AfterEach public void cleanUp() { userRepository.deleteAll(); } diff --git a/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/boot/daos/UserRepositoryIntegrationTest.java b/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/boot/daos/UserRepositoryIntegrationTest.java index 1b1d264574..c4d9d65746 100644 --- a/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/boot/daos/UserRepositoryIntegrationTest.java +++ b/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/boot/daos/UserRepositoryIntegrationTest.java @@ -2,11 +2,10 @@ package com.baeldung.boot.daos; import com.baeldung.boot.Application; import com.baeldung.boot.domain.User; -import org.junit.Test; -import org.junit.runner.RunWith; + +import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.annotation.DirtiesContext; -import org.springframework.test.context.junit4.SpringRunner; import org.springframework.transaction.annotation.Transactional; import java.time.LocalDate; @@ -16,7 +15,6 @@ import static org.assertj.core.api.Assertions.assertThat; /** * Created by adam. */ -@RunWith(SpringRunner.class) @SpringBootTest(classes = Application.class) @DirtiesContext public class UserRepositoryIntegrationTest extends UserRepositoryCommon { diff --git a/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/boot/daos/UserRepositoryTCAutoLiveTest.java b/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/boot/daos/UserRepositoryTCAutoLiveTest.java index 99eabc8271..056b3cea28 100644 --- a/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/boot/daos/UserRepositoryTCAutoLiveTest.java +++ b/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/boot/daos/UserRepositoryTCAutoLiveTest.java @@ -3,14 +3,15 @@ package com.baeldung.boot.daos; import com.baeldung.boot.Application; import com.baeldung.boot.domain.User; import com.baeldung.util.BaeldungPostgresqlContainer; -import org.junit.ClassRule; -import org.junit.Test; -import org.junit.runner.RunWith; + +import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.transaction.annotation.Transactional; import org.testcontainers.containers.PostgreSQLContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; import java.time.LocalDate; @@ -19,12 +20,12 @@ import static org.assertj.core.api.Assertions.assertThat; /** * Created by adam. */ -@RunWith(SpringRunner.class) +@Testcontainers @SpringBootTest(classes = Application.class) @ActiveProfiles({"tc", "tc-auto"}) public class UserRepositoryTCAutoLiveTest extends UserRepositoryCommon { - @ClassRule + @Container public static PostgreSQLContainer postgreSQLContainer = BaeldungPostgresqlContainer.getInstance(); @Test diff --git a/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/boot/daos/UserRepositoryTCJdbcLiveTest.java b/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/boot/daos/UserRepositoryTCJdbcLiveTest.java index c976590966..f4af7284bd 100644 --- a/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/boot/daos/UserRepositoryTCJdbcLiveTest.java +++ b/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/boot/daos/UserRepositoryTCJdbcLiveTest.java @@ -1,21 +1,21 @@ package com.baeldung.boot.daos; +import static org.assertj.core.api.Assertions.assertThat; + +import java.time.LocalDate; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.transaction.annotation.Transactional; + import com.baeldung.boot.Application; import com.baeldung.boot.daos.user.UserRepository; import com.baeldung.boot.domain.User; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.ActiveProfiles; -import org.springframework.test.context.junit4.SpringRunner; -import org.springframework.transaction.annotation.Transactional; -import java.time.LocalDate; - -import static org.assertj.core.api.Assertions.assertThat; - -@RunWith(SpringRunner.class) @ActiveProfiles("tc-jdbc") @SpringBootTest(classes = Application.class) public class UserRepositoryTCJdbcLiveTest { diff --git a/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/boot/daos/UserRepositoryTCLiveTest.java b/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/boot/daos/UserRepositoryTCLiveTest.java index be8843c166..33f4bbeeff 100644 --- a/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/boot/daos/UserRepositoryTCLiveTest.java +++ b/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/boot/daos/UserRepositoryTCLiveTest.java @@ -1,33 +1,29 @@ package com.baeldung.boot.daos; -import com.baeldung.boot.Application; -import com.baeldung.boot.domain.User; -import org.junit.ClassRule; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.util.TestPropertyValues; -import org.springframework.context.ApplicationContextInitializer; -import org.springframework.context.ConfigurableApplicationContext; -import org.springframework.test.context.ActiveProfiles; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringRunner; -import org.springframework.transaction.annotation.Transactional; -import org.testcontainers.containers.PostgreSQLContainer; - -import java.time.LocalDate; - import static org.assertj.core.api.Assertions.assertThat; -@RunWith(SpringRunner.class) -@SpringBootTest(classes = Application.class) +import java.time.LocalDate; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.DynamicPropertyRegistry; +import org.springframework.test.context.DynamicPropertySource; +import org.springframework.transaction.annotation.Transactional; +import org.testcontainers.containers.PostgreSQLContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; + +import com.baeldung.boot.domain.User; + +@Testcontainers +@SpringBootTest @ActiveProfiles("tc") -@ContextConfiguration(initializers = {UserRepositoryTCLiveTest.Initializer.class}) public class UserRepositoryTCLiveTest extends UserRepositoryCommon { - @ClassRule + @Container public static PostgreSQLContainer postgreSQLContainer = new PostgreSQLContainer("postgres:11.1") - .withDatabaseName("integration-tests-db") + .withDatabaseName("integration-tests-db") .withUsername("sa") .withPassword("sa"); @@ -45,14 +41,10 @@ public class UserRepositoryTCLiveTest extends UserRepositoryCommon { assertThat(updatedUsersSize).isEqualTo(2); } - static class Initializer - implements ApplicationContextInitializer { - public void initialize(ConfigurableApplicationContext configurableApplicationContext) { - TestPropertyValues.of( - "spring.datasource.url=" + postgreSQLContainer.getJdbcUrl(), - "spring.datasource.username=" + postgreSQLContainer.getUsername(), - "spring.datasource.password=" + postgreSQLContainer.getPassword() - ).applyTo(configurableApplicationContext.getEnvironment()); - } + @DynamicPropertySource + static void registerPgProperties(DynamicPropertyRegistry registry) { + registry.add("spring.datasource.url", postgreSQLContainer::getJdbcUrl); + registry.add("spring.datasource.username", postgreSQLContainer::getUsername); + registry.add("spring.datasource.password", postgreSQLContainer::getPassword); } } diff --git a/persistence-modules/spring-data-shardingsphere/src/test/java/com/baeldung/shardingsphere/OrderServiceManualTest.java b/persistence-modules/spring-data-shardingsphere/src/test/java/com/baeldung/shardingsphere/OrderServiceManualTest.java new file mode 100644 index 0000000000..895dd52afb --- /dev/null +++ b/persistence-modules/spring-data-shardingsphere/src/test/java/com/baeldung/shardingsphere/OrderServiceManualTest.java @@ -0,0 +1,90 @@ +package com.baeldung.shardingsphere; + +import org.assertj.core.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.test.context.DynamicPropertyRegistry; +import org.springframework.test.context.DynamicPropertySource; +import org.testcontainers.containers.MySQLContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; + +import java.math.BigDecimal; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.time.LocalDate; +import java.util.List; + + +/** + * This Manual test requires: Docker service running. + */ +@Testcontainers +@SpringBootTest +class OrderServiceManualTest { + + @Container + static MySQLContainer mySQLContainer1 = new MySQLContainer<>("mysql:8.0.23") + .withDatabaseName("ds0") + .withUsername("test") + .withPassword("test"); + + @Container + static MySQLContainer mySQLContainer2 = new MySQLContainer<>("mysql:8.0.23") + .withDatabaseName("ds1") + .withUsername("test") + .withPassword("test"); + + static { + mySQLContainer2.setPortBindings(List.of("13307:3306")); + mySQLContainer1.setPortBindings(List.of("13306:3306")); + } + @Autowired + private OrderService orderService; + + @Autowired + private OrderRepository orderRepository; + + @DynamicPropertySource + static void setProperties(DynamicPropertyRegistry registry) { + registry.add("spring.jpa.hibernate.ddl-auto", () -> "create-drop"); + } + + @Test + void shouldFindOrderInCorrectShard() { + // given + Order order1 = new Order(1L, 1L, BigDecimal.TEN, Status.PROCESSING, LocalDate.now(), "123 Main St"); + Order order2 = new Order(2L, 2L, BigDecimal.valueOf(12.5), Status.SHIPPED, LocalDate.now(), "456 Main St"); + + // when + Order savedOrder1 = orderService.createOrder(order1); + Order savedOrder2 = orderService.createOrder(order2); + + // then + // Assuming the sharding strategy is based on the order id, data for order1 should be present only in ds0 + // and data for order2 should be present only in ds1 + Assertions.assertThat(orderService.getOrder(savedOrder1.getOrderId())).isEqualTo(savedOrder1); + Assertions.assertThat(orderService.getOrder(savedOrder2.getOrderId())).isEqualTo(savedOrder2); + + // Verify that the orders are not present in the wrong shards. + // You would need to implement these methods in your OrderService. + // They should use a JdbcTemplate or EntityManager to execute SQL directly against each shard. + Assertions.assertThat(assertOrderInShard(savedOrder1, mySQLContainer2)).isTrue(); + Assertions.assertThat(assertOrderInShard(savedOrder2, mySQLContainer1)).isTrue(); + } + + private boolean assertOrderInShard(Order order, MySQLContainer container) { + try (Connection conn = DriverManager.getConnection(container.getJdbcUrl(), container.getUsername(), container.getPassword())) { + PreparedStatement stmt = conn.prepareStatement("SELECT * FROM `order` WHERE order_id = ?"); + stmt.setLong(1, order.getOrderId()); + ResultSet rs = stmt.executeQuery(); + return rs.next(); + } catch (SQLException ex) { + throw new RuntimeException("Error querying order in shard", ex); + } + } +} diff --git a/persistence-modules/spring-jdbc/README.md b/persistence-modules/spring-jdbc/README.md index 21d25915de..19f8537a4e 100644 --- a/persistence-modules/spring-jdbc/README.md +++ b/persistence-modules/spring-jdbc/README.md @@ -7,3 +7,4 @@ - [Obtaining Auto-generated Keys in Spring JDBC](https://www.baeldung.com/spring-jdbc-autogenerated-keys) - [Spring JDBC Batch Inserts](https://www.baeldung.com/spring-jdbc-batch-inserts) - [Fix EmptyResultDataAccessException When Using JdbcTemplate](https://www.baeldung.com/jdbctemplate-fix-emptyresultdataaccessexception) +- [How to replace deprecated jdbcTemplate.queryForObject and jdbcTemplate.query in spring boot 2.4.X and above](https://www.baeldung.com/spring-boot-replace-deprecated-jdbctemplate-queryforobject-query) diff --git a/pom.xml b/pom.xml index 060f158888..197074c455 100644 --- a/pom.xml +++ b/pom.xml @@ -723,9 +723,12 @@ spring-boot-rest spring-drools spring-cloud-modules/spring-cloud-azure + spring-cloud-modules/spring-cloud-circuit-breaker spring-cloud-modules/spring-cloud-contract spring-cloud-modules/spring-cloud-data-flow - spring-cloud-modules/spring-cloud-circuit-breaker + spring-cloud-modules/spring-cloud-netflix-feign + spring-cloud-modules/spring-cloud-stream-starters + spring-cloud-modules/spring-cloud-zuul-eureka-integration spring-exceptions spring-jenkins-pipeline spring-core @@ -892,6 +895,7 @@ spring-5 spring-5-webflux spring-5-webflux-2 + spring-6-rsocket spring-activiti spring-actuator spring-core-2 @@ -1000,6 +1004,11 @@ spring-drools spring-cloud-modules/spring-cloud-azure spring-cloud-modules/spring-cloud-circuit-breaker + spring-cloud-modules/spring-cloud-contract + spring-cloud-modules/spring-cloud-data-flow + spring-cloud-modules/spring-cloud-netflix-feign + spring-cloud-modules/spring-cloud-stream-starters + spring-cloud-modules/spring-cloud-zuul-eureka-integration spring-exceptions spring-jenkins-pipeline spring-core @@ -1212,7 +1221,6 @@ gradle-modules/gradle/maven-to-gradle persistence-modules/spring-data-neo4j spring-actuator - spring-cloud-modules/spring-cloud-contract diff --git a/spring-6-rsocket/README.md b/spring-6-rsocket/README.md new file mode 100644 index 0000000000..95c805b0bf --- /dev/null +++ b/spring-6-rsocket/README.md @@ -0,0 +1,7 @@ +## RSocket + +This module contains articles about RSocket in Spring Framework 6. + +### Relevant articles +- [RSocket Interface in Spring 6](https://www.baeldung.com/spring-rsocket) + diff --git a/spring-6-rsocket/pom.xml b/spring-6-rsocket/pom.xml new file mode 100644 index 0000000000..5d15a605ae --- /dev/null +++ b/spring-6-rsocket/pom.xml @@ -0,0 +1,74 @@ + + + 4.0.0 + com.bealdung + rsocket + 0.0.1-SNAPSHOT + rsocket + + + com.baeldung + parent-spring-6 + 0.0.1-SNAPSHOT + ../parent-spring-6 + + + + + + org.springframework.boot + spring-boot-starter-rsocket + + + + org.springframework.boot + spring-boot-starter-test + test + + + org.junit + junit-bom + ${junit-jupiter.version} + pom + import + + + ch.qos.logback + logback-classic + ${logback.version} + + + ch.qos.logback + logback-core + ${logback.version} + + + org.slf4j + slf4j-api + ${slf4j.version} + + + org.slf4j + jcl-over-slf4j + ${slf4j.version} + + + + + + org.springframework.boot + spring-boot-dependencies + ${spring-boot.version} + pom + import + + + + + 3.1.3 + 1.4.11 + 2.0.9 + + diff --git a/spring-6-rsocket/src/main/java/com/bealdung/rsocket/requester/MessageClient.java b/spring-6-rsocket/src/main/java/com/bealdung/rsocket/requester/MessageClient.java new file mode 100644 index 0000000000..8fed6bee9b --- /dev/null +++ b/spring-6-rsocket/src/main/java/com/bealdung/rsocket/requester/MessageClient.java @@ -0,0 +1,21 @@ +package com.bealdung.rsocket.requester; + +import org.springframework.messaging.rsocket.service.RSocketExchange; + +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +public interface MessageClient { + + @RSocketExchange("MyDestination") + Mono sendMessage(Mono input); + + @RSocketExchange("Counter") + Flux Counter(); + + @RSocketExchange("Warning") + Mono Warning(Mono warning); + + @RSocketExchange("channel") + Flux channel(Flux input); +} diff --git a/spring-6-rsocket/src/main/java/com/bealdung/rsocket/responder/MessageController.java b/spring-6-rsocket/src/main/java/com/bealdung/rsocket/responder/MessageController.java new file mode 100644 index 0000000000..a2cfcc69ca --- /dev/null +++ b/spring-6-rsocket/src/main/java/com/bealdung/rsocket/responder/MessageController.java @@ -0,0 +1,45 @@ +package com.bealdung.rsocket.responder; + +import org.springframework.messaging.handler.annotation.MessageMapping; +import org.springframework.stereotype.Controller; + +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +@Controller +public class MessageController { + + @MessageMapping("MyDestination") + public Mono message(Mono input) { + return input.doOnNext(msg -> System.out.println("Request is:" + msg + ",Request!")) + .map(msg -> msg + ",Response!"); + } + + @MessageMapping("Counter") + public Flux Counter() { + return Flux.range(1, 10) + .map(i -> "Count is: " + i); + } + + @MessageMapping("Warning") + public Mono Warning(Mono error) { + error.doOnNext(e -> System.out.println("warning is :" + e)) + .subscribe(); + return Mono.empty(); + } + + @MessageMapping("channel") + public Flux channel(Flux input) { + return input.doOnNext(i -> { + System.out.println("Received message is : " + i); + }) + .map(m -> m.toUpperCase()) + .doOnNext(r -> { + System.out.println("RESPONSE IS :" + r); + }); + } + +} + + + diff --git a/spring-6-rsocket/src/main/java/com/bealdung/rsocket/responder/RSocketApplication.java b/spring-6-rsocket/src/main/java/com/bealdung/rsocket/responder/RSocketApplication.java new file mode 100644 index 0000000000..9e763007fe --- /dev/null +++ b/spring-6-rsocket/src/main/java/com/bealdung/rsocket/responder/RSocketApplication.java @@ -0,0 +1,73 @@ +package com.bealdung.rsocket.responder; + +import org.springframework.boot.ApplicationRunner; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; +import org.springframework.messaging.rsocket.RSocketRequester; +import org.springframework.messaging.rsocket.service.RSocketServiceProxyFactory; + +import com.bealdung.rsocket.requester.MessageClient; + +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +@SpringBootApplication +public class RSocketApplication { + public static void main(String[] args) { + SpringApplication.run(RSocketApplication.class, args); + } + + @Bean + public RSocketServiceProxyFactory getRSocketServiceProxyFactory(RSocketRequester.Builder requestBuilder) { + RSocketRequester requester = requestBuilder.tcp("localhost", 7000); + return RSocketServiceProxyFactory.builder(requester) + .build(); + } + + @Bean + public MessageClient getClient(RSocketServiceProxyFactory factory) { + return factory.createClient(MessageClient.class); + } + + @Bean + public ApplicationRunner runRequestResponseModel(MessageClient client) { + return args -> { + client.sendMessage(Mono.just("Request-Response test ")) + .doOnNext(message -> { + System.out.println("Response is :" + message); + }) + .subscribe(); + }; + } + + @Bean + public ApplicationRunner runStreamModel(MessageClient client) { + return args -> { + client.Counter() + .doOnNext(t -> { + System.out.println("message is :" + t); + }) + .subscribe(); + }; + } + + @Bean + public ApplicationRunner runFireAndForget(MessageClient client) { + return args -> { + client.Warning(Mono.just("Important Warning")) + .subscribe(); + }; + } + + @Bean + public ApplicationRunner runChannel(MessageClient client) { + return args -> { + client.channel(Flux.just("a", "b", "c", "d", "e")) + .doOnNext(i -> { + System.out.println(i); + }) + .subscribe(); + }; + } +} \ No newline at end of file diff --git a/spring-6-rsocket/src/main/resources/application.properties b/spring-6-rsocket/src/main/resources/application.properties new file mode 100644 index 0000000000..cab786cd30 --- /dev/null +++ b/spring-6-rsocket/src/main/resources/application.properties @@ -0,0 +1 @@ +spring.rsocket.server.port=7000 \ No newline at end of file diff --git a/spring-6-rsocket/src/test/java/com/bealdung/rsocket/RSocketRequestResponseIntegrationTest.java b/spring-6-rsocket/src/test/java/com/bealdung/rsocket/RSocketRequestResponseIntegrationTest.java new file mode 100644 index 0000000000..4b85c4c6fc --- /dev/null +++ b/spring-6-rsocket/src/test/java/com/bealdung/rsocket/RSocketRequestResponseIntegrationTest.java @@ -0,0 +1,35 @@ +package com.bealdung.rsocket; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.messaging.rsocket.RSocketRequester; +import org.springframework.messaging.rsocket.service.RSocketServiceProxyFactory; + +import com.bealdung.rsocket.requester.MessageClient; +import com.bealdung.rsocket.responder.RSocketApplication; + +import reactor.core.publisher.Mono; + +@SpringBootTest(classes = RSocketApplication.class) +public class RSocketRequestResponseIntegrationTest { + + MessageClient client; + + public RSocketRequestResponseIntegrationTest() { + RSocketRequester.Builder requesterBuilder = RSocketRequester.builder(); + RSocketRequester requester = requesterBuilder.tcp("localhost", 7000); + RSocketServiceProxyFactory factory = RSocketServiceProxyFactory.builder(requester) + .build(); + client = factory.createClient(MessageClient.class); + } + + @Test + public void whenSendingStream_thenReceiveTheSameStream() { + String message = "test message"; + assertEquals(message, client.sendMessage(Mono.just(message)) + .block()); + } + +} diff --git a/spring-boot-modules/pom.xml b/spring-boot-modules/pom.xml index 1c4b2bb38f..2b4a94a7a5 100644 --- a/spring-boot-modules/pom.xml +++ b/spring-boot-modules/pom.xml @@ -104,6 +104,7 @@ spring-boot-springdoc-2 spring-boot-documentation spring-boot-3-url-matching + spring-boot-graalvm-docker diff --git a/spring-boot-modules/spring-boot-3-testcontainers/src/test/java/com/baeldung/testcontainers/DynamicPropertiesLiveTest.java b/spring-boot-modules/spring-boot-3-testcontainers/src/test/java/com/baeldung/testcontainers/DynamicPropertiesLiveTest.java index e8818c1019..2633f227d4 100644 --- a/spring-boot-modules/spring-boot-3-testcontainers/src/test/java/com/baeldung/testcontainers/DynamicPropertiesLiveTest.java +++ b/spring-boot-modules/spring-boot-3-testcontainers/src/test/java/com/baeldung/testcontainers/DynamicPropertiesLiveTest.java @@ -25,6 +25,8 @@ import com.baeldung.testcontainers.support.MiddleEarthCharactersRepository; @Testcontainers @SpringBootTest(webEnvironment = DEFINED_PORT) @DirtiesContext(classMode = AFTER_CLASS) +// Testcontainers require a valid docker installation. +// When running the tests, ensure you have a valid Docker environment class DynamicPropertiesLiveTest { @Container static MongoDBContainer mongoDBContainer = new MongoDBContainer(DockerImageName.parse("mongo:4.0.10")); diff --git a/spring-boot-modules/spring-boot-3-testcontainers/src/test/java/com/baeldung/testcontainers/LocalDevApplication.java b/spring-boot-modules/spring-boot-3-testcontainers/src/test/java/com/baeldung/testcontainers/LocalDevApplication.java index a94c0f772a..1b6fe32c97 100644 --- a/spring-boot-modules/spring-boot-3-testcontainers/src/test/java/com/baeldung/testcontainers/LocalDevApplication.java +++ b/spring-boot-modules/spring-boot-3-testcontainers/src/test/java/com/baeldung/testcontainers/LocalDevApplication.java @@ -8,6 +8,9 @@ import org.springframework.context.annotation.Bean; import org.testcontainers.containers.MongoDBContainer; import org.testcontainers.utility.DockerImageName; + +// Testcontainers require a valid docker installation. +// When running the app locally, ensure you have a valid Docker environment class LocalDevApplication { public static void main(String[] args) { diff --git a/spring-boot-modules/spring-boot-3-testcontainers/src/test/java/com/baeldung/testcontainers/ServiceConnectionLiveTest.java b/spring-boot-modules/spring-boot-3-testcontainers/src/test/java/com/baeldung/testcontainers/ServiceConnectionLiveTest.java index 838ee127f6..51b69c44b3 100644 --- a/spring-boot-modules/spring-boot-3-testcontainers/src/test/java/com/baeldung/testcontainers/ServiceConnectionLiveTest.java +++ b/spring-boot-modules/spring-boot-3-testcontainers/src/test/java/com/baeldung/testcontainers/ServiceConnectionLiveTest.java @@ -24,6 +24,8 @@ import com.baeldung.testcontainers.support.MiddleEarthCharactersRepository; @Testcontainers @SpringBootTest(webEnvironment = DEFINED_PORT) @DirtiesContext(classMode = AFTER_CLASS) +// Testcontainers require a valid docker installation. +// When running the tests, ensure you have a valid Docker environment class ServiceConnectionLiveTest { @Container diff --git a/spring-boot-modules/spring-boot-3/pom.xml b/spring-boot-modules/spring-boot-3/pom.xml index 7e61ca18af..bb8c5dd53c 100644 --- a/spring-boot-modules/spring-boot-3/pom.xml +++ b/spring-boot-modules/spring-boot-3/pom.xml @@ -41,6 +41,31 @@ mockserver-netty ${mockserver.version} + + org.junit.jupiter + junit-jupiter + ${jupiter.version} + + + org.junit.jupiter + junit-jupiter-api + ${jupiter.version} + + + org.junit.jupiter + junit-jupiter-engine + ${jupiter.version} + + + org.junit.jupiter + junit-jupiter-params + ${jupiter.version} + + + org.junit.platform + junit-platform-commons + 1.10.0 + org.mock-server mockserver-client-java @@ -183,12 +208,50 @@ 19 1.5.2.Final - 2.0.0 + 2.2.0 3.0.0-M7 com.baeldung.sample.TodoApplication 5.14.0 - 3.1.0 + 3.2.0-SNAPSHOT 0.2.0 + 5.10.0 + + + spring-milestones + Spring Milestones + https://repo.spring.io/milestone + + false + + + + spring-snapshots + Spring Snapshots + https://repo.spring.io/snapshot + + false + + + + + + spring-milestones + Spring Milestones + https://repo.spring.io/milestone + + false + + + + spring-snapshots + Spring Snapshots + https://repo.spring.io/snapshot + + false + + + + \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/restclient/Article.java b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/restclient/Article.java new file mode 100644 index 0000000000..892cf3b5ae --- /dev/null +++ b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/restclient/Article.java @@ -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); + } +} diff --git a/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/restclient/ArticleController.java b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/restclient/ArticleController.java new file mode 100644 index 0000000000..5e1dff6fd7 --- /dev/null +++ b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/restclient/ArticleController.java @@ -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 database = new HashMap<>(); + + @GetMapping + public ResponseEntity> getArticles() { + Collection
values = database.values(); + if (values.isEmpty()) { + return ResponseEntity.noContent().build(); + } + return ResponseEntity.ok(values); + } + + @GetMapping("/{id}") + public ResponseEntity
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(); + } +} diff --git a/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/restclient/ArticleNotFoundException.java b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/restclient/ArticleNotFoundException.java new file mode 100644 index 0000000000..cdd13b8330 --- /dev/null +++ b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/restclient/ArticleNotFoundException.java @@ -0,0 +1,6 @@ +package com.baeldung.restclient; + +public class ArticleNotFoundException extends RuntimeException { + public ArticleNotFoundException() { + } +} diff --git a/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/restclient/InvalidArticleResponseException.java b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/restclient/InvalidArticleResponseException.java new file mode 100644 index 0000000000..26ca75036e --- /dev/null +++ b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/restclient/InvalidArticleResponseException.java @@ -0,0 +1,6 @@ +package com.baeldung.restclient; + +public class InvalidArticleResponseException extends RuntimeException { + public InvalidArticleResponseException() { + } +} diff --git a/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/restclient/RestClientApplication.java b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/restclient/RestClientApplication.java new file mode 100644 index 0000000000..c411a8f74a --- /dev/null +++ b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/restclient/RestClientApplication.java @@ -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); + } + +} diff --git a/spring-boot-modules/spring-boot-3/src/test/java/com/baeldung/restclient/RestClientIntegrationTest.java b/spring-boot-modules/spring-boot-3/src/test/java/com/baeldung/restclient/RestClientIntegrationTest.java new file mode 100644 index 0000000000..1a615faf4e --- /dev/null +++ b/spring-boot-modules/spring-boot-3/src/test/java/com/baeldung/restclient/RestClientIntegrationTest.java @@ -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
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
articles = getArticlesWithExchange(); + + assertThat(articles).isEqualTo(List.of(article)); + } + + private List
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
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 entity = restClient.get() + .uri(uriBase + "/articles") + .accept(MediaType.APPLICATION_JSON) + .retrieve() + .toBodilessEntity(); + + assertThat(entity.getStatusCode()).isEqualTo(HttpStatusCode.valueOf(204)); + } +} diff --git a/spring-boot-modules/spring-boot-actuator/pom.xml b/spring-boot-modules/spring-boot-actuator/pom.xml index 1ccf436bbf..7f630fa96e 100644 --- a/spring-boot-modules/spring-boot-actuator/pom.xml +++ b/spring-boot-modules/spring-boot-actuator/pom.xml @@ -9,9 +9,10 @@ This is simple boot application for Spring boot actuator test - com.baeldung.spring-boot-modules - spring-boot-modules - 1.0.0-SNAPSHOT + com.baeldung + parent-boot-3 + 0.0.1-SNAPSHOT + ../../parent-boot-3 @@ -39,16 +40,6 @@ com.h2database h2 - - javax.servlet - javax.servlet-api - provided - - - javax.servlet - jstl - runtime - org.springframework.boot spring-boot-starter-test diff --git a/spring-boot-modules/spring-boot-actuator/src/main/java/com/baeldung/endpoints/enabling/SecurityConfiguration.java b/spring-boot-modules/spring-boot-actuator/src/main/java/com/baeldung/endpoints/enabling/SecurityConfiguration.java index 894c24693e..20ee834d52 100644 --- a/spring-boot-modules/spring-boot-actuator/src/main/java/com/baeldung/endpoints/enabling/SecurityConfiguration.java +++ b/spring-boot-modules/spring-boot-actuator/src/main/java/com/baeldung/endpoints/enabling/SecurityConfiguration.java @@ -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); } } diff --git a/spring-boot-modules/spring-boot-actuator/src/main/java/com/baeldung/endpoints/info/User.java b/spring-boot-modules/spring-boot-actuator/src/main/java/com/baeldung/endpoints/info/User.java index db4e69127a..88f39d8ccc 100644 --- a/spring-boot-modules/spring-boot-actuator/src/main/java/com/baeldung/endpoints/info/User.java +++ b/spring-boot-modules/spring-boot-actuator/src/main/java/com/baeldung/endpoints/info/User.java @@ -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") diff --git a/spring-boot-modules/spring-boot-actuator/src/main/java/com/baeldung/metrics/MetricsApplication.java b/spring-boot-modules/spring-boot-actuator/src/main/java/com/baeldung/metrics/MetricsApplication.java index 729b3c0b96..ee87412986 100644 --- a/spring-boot-modules/spring-boot-actuator/src/main/java/com/baeldung/metrics/MetricsApplication.java +++ b/spring-boot-modules/spring-boot-actuator/src/main/java/com/baeldung/metrics/MetricsApplication.java @@ -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") diff --git a/spring-boot-modules/spring-boot-actuator/src/main/java/com/baeldung/metrics/filter/MetricFilter.java b/spring-boot-modules/spring-boot-actuator/src/main/java/com/baeldung/metrics/filter/MetricFilter.java index 0f7579f060..a7aaddf0fb 100644 --- a/spring-boot-modules/spring-boot-actuator/src/main/java/com/baeldung/metrics/filter/MetricFilter.java +++ b/spring-boot-modules/spring-boot-actuator/src/main/java/com/baeldung/metrics/filter/MetricFilter.java @@ -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 { diff --git a/spring-boot-modules/spring-boot-actuator/src/test/java/com/baeldung/endpoints/enabling/EndpointEnablingIntegrationTest.java b/spring-boot-modules/spring-boot-actuator/src/test/java/com/baeldung/endpoints/enabling/EndpointEnablingIntegrationTest.java index 8274619517..079195714b 100644 --- a/spring-boot-modules/spring-boot-actuator/src/test/java/com/baeldung/endpoints/enabling/EndpointEnablingIntegrationTest.java +++ b/spring-boot-modules/spring-boot-actuator/src/test/java/com/baeldung/endpoints/enabling/EndpointEnablingIntegrationTest.java @@ -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()) diff --git a/spring-boot-modules/spring-boot-bootstrap/pom.xml b/spring-boot-modules/spring-boot-bootstrap/pom.xml index 4ceae26f60..da16f79a2a 100644 --- a/spring-boot-modules/spring-boot-bootstrap/pom.xml +++ b/spring-boot-modules/spring-boot-bootstrap/pom.xml @@ -9,9 +9,10 @@ Demo project for Spring Boot - com.baeldung.spring-boot-modules - spring-boot-modules - 1.0.0-SNAPSHOT + com.baeldung + parent-boot-3 + 0.0.1-SNAPSHOT + ../../parent-boot-3 @@ -47,13 +48,12 @@ io.rest-assured rest-assured - ${rest-assured.version} test - javax.servlet - javax.servlet-api - ${servlet.version} + org.springframework.boot + spring-boot-starter-cloud-connectors + ${spring-boot-cloud-connectors.version} @@ -332,6 +332,7 @@ 4.0.0 Greenwich.RELEASE 1.0.0.RELEASE + 2.2.13.RELEASE \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-bootstrap/src/main/java/com/baeldung/config/SecurityConfig.java b/spring-boot-modules/spring-boot-bootstrap/src/main/java/com/baeldung/config/SecurityConfig.java index ecb21cdf4b..c876e1c3d4 100644 --- a/spring-boot-modules/spring-boot-bootstrap/src/main/java/com/baeldung/config/SecurityConfig.java +++ b/spring-boot-modules/spring-boot-bootstrap/src/main/java/com/baeldung/config/SecurityConfig.java @@ -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(); } } diff --git a/spring-boot-modules/spring-boot-bootstrap/src/main/java/com/baeldung/persistence/model/Book.java b/spring-boot-modules/spring-boot-bootstrap/src/main/java/com/baeldung/persistence/model/Book.java index 6be27d4cf0..d599c64567 100644 --- a/spring-boot-modules/spring-boot-bootstrap/src/main/java/com/baeldung/persistence/model/Book.java +++ b/spring-boot-modules/spring-boot-bootstrap/src/main/java/com/baeldung/persistence/model/Book.java @@ -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 { diff --git a/spring-boot-modules/spring-boot-documentation/pom.xml b/spring-boot-modules/spring-boot-documentation/pom.xml index f0806b3c75..3ac2799258 100644 --- a/spring-boot-modules/spring-boot-documentation/pom.xml +++ b/spring-boot-modules/spring-boot-documentation/pom.xml @@ -93,8 +93,8 @@ 2.2.11 - 0.12.1 - 0.8.0 + 0.14.0 + 0.14.0 1.18.3 diff --git a/spring-boot-modules/spring-boot-documentation/src/test/resources/asyncapi.json b/spring-boot-modules/spring-boot-documentation/src/test/resources/asyncapi.json index 0198733c1c..45be27f571 100644 --- a/spring-boot-modules/spring-boot-documentation/src/test/resources/asyncapi.json +++ b/spring-boot-modules/spring-boot-documentation/src/test/resources/asyncapi.json @@ -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" + } } } } diff --git a/spring-boot-modules/spring-boot-graalvm-docker/Dockerfile b/spring-boot-modules/spring-boot-graalvm-docker/Dockerfile new file mode 100644 index 0000000000..91a63074c1 --- /dev/null +++ b/spring-boot-modules/spring-boot-graalvm-docker/Dockerfile @@ -0,0 +1,3 @@ +FROM ubuntu:jammy +COPY target/springboot-graalvm-docker /springboot-graalvm-docker +CMD ["/springboot-graalvm-docker"] diff --git a/spring-boot-modules/spring-boot-graalvm-docker/README.md b/spring-boot-modules/spring-boot-graalvm-docker/README.md new file mode 100644 index 0000000000..10a764053e --- /dev/null +++ b/spring-boot-modules/spring-boot-graalvm-docker/README.md @@ -0,0 +1,2 @@ +## Relevant Articles +- [Create a GraalVM Docker Image](https://www.baeldung.com/java-graalvm-docker-image) diff --git a/spring-boot-modules/spring-boot-graalvm-docker/pom.xml b/spring-boot-modules/spring-boot-graalvm-docker/pom.xml new file mode 100644 index 0000000000..a3a1b148c2 --- /dev/null +++ b/spring-boot-modules/spring-boot-graalvm-docker/pom.xml @@ -0,0 +1,41 @@ + + + 4.0.0 + + + com.baeldung + parent-boot-3 + 0.0.1-SNAPSHOT + ../../parent-boot-3 + + + com.baeldung + spring-boot-graalvm-docker + 1.0.0 + spring-boot-graalvm-docker + Spring Boot GrralVM with Docker + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + org.graalvm.buildtools + native-maven-plugin + + + org.springframework.boot + spring-boot-maven-plugin + + + + diff --git a/spring-boot-modules/spring-boot-graalvm-docker/src/main/java/com/baeldung/graalvmdockerimage/GraalvmDockerImageApplication.java b/spring-boot-modules/spring-boot-graalvm-docker/src/main/java/com/baeldung/graalvmdockerimage/GraalvmDockerImageApplication.java new file mode 100644 index 0000000000..53e11aa749 --- /dev/null +++ b/spring-boot-modules/spring-boot-graalvm-docker/src/main/java/com/baeldung/graalvmdockerimage/GraalvmDockerImageApplication.java @@ -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"; + } +} diff --git a/spring-boot-modules/spring-boot-graalvm-docker/src/main/resources/application.properties b/spring-boot-modules/spring-boot-graalvm-docker/src/main/resources/application.properties new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/spring-boot-modules/spring-boot-graalvm-docker/src/main/resources/application.properties @@ -0,0 +1 @@ + diff --git a/spring-boot-modules/spring-boot-keycloak-2/pom.xml b/spring-boot-modules/spring-boot-keycloak-2/pom.xml index 39a7283328..7909e2e153 100644 --- a/spring-boot-modules/spring-boot-keycloak-2/pom.xml +++ b/spring-boot-modules/spring-boot-keycloak-2/pom.xml @@ -11,10 +11,9 @@ This is a simple application demonstrating integration between Keycloak and Spring Boot. - com.baeldung - parent-boot-2 - 0.0.1-SNAPSHOT - ../../parent-boot-2 + com.baeldung.spring-boot-modules + spring-boot-modules + 1.0.0-SNAPSHOT diff --git a/spring-boot-modules/spring-boot-keycloak-adapters/pom.xml b/spring-boot-modules/spring-boot-keycloak-adapters/pom.xml index 035c226b6d..34c0653fbd 100644 --- a/spring-boot-modules/spring-boot-keycloak-adapters/pom.xml +++ b/spring-boot-modules/spring-boot-keycloak-adapters/pom.xml @@ -11,10 +11,9 @@ This is a simple application demonstrating integration between Keycloak and Spring Boot. - com.baeldung - parent-boot-2 - 0.0.1-SNAPSHOT - ../../parent-boot-2 + com.baeldung.spring-boot-modules + spring-boot-modules + 1.0.0-SNAPSHOT diff --git a/spring-boot-modules/spring-boot-keycloak/pom.xml b/spring-boot-modules/spring-boot-keycloak/pom.xml index 64fb39d085..13339c9de1 100644 --- a/spring-boot-modules/spring-boot-keycloak/pom.xml +++ b/spring-boot-modules/spring-boot-keycloak/pom.xml @@ -11,10 +11,9 @@ This is a simple application demonstrating integration between Keycloak and Spring Boot. - com.baeldung - parent-boot-2 - 0.0.1-SNAPSHOT - ../../parent-boot-2 + com.baeldung.spring-boot-modules + spring-boot-modules + 1.0.0-SNAPSHOT @@ -103,7 +102,7 @@ - com.baeldung.keycloak.SpringBoot + com.baeldung.keycloak.SpringBootKeycloakApp 4.0.0 1.6.3 2.5.0 diff --git a/spring-boot-modules/spring-boot-keycloak/src/main/java/com/baeldung/keycloak/SpringBoot.java b/spring-boot-modules/spring-boot-keycloak/src/main/java/com/baeldung/keycloak/SpringBootKeycloakApp.java similarity index 80% rename from spring-boot-modules/spring-boot-keycloak/src/main/java/com/baeldung/keycloak/SpringBoot.java rename to spring-boot-modules/spring-boot-keycloak/src/main/java/com/baeldung/keycloak/SpringBootKeycloakApp.java index 90d7e774a4..a6f978fb3f 100644 --- a/spring-boot-modules/spring-boot-keycloak/src/main/java/com/baeldung/keycloak/SpringBoot.java +++ b/spring-boot-modules/spring-boot-keycloak/src/main/java/com/baeldung/keycloak/SpringBootKeycloakApp.java @@ -6,11 +6,10 @@ import org.springframework.context.annotation.Bean; import org.springframework.web.client.RestTemplate; @SpringBootApplication - -public class SpringBoot { +public class SpringBootKeycloakApp { public static void main(String[] args) { - SpringApplication.run(SpringBoot.class, args); + SpringApplication.run(SpringBootKeycloakApp.class, args); } @Bean diff --git a/spring-boot-modules/spring-boot-keycloak/src/test/java/com/baeldung/keycloak/KeycloakContextIntegrationTest.java b/spring-boot-modules/spring-boot-keycloak/src/test/java/com/baeldung/keycloak/KeycloakContextIntegrationTest.java index 336c8364aa..116516acfe 100644 --- a/spring-boot-modules/spring-boot-keycloak/src/test/java/com/baeldung/keycloak/KeycloakContextIntegrationTest.java +++ b/spring-boot-modules/spring-boot-keycloak/src/test/java/com/baeldung/keycloak/KeycloakContextIntegrationTest.java @@ -4,10 +4,9 @@ import org.junit.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit.jupiter.SpringExtension; -import com.baeldung.keycloak.SpringBoot; @ExtendWith(SpringExtension.class) -@SpringBootTest(classes = { SpringBoot.class }) +@SpringBootTest(classes = { SpringBootKeycloakApp.class }) public class KeycloakContextIntegrationTest { @Test diff --git a/spring-boot-modules/spring-boot-logging-log4j2/pom.xml b/spring-boot-modules/spring-boot-logging-log4j2/pom.xml index b429339417..31c0f4bd02 100644 --- a/spring-boot-modules/spring-boot-logging-log4j2/pom.xml +++ b/spring-boot-modules/spring-boot-logging-log4j2/pom.xml @@ -9,10 +9,9 @@ Demo project for Spring Boot Logging with Log4J2 - com.baeldung - parent-boot-2 - 0.0.1-SNAPSHOT - ../../parent-boot-2 + com.baeldung.spring-boot-modules + spring-boot-modules + 1.0.0-SNAPSHOT diff --git a/spring-boot-modules/spring-boot-mvc-4/pom.xml b/spring-boot-modules/spring-boot-mvc-4/pom.xml index dbbb03ad0e..0ae05a764b 100644 --- a/spring-boot-modules/spring-boot-mvc-4/pom.xml +++ b/spring-boot-modules/spring-boot-mvc-4/pom.xml @@ -9,9 +9,10 @@ Module For Spring Boot MVC Web - com.baeldung.spring-boot-modules - spring-boot-modules - 1.0.0-SNAPSHOT + com.baeldung + parent-boot-3 + 0.0.1-SNAPSHOT + ../../parent-boot-3 diff --git a/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/boot/controller/servlet/HelloWorldServlet.java b/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/boot/controller/servlet/HelloWorldServlet.java index 80c75aa8b5..cedc60bd92 100644 --- a/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/boot/controller/servlet/HelloWorldServlet.java +++ b/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/boot/controller/servlet/HelloWorldServlet.java @@ -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; diff --git a/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/boot/controller/servlet/SpringHelloWorldServlet.java b/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/boot/controller/servlet/SpringHelloWorldServlet.java index f276f94b7c..dbb8ea1b32 100644 --- a/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/boot/controller/servlet/SpringHelloWorldServlet.java +++ b/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/boot/controller/servlet/SpringHelloWorldServlet.java @@ -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; diff --git a/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/common/error/SpringHelloServletRegistrationBean.java b/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/common/error/SpringHelloServletRegistrationBean.java index 3f51a4ab69..b2d6f249a5 100644 --- a/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/common/error/SpringHelloServletRegistrationBean.java +++ b/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/common/error/SpringHelloServletRegistrationBean.java @@ -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 { diff --git a/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/servlets/configuration/WebAppInitializer.java b/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/servlets/configuration/WebAppInitializer.java index eadd40355a..7fd83fd59a 100644 --- a/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/servlets/configuration/WebAppInitializer.java +++ b/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/servlets/configuration/WebAppInitializer.java @@ -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 { diff --git a/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/servlets/servlets/GenericCustomServlet.java b/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/servlets/servlets/GenericCustomServlet.java index 49dd9404b7..ee70a142be 100644 --- a/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/servlets/servlets/GenericCustomServlet.java +++ b/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/servlets/servlets/GenericCustomServlet.java @@ -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; diff --git a/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/servlets/servlets/javaee/AnnotationServlet.java b/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/servlets/servlets/javaee/AnnotationServlet.java index 992976ca0e..62706be348 100644 --- a/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/servlets/servlets/javaee/AnnotationServlet.java +++ b/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/servlets/servlets/javaee/AnnotationServlet.java @@ -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" }) diff --git a/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/servlets/servlets/javaee/EEWebXmlServlet.java b/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/servlets/servlets/javaee/EEWebXmlServlet.java index c7b373064f..299a1b5d95 100644 --- a/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/servlets/servlets/javaee/EEWebXmlServlet.java +++ b/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/servlets/servlets/javaee/EEWebXmlServlet.java @@ -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; diff --git a/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/utils/UtilsApplication.java b/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/utils/UtilsApplication.java index ce3eae7ce0..eab5869cd5 100644 --- a/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/utils/UtilsApplication.java +++ b/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/utils/UtilsApplication.java @@ -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; diff --git a/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/utils/controller/UtilsController.java b/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/utils/controller/UtilsController.java index 8c7f2f932a..40acc1801f 100644 --- a/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/utils/controller/UtilsController.java +++ b/spring-boot-modules/spring-boot-mvc-4/src/main/java/com/baeldung/utils/controller/UtilsController.java @@ -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; diff --git a/spring-boot-modules/spring-boot-mvc-4/src/test/java/com/baeldung/utils/UtilsControllerIntegrationTest.java b/spring-boot-modules/spring-boot-mvc-4/src/test/java/com/baeldung/utils/UtilsControllerIntegrationTest.java index 080f660c40..f59d00f871 100644 --- a/spring-boot-modules/spring-boot-mvc-4/src/test/java/com/baeldung/utils/UtilsControllerIntegrationTest.java +++ b/spring-boot-modules/spring-boot-mvc-4/src/test/java/com/baeldung/utils/UtilsControllerIntegrationTest.java @@ -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()); } diff --git a/spring-boot-modules/spring-boot-mvc-birt/pom.xml b/spring-boot-modules/spring-boot-mvc-birt/pom.xml index 274932f06c..cc4b7f8283 100644 --- a/spring-boot-modules/spring-boot-mvc-birt/pom.xml +++ b/spring-boot-modules/spring-boot-mvc-birt/pom.xml @@ -10,10 +10,9 @@ Module For Spring Boot Integration with BIRT - com.baeldung - parent-boot-2 - 0.0.1-SNAPSHOT - ../../parent-boot-2 + com.baeldung.spring-boot-modules + spring-boot-modules + 1.0.0-SNAPSHOT diff --git a/spring-boot-modules/spring-boot-security-2/pom.xml b/spring-boot-modules/spring-boot-security-2/pom.xml new file mode 100644 index 0000000000..db094f33a6 --- /dev/null +++ b/spring-boot-modules/spring-boot-security-2/pom.xml @@ -0,0 +1,51 @@ + + + 4.0.0 + spring-boot-security-2 + spring-boot-security-1 + jar + Spring Boot Security Auto-Configuration + + + com.baeldung.spring-boot-modules + spring-boot-modules + 1.0.0-SNAPSHOT + + + + + org.springframework.boot + spring-boot-starter-security + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework.security + spring-security-test + test + + + org.springframework.boot + spring-boot-autoconfigure + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-security/src/main/java/com/baeldung/permitallanonymous/SecuredEcommerceApplication.java b/spring-boot-modules/spring-boot-security-2/src/main/java/com/baeldung/permitallanonymous/SecuredEcommerceApplication.java similarity index 100% rename from spring-boot-modules/spring-boot-security/src/main/java/com/baeldung/permitallanonymous/SecuredEcommerceApplication.java rename to spring-boot-modules/spring-boot-security-2/src/main/java/com/baeldung/permitallanonymous/SecuredEcommerceApplication.java diff --git a/spring-boot-modules/spring-boot-security/src/main/java/com/baeldung/permitallanonymous/controller/EcommerceController.java b/spring-boot-modules/spring-boot-security-2/src/main/java/com/baeldung/permitallanonymous/controller/EcommerceController.java similarity index 92% rename from spring-boot-modules/spring-boot-security/src/main/java/com/baeldung/permitallanonymous/controller/EcommerceController.java rename to spring-boot-modules/spring-boot-security-2/src/main/java/com/baeldung/permitallanonymous/controller/EcommerceController.java index 8f20baee10..d76075016a 100644 --- a/spring-boot-modules/spring-boot-security/src/main/java/com/baeldung/permitallanonymous/controller/EcommerceController.java +++ b/spring-boot-modules/spring-boot-security-2/src/main/java/com/baeldung/permitallanonymous/controller/EcommerceController.java @@ -13,7 +13,7 @@ public class EcommerceController { return "Show Cart"; } - //can we accessed by both anonymous and authenticated users + //can be accessed by both anonymous and authenticated users @GetMapping("/public/showProducts") public @ResponseBody String listProducts() { return "List Products"; diff --git a/spring-boot-modules/spring-boot-security/src/main/java/com/baeldung/permitallanonymous/filter/AuditInterceptor.java b/spring-boot-modules/spring-boot-security-2/src/main/java/com/baeldung/permitallanonymous/filter/AuditInterceptor.java similarity index 100% rename from spring-boot-modules/spring-boot-security/src/main/java/com/baeldung/permitallanonymous/filter/AuditInterceptor.java rename to spring-boot-modules/spring-boot-security-2/src/main/java/com/baeldung/permitallanonymous/filter/AuditInterceptor.java diff --git a/spring-boot-modules/spring-boot-security/src/main/java/com/baeldung/permitallanonymous/security/EcommerceWebSecurityConfig.java b/spring-boot-modules/spring-boot-security-2/src/main/java/com/baeldung/permitallanonymous/security/EcommerceWebSecurityConfig.java similarity index 100% rename from spring-boot-modules/spring-boot-security/src/main/java/com/baeldung/permitallanonymous/security/EcommerceWebSecurityConfig.java rename to spring-boot-modules/spring-boot-security-2/src/main/java/com/baeldung/permitallanonymous/security/EcommerceWebSecurityConfig.java diff --git a/spring-boot-modules/spring-boot-security/src/test/java/com/baeldung/permitallanonymous/SecureEcommerceApplicationUnitTest.java b/spring-boot-modules/spring-boot-security-2/src/test/java/com/baeldung/permitallanonymous/SecureEcommerceApplicationUnitTest.java similarity index 100% rename from spring-boot-modules/spring-boot-security/src/test/java/com/baeldung/permitallanonymous/SecureEcommerceApplicationUnitTest.java rename to spring-boot-modules/spring-boot-security-2/src/test/java/com/baeldung/permitallanonymous/SecureEcommerceApplicationUnitTest.java diff --git a/spring-boot-modules/spring-boot-security/README.md b/spring-boot-modules/spring-boot-security/README.md index d848f798ba..2fd9e77c92 100644 --- a/spring-boot-modules/spring-boot-security/README.md +++ b/spring-boot-modules/spring-boot-security/README.md @@ -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 diff --git a/spring-boot-modules/spring-boot-ssl-bundles/pom.xml b/spring-boot-modules/spring-boot-ssl-bundles/pom.xml index 056d0308c2..4802e9ec58 100644 --- a/spring-boot-modules/spring-boot-ssl-bundles/pom.xml +++ b/spring-boot-modules/spring-boot-ssl-bundles/pom.xml @@ -4,10 +4,10 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - org.springframework.boot - spring-boot-starter-parent - 3.1.3 - + com.baeldung + parent-boot-3 + 0.0.1-SNAPSHOT + ../../parent-boot-3 springbootsslbundles spring-boot-ssl-bundles diff --git a/spring-boot-modules/spring-boot-ssl-bundles/src/test/java/com/baeldung/springbootsslbundles/SSLBundleApplicationTests.java b/spring-boot-modules/spring-boot-ssl-bundles/src/test/java/com/baeldung/springbootsslbundles/SpringContextTest.java similarity index 85% rename from spring-boot-modules/spring-boot-ssl-bundles/src/test/java/com/baeldung/springbootsslbundles/SSLBundleApplicationTests.java rename to spring-boot-modules/spring-boot-ssl-bundles/src/test/java/com/baeldung/springbootsslbundles/SpringContextTest.java index 876641c8b5..6c9a2fb3f0 100644 --- a/spring-boot-modules/spring-boot-ssl-bundles/src/test/java/com/baeldung/springbootsslbundles/SSLBundleApplicationTests.java +++ b/spring-boot-modules/spring-boot-ssl-bundles/src/test/java/com/baeldung/springbootsslbundles/SpringContextTest.java @@ -4,7 +4,7 @@ import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; @SpringBootTest -class SSLBundleApplicationTests { +class SpringContextTest { @Test void contextLoads() { diff --git a/spring-boot-modules/spring-boot-swagger-keycloak/src/main/java/com/baeldung/swaggerkeycloak/GlobalSecurityConfig.java b/spring-boot-modules/spring-boot-swagger-keycloak/src/main/java/com/baeldung/swaggerkeycloak/GlobalSecurityConfig.java index 5c24368ce6..9a1bf547db 100644 --- a/spring-boot-modules/spring-boot-swagger-keycloak/src/main/java/com/baeldung/swaggerkeycloak/GlobalSecurityConfig.java +++ b/spring-boot-modules/spring-boot-swagger-keycloak/src/main/java/com/baeldung/swaggerkeycloak/GlobalSecurityConfig.java @@ -3,10 +3,11 @@ package com.baeldung.swaggerkeycloak; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpMethod; +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.core.session.SessionRegistryImpl; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy; @@ -24,16 +25,19 @@ public class GlobalSecurityConfig { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { - http.csrf() - .disable() - .authorizeRequests() - .requestMatchers(HttpMethod.OPTIONS) + + http.csrf(AbstractHttpConfigurer::disable) + .authorizeHttpRequests((requests) -> requests.requestMatchers(HttpMethod.OPTIONS) .permitAll() .requestMatchers("/api/**") .authenticated() .anyRequest() - .permitAll(); - http.oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt); + .permitAll()); + + http.oauth2ResourceServer((oauth2) -> oauth2 + .jwt(Customizer.withDefaults()) + ); + return http.build(); } diff --git a/spring-boot-modules/spring-boot-testing-2/README.md b/spring-boot-modules/spring-boot-testing-2/README.md index e6bc4c4590..1baf83bf34 100644 --- a/spring-boot-modules/spring-boot-testing-2/README.md +++ b/spring-boot-modules/spring-boot-testing-2/README.md @@ -13,4 +13,5 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring - [Spring Web Service Integration Tests with @WebServiceServerTest](https://www.baeldung.com/spring-webserviceservertest) - [Spring Boot – Testing Redis With Testcontainers](https://www.baeldung.com/spring-boot-redis-testcontainers) - [Spring Boot – Keycloak Integration Testing with Testcontainers](https://www.baeldung.com/spring-boot-keycloak-integration-testing) +- [Difference Between @Spy and @SpyBean](https://www.baeldung.com/spring-spy-vs-spybean) - More articles: [[<-- prev]](../spring-boot-testing) diff --git a/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/spytest/ExternalAlertService.java b/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/spytest/ExternalAlertService.java new file mode 100644 index 0000000000..fd321a0e68 --- /dev/null +++ b/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/spytest/ExternalAlertService.java @@ -0,0 +1,6 @@ +package com.baeldung.spytest; + +public interface ExternalAlertService { + public boolean alert(Order order); + +} diff --git a/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/spytest/NotificationService.java b/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/spytest/NotificationService.java new file mode 100644 index 0000000000..f0b2f92bee --- /dev/null +++ b/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/spytest/NotificationService.java @@ -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); + } + +} diff --git a/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/spytest/Order.java b/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/spytest/Order.java new file mode 100644 index 0000000000..23f5a05e9d --- /dev/null +++ b/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/spytest/Order.java @@ -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; + } +} + + diff --git a/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/spytest/OrderRepository.java b/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/spytest/OrderRepository.java new file mode 100644 index 0000000000..90fe5ba2b8 --- /dev/null +++ b/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/spytest/OrderRepository.java @@ -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 orders = new HashMap<>(); + + public Order save(Order order) { + UUID orderId = UUID.randomUUID(); + order.setId(orderId); + orders.put(UUID.randomUUID(), order); + return order; + } +} diff --git a/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/spytest/OrderService.java b/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/spytest/OrderService.java new file mode 100644 index 0000000000..47647b8721 --- /dev/null +++ b/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/spytest/OrderService.java @@ -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; + } +} diff --git a/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/spytest/SpyTestApplication.java b/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/spytest/SpyTestApplication.java new file mode 100644 index 0000000000..d8d81378df --- /dev/null +++ b/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/spytest/SpyTestApplication.java @@ -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); + } + +} diff --git a/spring-boot-modules/spring-boot-testing-2/src/test/java/com/baeldung/spytest/OrderServiceIntegrationTest.java b/spring-boot-modules/spring-boot-testing-2/src/test/java/com/baeldung/spytest/OrderServiceIntegrationTest.java new file mode 100644 index 0000000000..96c7b09dfc --- /dev/null +++ b/spring-boot-modules/spring-boot-testing-2/src/test/java/com/baeldung/spytest/OrderServiceIntegrationTest.java @@ -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)); + } + +} \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-testing-2/src/test/java/com/baeldung/spytest/OrderServiceUnitTest.java b/spring-boot-modules/spring-boot-testing-2/src/test/java/com/baeldung/spytest/OrderServiceUnitTest.java new file mode 100644 index 0000000000..21ae849bcf --- /dev/null +++ b/spring-boot-modules/spring-boot-testing-2/src/test/java/com/baeldung/spytest/OrderServiceUnitTest.java @@ -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)); + } + +} \ No newline at end of file diff --git a/spring-cloud-modules/pom.xml b/spring-cloud-modules/pom.xml index 9c926bbe61..b21b208414 100644 --- a/spring-cloud-modules/pom.xml +++ b/spring-cloud-modules/pom.xml @@ -27,11 +27,11 @@ spring-cloud-gateway spring-cloud-gateway-2 spring-cloud-stream - spring-cloud-stream-starters + spring-cloud-connectors-heroku spring-cloud-aws spring-cloud-consul - spring-cloud-zuul-eureka-integration + spring-cloud-kubernetes spring-cloud-open-service-broker @@ -46,7 +46,7 @@ spring-cloud-eureka-self-preservation spring-cloud-openfeign - spring-cloud-netflix-feign + spring-cloud-netflix-sidecar spring-cloud-sentinel spring-cloud-dapr diff --git a/spring-cloud-modules/spring-cloud-archaius/pom.xml b/spring-cloud-modules/spring-cloud-archaius/pom.xml index 4d7ca3943d..3e90c7390c 100644 --- a/spring-cloud-modules/spring-cloud-archaius/pom.xml +++ b/spring-cloud-modules/spring-cloud-archaius/pom.xml @@ -40,6 +40,7 @@ org.springframework.cloud spring-cloud-starter-netflix-archaius + ${spring-cloud-starter-netflix-archaius.version} org.springframework.boot @@ -54,7 +55,8 @@ - 2.0.3.RELEASE + 2.2.10.RELEASE + 2.2.10.RELEASE \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-dynamodb-config/pom.xml b/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-dynamodb-config/pom.xml index 6e25ace6a8..600fedc774 100644 --- a/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-dynamodb-config/pom.xml +++ b/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-dynamodb-config/pom.xml @@ -36,7 +36,7 @@ org.projectlombok lombok - provided + ${lombok.version} @@ -44,6 +44,7 @@ 1.11.407 5.0.3 0.7.6 + 1.18.26 \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-extra-configs/pom.xml b/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-extra-configs/pom.xml index f90570abc2..383ad6a780 100644 --- a/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-extra-configs/pom.xml +++ b/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-extra-configs/pom.xml @@ -37,6 +37,22 @@ + + + + org.apache.maven.plugins + maven-surefire-plugin + + + --add-opens java.base/java.lang=ALL-UNNAMED + --add-opens java.base/java.util=ALL-UNNAMED + --add-opens java.base/java.lang.reflect=ALL-UNNAMED + + + + + + 2.0.1.RELEASE diff --git a/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-jdbc-config/pom.xml b/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-jdbc-config/pom.xml index 7fb5747739..2871f129b5 100644 --- a/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-jdbc-config/pom.xml +++ b/spring-cloud-modules/spring-cloud-archaius/spring-cloud-archaius-jdbc-config/pom.xml @@ -27,6 +27,15 @@ h2 runtime + + org.projectlombok + lombok + ${lombok.version} + + + 1.18.26 + + \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/README.md b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/README.md new file mode 100644 index 0000000000..b76ae19f26 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/README.md @@ -0,0 +1,7 @@ +## Spring Cloud Gateway + +This module contains articles about Spring Cloud Gateway + +### Relevant Articles: + +- [Exploring the New Spring Cloud Gateway](http://www.baeldung.com/spring-cloud-gateway) \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/pom.xml b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/pom.xml new file mode 100644 index 0000000000..3d64edc338 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/pom.xml @@ -0,0 +1,54 @@ + + + 4.0.0 + gateway-2 + gateway-2 + jar + + + com.baeldung + parent-boot-2 + 0.0.1-SNAPSHOT + ../../../parent-boot-2 + + + + + + org.junit + junit-bom + ${junit-jupiter.version} + pom + import + + + org.springframework.cloud + spring-cloud-dependencies + ${spring-cloud-dependencies.version} + pom + import + + + org.springframework.boot + spring-boot-dependencies + ${spring-boot.version} + pom + import + + + + + + + org.springframework.cloud + spring-cloud-starter-gateway + + + + + 2021.0.3 + + + \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/custompredicates/CustomPredicatesApplication.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/custompredicates/CustomPredicatesApplication.java new file mode 100644 index 0000000000..e209b6cdf0 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/custompredicates/CustomPredicatesApplication.java @@ -0,0 +1,15 @@ +package com.baeldung.springcloudgateway.custompredicates; + +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; + +@SpringBootApplication +public class CustomPredicatesApplication { + + public static void main(String[] args) { + new SpringApplicationBuilder(CustomPredicatesApplication.class) + .profiles("customroutes") + .run(args); + } + +} \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/custompredicates/config/CustomPredicatesConfig.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/custompredicates/config/CustomPredicatesConfig.java new file mode 100644 index 0000000000..ea58eb7e46 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/custompredicates/config/CustomPredicatesConfig.java @@ -0,0 +1,43 @@ +package com.baeldung.springcloudgateway.custompredicates.config; + +import org.springframework.cloud.gateway.route.RouteLocator; +import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import com.baeldung.springcloudgateway.custompredicates.factories.GoldenCustomerRoutePredicateFactory; +import com.baeldung.springcloudgateway.custompredicates.factories.GoldenCustomerRoutePredicateFactory.Config; +import com.baeldung.springcloudgateway.custompredicates.service.GoldenCustomerService; + +@Configuration +public class CustomPredicatesConfig { + + + @Bean + public GoldenCustomerRoutePredicateFactory goldenCustomer(GoldenCustomerService goldenCustomerService) { + return new GoldenCustomerRoutePredicateFactory(goldenCustomerService); + } + + + //@Bean + public RouteLocator routes(RouteLocatorBuilder builder, GoldenCustomerRoutePredicateFactory gf ) { + + return builder.routes() + .route("dsl_golden_route", r -> + r.predicate(gf.apply(new Config(true, "customerId"))) + .and() + .path("/dsl_api/**") + .filters(f -> f.stripPrefix(1)) + .uri("https://httpbin.org") + ) + .route("dsl_common_route", r -> + r.predicate(gf.apply(new Config(false, "customerId"))) + .and() + .path("/dsl_api/**") + .filters(f -> f.stripPrefix(1)) + .uri("https://httpbin.org") + ) + .build(); + } + +} diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/custompredicates/factories/GoldenCustomerRoutePredicateFactory.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/custompredicates/factories/GoldenCustomerRoutePredicateFactory.java new file mode 100644 index 0000000000..cb5c3a0b50 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/custompredicates/factories/GoldenCustomerRoutePredicateFactory.java @@ -0,0 +1,102 @@ +/** + * + */ +package com.baeldung.springcloudgateway.custompredicates.factories; + +import java.util.Arrays; +import java.util.List; +import java.util.function.Predicate; + +import javax.validation.constraints.NotEmpty; + +import org.springframework.cloud.gateway.handler.predicate.AbstractRoutePredicateFactory; +import org.springframework.http.HttpCookie; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.server.ServerWebExchange; + +import com.baeldung.springcloudgateway.custompredicates.service.GoldenCustomerService; + +/** + * @author Philippe + * + */ +public class GoldenCustomerRoutePredicateFactory extends AbstractRoutePredicateFactory { + + private final GoldenCustomerService goldenCustomerService; + + public GoldenCustomerRoutePredicateFactory(GoldenCustomerService goldenCustomerService ) { + super(Config.class); + this.goldenCustomerService = goldenCustomerService; + } + + + @Override + public List shortcutFieldOrder() { + return Arrays.asList("isGolden","customerIdCookie"); + } + + + @Override + public Predicate apply(Config config) { + + return (ServerWebExchange t) -> { + List cookies = t.getRequest() + .getCookies() + .get(config.getCustomerIdCookie()); + + boolean isGolden; + if ( cookies == null || cookies.isEmpty()) { + isGolden = false; + } + else { + String customerId = cookies.get(0).getValue(); + isGolden = goldenCustomerService.isGoldenCustomer(customerId); + } + + return config.isGolden()?isGolden:!isGolden; + }; + } + + + @Validated + public static class Config { + boolean isGolden = true; + + @NotEmpty + String customerIdCookie = "customerId"; + + + public Config() {} + + public Config( boolean isGolden, String customerIdCookie) { + this.isGolden = isGolden; + this.customerIdCookie = customerIdCookie; + } + + public boolean isGolden() { + return isGolden; + } + + public void setGolden(boolean value) { + this.isGolden = value; + } + + /** + * @return the customerIdCookie + */ + public String getCustomerIdCookie() { + return customerIdCookie; + } + + /** + * @param customerIdCookie the customerIdCookie to set + */ + public void setCustomerIdCookie(String customerIdCookie) { + this.customerIdCookie = customerIdCookie; + } + + + + } + +} diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/custompredicates/service/GoldenCustomerService.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/custompredicates/service/GoldenCustomerService.java new file mode 100644 index 0000000000..82bf2e6ae9 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/custompredicates/service/GoldenCustomerService.java @@ -0,0 +1,26 @@ +/** + * + */ +package com.baeldung.springcloudgateway.custompredicates.service; + +import org.springframework.stereotype.Component; + +/** + * @author Philippe + * + */ +@Component +public class GoldenCustomerService { + + public boolean isGoldenCustomer(String customerId) { + + // TODO: Add some AI logic to check is this customer deserves a "golden" status ;^) + if ( "baeldung".equalsIgnoreCase(customerId)) { + return true; + } + else { + return false; + } + } + +} diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/introduction/IntroductionGatewayApplication.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/introduction/IntroductionGatewayApplication.java new file mode 100644 index 0000000000..d276597a6b --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/java/com/baeldung/springcloudgateway/introduction/IntroductionGatewayApplication.java @@ -0,0 +1,15 @@ +package com.baeldung.springcloudgateway.introduction; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.PropertySource; + +@SpringBootApplication +@PropertySource("classpath:introduction-application.properties") +public class IntroductionGatewayApplication { + + public static void main(String[] args) { + SpringApplication.run(IntroductionGatewayApplication.class, args); + } + +} \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/application-customroutes.yml b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/application-customroutes.yml new file mode 100644 index 0000000000..859aa60bda --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/application-customroutes.yml @@ -0,0 +1,26 @@ +spring: + cloud: + gateway: + routes: + - id: golden_route + uri: https://httpbin.org + predicates: + - Path=/api/** + - GoldenCustomer=true + filters: + - StripPrefix=1 + - AddRequestHeader=GoldenCustomer,true + - id: common_route + uri: https://httpbin.org + predicates: + - Path=/api/** + - name: GoldenCustomer + args: + golden: false + customerIdCookie: customerId + filters: + - StripPrefix=1 + - AddRequestHeader=GoldenCustomer,false + + + \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/application.yml b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/application.yml new file mode 100644 index 0000000000..a33bca2055 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/application.yml @@ -0,0 +1,4 @@ +logging: + level: + org.springframework.cloud.gateway: DEBUG + reactor.netty.http.client: DEBUG diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/introduction-application.properties b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/introduction-application.properties new file mode 100644 index 0000000000..d7a6c4e072 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/introduction-application.properties @@ -0,0 +1,7 @@ +spring.cloud.gateway.routes[0].id=baeldung_route +spring.cloud.gateway.routes[0].uri=http://www.baeldung.com +spring.cloud.gateway.routes[0].predicates[0]=Path=/baeldung + +management.endpoints.web.exposure.include=* + +server.port=80 diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/logback.xml b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/logback.xml new file mode 100644 index 0000000000..7d900d8ea8 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/main/resources/logback.xml @@ -0,0 +1,13 @@ + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/custompredicates/CustomPredicatesApplicationLiveTest.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/custompredicates/CustomPredicatesApplicationLiveTest.java new file mode 100644 index 0000000000..d9988ceb5e --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/custompredicates/CustomPredicatesApplicationLiveTest.java @@ -0,0 +1,67 @@ +package com.baeldung.springcloudgateway.custompredicates; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.*; + +import java.net.URI; + +import org.json.JSONException; +import org.json.JSONObject; +import org.json.JSONTokener; +import org.junit.Before; +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.context.SpringBootTest.WebEnvironment; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.boot.web.server.LocalServerPort; +import org.springframework.http.HttpStatus; +import org.springframework.http.RequestEntity; +import org.springframework.http.ResponseEntity; +import org.springframework.test.context.ActiveProfiles; + +/** + * This test requires + */ +@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) +@ActiveProfiles("customroutes") +public class CustomPredicatesApplicationLiveTest { + + @LocalServerPort + String serverPort; + + @Autowired + private TestRestTemplate restTemplate; + + @Test + void givenNormalCustomer_whenCallHeadersApi_thenResponseForNormalCustomer() throws JSONException { + + String url = "http://localhost:" + serverPort + "/api/headers"; + ResponseEntity response = restTemplate.getForEntity(url, String.class); + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); + + JSONObject json = new JSONObject(response.getBody()); + JSONObject headers = json.getJSONObject("headers"); + assertThat(headers.getString("Goldencustomer")).isEqualTo("false"); + + } + + @Test + void givenGoldenCustomer_whenCallHeadersApi_thenResponseForGoldenCustomer() throws JSONException { + + String url = "http://localhost:" + serverPort + "/api/headers"; + RequestEntity request = RequestEntity + .get(URI.create(url)) + .header("Cookie", "customerId=baeldung") + .build(); + + ResponseEntity response = restTemplate.exchange(request, String.class); + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); + + JSONObject json = new JSONObject(response.getBody()); + JSONObject headers = json.getJSONObject("headers"); + assertThat(headers.getString("Goldencustomer")).isEqualTo("true"); + + } + +} diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/introduction/LoggerListAppender.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/introduction/LoggerListAppender.java new file mode 100644 index 0000000000..33855cd15d --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/introduction/LoggerListAppender.java @@ -0,0 +1,25 @@ +package com.baeldung.springcloudgateway.introduction; + +import java.util.ArrayList; +import java.util.List; + +import ch.qos.logback.classic.spi.ILoggingEvent; +import ch.qos.logback.core.AppenderBase; + +public class LoggerListAppender extends AppenderBase { + + static private List events = new ArrayList<>(); + + @Override + protected void append(ILoggingEvent eventObject) { + events.add(eventObject); + } + + public static List getEvents() { + return events; + } + + public static void clearEventList() { + events.clear(); + } +} \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/introduction/SpringContextTest.java b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/introduction/SpringContextTest.java new file mode 100644 index 0000000000..1550265f22 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/java/com/baeldung/springcloudgateway/introduction/SpringContextTest.java @@ -0,0 +1,15 @@ +package com.baeldung.springcloudgateway.introduction; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +import com.baeldung.springcloudgateway.introduction.IntroductionGatewayApplication; + + +@SpringBootTest(classes = IntroductionGatewayApplication.class) +public class SpringContextTest { + + @Test + public void whenSpringContextIsBootstrapped_thenNoExceptions() { + } +} diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/resources/logback-test.xml b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/resources/logback-test.xml new file mode 100644 index 0000000000..90c8f570aa --- /dev/null +++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway-2/src/test/resources/logback-test.xml @@ -0,0 +1,17 @@ + + + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + + \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-bootstrap/pom.xml b/spring-cloud-modules/spring-cloud-bootstrap/pom.xml index e7fe7e7485..f4d4073ef1 100644 --- a/spring-cloud-modules/spring-cloud-bootstrap/pom.xml +++ b/spring-cloud-modules/spring-cloud-bootstrap/pom.xml @@ -18,6 +18,7 @@ config discovery gateway + gateway-2 svc-book svc-rating customer-service diff --git a/spring-cloud-modules/spring-cloud-contract/pom.xml b/spring-cloud-modules/spring-cloud-contract/pom.xml index 7a9c8c32cd..f2d0d1b5b0 100644 --- a/spring-cloud-modules/spring-cloud-contract/pom.xml +++ b/spring-cloud-modules/spring-cloud-contract/pom.xml @@ -41,28 +41,35 @@ org.springframework.cloud spring-cloud-contract-wiremock - ${spring-cloud.version} + ${spring-cloud-contract.version} test org.springframework.cloud spring-cloud-contract-stub-runner - ${spring-cloud.version} + ${spring-cloud-contract.version} test org.springframework.cloud spring-cloud-starter-contract-verifier - ${spring-cloud.version} + ${spring-cloud-contract.version} test + + org.codehaus.groovy + groovy + ${groovy.version} + 4.0.3 + 4.0.4 2.1.4.RELEASE 2.17.1 + 2.5.6 \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-contract/spring-cloud-contract-consumer/pom.xml b/spring-cloud-modules/spring-cloud-contract/spring-cloud-contract-consumer/pom.xml index 680e2e1795..a8c3337de5 100644 --- a/spring-cloud-modules/spring-cloud-contract/spring-cloud-contract-consumer/pom.xml +++ b/spring-cloud-modules/spring-cloud-contract/spring-cloud-contract-consumer/pom.xml @@ -16,6 +16,15 @@ + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-data-rest + + org.springframework.cloud spring-cloud-contract-wiremock @@ -26,20 +35,13 @@ spring-cloud-contract-stub-runner test - - org.springframework.boot - spring-boot-starter-web - - - org.springframework.boot - spring-boot-starter-data-rest - com.baeldung.spring.cloud spring-cloud-contract-producer ${project.parent.version} test + io.rest-assured rest-assured @@ -50,6 +52,12 @@ + + + org.codehaus.groovy + groovy + + \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-contract/spring-cloud-contract-producer/pom.xml b/spring-cloud-modules/spring-cloud-contract/spring-cloud-contract-producer/pom.xml index 35dd9596f7..eb80f8d3dd 100644 --- a/spring-cloud-modules/spring-cloud-contract/spring-cloud-contract-producer/pom.xml +++ b/spring-cloud-modules/spring-cloud-contract/spring-cloud-contract-producer/pom.xml @@ -16,19 +16,17 @@ - - org.springframework.cloud - spring-cloud-starter-contract-verifier - test - + org.springframework.boot spring-boot-starter-web + org.springframework.boot spring-boot-starter-data-rest + io.rest-assured rest-assured @@ -39,6 +37,18 @@ + + + org.springframework.cloud + spring-cloud-starter-contract-verifier + test + + + + org.codehaus.groovy + groovy + + @@ -46,7 +56,7 @@ org.springframework.cloud spring-cloud-contract-maven-plugin - 2.1.1.RELEASE + ${spring-cloud-contract.version} true com.baeldung.spring.cloud.springcloudcontractproducer.BaseTestClass diff --git a/spring-cloud-modules/spring-cloud-data-flow/spring-cloud-data-flow-stream-processing/data-flow-server/src/test/java/com/baeldung/spring/cloud/DataFlowServerApplicationIntegrationTest.java b/spring-cloud-modules/spring-cloud-data-flow/spring-cloud-data-flow-stream-processing/data-flow-server/src/test/java/com/baeldung/spring/cloud/DataFlowServerApplicationIntegrationTest.java index 68f0db60eb..49eb255303 100644 --- a/spring-cloud-modules/spring-cloud-data-flow/spring-cloud-data-flow-stream-processing/data-flow-server/src/test/java/com/baeldung/spring/cloud/DataFlowServerApplicationIntegrationTest.java +++ b/spring-cloud-modules/spring-cloud-data-flow/spring-cloud-data-flow-stream-processing/data-flow-server/src/test/java/com/baeldung/spring/cloud/DataFlowServerApplicationIntegrationTest.java @@ -9,6 +9,7 @@ import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.connection.RedisConnection; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.serializer.RedisSerializer; +import org.springframework.session.data.redis.config.ConfigureRedisAction; import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession; import org.springframework.test.context.junit4.SpringRunner; @@ -39,5 +40,10 @@ public class DataFlowServerApplicationIntegrationTest { return factory; } + + @Bean + public static ConfigureRedisAction configureRedisAction() { + return ConfigureRedisAction.NO_OP; + } } } diff --git a/spring-cloud-modules/spring-cloud-netflix-feign/pom.xml b/spring-cloud-modules/spring-cloud-netflix-feign/pom.xml index f519b6316b..92d66c03df 100644 --- a/spring-cloud-modules/spring-cloud-netflix-feign/pom.xml +++ b/spring-cloud-modules/spring-cloud-netflix-feign/pom.xml @@ -58,6 +58,20 @@ + + + + org.apache.maven.plugins + maven-surefire-plugin + + + --add-opens java.base/java.lang=ALL-UNNAMED + + + + + + Camden.SR7 8.18.0 diff --git a/spring-cloud-modules/spring-cloud-stream-starters/pom.xml b/spring-cloud-modules/spring-cloud-stream-starters/pom.xml index eee5b27396..95176d1e5c 100644 --- a/spring-cloud-modules/spring-cloud-stream-starters/pom.xml +++ b/spring-cloud-modules/spring-cloud-stream-starters/pom.xml @@ -3,7 +3,6 @@ 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"> 4.0.0 - com.baeldung.spring.cloud spring-cloud-stream-starters 1.0.0-SNAPSHOT spring-cloud-stream-starters @@ -32,7 +31,7 @@ - 2021.0.0 + 2022.0.4 \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-stream-starters/twitterhdfs/pom.xml b/spring-cloud-modules/spring-cloud-stream-starters/twitterhdfs/pom.xml index 51e8703e6e..1a19415a3f 100644 --- a/spring-cloud-modules/spring-cloud-stream-starters/twitterhdfs/pom.xml +++ b/spring-cloud-modules/spring-cloud-stream-starters/twitterhdfs/pom.xml @@ -61,16 +61,21 @@ org.junit.vintage junit-vintage-engine + + org.codehaus.groovy + groovy + ${groovy.version} + + twitterhdfs org.springframework.boot spring-boot-maven-plugin - twitterhdfs @@ -83,6 +88,7 @@ 4.13.2 5.8.1 2.17.1 + 3.0.8 \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-zuul-eureka-integration/eureka-client/pom.xml b/spring-cloud-modules/spring-cloud-zuul-eureka-integration/eureka-client/pom.xml index 3960cfde5d..46b3e7047f 100644 --- a/spring-cloud-modules/spring-cloud-zuul-eureka-integration/eureka-client/pom.xml +++ b/spring-cloud-modules/spring-cloud-zuul-eureka-integration/eureka-client/pom.xml @@ -53,6 +53,24 @@ + + + + org.apache.maven.plugins + maven-surefire-plugin + + + --add-opens java.base/java.lang=ALL-UNNAMED + --add-opens java.base/java.util=ALL-UNNAMED + --add-opens java.base/java.lang.reflect=ALL-UNNAMED + --add-opens java.base/java.text=ALL-UNNAMED + --add-opens java.desktop/java.awt.font=ALL-UNNAMED + + + + + + 2.17.1 diff --git a/spring-cloud-modules/spring-cloud-zuul-eureka-integration/eureka-server/pom.xml b/spring-cloud-modules/spring-cloud-zuul-eureka-integration/eureka-server/pom.xml index c9bc120e4d..796b908bca 100644 --- a/spring-cloud-modules/spring-cloud-zuul-eureka-integration/eureka-server/pom.xml +++ b/spring-cloud-modules/spring-cloud-zuul-eureka-integration/eureka-server/pom.xml @@ -53,6 +53,24 @@ + + + + org.apache.maven.plugins + maven-surefire-plugin + + + --add-opens java.base/java.lang=ALL-UNNAMED + --add-opens java.base/java.util=ALL-UNNAMED + --add-opens java.base/java.lang.reflect=ALL-UNNAMED + --add-opens java.base/java.text=ALL-UNNAMED + --add-opens java.desktop/java.awt.font=ALL-UNNAMED + + + + + + 2.17.1 diff --git a/spring-cloud-modules/spring-cloud-zuul-eureka-integration/zuul-server/pom.xml b/spring-cloud-modules/spring-cloud-zuul-eureka-integration/zuul-server/pom.xml index 76d899447f..11cc992523 100644 --- a/spring-cloud-modules/spring-cloud-zuul-eureka-integration/zuul-server/pom.xml +++ b/spring-cloud-modules/spring-cloud-zuul-eureka-integration/zuul-server/pom.xml @@ -61,6 +61,24 @@ + + + + org.apache.maven.plugins + maven-surefire-plugin + + + --add-opens java.base/java.lang=ALL-UNNAMED + --add-opens java.base/java.util=ALL-UNNAMED + --add-opens java.base/java.lang.reflect=ALL-UNNAMED + --add-opens java.base/java.text=ALL-UNNAMED + --add-opens java.desktop/java.awt.font=ALL-UNNAMED + + + + + + 2.17.1 diff --git a/spring-core/src/main/java/com/baeldung/config/scope/AppConfigFunctionBean.java b/spring-core/src/main/java/com/baeldung/config/scope/AppConfigFunctionBean.java index a3c5445698..aa526b5403 100644 --- a/spring-core/src/main/java/com/baeldung/config/scope/AppConfigFunctionBean.java +++ b/spring-core/src/main/java/com/baeldung/config/scope/AppConfigFunctionBean.java @@ -7,7 +7,7 @@ import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Scope; import com.baeldung.scope.prototype.PrototypeBean; -import com.baeldung.scope.singletone.SingletonFunctionBean; +import com.baeldung.scope.singleton.SingletonFunctionBean; @Configuration public class AppConfigFunctionBean { diff --git a/spring-core/src/main/java/com/baeldung/scope/AppConfig.java b/spring-core/src/main/java/com/baeldung/scope/AppConfig.java index 33a9c5c21e..2ef775ee4f 100644 --- a/spring-core/src/main/java/com/baeldung/scope/AppConfig.java +++ b/spring-core/src/main/java/com/baeldung/scope/AppConfig.java @@ -1,10 +1,10 @@ package com.baeldung.scope; import com.baeldung.scope.prototype.PrototypeBean; -import com.baeldung.scope.singletone.SingletonAppContextBean; -import com.baeldung.scope.singletone.SingletonBean; -import com.baeldung.scope.singletone.SingletonObjectFactoryBean; -import com.baeldung.scope.singletone.SingletonProviderBean; +import com.baeldung.scope.singleton.SingletonAppContextBean; +import com.baeldung.scope.singleton.SingletonBean; +import com.baeldung.scope.singleton.SingletonObjectFactoryBean; +import com.baeldung.scope.singleton.SingletonProviderBean; import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; diff --git a/spring-core/src/main/java/com/baeldung/scope/AppProxyScopeConfig.java b/spring-core/src/main/java/com/baeldung/scope/AppProxyScopeConfig.java index 9f1874375e..0564dfb3c0 100644 --- a/spring-core/src/main/java/com/baeldung/scope/AppProxyScopeConfig.java +++ b/spring-core/src/main/java/com/baeldung/scope/AppProxyScopeConfig.java @@ -1,7 +1,7 @@ package com.baeldung.scope; import com.baeldung.scope.prototype.PrototypeBean; -import com.baeldung.scope.singletone.SingletonBean; +import com.baeldung.scope.singleton.SingletonBean; import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.context.annotation.*; diff --git a/spring-core/src/main/java/com/baeldung/scope/BeanInjectionStarter.java b/spring-core/src/main/java/com/baeldung/scope/BeanInjectionStarter.java index 5cf0c9170c..47014aa2d1 100644 --- a/spring-core/src/main/java/com/baeldung/scope/BeanInjectionStarter.java +++ b/spring-core/src/main/java/com/baeldung/scope/BeanInjectionStarter.java @@ -1,7 +1,7 @@ package com.baeldung.scope; import com.baeldung.scope.prototype.PrototypeBean; -import com.baeldung.scope.singletone.SingletonBean; +import com.baeldung.scope.singleton.SingletonBean; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.util.Assert; diff --git a/spring-core/src/main/java/com/baeldung/scope/singletone/SingletonAppContextBean.java b/spring-core/src/main/java/com/baeldung/scope/singleton/SingletonAppContextBean.java similarity index 94% rename from spring-core/src/main/java/com/baeldung/scope/singletone/SingletonAppContextBean.java rename to spring-core/src/main/java/com/baeldung/scope/singleton/SingletonAppContextBean.java index f4d57a0f63..4f5b3274c8 100644 --- a/spring-core/src/main/java/com/baeldung/scope/singletone/SingletonAppContextBean.java +++ b/spring-core/src/main/java/com/baeldung/scope/singleton/SingletonAppContextBean.java @@ -1,4 +1,4 @@ -package com.baeldung.scope.singletone; +package com.baeldung.scope.singleton; import com.baeldung.scope.prototype.PrototypeBean; import org.springframework.beans.BeansException; diff --git a/spring-core/src/main/java/com/baeldung/scope/singletone/SingletonBean.java b/spring-core/src/main/java/com/baeldung/scope/singleton/SingletonBean.java similarity index 93% rename from spring-core/src/main/java/com/baeldung/scope/singletone/SingletonBean.java rename to spring-core/src/main/java/com/baeldung/scope/singleton/SingletonBean.java index 8d3a09b8fd..9c4cea4439 100644 --- a/spring-core/src/main/java/com/baeldung/scope/singletone/SingletonBean.java +++ b/spring-core/src/main/java/com/baeldung/scope/singleton/SingletonBean.java @@ -1,4 +1,4 @@ -package com.baeldung.scope.singletone; +package com.baeldung.scope.singleton; import com.baeldung.scope.prototype.PrototypeBean; import org.apache.log4j.Logger; diff --git a/spring-core/src/main/java/com/baeldung/scope/singletone/SingletonFunctionBean.java b/spring-core/src/main/java/com/baeldung/scope/singleton/SingletonFunctionBean.java similarity index 91% rename from spring-core/src/main/java/com/baeldung/scope/singletone/SingletonFunctionBean.java rename to spring-core/src/main/java/com/baeldung/scope/singleton/SingletonFunctionBean.java index 8cdc56a6fa..2788af1701 100644 --- a/spring-core/src/main/java/com/baeldung/scope/singletone/SingletonFunctionBean.java +++ b/spring-core/src/main/java/com/baeldung/scope/singleton/SingletonFunctionBean.java @@ -1,4 +1,4 @@ -package com.baeldung.scope.singletone; +package com.baeldung.scope.singleton; import java.util.function.Function; diff --git a/spring-core/src/main/java/com/baeldung/scope/singletone/SingletonLookupBean.java b/spring-core/src/main/java/com/baeldung/scope/singleton/SingletonLookupBean.java similarity index 88% rename from spring-core/src/main/java/com/baeldung/scope/singletone/SingletonLookupBean.java rename to spring-core/src/main/java/com/baeldung/scope/singleton/SingletonLookupBean.java index 4c3c9b69da..e5461826ef 100644 --- a/spring-core/src/main/java/com/baeldung/scope/singletone/SingletonLookupBean.java +++ b/spring-core/src/main/java/com/baeldung/scope/singleton/SingletonLookupBean.java @@ -1,4 +1,4 @@ -package com.baeldung.scope.singletone; +package com.baeldung.scope.singleton; import com.baeldung.scope.prototype.PrototypeBean; import org.springframework.beans.factory.annotation.Lookup; diff --git a/spring-core/src/main/java/com/baeldung/scope/singletone/SingletonObjectFactoryBean.java b/spring-core/src/main/java/com/baeldung/scope/singleton/SingletonObjectFactoryBean.java similarity index 91% rename from spring-core/src/main/java/com/baeldung/scope/singletone/SingletonObjectFactoryBean.java rename to spring-core/src/main/java/com/baeldung/scope/singleton/SingletonObjectFactoryBean.java index 55a91f8202..0e70d12e6e 100644 --- a/spring-core/src/main/java/com/baeldung/scope/singletone/SingletonObjectFactoryBean.java +++ b/spring-core/src/main/java/com/baeldung/scope/singleton/SingletonObjectFactoryBean.java @@ -1,4 +1,4 @@ -package com.baeldung.scope.singletone; +package com.baeldung.scope.singleton; import com.baeldung.scope.prototype.PrototypeBean; import org.springframework.beans.factory.ObjectFactory; diff --git a/spring-core/src/main/java/com/baeldung/scope/singletone/SingletonProviderBean.java b/spring-core/src/main/java/com/baeldung/scope/singleton/SingletonProviderBean.java similarity index 90% rename from spring-core/src/main/java/com/baeldung/scope/singletone/SingletonProviderBean.java rename to spring-core/src/main/java/com/baeldung/scope/singleton/SingletonProviderBean.java index 37d0ad9404..01a4a0ff11 100644 --- a/spring-core/src/main/java/com/baeldung/scope/singletone/SingletonProviderBean.java +++ b/spring-core/src/main/java/com/baeldung/scope/singleton/SingletonProviderBean.java @@ -1,4 +1,4 @@ -package com.baeldung.scope.singletone; +package com.baeldung.scope.singleton; import com.baeldung.scope.prototype.PrototypeBean; import org.springframework.beans.factory.annotation.Autowired; diff --git a/spring-core/src/test/java/com/baeldung/scope/PrototypeBeanInjectionIntegrationTest.java b/spring-core/src/test/java/com/baeldung/scope/PrototypeBeanInjectionIntegrationTest.java index d0c2733765..df04957992 100644 --- a/spring-core/src/test/java/com/baeldung/scope/PrototypeBeanInjectionIntegrationTest.java +++ b/spring-core/src/test/java/com/baeldung/scope/PrototypeBeanInjectionIntegrationTest.java @@ -1,10 +1,9 @@ package com.baeldung.scope; import com.baeldung.scope.prototype.PrototypeBean; -import com.baeldung.scope.singletone.SingletonFunctionBean; -import com.baeldung.scope.singletone.SingletonLookupBean; -import com.baeldung.scope.singletone.SingletonObjectFactoryBean; -import com.baeldung.scope.singletone.SingletonProviderBean; +import com.baeldung.scope.singleton.SingletonLookupBean; +import com.baeldung.scope.singleton.SingletonObjectFactoryBean; +import com.baeldung.scope.singleton.SingletonProviderBean; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; diff --git a/spring-core/src/test/java/com/baeldung/scope/PrototypeFunctionBeanIntegrationTest.java b/spring-core/src/test/java/com/baeldung/scope/PrototypeFunctionBeanIntegrationTest.java index 1e3c652599..dac3461ceb 100644 --- a/spring-core/src/test/java/com/baeldung/scope/PrototypeFunctionBeanIntegrationTest.java +++ b/spring-core/src/test/java/com/baeldung/scope/PrototypeFunctionBeanIntegrationTest.java @@ -11,7 +11,7 @@ import org.springframework.test.context.support.AnnotationConfigContextLoader; import com.baeldung.config.scope.AppConfigFunctionBean; import com.baeldung.scope.prototype.PrototypeBean; -import com.baeldung.scope.singletone.SingletonFunctionBean; +import com.baeldung.scope.singleton.SingletonFunctionBean; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(loader = AnnotationConfigContextLoader.class, classes = AppConfigFunctionBean.class) diff --git a/spring-kafka-2/README.md b/spring-kafka-2/README.md index d71e75f15c..318312ace6 100644 --- a/spring-kafka-2/README.md +++ b/spring-kafka-2/README.md @@ -7,3 +7,4 @@ This module contains articles about Spring with Kafka - [Implementing Retry in Kafka Consumer](https://www.baeldung.com/spring-retry-kafka-consumer) - [Spring Kafka: Configure Multiple Listeners on Same Topic](https://www.baeldung.com/spring-kafka-multiple-listeners-same-topic) - [Understanding Kafka Topics and Partitions](https://www.baeldung.com/kafka-topics-partitions) +- [How to Subscribe a Kafka Consumer to Multiple Topics](https://www.baeldung.com/kafka-subscribe-consumer-multiple-topics) diff --git a/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/multipletopics/KafkaConsumerConfig.java b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/multipletopics/KafkaConsumerConfig.java new file mode 100644 index 0000000000..741fb6bba4 --- /dev/null +++ b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/multipletopics/KafkaConsumerConfig.java @@ -0,0 +1,36 @@ +package com.baeldung.spring.kafka.multipletopics; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.kafka.clients.consumer.ConsumerConfig; +import org.apache.kafka.common.serialization.StringDeserializer; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.kafka.config.ConcurrentKafkaListenerContainerFactory; +import org.springframework.kafka.core.ConsumerFactory; +import org.springframework.kafka.core.DefaultKafkaConsumerFactory; +import org.springframework.kafka.support.serializer.JsonDeserializer; + +@Configuration +public class KafkaConsumerConfig { + + @Value(value = "${spring.kafka.bootstrap-servers}") + private String bootstrapServers; + + @Bean + public ConsumerFactory consumerFactory() { + Map config = new HashMap<>(); + config.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers); + + return new DefaultKafkaConsumerFactory<>(config, new StringDeserializer(), new JsonDeserializer<>(PaymentData.class)); + } + + @Bean + public ConcurrentKafkaListenerContainerFactory kafkaListenerContainerFactory() { + ConcurrentKafkaListenerContainerFactory factory = new ConcurrentKafkaListenerContainerFactory<>(); + factory.setConsumerFactory(consumerFactory()); + return factory; + } +} \ No newline at end of file diff --git a/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/multipletopics/KafkaMultipleTopicsApplication.java b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/multipletopics/KafkaMultipleTopicsApplication.java new file mode 100644 index 0000000000..2135a27f39 --- /dev/null +++ b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/multipletopics/KafkaMultipleTopicsApplication.java @@ -0,0 +1,13 @@ +package com.baeldung.spring.kafka.multipletopics; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.kafka.annotation.EnableKafka; + +@EnableKafka +@SpringBootApplication +public class KafkaMultipleTopicsApplication { + public static void main(String[] args) { + SpringApplication.run(KafkaMultipleTopicsApplication.class, args); + } +} \ No newline at end of file diff --git a/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/multipletopics/KafkaProducerConfig.java b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/multipletopics/KafkaProducerConfig.java new file mode 100644 index 0000000000..2cb0117bf1 --- /dev/null +++ b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/multipletopics/KafkaProducerConfig.java @@ -0,0 +1,34 @@ +package com.baeldung.spring.kafka.multipletopics; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.kafka.clients.producer.ProducerConfig; +import org.apache.kafka.common.serialization.StringSerializer; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.kafka.core.DefaultKafkaProducerFactory; +import org.springframework.kafka.core.KafkaTemplate; +import org.springframework.kafka.core.ProducerFactory; +import org.springframework.kafka.support.serializer.JsonSerializer; + +@Configuration +public class KafkaProducerConfig { + + @Value(value = "${spring.kafka.bootstrap-servers}") + private String bootstrapServers; + + @Bean + public ProducerFactory producerFactory() { + Map config = new HashMap<>(); + config.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers); + + return new DefaultKafkaProducerFactory<>(config, new StringSerializer(), new JsonSerializer<>()); + } + + @Bean + public KafkaTemplate kafkaProducer() { + return new KafkaTemplate<>(producerFactory()); + } +} \ No newline at end of file diff --git a/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/multipletopics/PaymentData.java b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/multipletopics/PaymentData.java new file mode 100644 index 0000000000..e81138c089 --- /dev/null +++ b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/multipletopics/PaymentData.java @@ -0,0 +1,54 @@ +package com.baeldung.spring.kafka.multipletopics; + +import java.math.BigDecimal; +import java.util.Currency; +import java.util.StringJoiner; + +public class PaymentData { + private String paymentReference; + private String type; + private BigDecimal amount; + private Currency currency; + + public String getPaymentReference() { + return paymentReference; + } + + public void setPaymentReference(String paymentReference) { + this.paymentReference = paymentReference; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public BigDecimal getAmount() { + return amount; + } + + public void setAmount(BigDecimal amount) { + this.amount = amount; + } + + public Currency getCurrency() { + return currency; + } + + public void setCurrency(Currency currency) { + this.currency = currency; + } + + @Override + public String toString() { + return new StringJoiner(", ", PaymentData.class.getSimpleName() + "[", "]") + .add("paymentReference='" + paymentReference + "'") + .add("type='" + type + "'") + .add("amount=" + amount) + .add("currency=" + currency) + .toString(); + } +} \ No newline at end of file diff --git a/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/multipletopics/PaymentDataListener.java b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/multipletopics/PaymentDataListener.java new file mode 100644 index 0000000000..fb640cca25 --- /dev/null +++ b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/multipletopics/PaymentDataListener.java @@ -0,0 +1,18 @@ +package com.baeldung.spring.kafka.multipletopics; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.kafka.annotation.KafkaListener; +import org.springframework.kafka.support.KafkaHeaders; +import org.springframework.messaging.handler.annotation.Header; +import org.springframework.stereotype.Service; + +@Service +public class PaymentDataListener { + private final Logger log = LoggerFactory.getLogger(PaymentDataListener.class); + + @KafkaListener(topics = { "card-payments", "bank-transfers" }, groupId = "payments") + public void handlePaymentEvents(PaymentData paymentData, @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { + log.info("Event on topic={}, payload={}", topic, paymentData); + } +} \ No newline at end of file diff --git a/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/topicsandpartitions/TemperatureConsumer.java b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/topicsandpartitions/TemperatureConsumer.java index 7cfbdd5fb0..2919ae1d7b 100644 --- a/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/topicsandpartitions/TemperatureConsumer.java +++ b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/topicsandpartitions/TemperatureConsumer.java @@ -8,29 +8,22 @@ import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.CountDownLatch; @Service public class TemperatureConsumer { - private CountDownLatch latch = new CountDownLatch(1); - Map> consumedRecords = new ConcurrentHashMap<>(); @KafkaListener(topics = "celcius-scale-topic", groupId = "group-1") public void consumer1(ConsumerRecord consumerRecord) { - computeConsumedRecord("consumer-1", consumerRecord.partition()); + trackConsumedPartitions("consumer-1", consumerRecord.partition()); } - private void computeConsumedRecord(String key, int consumerRecord) { - consumedRecords.computeIfAbsent(key, k -> new HashSet<>()); - consumedRecords.computeIfPresent(key, (k, v) -> { - v.add(String.valueOf(consumerRecord)); + private void trackConsumedPartitions(String consumerName, int partitionNumber) { + consumedRecords.computeIfAbsent(consumerName, k -> new HashSet<>()); + consumedRecords.computeIfPresent(consumerName, (k, v) -> { + v.add(String.valueOf(partitionNumber)); return v; }); } - - public CountDownLatch getLatch() { - return latch; - } } diff --git a/spring-kafka-2/src/test/java/com/baeldung/spring/kafka/multipletopics/KafkaMultipleTopicsIntegrationTest.java b/spring-kafka-2/src/test/java/com/baeldung/spring/kafka/multipletopics/KafkaMultipleTopicsIntegrationTest.java new file mode 100644 index 0000000000..345e84b65b --- /dev/null +++ b/spring-kafka-2/src/test/java/com/baeldung/spring/kafka/multipletopics/KafkaMultipleTopicsIntegrationTest.java @@ -0,0 +1,78 @@ +package com.baeldung.spring.kafka.multipletopics; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doAnswer; + +import java.math.BigDecimal; +import java.util.Currency; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +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.mock.mockito.SpyBean; +import org.springframework.kafka.config.KafkaListenerEndpointRegistry; +import org.springframework.kafka.core.KafkaTemplate; +import org.springframework.kafka.listener.MessageListenerContainer; +import org.springframework.kafka.test.context.EmbeddedKafka; +import org.springframework.kafka.test.utils.ContainerTestUtils; + +@SpringBootTest(classes = KafkaMultipleTopicsApplication.class) +@EmbeddedKafka(partitions = 1, brokerProperties = { "listeners=PLAINTEXT://localhost:9092", "port=9092" }) +public class KafkaMultipleTopicsIntegrationTest { + private static final String CARD_PAYMENTS_TOPIC = "card-payments"; + private static final String BANK_TRANSFERS_TOPIC = "bank-transfers"; + + @Autowired + private KafkaListenerEndpointRegistry kafkaListenerEndpointRegistry; + + @Autowired + private KafkaTemplate kafkaProducer; + + @SpyBean + private PaymentDataListener paymentsConsumer; + + @BeforeEach + void setUp() { + // wait for embedded Kafka + for (MessageListenerContainer messageListenerContainer : kafkaListenerEndpointRegistry.getListenerContainers()) { + ContainerTestUtils.waitForAssignment(messageListenerContainer, 2); + } + } + + @Test + public void whenSendingMessagesOnTwoTopics_thenConsumerReceivesMessages() throws Exception { + CountDownLatch countDownLatch = new CountDownLatch(2); + doAnswer(invocation -> { + countDownLatch.countDown(); + return null; + }).when(paymentsConsumer) + .handlePaymentEvents(any(), any()); + + kafkaProducer.send(CARD_PAYMENTS_TOPIC, createCardPayment()); + kafkaProducer.send(BANK_TRANSFERS_TOPIC, createBankTransfer()); + + assertThat(countDownLatch.await(5, TimeUnit.SECONDS)).isTrue(); + } + + private PaymentData createCardPayment() { + PaymentData cardPayment = new PaymentData(); + cardPayment.setAmount(BigDecimal.valueOf(275)); + cardPayment.setPaymentReference("A184028KM0013790"); + cardPayment.setCurrency(Currency.getInstance("GBP")); + cardPayment.setType("card"); + return cardPayment; + } + + private PaymentData createBankTransfer() { + PaymentData bankTransfer = new PaymentData(); + bankTransfer.setAmount(BigDecimal.valueOf(150)); + bankTransfer.setPaymentReference("19ae2-18mk73-009"); + bankTransfer.setCurrency(Currency.getInstance("EUR")); + bankTransfer.setType("bank"); + return bankTransfer; + } +} \ No newline at end of file diff --git a/spring-kafka-2/src/test/java/com/baeldung/spring/kafka/topicsandpartitions/KafkaTopicsAndPartitionsIntegrationTest.java b/spring-kafka-2/src/test/java/com/baeldung/spring/kafka/topicsandpartitions/KafkaTopicsAndPartitionsIntegrationTest.java index 309c87125a..de720ef955 100644 --- a/spring-kafka-2/src/test/java/com/baeldung/spring/kafka/topicsandpartitions/KafkaTopicsAndPartitionsIntegrationTest.java +++ b/spring-kafka-2/src/test/java/com/baeldung/spring/kafka/topicsandpartitions/KafkaTopicsAndPartitionsIntegrationTest.java @@ -7,8 +7,6 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.kafka.test.EmbeddedKafkaBroker; import org.springframework.kafka.test.context.EmbeddedKafka; -import java.util.concurrent.TimeUnit; - @SpringBootTest(classes = ThermostatApplicationKafkaApp.class) @EmbeddedKafka(partitions = 2, brokerProperties = {"listeners=PLAINTEXT://localhost:9092", "port=9092"}) public class KafkaTopicsAndPartitionsIntegrationTest { @@ -24,7 +22,7 @@ public class KafkaTopicsAndPartitionsIntegrationTest { @Test public void givenTopic_andConsumerGroup_whenConsumersListenToEvents_thenConsumeItCorrectly() throws Exception { service.measureCelsiusAndPublish(10000); - consumer.getLatch().await(1, TimeUnit.SECONDS); + Thread.sleep(1000); System.out.println(consumer.consumedRecords); } } diff --git a/spring-reactive-modules/pom.xml b/spring-reactive-modules/pom.xml index efae864b46..06519d723a 100644 --- a/spring-reactive-modules/pom.xml +++ b/spring-reactive-modules/pom.xml @@ -19,7 +19,7 @@ spring-reactive-data spring-reactive-data-2 - spring-reactive + spring-5-reactive spring-reactive-2 spring-reactive-3 spring-reactive-client @@ -28,7 +28,7 @@ spring-reactive-oauth spring-reactive-security spring-data-couchbase - spring-reactive-webflux + spring-reactive spring-reactive-exceptions spring-reactor spring-webflux-amqp diff --git a/spring-reactive-modules/spring-reactive/.gitignore b/spring-reactive-modules/spring-5-reactive/.gitignore similarity index 100% rename from spring-reactive-modules/spring-reactive/.gitignore rename to spring-reactive-modules/spring-5-reactive/.gitignore diff --git a/spring-reactive-modules/spring-5-reactive/README.md b/spring-reactive-modules/spring-5-reactive/README.md new file mode 100644 index 0000000000..3f44267234 --- /dev/null +++ b/spring-reactive-modules/spring-5-reactive/README.md @@ -0,0 +1,14 @@ +## Spring 5 Reactive Project + +This module contains articles about reactive Spring Boot + +### The Course +The "REST With Spring" Classes: https://bit.ly/restwithspring + +### Relevant Articles + +- [Exploring the Spring 5 WebFlux URL Matching](https://www.baeldung.com/spring-5-mvc-url-matching) +- [Reactive WebSockets with Spring 5](https://www.baeldung.com/spring-5-reactive-websockets) +- [How to Set a Header on a Response with Spring 5](https://www.baeldung.com/spring-response-header) +- [A Guide to Spring Session Reactive Support: WebSession](https://www.baeldung.com/spring-session-reactive) +- More articles: [[next -->]](../spring-5-reactive-2) \ No newline at end of file diff --git a/spring-reactive-modules/spring-5-reactive/pom.xml b/spring-reactive-modules/spring-5-reactive/pom.xml new file mode 100644 index 0000000000..fd47c70a07 --- /dev/null +++ b/spring-reactive-modules/spring-5-reactive/pom.xml @@ -0,0 +1,164 @@ + + 4.0.0 + spring-5-reactive + 0.0.1-SNAPSHOT + spring-5-reactive + jar + spring 5 sample project about new features + + + com.baeldung.spring.reactive + spring-reactive-modules + 1.0.0-SNAPSHOT + + + + + org.springframework.boot + spring-boot-starter-validation + + + org.springframework.boot + spring-boot-starter-tomcat + + + org.springframework.boot + spring-boot-starter-integration + + + org.springframework.boot + spring-boot-starter-websocket + + + javax.json.bind + javax.json.bind-api + + + org.projectlombok + lombok + compile + + + org.apache.geronimo.specs + geronimo-json_1.1_spec + ${geronimo-json_1.1_spec.version} + + + org.apache.johnzon + johnzon-jsonb + + + + org.apache.commons + commons-lang3 + + + + org.springframework.boot + spring-boot-devtools + runtime + + + org.springframework + spring-test + + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework.security + spring-security-test + test + + + io.projectreactor + reactor-test + test + + + + org.springframework.boot + spring-boot-starter-webflux + + + org.springframework.boot + spring-boot-starter-data-redis + + + org.springframework.boot + spring-boot-starter-security + + + org.springframework.session + spring-session-core + + + org.springframework.session + spring-session-data-redis + + + org.apache.commons + commons-collections4 + ${commons-collections4.version} + test + + + io.reactivex.rxjava2 + rxjava + + + org.apache.httpcomponents + httpclient + + + io.netty + netty-all + + + + + + + maven-resources-plugin + 3.0.1 + + + copy-resources + validate + + copy-resources + + + + + src/main/assets + true + + + ${basedir}/target/classes/assets + + + + + + org.springframework.boot + spring-boot-maven-plugin + + com.baeldung.reactive.Spring5ReactiveApplication + JAR + + + + + + + 1.1.3 + 1.0 + 1.0 + + + \ No newline at end of file diff --git a/spring-reactive-modules/spring-reactive/src/main/webapp/WEB-INF/web.xml b/spring-reactive-modules/spring-5-reactive/src/main/WEB-INF/web.xml similarity index 100% rename from spring-reactive-modules/spring-reactive/src/main/webapp/WEB-INF/web.xml rename to spring-reactive-modules/spring-5-reactive/src/main/WEB-INF/web.xml diff --git a/spring-reactive-modules/spring-reactive/src/main/assets/index.html b/spring-reactive-modules/spring-5-reactive/src/main/assets/index.html similarity index 100% rename from spring-reactive-modules/spring-reactive/src/main/assets/index.html rename to spring-reactive-modules/spring-5-reactive/src/main/assets/index.html diff --git a/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/functional/Actor.java b/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/functional/Actor.java similarity index 100% rename from spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/functional/Actor.java rename to spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/functional/Actor.java diff --git a/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/functional/FormHandler.java b/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/functional/FormHandler.java similarity index 100% rename from spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/functional/FormHandler.java rename to spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/functional/FormHandler.java diff --git a/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/functional/FunctionalSpringBootApplication.java b/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/functional/FunctionalSpringBootApplication.java similarity index 100% rename from spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/functional/FunctionalSpringBootApplication.java rename to spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/functional/FunctionalSpringBootApplication.java diff --git a/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/functional/FunctionalWebApplication.java b/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/functional/FunctionalWebApplication.java similarity index 100% rename from spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/functional/FunctionalWebApplication.java rename to spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/functional/FunctionalWebApplication.java diff --git a/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/functional/IndexRewriteFilter.java b/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/functional/IndexRewriteFilter.java similarity index 100% rename from spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/functional/IndexRewriteFilter.java rename to spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/functional/IndexRewriteFilter.java diff --git a/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/functional/RootServlet.java b/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/functional/RootServlet.java similarity index 100% rename from spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/functional/RootServlet.java rename to spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/functional/RootServlet.java diff --git a/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/Spring5ReactiveApplication.java b/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/reactive/Spring5ReactiveApplication.java similarity index 100% rename from spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/Spring5ReactiveApplication.java rename to spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/reactive/Spring5ReactiveApplication.java diff --git a/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/controller/FooReactiveController.java b/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/reactive/controller/FooReactiveController.java similarity index 100% rename from spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/controller/FooReactiveController.java rename to spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/reactive/controller/FooReactiveController.java diff --git a/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/controller/PathPatternController.java b/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/reactive/controller/PathPatternController.java similarity index 100% rename from spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/controller/PathPatternController.java rename to spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/reactive/controller/PathPatternController.java diff --git a/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/model/Foo.java b/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/reactive/model/Foo.java similarity index 100% rename from spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/model/Foo.java rename to spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/reactive/model/Foo.java diff --git a/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/responseheaders/controllers/ResponseHeaderController.java b/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/reactive/responseheaders/controllers/ResponseHeaderController.java similarity index 100% rename from spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/responseheaders/controllers/ResponseHeaderController.java rename to spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/reactive/responseheaders/controllers/ResponseHeaderController.java diff --git a/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/responseheaders/filter/AddResponseHeaderWebFilter.java b/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/reactive/responseheaders/filter/AddResponseHeaderWebFilter.java similarity index 100% rename from spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/responseheaders/filter/AddResponseHeaderWebFilter.java rename to spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/reactive/responseheaders/filter/AddResponseHeaderWebFilter.java diff --git a/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/responseheaders/functional/handlers/ResponseHeaderHandler.java b/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/reactive/responseheaders/functional/handlers/ResponseHeaderHandler.java similarity index 100% rename from spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/responseheaders/functional/handlers/ResponseHeaderHandler.java rename to spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/reactive/responseheaders/functional/handlers/ResponseHeaderHandler.java diff --git a/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/responseheaders/functional/routers/ResponseHeadersRouterFunctions.java b/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/reactive/responseheaders/functional/routers/ResponseHeadersRouterFunctions.java similarity index 100% rename from spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/responseheaders/functional/routers/ResponseHeadersRouterFunctions.java rename to spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/reactive/responseheaders/functional/routers/ResponseHeadersRouterFunctions.java diff --git a/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/urlmatch/Actor.java b/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/reactive/urlmatch/Actor.java similarity index 100% rename from spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/urlmatch/Actor.java rename to spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/reactive/urlmatch/Actor.java diff --git a/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/urlmatch/ExploreSpring5URLPatternUsingRouterFunctions.java b/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/reactive/urlmatch/ExploreSpring5URLPatternUsingRouterFunctions.java similarity index 100% rename from spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/urlmatch/ExploreSpring5URLPatternUsingRouterFunctions.java rename to spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/reactive/urlmatch/ExploreSpring5URLPatternUsingRouterFunctions.java diff --git a/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/urlmatch/FormHandler.java b/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/reactive/urlmatch/FormHandler.java similarity index 100% rename from spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/urlmatch/FormHandler.java rename to spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/reactive/urlmatch/FormHandler.java diff --git a/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/urlmatch/FunctionalWebApplication.java b/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/reactive/urlmatch/FunctionalWebApplication.java similarity index 100% rename from spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/urlmatch/FunctionalWebApplication.java rename to spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/reactive/urlmatch/FunctionalWebApplication.java diff --git a/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/urlmatch/IndexRewriteFilter.java b/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/reactive/urlmatch/IndexRewriteFilter.java similarity index 100% rename from spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/urlmatch/IndexRewriteFilter.java rename to spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/reactive/urlmatch/IndexRewriteFilter.java diff --git a/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/util/CpuUtils.java b/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/reactive/util/CpuUtils.java similarity index 100% rename from spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/util/CpuUtils.java rename to spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/reactive/util/CpuUtils.java diff --git a/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/websession/Application.java b/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/websession/Application.java similarity index 100% rename from spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/websession/Application.java rename to spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/websession/Application.java diff --git a/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/websession/configuration/RedisConfig.java b/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/websession/configuration/RedisConfig.java similarity index 100% rename from spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/websession/configuration/RedisConfig.java rename to spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/websession/configuration/RedisConfig.java diff --git a/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/websession/configuration/SessionConfig.java b/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/websession/configuration/SessionConfig.java similarity index 100% rename from spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/websession/configuration/SessionConfig.java rename to spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/websession/configuration/SessionConfig.java diff --git a/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/websession/configuration/WebFluxConfig.java b/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/websession/configuration/WebFluxConfig.java similarity index 100% rename from spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/websession/configuration/WebFluxConfig.java rename to spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/websession/configuration/WebFluxConfig.java diff --git a/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/websession/configuration/WebFluxSecurityConfig.java b/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/websession/configuration/WebFluxSecurityConfig.java similarity index 100% rename from spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/websession/configuration/WebFluxSecurityConfig.java rename to spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/websession/configuration/WebFluxSecurityConfig.java diff --git a/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/websession/controller/SessionController.java b/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/websession/controller/SessionController.java similarity index 100% rename from spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/websession/controller/SessionController.java rename to spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/websession/controller/SessionController.java diff --git a/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/websession/transfer/CustomResponse.java b/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/websession/transfer/CustomResponse.java similarity index 100% rename from spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/websession/transfer/CustomResponse.java rename to spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/websession/transfer/CustomResponse.java diff --git a/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/websocket/Event.java b/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/websocket/Event.java similarity index 100% rename from spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/websocket/Event.java rename to spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/websocket/Event.java diff --git a/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/websocket/ReactiveJavaClientWebSocket.java b/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/websocket/ReactiveJavaClientWebSocket.java similarity index 100% rename from spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/websocket/ReactiveJavaClientWebSocket.java rename to spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/websocket/ReactiveJavaClientWebSocket.java diff --git a/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/websocket/ReactiveWebSocketApplication.java b/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/websocket/ReactiveWebSocketApplication.java similarity index 100% rename from spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/websocket/ReactiveWebSocketApplication.java rename to spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/websocket/ReactiveWebSocketApplication.java diff --git a/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/websocket/ReactiveWebSocketConfiguration.java b/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/websocket/ReactiveWebSocketConfiguration.java similarity index 100% rename from spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/websocket/ReactiveWebSocketConfiguration.java rename to spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/websocket/ReactiveWebSocketConfiguration.java diff --git a/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/websocket/ReactiveWebSocketHandler.java b/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/websocket/ReactiveWebSocketHandler.java similarity index 100% rename from spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/websocket/ReactiveWebSocketHandler.java rename to spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/websocket/ReactiveWebSocketHandler.java diff --git a/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/websocket/WebSocketController.java b/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/websocket/WebSocketController.java similarity index 92% rename from spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/websocket/WebSocketController.java rename to spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/websocket/WebSocketController.java index bf4a463ae6..0c8f9debc9 100644 --- a/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/websocket/WebSocketController.java +++ b/spring-reactive-modules/spring-5-reactive/src/main/java/com/baeldung/websocket/WebSocketController.java @@ -6,8 +6,6 @@ import org.slf4j.LoggerFactory; import javax.websocket.*; import javax.websocket.server.ServerEndpoint; import java.io.IOException; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; @ServerEndpoint("/event-emitter") public class WebSocketController { diff --git a/spring-reactive-modules/spring-reactive/src/main/resources/application.properties b/spring-reactive-modules/spring-5-reactive/src/main/resources/application.properties similarity index 100% rename from spring-reactive-modules/spring-reactive/src/main/resources/application.properties rename to spring-reactive-modules/spring-5-reactive/src/main/resources/application.properties diff --git a/spring-reactive-modules/spring-reactive/src/main/resources/files/hello.txt b/spring-reactive-modules/spring-5-reactive/src/main/resources/files/hello.txt similarity index 100% rename from spring-reactive-modules/spring-reactive/src/main/resources/files/hello.txt rename to spring-reactive-modules/spring-5-reactive/src/main/resources/files/hello.txt diff --git a/spring-reactive-modules/spring-reactive/src/main/resources/files/test/test.txt b/spring-reactive-modules/spring-5-reactive/src/main/resources/files/test/test.txt similarity index 100% rename from spring-reactive-modules/spring-reactive/src/main/resources/files/test/test.txt rename to spring-reactive-modules/spring-5-reactive/src/main/resources/files/test/test.txt diff --git a/spring-reactive-modules/spring-5-reactive/src/main/resources/logback.xml b/spring-reactive-modules/spring-5-reactive/src/main/resources/logback.xml new file mode 100644 index 0000000000..7d900d8ea8 --- /dev/null +++ b/spring-reactive-modules/spring-5-reactive/src/main/resources/logback.xml @@ -0,0 +1,13 @@ + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + \ No newline at end of file diff --git a/spring-reactive-modules/spring-reactive/src/main/resources/resources/test/test.txt b/spring-reactive-modules/spring-5-reactive/src/main/resources/resources/test/test.txt similarity index 100% rename from spring-reactive-modules/spring-reactive/src/main/resources/resources/test/test.txt rename to spring-reactive-modules/spring-5-reactive/src/main/resources/resources/test/test.txt diff --git a/spring-reactive-modules/spring-reactive/src/main/resources/static/client-websocket.html b/spring-reactive-modules/spring-5-reactive/src/main/resources/static/client-websocket.html similarity index 100% rename from spring-reactive-modules/spring-reactive/src/main/resources/static/client-websocket.html rename to spring-reactive-modules/spring-5-reactive/src/main/resources/static/client-websocket.html diff --git a/spring-reactive-modules/spring-reactive/src/test/java/com/baeldung/SpringContextTest.java b/spring-reactive-modules/spring-5-reactive/src/test/java/com/baeldung/SpringContextTest.java similarity index 100% rename from spring-reactive-modules/spring-reactive/src/test/java/com/baeldung/SpringContextTest.java rename to spring-reactive-modules/spring-5-reactive/src/test/java/com/baeldung/SpringContextTest.java diff --git a/spring-reactive-modules/spring-reactive/src/test/java/com/baeldung/functional/FunctionalWebApplicationIntegrationTest.java b/spring-reactive-modules/spring-5-reactive/src/test/java/com/baeldung/functional/FunctionalWebApplicationIntegrationTest.java similarity index 100% rename from spring-reactive-modules/spring-reactive/src/test/java/com/baeldung/functional/FunctionalWebApplicationIntegrationTest.java rename to spring-reactive-modules/spring-5-reactive/src/test/java/com/baeldung/functional/FunctionalWebApplicationIntegrationTest.java diff --git a/spring-reactive-modules/spring-reactive/src/test/java/com/baeldung/reactive/FluxUnitTest.java b/spring-reactive-modules/spring-5-reactive/src/test/java/com/baeldung/reactive/FluxUnitTest.java similarity index 100% rename from spring-reactive-modules/spring-reactive/src/test/java/com/baeldung/reactive/FluxUnitTest.java rename to spring-reactive-modules/spring-5-reactive/src/test/java/com/baeldung/reactive/FluxUnitTest.java diff --git a/spring-reactive-modules/spring-reactive/src/test/java/com/baeldung/reactive/responseheaders/ResponseHeaderLiveTest.java b/spring-reactive-modules/spring-5-reactive/src/test/java/com/baeldung/reactive/responseheaders/ResponseHeaderLiveTest.java similarity index 100% rename from spring-reactive-modules/spring-reactive/src/test/java/com/baeldung/reactive/responseheaders/ResponseHeaderLiveTest.java rename to spring-reactive-modules/spring-5-reactive/src/test/java/com/baeldung/reactive/responseheaders/ResponseHeaderLiveTest.java diff --git a/spring-reactive-modules/spring-reactive/src/test/java/com/baeldung/reactive/urlmatch/ExploreSpring5URLPatternUsingRouterFunctionsIntegrationTest.java b/spring-reactive-modules/spring-5-reactive/src/test/java/com/baeldung/reactive/urlmatch/ExploreSpring5URLPatternUsingRouterFunctionsIntegrationTest.java similarity index 97% rename from spring-reactive-modules/spring-reactive/src/test/java/com/baeldung/reactive/urlmatch/ExploreSpring5URLPatternUsingRouterFunctionsIntegrationTest.java rename to spring-reactive-modules/spring-5-reactive/src/test/java/com/baeldung/reactive/urlmatch/ExploreSpring5URLPatternUsingRouterFunctionsIntegrationTest.java index a77a67c6ba..113376318e 100644 --- a/spring-reactive-modules/spring-reactive/src/test/java/com/baeldung/reactive/urlmatch/ExploreSpring5URLPatternUsingRouterFunctionsIntegrationTest.java +++ b/spring-reactive-modules/spring-5-reactive/src/test/java/com/baeldung/reactive/urlmatch/ExploreSpring5URLPatternUsingRouterFunctionsIntegrationTest.java @@ -108,7 +108,7 @@ public class ExploreSpring5URLPatternUsingRouterFunctionsIntegrationTest { } @Test - public void givenRouter_whenAccess_thenGot() throws Exception { + public void givenRouter_whenAccess_thenGot() { client.get() .uri("/resources/test/test.txt") .exchange() diff --git a/spring-reactive-modules/spring-reactive/src/test/java/com/baeldung/reactive/urlmatch/PathPatternsUsingHandlerMethodIntegrationTest.java b/spring-reactive-modules/spring-5-reactive/src/test/java/com/baeldung/reactive/urlmatch/PathPatternsUsingHandlerMethodIntegrationTest.java similarity index 100% rename from spring-reactive-modules/spring-reactive/src/test/java/com/baeldung/reactive/urlmatch/PathPatternsUsingHandlerMethodIntegrationTest.java rename to spring-reactive-modules/spring-5-reactive/src/test/java/com/baeldung/reactive/urlmatch/PathPatternsUsingHandlerMethodIntegrationTest.java diff --git a/spring-reactive-modules/spring-reactive/src/test/resources/baeldung-weekly.png b/spring-reactive-modules/spring-5-reactive/src/test/resources/baeldung-weekly.png similarity index 100% rename from spring-reactive-modules/spring-reactive/src/test/resources/baeldung-weekly.png rename to spring-reactive-modules/spring-5-reactive/src/test/resources/baeldung-weekly.png diff --git a/spring-reactive-modules/spring-reactive-exceptions/README.md b/spring-reactive-modules/spring-reactive-exceptions/README.md index f7e2c8cae0..f10774d188 100644 --- a/spring-reactive-modules/spring-reactive-exceptions/README.md +++ b/spring-reactive-modules/spring-reactive-exceptions/README.md @@ -1,4 +1,3 @@ ## Relevant Articles - [How to Resolve Spring Webflux DataBufferLimitException](https://www.baeldung.com/spring-webflux-databufferlimitexception) -- [Custom WebFlux Exceptions in Spring Boot 3](https://www.baeldung.com/spring-boot-custom-webflux-exceptions) -- [Handling Errors in Spring WebFlux](https://www.baeldung.com/spring-webflux-errors) \ No newline at end of file +- [Custom WebFlux Exceptions in Spring Boot 3](https://www.baeldung.com/spring-boot-custom-webflux-exceptions) \ No newline at end of file diff --git a/spring-reactive-modules/spring-reactive-webflux/README.md b/spring-reactive-modules/spring-reactive-webflux/README.md deleted file mode 100644 index d2b63b2186..0000000000 --- a/spring-reactive-modules/spring-reactive-webflux/README.md +++ /dev/null @@ -1,23 +0,0 @@ -### Spring Reactive Articles that are also part of the e-book - -This module contains articles about Spring Reactive that are also part of an Ebook. - -## Spring Reactive - -This module contains articles describing reactive processing in Spring. - -## Relevant articles: - -- [Intro To Reactor Core](https://www.baeldung.com/reactor-core) -- [Debugging Reactive Streams in Java](https://www.baeldung.com/spring-debugging-reactive-streams) -- [Guide to Spring 5 WebFlux](https://www.baeldung.com/spring-webflux) -- [Introduction to the Functional Web Framework in Spring 5](https://www.baeldung.com/spring-5-functional-web) -- [Spring 5 WebClient](https://www.baeldung.com/spring-5-webclient) -- [Spring WebClient vs. RestTemplate](https://www.baeldung.com/spring-webclient-resttemplate) -- [Spring WebClient Requests with Parameters](https://www.baeldung.com/webflux-webclient-parameters) -- [Spring Security 5 for Reactive Applications](https://www.baeldung.com/spring-security-5-reactive) -- [Concurrency in Spring WebFlux](https://www.baeldung.com/spring-webflux-concurrency) - -### NOTE: - -Since this is a module tied to an e-book, it should **not** be moved or used to store the code for any further article. diff --git a/spring-reactive-modules/spring-reactive-webflux/pom.xml b/spring-reactive-modules/spring-reactive-webflux/pom.xml deleted file mode 100644 index cecaeff20c..0000000000 --- a/spring-reactive-modules/spring-reactive-webflux/pom.xml +++ /dev/null @@ -1,112 +0,0 @@ - - - 4.0.0 - spring-reactive-webflux - - - com.baeldung - parent-boot-3 - 0.0.1-SNAPSHOT - ../../parent-boot-3 - - - - - org.springframework.boot - spring-boot-starter-webflux - - - org.springframework.boot - spring-boot-starter-validation - - - org.springframework.boot - spring-boot-starter-security - - - io.reactivex.rxjava2 - rxjava - ${rxjava.version} - - - io.projectreactor.kafka - reactor-kafka - ${reactor-kafka.version} - - - org.springframework.boot - spring-boot-starter-data-mongodb-reactive - - - org.springframework.security - spring-security-test - test - - - io.projectreactor - reactor-test - ${reactor.version} - test - - - org.projectlombok - lombok - - - - - - integration-lite-first - - - - org.apache.maven.plugins - maven-surefire-plugin - - - ${project.basedir}/src/test/resources/logback-test.xml - - - - - - - - integration-lite-second - - - - org.apache.maven.plugins - maven-surefire-plugin - - - ${project.basedir}/src/test/resources/logback-test.xml - - - - - - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - true - - - - - - - 3.4.16 - 1.3.10 - 2.2.21 - - - \ No newline at end of file diff --git a/spring-reactive-modules/spring-reactive/README.md b/spring-reactive-modules/spring-reactive/README.md index f3148fe696..61d781b312 100644 --- a/spring-reactive-modules/spring-reactive/README.md +++ b/spring-reactive-modules/spring-reactive/README.md @@ -1,14 +1,23 @@ -## Spring 5 Reactive Project -This module contains articles about reactive Spring 5 +This module contains articles about Spring Reactive that **are also part of an Ebook.** -### The Course -The "REST With Spring" Classes: https://bit.ly/restwithspring +## Spring Reactive -### Relevant Articles +This module contains articles describing reactive processing in Spring. -- [Exploring the Spring 5 WebFlux URL Matching](https://www.baeldung.com/spring-5-mvc-url-matching) -- [Reactive WebSockets with Spring 5](https://www.baeldung.com/spring-5-reactive-websockets) -- [How to Set a Header on a Response with Spring 5](https://www.baeldung.com/spring-response-header) -- [A Guide to Spring Session Reactive Support: WebSession](https://www.baeldung.com/spring-session-reactive) -- More articles: [[next -->]](../spring-5-reactive-2) +## Relevant articles: + +- [Intro To Reactor Core](https://www.baeldung.com/reactor-core) +- [Debugging Reactive Streams in Java](https://www.baeldung.com/spring-debugging-reactive-streams) +- [Guide to Spring 5 WebFlux](https://www.baeldung.com/spring-webflux) +- [Introduction to the Functional Web Framework in Spring 5](https://www.baeldung.com/spring-5-functional-web) +- [Spring 5 WebClient](https://www.baeldung.com/spring-5-webclient) +- [Spring WebClient vs. RestTemplate](https://www.baeldung.com/spring-webclient-resttemplate) +- [Spring WebClient Requests with Parameters](https://www.baeldung.com/webflux-webclient-parameters) +- [Handling Errors in Spring WebFlux](https://www.baeldung.com/spring-webflux-errors) +- [Spring Security 5 for Reactive Applications](https://www.baeldung.com/spring-security-5-reactive) +- [Concurrency in Spring WebFlux](https://www.baeldung.com/spring-webflux-concurrency) + +### NOTE: + +## Since this is a module tied to an e-book, it should **not** be moved or used to store the code for any further article. diff --git a/spring-reactive-modules/spring-reactive/pom.xml b/spring-reactive-modules/spring-reactive/pom.xml index f843e04c7b..f19809e302 100644 --- a/spring-reactive-modules/spring-reactive/pom.xml +++ b/spring-reactive-modules/spring-reactive/pom.xml @@ -4,71 +4,40 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 spring-reactive - 0.0.1-SNAPSHOT - spring-5-reactive - jar - spring 5 sample project about new features - com.baeldung.spring.reactive - spring-reactive-modules - 1.0.0-SNAPSHOT + com.baeldung + parent-boot-3 + 0.0.1-SNAPSHOT + ../../parent-boot-3 + + org.springframework.boot + spring-boot-starter-webflux + org.springframework.boot spring-boot-starter-validation org.springframework.boot - spring-boot-starter-tomcat + spring-boot-starter-security + + + io.reactivex.rxjava2 + rxjava + ${rxjava.version} + + + io.projectreactor.kafka + reactor-kafka + ${reactor-kafka.version} org.springframework.boot - spring-boot-starter-integration - - - org.springframework.boot - spring-boot-starter-websocket - - - javax.json.bind - javax.json.bind-api - - - org.projectlombok - lombok - compile - - - org.apache.geronimo.specs - geronimo-json_1.1_spec - ${geronimo-json_1.1_spec.version} - - - org.apache.johnzon - johnzon-jsonb - - - - org.apache.commons - commons-lang3 - - - - org.springframework.boot - spring-boot-devtools - runtime - - - org.springframework - spring-test - - - org.springframework.boot - spring-boot-starter-test - test + spring-boot-starter-data-mongodb-reactive org.springframework.security @@ -78,88 +47,66 @@ io.projectreactor reactor-test - test - - - - org.springframework.boot - spring-boot-starter-webflux - - - org.springframework.boot - spring-boot-starter-data-redis - - - org.springframework.boot - spring-boot-starter-security - - - org.springframework.session - spring-session-core - - - org.springframework.session - spring-session-data-redis - - - org.apache.commons - commons-collections4 - ${commons-collections4.version} + ${reactor.version} test - io.reactivex.rxjava2 - rxjava - - - org.apache.httpcomponents - httpclient - - - io.netty - netty-all + org.projectlombok + lombok + + + integration-lite-first + + + + org.apache.maven.plugins + maven-surefire-plugin + + + ${project.basedir}/src/test/resources/logback-test.xml + + + + + + + + integration-lite-second + + + + org.apache.maven.plugins + maven-surefire-plugin + + + ${project.basedir}/src/test/resources/logback-test.xml + + + + + + + + - - maven-resources-plugin - 3.0.1 - - - copy-resources - validate - - copy-resources - - - - - src/main/assets - true - - - ${basedir}/target/classes/assets - - - - org.springframework.boot spring-boot-maven-plugin - com.baeldung.reactive.Spring5ReactiveApplication - JAR + true - 1.1.3 - 1.0 - 1.0 + 3.4.16 + 1.3.10 + 2.2.21 \ No newline at end of file diff --git a/spring-reactive-modules/spring-reactive-webflux/src/main/java/com/baeldung/reactive/concurrency/Application.java b/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/concurrency/Application.java similarity index 100% rename from spring-reactive-modules/spring-reactive-webflux/src/main/java/com/baeldung/reactive/concurrency/Application.java rename to spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/concurrency/Application.java diff --git a/spring-reactive-modules/spring-reactive-webflux/src/main/java/com/baeldung/reactive/concurrency/Controller.java b/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/concurrency/Controller.java similarity index 100% rename from spring-reactive-modules/spring-reactive-webflux/src/main/java/com/baeldung/reactive/concurrency/Controller.java rename to spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/concurrency/Controller.java diff --git a/spring-reactive-modules/spring-reactive-webflux/src/main/java/com/baeldung/reactive/concurrency/Person.java b/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/concurrency/Person.java similarity index 100% rename from spring-reactive-modules/spring-reactive-webflux/src/main/java/com/baeldung/reactive/concurrency/Person.java rename to spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/concurrency/Person.java diff --git a/spring-reactive-modules/spring-reactive-webflux/src/main/java/com/baeldung/reactive/concurrency/PersonRepository.java b/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/concurrency/PersonRepository.java similarity index 100% rename from spring-reactive-modules/spring-reactive-webflux/src/main/java/com/baeldung/reactive/concurrency/PersonRepository.java rename to spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/concurrency/PersonRepository.java diff --git a/spring-reactive-modules/spring-reactive-webflux/src/main/java/com/baeldung/reactive/debugging/consumer/ConsumerDebuggingApplication.java b/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/debugging/consumer/ConsumerDebuggingApplication.java similarity index 100% rename from spring-reactive-modules/spring-reactive-webflux/src/main/java/com/baeldung/reactive/debugging/consumer/ConsumerDebuggingApplication.java rename to spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/debugging/consumer/ConsumerDebuggingApplication.java diff --git a/spring-reactive-modules/spring-reactive-webflux/src/main/java/com/baeldung/reactive/debugging/consumer/controllers/ReactiveConfigsToggleRestController.java b/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/debugging/consumer/controllers/ReactiveConfigsToggleRestController.java similarity index 100% rename from spring-reactive-modules/spring-reactive-webflux/src/main/java/com/baeldung/reactive/debugging/consumer/controllers/ReactiveConfigsToggleRestController.java rename to spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/debugging/consumer/controllers/ReactiveConfigsToggleRestController.java diff --git a/spring-reactive-modules/spring-reactive-webflux/src/main/java/com/baeldung/reactive/debugging/consumer/cronjobs/CronJobs.java b/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/debugging/consumer/cronjobs/CronJobs.java similarity index 100% rename from spring-reactive-modules/spring-reactive-webflux/src/main/java/com/baeldung/reactive/debugging/consumer/cronjobs/CronJobs.java rename to spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/debugging/consumer/cronjobs/CronJobs.java diff --git a/spring-reactive-modules/spring-reactive-webflux/src/main/java/com/baeldung/reactive/debugging/consumer/model/Foo.java b/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/debugging/consumer/model/Foo.java similarity index 100% rename from spring-reactive-modules/spring-reactive-webflux/src/main/java/com/baeldung/reactive/debugging/consumer/model/Foo.java rename to spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/debugging/consumer/model/Foo.java diff --git a/spring-reactive-modules/spring-reactive-webflux/src/main/java/com/baeldung/reactive/debugging/consumer/model/FooDto.java b/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/debugging/consumer/model/FooDto.java similarity index 100% rename from spring-reactive-modules/spring-reactive-webflux/src/main/java/com/baeldung/reactive/debugging/consumer/model/FooDto.java rename to spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/debugging/consumer/model/FooDto.java diff --git a/spring-reactive-modules/spring-reactive-webflux/src/main/java/com/baeldung/reactive/debugging/consumer/service/FooNameHelper.java b/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/debugging/consumer/service/FooNameHelper.java similarity index 100% rename from spring-reactive-modules/spring-reactive-webflux/src/main/java/com/baeldung/reactive/debugging/consumer/service/FooNameHelper.java rename to spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/debugging/consumer/service/FooNameHelper.java diff --git a/spring-reactive-modules/spring-reactive-webflux/src/main/java/com/baeldung/reactive/debugging/consumer/service/FooQuantityHelper.java b/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/debugging/consumer/service/FooQuantityHelper.java similarity index 100% rename from spring-reactive-modules/spring-reactive-webflux/src/main/java/com/baeldung/reactive/debugging/consumer/service/FooQuantityHelper.java rename to spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/debugging/consumer/service/FooQuantityHelper.java diff --git a/spring-reactive-modules/spring-reactive-webflux/src/main/java/com/baeldung/reactive/debugging/consumer/service/FooReporter.java b/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/debugging/consumer/service/FooReporter.java similarity index 100% rename from spring-reactive-modules/spring-reactive-webflux/src/main/java/com/baeldung/reactive/debugging/consumer/service/FooReporter.java rename to spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/debugging/consumer/service/FooReporter.java diff --git a/spring-reactive-modules/spring-reactive-webflux/src/main/java/com/baeldung/reactive/debugging/consumer/service/FooService.java b/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/debugging/consumer/service/FooService.java similarity index 100% rename from spring-reactive-modules/spring-reactive-webflux/src/main/java/com/baeldung/reactive/debugging/consumer/service/FooService.java rename to spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/debugging/consumer/service/FooService.java diff --git a/spring-reactive-modules/spring-reactive-webflux/src/main/java/com/baeldung/reactive/debugging/server/ServerDebuggingApplication.java b/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/debugging/server/ServerDebuggingApplication.java similarity index 100% rename from spring-reactive-modules/spring-reactive-webflux/src/main/java/com/baeldung/reactive/debugging/server/ServerDebuggingApplication.java rename to spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/debugging/server/ServerDebuggingApplication.java diff --git a/spring-reactive-modules/spring-reactive-webflux/src/main/java/com/baeldung/reactive/debugging/server/handlers/ServerHandler.java b/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/debugging/server/handlers/ServerHandler.java similarity index 100% rename from spring-reactive-modules/spring-reactive-webflux/src/main/java/com/baeldung/reactive/debugging/server/handlers/ServerHandler.java rename to spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/debugging/server/handlers/ServerHandler.java diff --git a/spring-reactive-modules/spring-reactive-webflux/src/main/java/com/baeldung/reactive/debugging/server/model/Foo.java b/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/debugging/server/model/Foo.java similarity index 100% rename from spring-reactive-modules/spring-reactive-webflux/src/main/java/com/baeldung/reactive/debugging/server/model/Foo.java rename to spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/debugging/server/model/Foo.java diff --git a/spring-reactive-modules/spring-reactive-webflux/src/main/java/com/baeldung/reactive/debugging/server/routers/ServerRouter.java b/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/debugging/server/routers/ServerRouter.java similarity index 100% rename from spring-reactive-modules/spring-reactive-webflux/src/main/java/com/baeldung/reactive/debugging/server/routers/ServerRouter.java rename to spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/debugging/server/routers/ServerRouter.java diff --git a/spring-reactive-modules/spring-reactive-exceptions/src/main/java/com/baeldung/spring/reactive/errorhandling/ErrorHandlingApplication.java b/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/errorhandling/ErrorHandlingApplication.java similarity index 93% rename from spring-reactive-modules/spring-reactive-exceptions/src/main/java/com/baeldung/spring/reactive/errorhandling/ErrorHandlingApplication.java rename to spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/errorhandling/ErrorHandlingApplication.java index c34f86febd..50579d8721 100644 --- a/spring-reactive-modules/spring-reactive-exceptions/src/main/java/com/baeldung/spring/reactive/errorhandling/ErrorHandlingApplication.java +++ b/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/errorhandling/ErrorHandlingApplication.java @@ -1,4 +1,4 @@ -package com.baeldung.spring.reactive.errorhandling; +package com.baeldung.reactive.errorhandling; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; diff --git a/spring-reactive-modules/spring-reactive-exceptions/src/main/java/com/baeldung/spring/reactive/errorhandling/GlobalErrorAttributes.java b/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/errorhandling/GlobalErrorAttributes.java similarity index 93% rename from spring-reactive-modules/spring-reactive-exceptions/src/main/java/com/baeldung/spring/reactive/errorhandling/GlobalErrorAttributes.java rename to spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/errorhandling/GlobalErrorAttributes.java index 9dce1b3e5b..549ae749f2 100644 --- a/spring-reactive-modules/spring-reactive-exceptions/src/main/java/com/baeldung/spring/reactive/errorhandling/GlobalErrorAttributes.java +++ b/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/errorhandling/GlobalErrorAttributes.java @@ -1,4 +1,4 @@ -package com.baeldung.spring.reactive.errorhandling; +package com.baeldung.reactive.errorhandling; import java.util.Map; diff --git a/spring-reactive-modules/spring-reactive-exceptions/src/main/java/com/baeldung/spring/reactive/errorhandling/GlobalErrorWebExceptionHandler.java b/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/errorhandling/GlobalErrorWebExceptionHandler.java similarity index 97% rename from spring-reactive-modules/spring-reactive-exceptions/src/main/java/com/baeldung/spring/reactive/errorhandling/GlobalErrorWebExceptionHandler.java rename to spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/errorhandling/GlobalErrorWebExceptionHandler.java index bfd3bba2a1..69f9a0420e 100644 --- a/spring-reactive-modules/spring-reactive-exceptions/src/main/java/com/baeldung/spring/reactive/errorhandling/GlobalErrorWebExceptionHandler.java +++ b/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/errorhandling/GlobalErrorWebExceptionHandler.java @@ -1,4 +1,4 @@ -package com.baeldung.spring.reactive.errorhandling; +package com.baeldung.reactive.errorhandling; import java.util.Map; diff --git a/spring-reactive-modules/spring-reactive-exceptions/src/main/java/com/baeldung/spring/reactive/errorhandling/Handler.java b/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/errorhandling/Handler.java similarity index 97% rename from spring-reactive-modules/spring-reactive-exceptions/src/main/java/com/baeldung/spring/reactive/errorhandling/Handler.java rename to spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/errorhandling/Handler.java index 2956cc1686..f9e4ee4c35 100644 --- a/spring-reactive-modules/spring-reactive-exceptions/src/main/java/com/baeldung/spring/reactive/errorhandling/Handler.java +++ b/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/errorhandling/Handler.java @@ -1,4 +1,4 @@ -package com.baeldung.spring.reactive.errorhandling; +package com.baeldung.reactive.errorhandling; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; diff --git a/spring-reactive-modules/spring-reactive-exceptions/src/main/java/com/baeldung/spring/reactive/errorhandling/NameRequiredException.java b/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/errorhandling/NameRequiredException.java similarity index 85% rename from spring-reactive-modules/spring-reactive-exceptions/src/main/java/com/baeldung/spring/reactive/errorhandling/NameRequiredException.java rename to spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/errorhandling/NameRequiredException.java index 1926d6416a..bdc7771b80 100644 --- a/spring-reactive-modules/spring-reactive-exceptions/src/main/java/com/baeldung/spring/reactive/errorhandling/NameRequiredException.java +++ b/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/errorhandling/NameRequiredException.java @@ -1,4 +1,4 @@ -package com.baeldung.spring.reactive.errorhandling; +package com.baeldung.reactive.errorhandling; import org.springframework.http.HttpStatus; import org.springframework.web.server.ResponseStatusException; diff --git a/spring-reactive-modules/spring-reactive-exceptions/src/main/java/com/baeldung/spring/reactive/errorhandling/Router.java b/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/errorhandling/Router.java similarity index 96% rename from spring-reactive-modules/spring-reactive-exceptions/src/main/java/com/baeldung/spring/reactive/errorhandling/Router.java rename to spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/errorhandling/Router.java index c65b645f09..aeea202c31 100644 --- a/spring-reactive-modules/spring-reactive-exceptions/src/main/java/com/baeldung/spring/reactive/errorhandling/Router.java +++ b/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/errorhandling/Router.java @@ -1,4 +1,4 @@ -package com.baeldung.spring.reactive.errorhandling; +package com.baeldung.reactive.errorhandling; import static org.springframework.http.MediaType.TEXT_PLAIN; import static org.springframework.web.reactive.function.server.RequestPredicates.GET; diff --git a/spring-reactive-modules/spring-reactive-webflux/src/main/java/com/baeldung/reactive/security/GreetingController.java b/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/security/GreetingController.java similarity index 100% rename from spring-reactive-modules/spring-reactive-webflux/src/main/java/com/baeldung/reactive/security/GreetingController.java rename to spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/security/GreetingController.java diff --git a/spring-reactive-modules/spring-reactive-webflux/src/main/java/com/baeldung/reactive/security/GreetingService.java b/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/security/GreetingService.java similarity index 100% rename from spring-reactive-modules/spring-reactive-webflux/src/main/java/com/baeldung/reactive/security/GreetingService.java rename to spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/security/GreetingService.java diff --git a/spring-reactive-modules/spring-reactive-webflux/src/main/java/com/baeldung/reactive/security/SecurityConfig.java b/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/security/SecurityConfig.java similarity index 100% rename from spring-reactive-modules/spring-reactive-webflux/src/main/java/com/baeldung/reactive/security/SecurityConfig.java rename to spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/security/SecurityConfig.java diff --git a/spring-reactive-modules/spring-reactive-webflux/src/main/java/com/baeldung/reactive/security/SpringSecurity6Application.java b/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/security/SpringSecurity6Application.java similarity index 100% rename from spring-reactive-modules/spring-reactive-webflux/src/main/java/com/baeldung/reactive/security/SpringSecurity6Application.java rename to spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/security/SpringSecurity6Application.java diff --git a/spring-reactive-modules/spring-reactive-webflux/src/main/java/com/baeldung/reactive/webclient/Foo.java b/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/webclient/Foo.java similarity index 100% rename from spring-reactive-modules/spring-reactive-webflux/src/main/java/com/baeldung/reactive/webclient/Foo.java rename to spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/webclient/Foo.java diff --git a/spring-reactive-modules/spring-reactive-webflux/src/main/java/com/baeldung/reactive/webclient/Tweet.java b/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/webclient/Tweet.java similarity index 100% rename from spring-reactive-modules/spring-reactive-webflux/src/main/java/com/baeldung/reactive/webclient/Tweet.java rename to spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/webclient/Tweet.java diff --git a/spring-reactive-modules/spring-reactive-webflux/src/main/java/com/baeldung/reactive/webclient/TweetsSlowServiceController.java b/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/webclient/TweetsSlowServiceController.java similarity index 100% rename from spring-reactive-modules/spring-reactive-webflux/src/main/java/com/baeldung/reactive/webclient/TweetsSlowServiceController.java rename to spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/webclient/TweetsSlowServiceController.java diff --git a/spring-reactive-modules/spring-reactive-webflux/src/main/java/com/baeldung/reactive/webclient/WebClientApplication.java b/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/webclient/WebClientApplication.java similarity index 100% rename from spring-reactive-modules/spring-reactive-webflux/src/main/java/com/baeldung/reactive/webclient/WebClientApplication.java rename to spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/webclient/WebClientApplication.java diff --git a/spring-reactive-modules/spring-reactive-webflux/src/main/java/com/baeldung/reactive/webclient/WebClientController.java b/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/webclient/WebClientController.java similarity index 100% rename from spring-reactive-modules/spring-reactive-webflux/src/main/java/com/baeldung/reactive/webclient/WebClientController.java rename to spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/webclient/WebClientController.java diff --git a/spring-reactive-modules/spring-reactive-webflux/src/main/java/com/baeldung/reactive/webclient/WebController.java b/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/webclient/WebController.java similarity index 100% rename from spring-reactive-modules/spring-reactive-webflux/src/main/java/com/baeldung/reactive/webclient/WebController.java rename to spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/webclient/WebController.java diff --git a/spring-reactive-modules/spring-reactive-webflux/src/main/java/com/baeldung/reactive/webclientrequests/SpringWebClientRequestsApp.java b/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/webclientrequests/SpringWebClientRequestsApp.java similarity index 100% rename from spring-reactive-modules/spring-reactive-webflux/src/main/java/com/baeldung/reactive/webclientrequests/SpringWebClientRequestsApp.java rename to spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/webclientrequests/SpringWebClientRequestsApp.java diff --git a/spring-reactive-modules/spring-reactive-webflux/src/main/java/com/baeldung/reactive/webflux/Employee.java b/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/webflux/Employee.java similarity index 100% rename from spring-reactive-modules/spring-reactive-webflux/src/main/java/com/baeldung/reactive/webflux/Employee.java rename to spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/webflux/Employee.java diff --git a/spring-reactive-modules/spring-reactive-webflux/src/main/java/com/baeldung/reactive/webflux/EmployeeRepository.java b/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/webflux/EmployeeRepository.java similarity index 100% rename from spring-reactive-modules/spring-reactive-webflux/src/main/java/com/baeldung/reactive/webflux/EmployeeRepository.java rename to spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/webflux/EmployeeRepository.java diff --git a/spring-reactive-modules/spring-reactive-webflux/src/main/java/com/baeldung/reactive/webflux/annotation/EmployeeController.java b/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/webflux/annotation/EmployeeController.java similarity index 100% rename from spring-reactive-modules/spring-reactive-webflux/src/main/java/com/baeldung/reactive/webflux/annotation/EmployeeController.java rename to spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/webflux/annotation/EmployeeController.java diff --git a/spring-reactive-modules/spring-reactive-webflux/src/main/java/com/baeldung/reactive/webflux/annotation/EmployeeSpringApplication.java b/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/webflux/annotation/EmployeeSpringApplication.java similarity index 100% rename from spring-reactive-modules/spring-reactive-webflux/src/main/java/com/baeldung/reactive/webflux/annotation/EmployeeSpringApplication.java rename to spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/webflux/annotation/EmployeeSpringApplication.java diff --git a/spring-reactive-modules/spring-reactive-webflux/src/main/java/com/baeldung/reactive/webflux/annotation/EmployeeWebClient.java b/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/webflux/annotation/EmployeeWebClient.java similarity index 100% rename from spring-reactive-modules/spring-reactive-webflux/src/main/java/com/baeldung/reactive/webflux/annotation/EmployeeWebClient.java rename to spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/webflux/annotation/EmployeeWebClient.java diff --git a/spring-reactive-modules/spring-reactive-webflux/src/main/java/com/baeldung/reactive/webflux/annotation/EmployeeWebSecurityConfig.java b/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/webflux/annotation/EmployeeWebSecurityConfig.java similarity index 100% rename from spring-reactive-modules/spring-reactive-webflux/src/main/java/com/baeldung/reactive/webflux/annotation/EmployeeWebSecurityConfig.java rename to spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/webflux/annotation/EmployeeWebSecurityConfig.java diff --git a/spring-reactive-modules/spring-reactive-webflux/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 similarity index 100% rename from spring-reactive-modules/spring-reactive-webflux/src/main/java/com/baeldung/reactive/webflux/functional/EmployeeFunctionalConfig.java rename to spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/webflux/functional/EmployeeFunctionalConfig.java diff --git a/spring-reactive-modules/spring-reactive-webflux/src/main/java/com/baeldung/reactive/webflux/functional/EmployeeSpringFunctionalApplication.java b/spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/webflux/functional/EmployeeSpringFunctionalApplication.java similarity index 100% rename from spring-reactive-modules/spring-reactive-webflux/src/main/java/com/baeldung/reactive/webflux/functional/EmployeeSpringFunctionalApplication.java rename to spring-reactive-modules/spring-reactive/src/main/java/com/baeldung/reactive/webflux/functional/EmployeeSpringFunctionalApplication.java diff --git a/spring-reactive-modules/spring-reactive-webflux/src/test/java/com/baeldung/reactive/debugging/consumer/ConsumerFooServiceIntegrationTest.java b/spring-reactive-modules/spring-reactive/src/test/java/com/baeldung/reactive/debugging/consumer/ConsumerFooServiceIntegrationTest.java similarity index 100% rename from spring-reactive-modules/spring-reactive-webflux/src/test/java/com/baeldung/reactive/debugging/consumer/ConsumerFooServiceIntegrationTest.java rename to spring-reactive-modules/spring-reactive/src/test/java/com/baeldung/reactive/debugging/consumer/ConsumerFooServiceIntegrationTest.java diff --git a/spring-reactive-modules/spring-reactive-webflux/src/test/java/com/baeldung/reactive/debugging/consumer/ConsumerFooServiceLiveTest.java b/spring-reactive-modules/spring-reactive/src/test/java/com/baeldung/reactive/debugging/consumer/ConsumerFooServiceLiveTest.java similarity index 100% rename from spring-reactive-modules/spring-reactive-webflux/src/test/java/com/baeldung/reactive/debugging/consumer/ConsumerFooServiceLiveTest.java rename to spring-reactive-modules/spring-reactive/src/test/java/com/baeldung/reactive/debugging/consumer/ConsumerFooServiceLiveTest.java diff --git a/spring-reactive-modules/spring-reactive-webflux/src/test/java/com/baeldung/reactive/debugging/consumer/utils/ListAppender.java b/spring-reactive-modules/spring-reactive/src/test/java/com/baeldung/reactive/debugging/consumer/utils/ListAppender.java similarity index 100% rename from spring-reactive-modules/spring-reactive-webflux/src/test/java/com/baeldung/reactive/debugging/consumer/utils/ListAppender.java rename to spring-reactive-modules/spring-reactive/src/test/java/com/baeldung/reactive/debugging/consumer/utils/ListAppender.java diff --git a/spring-reactive-modules/spring-reactive-exceptions/src/test/java/com/baeldung/spring/reactive/errorhandling/ErrorHandlingIntegrationTest.java b/spring-reactive-modules/spring-reactive/src/test/java/com/baeldung/reactive/errorhandling/ErrorHandlingIntegrationTest.java similarity index 98% rename from spring-reactive-modules/spring-reactive-exceptions/src/test/java/com/baeldung/spring/reactive/errorhandling/ErrorHandlingIntegrationTest.java rename to spring-reactive-modules/spring-reactive/src/test/java/com/baeldung/reactive/errorhandling/ErrorHandlingIntegrationTest.java index 972eefa5ac..0068379d61 100644 --- a/spring-reactive-modules/spring-reactive-exceptions/src/test/java/com/baeldung/spring/reactive/errorhandling/ErrorHandlingIntegrationTest.java +++ b/spring-reactive-modules/spring-reactive/src/test/java/com/baeldung/reactive/errorhandling/ErrorHandlingIntegrationTest.java @@ -1,4 +1,4 @@ -package com.baeldung.spring.reactive.errorhandling; +package com.baeldung.reactive.errorhandling; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; diff --git a/spring-reactive-modules/spring-reactive-webflux/src/test/java/com/baeldung/reactive/introduction/ReactorIntegrationTest.java b/spring-reactive-modules/spring-reactive/src/test/java/com/baeldung/reactive/introduction/ReactorIntegrationTest.java similarity index 100% rename from spring-reactive-modules/spring-reactive-webflux/src/test/java/com/baeldung/reactive/introduction/ReactorIntegrationTest.java rename to spring-reactive-modules/spring-reactive/src/test/java/com/baeldung/reactive/introduction/ReactorIntegrationTest.java diff --git a/spring-reactive-modules/spring-reactive-webflux/src/test/java/com/baeldung/reactive/security/SecurityIntegrationTest.java b/spring-reactive-modules/spring-reactive/src/test/java/com/baeldung/reactive/security/SecurityIntegrationTest.java similarity index 100% rename from spring-reactive-modules/spring-reactive-webflux/src/test/java/com/baeldung/reactive/security/SecurityIntegrationTest.java rename to spring-reactive-modules/spring-reactive/src/test/java/com/baeldung/reactive/security/SecurityIntegrationTest.java diff --git a/spring-reactive-modules/spring-reactive-webflux/src/test/java/com/baeldung/reactive/webclient/SpringContextTest.java b/spring-reactive-modules/spring-reactive/src/test/java/com/baeldung/reactive/webclient/SpringContextTest.java similarity index 100% rename from spring-reactive-modules/spring-reactive-webflux/src/test/java/com/baeldung/reactive/webclient/SpringContextTest.java rename to spring-reactive-modules/spring-reactive/src/test/java/com/baeldung/reactive/webclient/SpringContextTest.java diff --git a/spring-reactive-modules/spring-reactive-webflux/src/test/java/com/baeldung/reactive/webclient/WebClientIntegrationTest.java b/spring-reactive-modules/spring-reactive/src/test/java/com/baeldung/reactive/webclient/WebClientIntegrationTest.java similarity index 100% rename from spring-reactive-modules/spring-reactive-webflux/src/test/java/com/baeldung/reactive/webclient/WebClientIntegrationTest.java rename to spring-reactive-modules/spring-reactive/src/test/java/com/baeldung/reactive/webclient/WebClientIntegrationTest.java diff --git a/spring-reactive-modules/spring-reactive-webflux/src/test/java/com/baeldung/reactive/webclient/WebControllerIntegrationTest.java b/spring-reactive-modules/spring-reactive/src/test/java/com/baeldung/reactive/webclient/WebControllerIntegrationTest.java similarity index 100% rename from spring-reactive-modules/spring-reactive-webflux/src/test/java/com/baeldung/reactive/webclient/WebControllerIntegrationTest.java rename to spring-reactive-modules/spring-reactive/src/test/java/com/baeldung/reactive/webclient/WebControllerIntegrationTest.java diff --git a/spring-reactive-modules/spring-reactive-webflux/src/test/java/com/baeldung/reactive/webclient/WebTestClientIntegrationTest.java b/spring-reactive-modules/spring-reactive/src/test/java/com/baeldung/reactive/webclient/WebTestClientIntegrationTest.java similarity index 100% rename from spring-reactive-modules/spring-reactive-webflux/src/test/java/com/baeldung/reactive/webclient/WebTestClientIntegrationTest.java rename to spring-reactive-modules/spring-reactive/src/test/java/com/baeldung/reactive/webclient/WebTestClientIntegrationTest.java diff --git a/spring-reactive-modules/spring-reactive-webflux/src/test/java/com/baeldung/reactive/webclientrequests/WebClientRequestsWithParametersUnitTest.java b/spring-reactive-modules/spring-reactive/src/test/java/com/baeldung/reactive/webclientrequests/WebClientRequestsWithParametersUnitTest.java similarity index 100% rename from spring-reactive-modules/spring-reactive-webflux/src/test/java/com/baeldung/reactive/webclientrequests/WebClientRequestsWithParametersUnitTest.java rename to spring-reactive-modules/spring-reactive/src/test/java/com/baeldung/reactive/webclientrequests/WebClientRequestsWithParametersUnitTest.java diff --git a/spring-reactive-modules/spring-reactive-webflux/src/test/java/com/baeldung/reactive/webflux/annotation/EmployeeControllerIntegrationTest.java b/spring-reactive-modules/spring-reactive/src/test/java/com/baeldung/reactive/webflux/annotation/EmployeeControllerIntegrationTest.java similarity index 100% rename from spring-reactive-modules/spring-reactive-webflux/src/test/java/com/baeldung/reactive/webflux/annotation/EmployeeControllerIntegrationTest.java rename to spring-reactive-modules/spring-reactive/src/test/java/com/baeldung/reactive/webflux/annotation/EmployeeControllerIntegrationTest.java diff --git a/spring-reactive-modules/spring-reactive-webflux/src/test/java/com/baeldung/reactive/webflux/functional/EmployeeSpringFunctionalIntegrationTest.java b/spring-reactive-modules/spring-reactive/src/test/java/com/baeldung/reactive/webflux/functional/EmployeeSpringFunctionalIntegrationTest.java similarity index 100% rename from spring-reactive-modules/spring-reactive-webflux/src/test/java/com/baeldung/reactive/webflux/functional/EmployeeSpringFunctionalIntegrationTest.java rename to spring-reactive-modules/spring-reactive/src/test/java/com/baeldung/reactive/webflux/functional/EmployeeSpringFunctionalIntegrationTest.java diff --git a/spring-reactive-modules/spring-reactive-webflux/src/test/resources/logback-test.xml b/spring-reactive-modules/spring-reactive/src/test/resources/logback-test.xml similarity index 100% rename from spring-reactive-modules/spring-reactive-webflux/src/test/resources/logback-test.xml rename to spring-reactive-modules/spring-reactive/src/test/resources/logback-test.xml diff --git a/testing-modules/junit-5-advanced/README.md b/testing-modules/junit-5-advanced/README.md index a89bcd2de2..873ab0835b 100644 --- a/testing-modules/junit-5-advanced/README.md +++ b/testing-modules/junit-5-advanced/README.md @@ -9,3 +9,4 @@ - [JUnit – Testing Methods That Call System.exit()](https://www.baeldung.com/junit-system-exit) - [Single Assert Call for Multiple Properties in Java Unit Testing](https://www.baeldung.com/java-testing-single-assert-multiple-properties) - [Creating a Test Suite With JUnit](https://www.baeldung.com/java-junit-test-suite) +- [Testing Interface Contract in Java](https://www.baeldung.com/java-junit-verify-interface-contract) diff --git a/testing-modules/junit-5-advanced/src/main/java/com/baeldung/interfaces/unittest/Circle.java b/testing-modules/junit-5-advanced/src/main/java/com/baeldung/interfaces/unittest/Circle.java new file mode 100644 index 0000000000..b0e63155f4 --- /dev/null +++ b/testing-modules/junit-5-advanced/src/main/java/com/baeldung/interfaces/unittest/Circle.java @@ -0,0 +1,19 @@ +package com.baeldung.interfaces.unittest; + +public class Circle implements Shape { + + private double radius; + + Circle(double radius) { + this.radius = radius; + } + + @Override + public double area() { + return 3.14 * radius * radius; + } + + public double circumference() { + return 2 * 3.14 * radius; + } +} diff --git a/testing-modules/junit-5-advanced/src/main/java/com/baeldung/interfaces/unittest/Rectangle.java b/testing-modules/junit-5-advanced/src/main/java/com/baeldung/interfaces/unittest/Rectangle.java new file mode 100644 index 0000000000..a88233e83b --- /dev/null +++ b/testing-modules/junit-5-advanced/src/main/java/com/baeldung/interfaces/unittest/Rectangle.java @@ -0,0 +1,21 @@ +package com.baeldung.interfaces.unittest; + +public class Rectangle implements Shape { + + private double length; + private double breadth; + + public Rectangle(double length, double breadth) { + this.length = length; + this.breadth = breadth; + } + + @Override + public double area() { + return length * breadth; + } + + public double perimeter() { + return 2 * (length + breadth); + } +} diff --git a/testing-modules/junit-5-advanced/src/main/java/com/baeldung/interfaces/unittest/Shape.java b/testing-modules/junit-5-advanced/src/main/java/com/baeldung/interfaces/unittest/Shape.java new file mode 100644 index 0000000000..bac42fb246 --- /dev/null +++ b/testing-modules/junit-5-advanced/src/main/java/com/baeldung/interfaces/unittest/Shape.java @@ -0,0 +1,6 @@ +package com.baeldung.interfaces.unittest; + +public interface Shape { + + double area(); +} diff --git a/testing-modules/junit-5-advanced/src/test/java/com/baeldung/interfaces/unittest/CircleExtendsBaseUnitTest.java b/testing-modules/junit-5-advanced/src/test/java/com/baeldung/interfaces/unittest/CircleExtendsBaseUnitTest.java new file mode 100644 index 0000000000..08ce2bc779 --- /dev/null +++ b/testing-modules/junit-5-advanced/src/test/java/com/baeldung/interfaces/unittest/CircleExtendsBaseUnitTest.java @@ -0,0 +1,26 @@ +package com.baeldung.interfaces.unittest; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.HashMap; +import java.util.Map; + +import org.junit.jupiter.api.Test; + +class CircleExtendsBaseUnitTest extends ShapeUnitTest { + + @Override + public Map instantiateShapeWithExpectedArea() { + Map shapeAreaMap = new HashMap<>(); + shapeAreaMap.put("shape", new Circle(5)); + shapeAreaMap.put("area", 78.5); + return shapeAreaMap; + } + + @Test + void whenCircumferenceIsCalculated_thenSuccessful() { + Circle circle = new Circle(2); + double circumference = circle.circumference(); + assertEquals(12.56, circumference); + } +} \ No newline at end of file diff --git a/testing-modules/junit-5-advanced/src/test/java/com/baeldung/interfaces/unittest/CircleUnitTest.java b/testing-modules/junit-5-advanced/src/test/java/com/baeldung/interfaces/unittest/CircleUnitTest.java new file mode 100644 index 0000000000..c0b4eecedc --- /dev/null +++ b/testing-modules/junit-5-advanced/src/test/java/com/baeldung/interfaces/unittest/CircleUnitTest.java @@ -0,0 +1,22 @@ +package com.baeldung.interfaces.unittest; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; + +class CircleUnitTest { + + @Test + void whenAreaIsCalculated_thenSuccessful() { + Shape circle = new Circle(5); + double area = circle.area(); + assertEquals(78.5, area); + } + + @Test + void whenCircumferenceIsCalculated_thenSuccessful() { + Circle circle = new Circle(2); + double circumference = circle.circumference(); + assertEquals(12.56, circumference); + } +} \ No newline at end of file diff --git a/testing-modules/junit-5-advanced/src/test/java/com/baeldung/interfaces/unittest/ParameterizedUnitTest.java b/testing-modules/junit-5-advanced/src/test/java/com/baeldung/interfaces/unittest/ParameterizedUnitTest.java new file mode 100644 index 0000000000..6b5cd6b6ab --- /dev/null +++ b/testing-modules/junit-5-advanced/src/test/java/com/baeldung/interfaces/unittest/ParameterizedUnitTest.java @@ -0,0 +1,27 @@ +package com.baeldung.interfaces.unittest; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.Arrays; +import java.util.Collection; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +public class ParameterizedUnitTest { + + @ParameterizedTest + @MethodSource("data") + void givenShapeInstance_whenAreaIsCalculated_thenSuccessful(Shape shapeInstance, double expectedArea) { + double area = shapeInstance.area(); + assertEquals(expectedArea, area); + + } + + private static Collection data() { + return Arrays.asList(new Object[][] { + { new Circle(5), 78.5 }, + { new Rectangle(4, 5), 20 } + }); + } +} diff --git a/testing-modules/junit-5-advanced/src/test/java/com/baeldung/interfaces/unittest/RectangleExtendsBaseUnitTest.java b/testing-modules/junit-5-advanced/src/test/java/com/baeldung/interfaces/unittest/RectangleExtendsBaseUnitTest.java new file mode 100644 index 0000000000..b6771ad648 --- /dev/null +++ b/testing-modules/junit-5-advanced/src/test/java/com/baeldung/interfaces/unittest/RectangleExtendsBaseUnitTest.java @@ -0,0 +1,26 @@ +package com.baeldung.interfaces.unittest; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.HashMap; +import java.util.Map; + +import org.junit.jupiter.api.Test; + +class RectangleExtendsBaseUnitTest extends ShapeUnitTest { + + @Override + public Map instantiateShapeWithExpectedArea() { + Map shapeAreaMap = new HashMap<>(); + shapeAreaMap.put("shape", new Rectangle(5, 4)); + shapeAreaMap.put("area", 20.0); + return shapeAreaMap; + } + + @Test + void whenPerimeterIsCalculated_thenSuccessful() { + Rectangle rectangle = new Rectangle(5, 4); + double perimeter = rectangle.perimeter(); + assertEquals(18, perimeter); + } +} \ No newline at end of file diff --git a/testing-modules/junit-5-advanced/src/test/java/com/baeldung/interfaces/unittest/RectangleUnitTest.java b/testing-modules/junit-5-advanced/src/test/java/com/baeldung/interfaces/unittest/RectangleUnitTest.java new file mode 100644 index 0000000000..1983353667 --- /dev/null +++ b/testing-modules/junit-5-advanced/src/test/java/com/baeldung/interfaces/unittest/RectangleUnitTest.java @@ -0,0 +1,22 @@ +package com.baeldung.interfaces.unittest; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; + +class RectangleUnitTest { + + @Test + void whenAreaIsCalculated_thenSuccessful() { + Shape rectangle = new Rectangle(5, 4); + double area = rectangle.area(); + assertEquals(20, area); + } + + @Test + void whenPerimeterIsCalculated_thenSuccessful() { + Rectangle rectangle = new Rectangle(5, 4); + double perimeter = rectangle.perimeter(); + assertEquals(18, perimeter); + } +} \ No newline at end of file diff --git a/testing-modules/junit-5-advanced/src/test/java/com/baeldung/interfaces/unittest/ShapeUnitTest.java b/testing-modules/junit-5-advanced/src/test/java/com/baeldung/interfaces/unittest/ShapeUnitTest.java new file mode 100644 index 0000000000..a9d318f698 --- /dev/null +++ b/testing-modules/junit-5-advanced/src/test/java/com/baeldung/interfaces/unittest/ShapeUnitTest.java @@ -0,0 +1,21 @@ +package com.baeldung.interfaces.unittest; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.Map; + +import org.junit.jupiter.api.Test; + +public abstract class ShapeUnitTest { + + public abstract Map instantiateShapeWithExpectedArea(); + + @Test + void givenShapeInstance_whenAreaIsCalculated_thenSuccessful() { + Map shapeAreaMap = instantiateShapeWithExpectedArea(); + Shape shape = (Shape) shapeAreaMap.get("shape"); + double expectedArea = (double) shapeAreaMap.get("area"); + double area = shape.area(); + assertEquals(expectedArea, area); + } +} diff --git a/testing-modules/mockito-2/README.md b/testing-modules/mockito-2/README.md index b60885c6d5..da8f339e56 100644 --- a/testing-modules/mockito-2/README.md +++ b/testing-modules/mockito-2/README.md @@ -8,3 +8,4 @@ This module contains articles about Mockito - [Matching Null With Mockito](https://www.baeldung.com/mockito-match-null) - [Mock Same Method with Different Parameters](https://www.baeldung.com/java-mock-same-method-other-parameters) - [How to Mock Constructors for Unit Testing using Mockito](https://www.baeldung.com/java-mockito-constructors-unit-testing) +- [Overview of Mockito MockedConstruction](https://www.baeldung.com/java-mockito-mockedconstruction)