diff --git a/algorithms-genetic/pom.xml b/algorithms-genetic/pom.xml index 1c9224aff2..00c9b88dfe 100644 --- a/algorithms-genetic/pom.xml +++ b/algorithms-genetic/pom.xml @@ -50,4 +50,4 @@ 1.11 - + \ No newline at end of file diff --git a/algorithms-miscellaneous-5/src/test/java/com/baeldung/algorithms/prim/PrimUnitTest.java b/algorithms-miscellaneous-5/src/test/java/com/baeldung/algorithms/prim/PrimUnitTest.java index 41e53fc9f2..fac3b3a81f 100644 --- a/algorithms-miscellaneous-5/src/test/java/com/baeldung/algorithms/prim/PrimUnitTest.java +++ b/algorithms-miscellaneous-5/src/test/java/com/baeldung/algorithms/prim/PrimUnitTest.java @@ -1,10 +1,10 @@ package com.baeldung.algorithms.prim; +import org.junit.Test; + import java.util.ArrayList; import java.util.List; -import org.junit.Test; - public class PrimUnitTest { @Test diff --git a/algorithms-searching/src/main/java/com/baeldung/algorithms/dfs/Graph.java b/algorithms-searching/src/main/java/com/baeldung/algorithms/dfs/Graph.java index d2cc723cf9..4623dbb7a4 100644 --- a/algorithms-searching/src/main/java/com/baeldung/algorithms/dfs/Graph.java +++ b/algorithms-searching/src/main/java/com/baeldung/algorithms/dfs/Graph.java @@ -29,11 +29,13 @@ public class Graph { stack.push(start); while (!stack.isEmpty()) { int current = stack.pop(); - isVisited[current] = true; - visit(current); - for (int dest : adjVertices.get(current)) { - if (!isVisited[dest]) - stack.push(dest); + if(!isVisited[current]){ + isVisited[current] = true; + visit(current); + for (int dest : adjVertices.get(current)) { + if (!isVisited[dest]) + stack.push(dest); + } } } } diff --git a/algorithms-searching/src/main/java/com/baeldung/algorithms/suffixtree/SuffixTree.java b/algorithms-searching/src/main/java/com/baeldung/algorithms/suffixtree/SuffixTree.java index eb58c2bfab..b6b29ede78 100644 --- a/algorithms-searching/src/main/java/com/baeldung/algorithms/suffixtree/SuffixTree.java +++ b/algorithms-searching/src/main/java/com/baeldung/algorithms/suffixtree/SuffixTree.java @@ -8,7 +8,9 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class SuffixTree { + private static final Logger LOGGER = LoggerFactory.getLogger(SuffixTree.class); + private static final String WORD_TERMINATION = "$"; private static final int POSITION_UNDEFINED = -1; private Node root; @@ -23,7 +25,7 @@ public class SuffixTree { } public List searchText(String pattern) { - LOGGER.info("Searching for pattern \"{}\"", pattern); + LOGGER.debug("Searching for pattern \"{}\"", pattern); List result = new ArrayList<>(); List nodes = getAllNodesInTraversePath(pattern, root, false); @@ -41,11 +43,11 @@ public class SuffixTree { } private void addSuffix(String suffix, int position) { - LOGGER.info(">>>>>>>>>>>> Adding new suffix {}", suffix); + LOGGER.debug(">>>>>>>>>>>> Adding new suffix {}", suffix); List nodes = getAllNodesInTraversePath(suffix, root, true); if (nodes.size() == 0) { addChildNode(root, suffix, position); - LOGGER.info("{}", printTree()); + LOGGER.debug("{}", printTree()); } else { Node lastNode = nodes.remove(nodes.size() - 1); String newText = suffix; @@ -58,7 +60,7 @@ public class SuffixTree { newText = newText.substring(existingSuffixUptoLastNode.length()); } extendNode(lastNode, newText, position); - LOGGER.info("{}", printTree()); + LOGGER.debug("{}", printTree()); } } diff --git a/algorithms-searching/src/test/java/com/baeldung/algorithms/dfs/GraphUnitTest.java b/algorithms-searching/src/test/java/com/baeldung/algorithms/dfs/GraphUnitTest.java index 715bb55fcb..7af25a85ca 100644 --- a/algorithms-searching/src/test/java/com/baeldung/algorithms/dfs/GraphUnitTest.java +++ b/algorithms-searching/src/test/java/com/baeldung/algorithms/dfs/GraphUnitTest.java @@ -2,7 +2,6 @@ package com.baeldung.algorithms.dfs; import java.util.List; -import com.baeldung.algorithms.dfs.Graph; import org.junit.Test; public class GraphUnitTest { diff --git a/algorithms-searching/src/test/java/com/baeldung/algorithms/quadtree/QuadTreeSearchUnitTest.java b/algorithms-searching/src/test/java/com/baeldung/algorithms/quadtree/QuadTreeSearchUnitTest.java index 0b58ae9f14..faf06ced31 100644 --- a/algorithms-searching/src/test/java/com/baeldung/algorithms/quadtree/QuadTreeSearchUnitTest.java +++ b/algorithms-searching/src/test/java/com/baeldung/algorithms/quadtree/QuadTreeSearchUnitTest.java @@ -10,7 +10,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class QuadTreeSearchUnitTest { - + private static final Logger LOGGER = LoggerFactory.getLogger(QuadTreeSearchUnitTest.class); private static QuadTree quadTree; @@ -20,41 +20,41 @@ public class QuadTreeSearchUnitTest { Region area = new Region(0, 0, 400, 400); quadTree = new QuadTree(area); - float[][] points = new float[][] { { 21, 25 }, { 55, 53 }, { 70, 318 }, { 98, 302 }, + float[][] points = new float[][] { { 21, 25 }, { 55, 53 }, { 70, 318 }, { 98, 302 }, { 49, 229 }, { 135, 229 }, { 224, 292 }, { 206, 321 }, { 197, 258 }, { 245, 238 } }; for (int i = 0; i < points.length; i++) { Point point = new Point(points[i][0], points[i][1]); quadTree.addPoint(point); } - LOGGER.info("\n" + quadTree.printTree("")); - LOGGER.info("=============================================="); + LOGGER.debug("\n" + quadTree.printTree("")); + LOGGER.debug("=============================================="); } @Test public void givenQuadTree_whenSearchingForRange_thenReturn1MatchingItem() { Region searchArea = new Region(200, 200, 250, 250); List result = quadTree.search(searchArea, null, ""); - LOGGER.info(result.toString()); - LOGGER.info(quadTree.printSearchTraversePath()); - + LOGGER.debug(result.toString()); + LOGGER.debug(quadTree.printSearchTraversePath()); + Assert.assertEquals(1, result.size()); - Assert.assertArrayEquals(new float[] { 245, 238 }, + Assert.assertArrayEquals(new float[] { 245, 238 }, new float[]{result.get(0).getX(), result.get(0).getY() }, 0); } - + @Test public void givenQuadTree_whenSearchingForRange_thenReturn2MatchingItems() { Region searchArea = new Region(0, 0, 100, 100); List result = quadTree.search(searchArea, null, ""); - LOGGER.info(result.toString()); - LOGGER.info(quadTree.printSearchTraversePath()); - + LOGGER.debug(result.toString()); + LOGGER.debug(quadTree.printSearchTraversePath()); + Assert.assertEquals(2, result.size()); - Assert.assertArrayEquals(new float[] { 21, 25 }, + Assert.assertArrayEquals(new float[] { 21, 25 }, new float[]{result.get(0).getX(), result.get(0).getY() }, 0); - Assert.assertArrayEquals(new float[] { 55, 53 }, + Assert.assertArrayEquals(new float[] { 55, 53 }, new float[]{result.get(1).getX(), result.get(1).getY() }, 0); - + } } diff --git a/apache-kafka/README.md b/apache-kafka/README.md index 5e724f95b6..8a1d748482 100644 --- a/apache-kafka/README.md +++ b/apache-kafka/README.md @@ -3,7 +3,7 @@ This module contains articles about Apache Kafka. ### Relevant articles -- [Kafka Streams vs Kafka Consumer](https://www.baeldung.com/java-kafka-streams-vs-kafka-consumer) +- [Kafka Streams vs. Kafka Consumer](https://www.baeldung.com/java-kafka-streams-vs-kafka-consumer) - [Kafka Topic Creation Using Java](https://www.baeldung.com/kafka-topic-creation) - [Using Kafka MockConsumer](https://www.baeldung.com/kafka-mockconsumer) - [Using Kafka MockProducer](https://www.baeldung.com/kafka-mockproducer) @@ -12,7 +12,8 @@ This module contains articles about Apache Kafka. - [Kafka Connect Example with MQTT and MongoDB](https://www.baeldung.com/kafka-connect-mqtt-mongodb) - [Building a Data Pipeline with Flink and Kafka](https://www.baeldung.com/kafka-flink-data-pipeline) - [Exactly Once Processing in Kafka with Java](https://www.baeldung.com/kafka-exactly-once) +- [Custom Serializers in Apache Kafka](https://www.baeldung.com/kafka-custom-serializer) ##### Building the project -You can build the project from the command line using: *mvn clean install*, or in an IDE. \ No newline at end of file +You can build the project from the command line using: *mvn clean install*, or in an IDE. diff --git a/apache-kafka/pom.xml b/apache-kafka/pom.xml index cda91ed92f..8003743f95 100644 --- a/apache-kafka/pom.xml +++ b/apache-kafka/pom.xml @@ -161,6 +161,12 @@ spark-cassandra-connector-java_2.11 ${com.datastax.spark.spark-cassandra-connector-java.version} + + org.projectlombok + lombok + ${lombok.version} + provided + @@ -175,6 +181,7 @@ 0.8.1-spark3.0-s_2.12 2.5.2 1.6.0-M1 + 1.18.20 \ No newline at end of file diff --git a/apache-kafka/src/main/java/com/baeldung/kafka/dto/MessageDto.java b/apache-kafka/src/main/java/com/baeldung/kafka/dto/MessageDto.java new file mode 100644 index 0000000000..7f9e206358 --- /dev/null +++ b/apache-kafka/src/main/java/com/baeldung/kafka/dto/MessageDto.java @@ -0,0 +1,15 @@ +package com.baeldung.kafka.dto; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class MessageDto { + private String message; + private String version; +} diff --git a/apache-kafka/src/main/java/com/baeldung/kafka/serdes/CustomDeserializer.java b/apache-kafka/src/main/java/com/baeldung/kafka/serdes/CustomDeserializer.java new file mode 100644 index 0000000000..ee6e79dcd1 --- /dev/null +++ b/apache-kafka/src/main/java/com/baeldung/kafka/serdes/CustomDeserializer.java @@ -0,0 +1,35 @@ +package com.baeldung.kafka.serdes; + +import com.baeldung.kafka.dto.MessageDto; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.kafka.common.errors.SerializationException; +import org.apache.kafka.common.serialization.Deserializer; + +import java.util.Map; + +public class CustomDeserializer implements Deserializer { + + private ObjectMapper objectMapper = new ObjectMapper(); + + @Override + public void configure(Map configs, boolean isKey) { + } + + @Override + public MessageDto deserialize(String topic, byte[] data) { + try { + if (data == null){ + System.out.println("Null received at deserializing"); + return null; + } + System.out.println("Deserializing..."); + return objectMapper.readValue(new String(data, "UTF-8"), MessageDto.class); + } catch (Exception e) { + throw new SerializationException("Error when deserializing byte[] to MessageDto"); + } + } + + @Override + public void close() { + } +} diff --git a/apache-kafka/src/main/java/com/baeldung/kafka/serdes/CustomSerializer.java b/apache-kafka/src/main/java/com/baeldung/kafka/serdes/CustomSerializer.java new file mode 100644 index 0000000000..a414ad8e23 --- /dev/null +++ b/apache-kafka/src/main/java/com/baeldung/kafka/serdes/CustomSerializer.java @@ -0,0 +1,34 @@ +package com.baeldung.kafka.serdes; + +import com.baeldung.kafka.dto.MessageDto; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.kafka.common.errors.SerializationException; +import org.apache.kafka.common.serialization.Serializer; + +import java.util.Map; + +public class CustomSerializer implements Serializer { + private final ObjectMapper objectMapper = new ObjectMapper(); + + @Override + public void configure(Map configs, boolean isKey) { + } + + @Override + public byte[] serialize(String topic, MessageDto data) { + try { + if (data == null){ + System.out.println("Null received at serializing"); + return null; + } + System.out.println("Serializing..."); + return objectMapper.writeValueAsBytes(data); + } catch (Exception e) { + throw new SerializationException("Error when serializing MessageDto to byte[]"); + } + } + + @Override + public void close() { + } +} diff --git a/apache-kafka/src/test/java/com/baeldung/kafka/serdes/KafkaSerDesLiveTest.java b/apache-kafka/src/test/java/com/baeldung/kafka/serdes/KafkaSerDesLiveTest.java new file mode 100644 index 0000000000..67fff12f5e --- /dev/null +++ b/apache-kafka/src/test/java/com/baeldung/kafka/serdes/KafkaSerDesLiveTest.java @@ -0,0 +1,92 @@ +package com.baeldung.kafka.serdes; + +import com.baeldung.kafka.dto.MessageDto; +import org.apache.kafka.clients.consumer.ConsumerConfig; +import org.apache.kafka.clients.consumer.ConsumerRecords; +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.junit.Before; +import org.junit.ClassRule; +import org.junit.Test; +import org.testcontainers.containers.KafkaContainer; +import org.testcontainers.utility.DockerImageName; + +import java.time.Duration; +import java.util.Arrays; +import java.util.Properties; +import java.util.concurrent.atomic.AtomicReference; + +import static org.junit.Assert.assertEquals; + +public class KafkaSerDesLiveTest { + private static final String CONSUMER_APP_ID = "consumer_id"; + private static final String CONSUMER_GROUP_ID = "group_id"; + + @ClassRule + public static KafkaContainer kafka = new KafkaContainer(DockerImageName.parse("confluentinc/cp-kafka:5.4.3")); + private final String TOPIC = "mytopic"; + + private static KafkaConsumer createKafkaConsumer() { + + Properties props = new Properties(); + props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, kafka.getBootstrapServers()); + props.put(ConsumerConfig.CLIENT_ID_CONFIG, CONSUMER_APP_ID); + props.put(ConsumerConfig.GROUP_ID_CONFIG, CONSUMER_GROUP_ID); + props.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "earliest"); + props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.StringDeserializer"); + props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, "com.baeldung.kafka.serdes.CustomDeserializer"); + + return new KafkaConsumer<>(props); + + } + + private static KafkaProducer createKafkaProducer() { + + Properties props = new Properties(); + props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, kafka.getBootstrapServers()); + props.put(ProducerConfig.CLIENT_ID_CONFIG, CONSUMER_APP_ID); + props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.StringSerializer"); + props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, "com.baeldung.kafka.serdes.CustomSerializer"); + + return new KafkaProducer(props); + + } + + @Before + public void setUp() { + } + + @Test + public void givenKafkaClientShouldSerializeAndDeserialize() throws InterruptedException { + + MessageDto msgProd = MessageDto.builder().message("test").version("1.0").build(); + + KafkaProducer producer = createKafkaProducer(); + producer.send(new ProducerRecord(TOPIC, "1", msgProd)); + System.out.println("Message sent " + msgProd); + producer.close(); + + Thread.sleep(2000); + + AtomicReference msgCons = new AtomicReference<>(); + + KafkaConsumer consumer = createKafkaConsumer(); + consumer.subscribe(Arrays.asList(TOPIC)); + + ConsumerRecords records = consumer.poll(Duration.ofSeconds(1)); + records.forEach(record -> { + msgCons.set(record.value()); + System.out.println("Message received " + record.value()); + }); + + consumer.close(); + + assertEquals(msgProd, msgCons.get()); + + } + +} + + diff --git a/apache-libraries/pom.xml b/apache-libraries/pom.xml index ded10b939f..b4cf11b07d 100644 --- a/apache-libraries/pom.xml +++ b/apache-libraries/pom.xml @@ -133,6 +133,11 @@ jackson-databind ${jackson.version} + + com.fasterxml.jackson.core + jackson-annotations + ${jackson.version} + com.jayway.awaitility awaitility @@ -196,7 +201,6 @@ 1.8 1.8 1.8.2 - 1.7.25 2.19.0 3.9.0 1.1.2 diff --git a/apache-libraries/src/main/resources/log4j2.xml b/apache-libraries/src/main/resources/log4j2.xml new file mode 100644 index 0000000000..d1ea5173fa --- /dev/null +++ b/apache-libraries/src/main/resources/log4j2.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/apache-libraries/src/test/java/com/baeldung/apache/beam/intro/WordCountUnitTest.java b/apache-libraries/src/test/java/com/baeldung/apache/beam/intro/WordCountUnitTest.java index f2558635dc..77287066ac 100644 --- a/apache-libraries/src/test/java/com/baeldung/apache/beam/intro/WordCountUnitTest.java +++ b/apache-libraries/src/test/java/com/baeldung/apache/beam/intro/WordCountUnitTest.java @@ -10,7 +10,6 @@ import com.baeldung.apache.beam.intro.WordCount; public class WordCountUnitTest { @Test - // @Ignore public void givenInputFile_whenWordCountRuns_thenJobFinishWithoutError() { boolean jobDone = WordCount.wordCount("src/test/resources/wordcount.txt", "target/output"); assertTrue(jobDone); diff --git a/apache-spark/src/main/resources/log4j.properties b/apache-spark/src/main/resources/log4j.properties new file mode 100644 index 0000000000..07a2943655 --- /dev/null +++ b/apache-spark/src/main/resources/log4j.properties @@ -0,0 +1,42 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# Set everything to be logged to the console +log4j.rootCategory=WARN, console +log4j.appender.console=org.apache.log4j.ConsoleAppender +log4j.appender.console.target=System.err +log4j.appender.console.layout=org.apache.log4j.PatternLayout +log4j.appender.console.layout.ConversionPattern=%d{yy/MM/dd HH:mm:ss} %p %c{1}: %m%n + +# Set the default spark-shell log level to WARN. When running the spark-shell, the +# log level for this class is used to overwrite the root logger's log level, so that +# the user can have different defaults for the shell and regular Spark apps. +log4j.logger.org.apache.spark.repl.Main=WARN + +# Settings to quiet third party logs that are too verbose +log4j.logger.org.spark_project.jetty=WARN +log4j.logger.org.spark_project.jetty.util.component.AbstractLifeCycle=ERROR +log4j.logger.org.apache.spark.repl.SparkIMain$exprTyper=INFO +log4j.logger.org.apache.spark.repl.SparkILoop$SparkILoopInterpreter=INFO + +# SPARK-9183: Settings to avoid annoying messages when looking up nonexistent UDFs in SparkSQL with Hive support +log4j.logger.org.apache.hadoop.hive.metastore.RetryingHMSHandler=FATAL +log4j.logger.org.apache.hadoop.hive.ql.exec.FunctionRegistry=ERROR + +# Parquet related logging +log4j.logger.org.apache.parquet.CorruptStatistics=ERROR +log4j.logger.parquet.CorruptStatistics=ERROR diff --git a/apache-tapestry/pom.xml b/apache-tapestry/pom.xml index 13ae49b0ba..7a4c2b53b5 100644 --- a/apache-tapestry/pom.xml +++ b/apache-tapestry/pom.xml @@ -32,7 +32,6 @@ - @@ -110,8 +109,6 @@ - - jboss diff --git a/apache-thrift/pom.xml b/apache-thrift/pom.xml index 9562ae7dfe..d2623f92e7 100644 --- a/apache-thrift/pom.xml +++ b/apache-thrift/pom.xml @@ -29,7 +29,7 @@ org.slf4j slf4j-simple - ${org.slf4j.slf4j-simple.version} + ${org.slf4j.version} test @@ -61,7 +61,6 @@ 0.10.0 0.1.11 - 1.7.12 3.0.0 diff --git a/aws-reactive/pom.xml b/aws-reactive/pom.xml index ea1e0c44a4..923e1361ab 100644 --- a/aws-reactive/pom.xml +++ b/aws-reactive/pom.xml @@ -93,5 +93,5 @@ 2.2.1.RELEASE 2.10.27 - + \ No newline at end of file diff --git a/aws/README.md b/aws/README.md index fcb9735878..9006c2d190 100644 --- a/aws/README.md +++ b/aws/README.md @@ -6,7 +6,7 @@ This module contains articles about Amazon Web Services (AWS) - [AWS Lambda Using DynamoDB With Java](https://www.baeldung.com/aws-lambda-dynamodb-java) - [AWS S3 with Java](https://www.baeldung.com/aws-s3-java) -- [AWS Lambda With Java](https://www.baeldung.com/java-aws-lambda) +- [A Basic AWS Lambda Example With Java](https://www.baeldung.com/java-aws-lambda) - [Managing EC2 Instances in Java](https://www.baeldung.com/ec2-java) - [Multipart Uploads in Amazon S3 with Java](https://www.baeldung.com/aws-s3-multipart-upload) - [Integration Testing with a Local DynamoDB Instance](https://www.baeldung.com/dynamodb-local-integration-tests) diff --git a/axon/README.md b/axon/README.md index 3b2fd0b5ff..18f5d568e6 100644 --- a/axon/README.md +++ b/axon/README.md @@ -6,3 +6,4 @@ This module contains articles about Axon - [A Guide to the Axon Framework](https://www.baeldung.com/axon-cqrs-event-sourcing) - [Multi-Entity Aggregates in Axon](https://www.baeldung.com/java-axon-multi-entity-aggregates) +- [Snapshotting Aggregates in Axon](https://www.baeldung.com/axon-snapshotting-aggregates) diff --git a/axon/src/main/java/com/baeldung/axon/OrderApplicationConfiguration.java b/axon/src/main/java/com/baeldung/axon/OrderApplicationConfiguration.java new file mode 100644 index 0000000000..8b743144b4 --- /dev/null +++ b/axon/src/main/java/com/baeldung/axon/OrderApplicationConfiguration.java @@ -0,0 +1,18 @@ +package com.baeldung.axon; + +import org.axonframework.eventsourcing.EventCountSnapshotTriggerDefinition; +import org.axonframework.eventsourcing.SnapshotTriggerDefinition; +import org.axonframework.eventsourcing.Snapshotter; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class OrderApplicationConfiguration { + + @Bean + public SnapshotTriggerDefinition orderAggregateSnapshotTriggerDefinition(Snapshotter snapshotter, + @Value("${axon.aggregate.order.snapshot-threshold:250}") int threshold) { + return new EventCountSnapshotTriggerDefinition(snapshotter, threshold); + } +} diff --git a/axon/src/main/java/com/baeldung/axon/commandmodel/order/OrderAggregate.java b/axon/src/main/java/com/baeldung/axon/commandmodel/order/OrderAggregate.java index 97342bdb3a..1065e9d22b 100644 --- a/axon/src/main/java/com/baeldung/axon/commandmodel/order/OrderAggregate.java +++ b/axon/src/main/java/com/baeldung/axon/commandmodel/order/OrderAggregate.java @@ -23,7 +23,7 @@ import java.util.Map; import static org.axonframework.modelling.command.AggregateLifecycle.apply; -@Aggregate +@Aggregate(snapshotTriggerDefinition = "orderAggregateSnapshotTriggerDefinition") public class OrderAggregate { @AggregateIdentifier diff --git a/core-groovy-2/pom.xml b/core-groovy-2/pom.xml index f8ef654293..89df666333 100644 --- a/core-groovy-2/pom.xml +++ b/core-groovy-2/pom.xml @@ -166,7 +166,6 @@ 2.4.0 1.1-groovy-2.4 1.1.3 - 1.2.3 2.5.7 3.1.0 3.8.0 diff --git a/core-java-modules/core-java-11-2/README.md b/core-java-modules/core-java-11-2/README.md index ca9a306b82..93920864cc 100644 --- a/core-java-modules/core-java-11-2/README.md +++ b/core-java-modules/core-java-11-2/README.md @@ -8,3 +8,4 @@ This module contains articles about Java 11 core features - [Guide to Java 8’s Collectors](https://www.baeldung.com/java-8-collectors) - [New Features in Java 11](https://www.baeldung.com/java-11-new-features) - [Getting the Java Version at Runtime](https://www.baeldung.com/get-java-version-runtime) +- [Invoking a SOAP Web Service in Java](https://www.baeldung.com/java-soap-web-service) diff --git a/core-java-modules/core-java-12/pom.xml b/core-java-modules/core-java-12/pom.xml index ce7ec72aeb..931fce820b 100644 --- a/core-java-modules/core-java-12/pom.xml +++ b/core-java-modules/core-java-12/pom.xml @@ -1,60 +1,60 @@ - 4.0.0 - core-java-12 - 0.1.0-SNAPSHOT - core-java-12 - jar - http://maven.apache.org + 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 + core-java-12 + 0.1.0-SNAPSHOT + core-java-12 + jar + http://maven.apache.org - - com.baeldung - parent-modules - 1.0.0-SNAPSHOT - ../../ - + + com.baeldung + parent-modules + 1.0.0-SNAPSHOT + ../../ + - - - org.assertj - assertj-core - ${assertj.version} - test - - - commons-io - commons-io - 2.11.0 - - + + + org.assertj + assertj-core + ${assertj.version} + test + + + commons-io + commons-io + 2.11.0 + + - - - - org.apache.maven.plugins - maven-compiler-plugin - ${maven-compiler-plugin.version} - - ${maven.compiler.source.version} - ${maven.compiler.target.version} - --enable-preview - - - - maven-surefire-plugin - - --enable-preview - - - - + + + + org.apache.maven.plugins + maven-compiler-plugin + ${maven-compiler-plugin.version} + + ${maven.compiler.source.version} + ${maven.compiler.target.version} + --enable-preview + + + + maven-surefire-plugin + + --enable-preview + + + + - - 12 - 12 - 3.6.1 - + + 12 + 12 + 3.6.1 + \ No newline at end of file diff --git a/core-java-modules/core-java-14/pom.xml b/core-java-modules/core-java-14/pom.xml index f3382f6577..a03332d8bc 100644 --- a/core-java-modules/core-java-14/pom.xml +++ b/core-java-modules/core-java-14/pom.xml @@ -14,7 +14,7 @@ 1.0.0-SNAPSHOT ../../ - + org.assertj @@ -35,7 +35,7 @@ test - + diff --git a/core-java-modules/core-java-16/README.md b/core-java-modules/core-java-16/README.md index 760513189f..b2740d194c 100644 --- a/core-java-modules/core-java-16/README.md +++ b/core-java-modules/core-java-16/README.md @@ -1,3 +1,7 @@ ### Relevant articles: - [Collect a Java Stream to an Immutable Collection](https://www.baeldung.com/java-stream-immutable-collection) +- [Guide to mapMulti in Stream API](https://www.baeldung.com/java-mapmulti) +- [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) diff --git a/core-java-modules/core-java-16/pom.xml b/core-java-modules/core-java-16/pom.xml index a8a84511db..5d10325f03 100644 --- a/core-java-modules/core-java-16/pom.xml +++ b/core-java-modules/core-java-16/pom.xml @@ -1,53 +1,86 @@ - 4.0.0 - core-java-16 - 0.1.0-SNAPSHOT - core-java-16 - jar - http://maven.apache.org + 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 + core-java-16 + 0.1.0-SNAPSHOT + core-java-16 + jar + http://maven.apache.org - - com.baeldung - parent-modules - 1.0.0-SNAPSHOT - ../../ - + + com.baeldung + parent-modules + 1.0.0-SNAPSHOT + ../../ + - + + + org.assertj + assertj-core + ${assertj.version} + test + + + org.apache.commons + commons-lang3 + 3.12.0 + - org.assertj - assertj-core - ${assertj.version} + org.junit.jupiter + junit-jupiter-engine + ${junit-jupiter.version} test - org.apache.commons - commons-lang3 - 3.12.0 + org.junit.jupiter + junit-jupiter-api + ${junit-jupiter.version} + test - + - - + + + + 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-compiler-plugin - ${maven-compiler-plugin.version} + maven-surefire-plugin + ${surefire.plugin.version} - ${maven.compiler.source.version} - ${maven.compiler.target.version} + --enable-preview + 1 + + + org.apache.maven.surefire + surefire-api + ${surefire.plugin.version} + + - - + + - - 16 - 16 - 3.6.1 - + + 16 + 16 + 16 + 3.8.1 + 3.0.0-M5 + 3.17.2 + \ No newline at end of file diff --git a/core-java-modules/core-java-16/src/main/java/com/baeldung/features/HelloWorld.java b/core-java-modules/core-java-16/src/main/java/com/baeldung/features/HelloWorld.java new file mode 100644 index 0000000000..7d72c4b71c --- /dev/null +++ b/core-java-modules/core-java-16/src/main/java/com/baeldung/features/HelloWorld.java @@ -0,0 +1,7 @@ +package com.baeldung.features; + +interface HelloWorld { + default String hello() { + return "world"; + } +} diff --git a/core-java-modules/core-java-16/src/main/java/com/baeldung/features/OuterClass.java b/core-java-modules/core-java-16/src/main/java/com/baeldung/features/OuterClass.java new file mode 100644 index 0000000000..6e08674bff --- /dev/null +++ b/core-java-modules/core-java-16/src/main/java/com/baeldung/features/OuterClass.java @@ -0,0 +1,9 @@ +package com.baeldung.features; + +import com.baeldung.features.record.Book; + +public class OuterClass { + class InnerClass { + Book book = new Book("Title", "author", "isbn"); + } +} diff --git a/core-java-modules/core-java-16/src/main/java/com/baeldung/features/VectorExample.java b/core-java-modules/core-java-16/src/main/java/com/baeldung/features/VectorExample.java new file mode 100644 index 0000000000..1f25290270 --- /dev/null +++ b/core-java-modules/core-java-16/src/main/java/com/baeldung/features/VectorExample.java @@ -0,0 +1,23 @@ +package com.baeldung.features; + +import jdk.incubator.vector.IntVector; + +public class VectorExample { + public int[] scalarComputation(int[] a, int[] b) { + var c = new int[a.length]; + for (int i = 0; i < a.length; i++) { + c[i] = a[i] * b[i]; + } + return c; + } + + public int[] vectorComputation(int[] a, int[] b) { + var c = new int[a.length]; + + var vectorA = IntVector.fromArray(IntVector.SPECIES_128, a, 0); + var vectorB = IntVector.fromArray(IntVector.SPECIES_128, b, 0); + var vectorC = vectorA.mul(vectorB); + vectorC.intoArray(c, 0); + return c; + } +} diff --git a/core-java-modules/core-java-16/src/main/java/com/baeldung/features/model/Book.java b/core-java-modules/core-java-16/src/main/java/com/baeldung/features/model/Book.java new file mode 100644 index 0000000000..c532e41649 --- /dev/null +++ b/core-java-modules/core-java-16/src/main/java/com/baeldung/features/model/Book.java @@ -0,0 +1,44 @@ +package com.baeldung.features.model; + +import java.util.Objects; + +public final class Book { + private final String title; + private final String author; + private final String isbn; + + public Book(String title, String author, String isbn) { + this.title = title; + this.author = author; + this.isbn = isbn; + } + + public String getTitle() { + return title; + } + + public String getAuthor() { + return author; + } + + public String getIsbn() { + return isbn; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Book book = (Book) o; + return Objects.equals(title, book.title) && Objects.equals(author, book.author) && Objects.equals(isbn, book.isbn); + } + + @Override + public int hashCode() { + return Objects.hash(title, author, isbn); + } +} diff --git a/core-java-modules/core-java-16/src/main/java/com/baeldung/features/record/Book.java b/core-java-modules/core-java-16/src/main/java/com/baeldung/features/record/Book.java new file mode 100644 index 0000000000..3bddf143be --- /dev/null +++ b/core-java-modules/core-java-16/src/main/java/com/baeldung/features/record/Book.java @@ -0,0 +1,4 @@ +package com.baeldung.features.record; + +public record Book(String title, String author, String isbn) { +} diff --git a/core-java-modules/core-java-16/src/main/java/com/baeldung/features/sealed/JungleAnimal.java b/core-java-modules/core-java-16/src/main/java/com/baeldung/features/sealed/JungleAnimal.java new file mode 100644 index 0000000000..1853f8449c --- /dev/null +++ b/core-java-modules/core-java-16/src/main/java/com/baeldung/features/sealed/JungleAnimal.java @@ -0,0 +1,4 @@ +package com.baeldung.features.sealed; + +public sealed interface JungleAnimal permits Monkey, Snake { +} diff --git a/core-java-modules/core-java-16/src/main/java/com/baeldung/features/sealed/Monkey.java b/core-java-modules/core-java-16/src/main/java/com/baeldung/features/sealed/Monkey.java new file mode 100644 index 0000000000..aeddfdddda --- /dev/null +++ b/core-java-modules/core-java-16/src/main/java/com/baeldung/features/sealed/Monkey.java @@ -0,0 +1,4 @@ +package com.baeldung.features.sealed; + +public final class Monkey implements JungleAnimal { +} diff --git a/core-java-modules/core-java-16/src/main/java/com/baeldung/features/sealed/Sealed.java b/core-java-modules/core-java-16/src/main/java/com/baeldung/features/sealed/Sealed.java new file mode 100644 index 0000000000..1ee4ff6e57 --- /dev/null +++ b/core-java-modules/core-java-16/src/main/java/com/baeldung/features/sealed/Sealed.java @@ -0,0 +1,13 @@ +package com.baeldung.features.sealed; + +public class Sealed { + public static void main(String... args) { + JungleAnimal j = new Monkey(); + + if (j instanceof Monkey m) { + // do logic + } else if (j instanceof Snake s) { + // do logic + } + } +} diff --git a/core-java-modules/core-java-16/src/main/java/com/baeldung/features/sealed/Snake.java b/core-java-modules/core-java-16/src/main/java/com/baeldung/features/sealed/Snake.java new file mode 100644 index 0000000000..c35575f5e0 --- /dev/null +++ b/core-java-modules/core-java-16/src/main/java/com/baeldung/features/sealed/Snake.java @@ -0,0 +1,4 @@ +package com.baeldung.features.sealed; + +public non-sealed class Snake implements JungleAnimal { +} diff --git a/core-java-modules/core-java-16/src/main/java/com/baeldung/java_16_features/mapmulti/Album.java b/core-java-modules/core-java-16/src/main/java/com/baeldung/java_16_features/mapmulti/Album.java new file mode 100644 index 0000000000..fa7ec02307 --- /dev/null +++ b/core-java-modules/core-java-16/src/main/java/com/baeldung/java_16_features/mapmulti/Album.java @@ -0,0 +1,49 @@ +package com.baeldung.java_16_features.mapmulti; + +import java.util.List; +import java.util.function.Consumer; +import java.util.stream.Collectors; + +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.apache.commons.lang3.tuple.Pair; + +public class Album { + + private String albumName; + private int albumCost; + private List artists; + + Album(String name, int albumCost, List artists) { + this.albumName = name; + this.artists = artists; + this.albumCost = albumCost; + } + + public void artistAlbumPairsToMajorLabels(Consumer> consumer) { + + for (Artist artist : artists) { + if (artist.isAssociatedMajorLabels()) { + String concatLabels = artist.getMajorLabels() + .stream() + .collect(Collectors.joining(",")); + consumer.accept(new ImmutablePair<>(artist.getName() + ":" + albumName, concatLabels)); + } + } + } + + public String getAlbumName() { + return albumName; + } + + public int getAlbumCost() { + return albumCost; + } + + List getArtists() { + return artists; + } + + public String toString() { + return albumName; + } +} diff --git a/core-java-modules/core-java-16/src/main/java/com/baeldung/java_16_features/mapmulti/Artist.java b/core-java-modules/core-java-16/src/main/java/com/baeldung/java_16_features/mapmulti/Artist.java new file mode 100644 index 0000000000..b3b9b7aa10 --- /dev/null +++ b/core-java-modules/core-java-16/src/main/java/com/baeldung/java_16_features/mapmulti/Artist.java @@ -0,0 +1,50 @@ +package com.baeldung.java_16_features.mapmulti; + +import java.util.List; +import java.util.Objects; + +public class Artist { + + private final String name; + private boolean associatedMajorLabels; + private List majorLabels; + + Artist(String name, boolean associatedMajorLabels, List majorLabels) { + this.name = name; + this.associatedMajorLabels = associatedMajorLabels; + this.majorLabels = majorLabels; + } + + public String getName() { + return name; + } + + public boolean isAssociatedMajorLabels() { + return associatedMajorLabels; + } + + public List getMajorLabels() { + return majorLabels; + } + + @Override + public int hashCode() { + return Objects.hash(name); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Artist other = (Artist) obj; + return Objects.equals(name, other.name); + } + + public String toString() { + return name; + } +} diff --git a/core-java-modules/core-java-16/src/main/java/module-info.java b/core-java-modules/core-java-16/src/main/java/module-info.java new file mode 100644 index 0000000000..ee983a6832 --- /dev/null +++ b/core-java-modules/core-java-16/src/main/java/module-info.java @@ -0,0 +1,4 @@ +module core.java { + requires jdk.incubator.vector; + requires org.apache.commons.lang3; +} \ No newline at end of file diff --git a/core-java-modules/core-java-16/src/test/java/com/baeldung/features/DayPeriodSupportUnitTest.java b/core-java-modules/core-java-16/src/test/java/com/baeldung/features/DayPeriodSupportUnitTest.java new file mode 100644 index 0000000000..6ae6232f00 --- /dev/null +++ b/core-java-modules/core-java-16/src/test/java/com/baeldung/features/DayPeriodSupportUnitTest.java @@ -0,0 +1,24 @@ +package com.baeldung.features; + +import org.junit.jupiter.api.Test; + +import java.time.LocalTime; +import java.time.format.DateTimeFormatter; + +import static org.assertj.core.api.Assertions.assertThat; + +public class DayPeriodSupportUnitTest { + + @Test + public void givenASpecificTime_whenFormattingUsingTheBSymbol_thenExpectVerbosePeriodOfDay() { + LocalTime date = LocalTime.parse("15:25:08.690791"); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("h B"); + assertThat(date.format(formatter)).isEqualTo("3 in the afternoon"); + + formatter = DateTimeFormatter.ofPattern("h BBBB"); + assertThat(date.format(formatter)).isEqualTo("3 in the afternoon"); + + formatter = DateTimeFormatter.ofPattern("h BBBBB"); + assertThat(date.format(formatter)).isEqualTo("3 in the afternoon"); + } +} diff --git a/core-java-modules/core-java-16/src/test/java/com/baeldung/features/HelloWorldUnitTest.java b/core-java-modules/core-java-16/src/test/java/com/baeldung/features/HelloWorldUnitTest.java new file mode 100644 index 0000000000..d421f13dd1 --- /dev/null +++ b/core-java-modules/core-java-16/src/test/java/com/baeldung/features/HelloWorldUnitTest.java @@ -0,0 +1,28 @@ +package com.baeldung.features; + + +import org.junit.jupiter.api.Test; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; + +import static java.lang.ClassLoader.getSystemClassLoader; +import static org.assertj.core.api.Assertions.assertThat; + +class HelloWorldUnitTest { + + @Test + public void givenAnInterfaceWithDefaulMethod_whenCreatingProxyInstance_thenCanInvokeDefaultMethod() throws Exception { + Object proxy = Proxy.newProxyInstance(getSystemClassLoader(), new Class[] { HelloWorld.class }, + (prox, method, args) -> { + if (method.isDefault()) { + return InvocationHandler.invokeDefault(prox, method, args); + } + return method.invoke(prox, args); + } + ); + Method method = proxy.getClass().getMethod("hello"); + assertThat(method.invoke(proxy)).isEqualTo("world"); + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-16/src/test/java/com/baeldung/features/InstanceOfPatternMatchingUnitTest.java b/core-java-modules/core-java-16/src/test/java/com/baeldung/features/InstanceOfPatternMatchingUnitTest.java new file mode 100644 index 0000000000..7243957332 --- /dev/null +++ b/core-java-modules/core-java-16/src/test/java/com/baeldung/features/InstanceOfPatternMatchingUnitTest.java @@ -0,0 +1,18 @@ +package com.baeldung.features; + +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +public class InstanceOfPatternMatchingUnitTest { + + @Test + void givenTheNewPatternMatchingAbility_whenComparingAgainstTheTradiationalApproach_thenBothVariablesAreEqual() { + Object obj = "TEST"; + + if (obj instanceof String a) { + String b = (String) obj; + assertThat(a).isEqualTo(b); + } + } +} diff --git a/core-java-modules/core-java-16/src/test/java/com/baeldung/features/StreamToListUnitTest.java b/core-java-modules/core-java-16/src/test/java/com/baeldung/features/StreamToListUnitTest.java new file mode 100644 index 0000000000..00d090a240 --- /dev/null +++ b/core-java-modules/core-java-16/src/test/java/com/baeldung/features/StreamToListUnitTest.java @@ -0,0 +1,20 @@ +package com.baeldung.features; + +import org.junit.jupiter.api.Test; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +import static org.assertj.core.api.Assertions.assertThat; + +public class StreamToListUnitTest { + + @Test + void givenAStream_whenCreatingANewListFromStream_thenCollectorsOrInbuiltFunctionAreEquivalent() { + List integersAsString = Arrays.asList("1", "2", "3"); + List ints = integersAsString.stream().map(Integer::parseInt).collect(Collectors.toList()); + List intsEquivalent = integersAsString.stream().map(Integer::parseInt).toList(); + assertThat(ints).isEqualTo(intsEquivalent); + } +} diff --git a/core-java-modules/core-java-16/src/test/java/com/baeldung/features/VectorExampleUnitTest.java b/core-java-modules/core-java-16/src/test/java/com/baeldung/features/VectorExampleUnitTest.java new file mode 100644 index 0000000000..981f106ec7 --- /dev/null +++ b/core-java-modules/core-java-16/src/test/java/com/baeldung/features/VectorExampleUnitTest.java @@ -0,0 +1,21 @@ +package com.baeldung.features; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; + +class VectorExampleUnitTest { + + @Test + void givenAScalarComputation_whenCalculatingUsingVectorAPI_thenResultIsSameAsPreviousMethodOfComputation() { + VectorExample objectUnderTest = new VectorExample(); + + int[] a = {1, 2, 3, 4}; + int[] b = {5, 6, 7, 8}; + + int[] result = objectUnderTest.scalarComputation(a, b); + int[] result2 = objectUnderTest.vectorComputation(a, b); + + assertArrayEquals(result, result2); + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-16/src/test/java/com/baeldung/java_16_features/mapmulti/JavaStreamMapMultiUnitTest.java b/core-java-modules/core-java-16/src/test/java/com/baeldung/java_16_features/mapmulti/JavaStreamMapMultiUnitTest.java new file mode 100644 index 0000000000..0ab1a95ed0 --- /dev/null +++ b/core-java-modules/core-java-16/src/test/java/com/baeldung/java_16_features/mapmulti/JavaStreamMapMultiUnitTest.java @@ -0,0 +1,134 @@ +package com.baeldung.java_16_features.mapmulti; + +import static java.util.stream.Collectors.toList; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.offset; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.Arrays; +import java.util.List; + +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.apache.commons.lang3.tuple.Pair; +import org.junit.jupiter.api.Test; + +public class JavaStreamMapMultiUnitTest { + + private static final List albums = Arrays.asList(new Album("album1", 10, Arrays.asList(new Artist("bob", true, Arrays.asList("label1", "label3")), new Artist("tom", true, Arrays.asList("label2", "label3")))), + new Album("album2", 20, Arrays.asList(new Artist("bill", true, Arrays.asList("label2", "label3")), new Artist("tom", true, Arrays.asList("label2", "label4"))))); + + @Test + public void givenAListOfintegers_whenMapMulti_thenGetListOfOfEvenDoublesPlusPercentage() { + + List integers = Arrays.asList(1, 2, 3, 4, 5); + double percentage = .01; + List evenDoubles = integers.stream() + . mapMulti((integer, consumer) -> { + if (integer % 2 == 0) { + consumer.accept((double) integer * (1 + percentage)); + } + }) + .collect(toList()); + + assertThat(evenDoubles).containsAll(Arrays.asList(2.02D, 4.04D)); + } + + @Test + public void givenAListOfintegers_whenFilterMap_thenGetListOfOfEvenDoublesPlusPercentage() { + + List integers = Arrays.asList(1, 2, 3, 4, 5); + double percentage = .01; + List evenDoubles = integers.stream() + .filter(integer -> integer % 2 == 0) + . map(integer -> ((double) integer * (1 + percentage))) + .collect(toList()); + + assertThat(evenDoubles).containsAll(Arrays.asList(2.02D, 4.04D)); + } + + @Test + public void givenAListOfintegers_whenMapMultiToDouble_thenGetSumOfEvenNumbersAfterApplyPercentage() { + + List integers = Arrays.asList(1, 2, 3, 4, 5, 6, 7); + double percentage = .01; + double sum = integers.stream() + .mapMultiToDouble((integer, consumer) -> { + if (integer % 2 == 0) { + consumer.accept(integer * (1 + percentage)); + } + }) + .sum(); + + assertThat(sum).isEqualTo(12.12, offset(0.001d)); + } + + @Test + public void givenAListOfAlbums_whenFlatMap_thenGetListOfArtistAlbumPairs() { + + List> artistAlbum = albums.stream() + .flatMap(album -> album.getArtists() + .stream() + .map(artist -> new ImmutablePair(artist.getName(), album.getAlbumName()))) + .collect(toList()); + + assertThat(artistAlbum).contains(new ImmutablePair("bob", "album1"), new ImmutablePair("tom", "album1"), new ImmutablePair("bill", "album2"), new ImmutablePair("tom", "album2")); + } + + @Test + public void givenAListOfAlbums_whenMapMulti_thenGetListOfPairsOfArtistAlbum() { + + List> artistAlbum = albums.stream() + .> mapMulti((album, consumer) -> { + for (Artist artist : album.getArtists()) { + consumer.accept(new ImmutablePair(artist.getName(), album.getAlbumName())); + } + }) + .collect(toList()); + + assertThat(artistAlbum).contains(new ImmutablePair("bob", "album1"), new ImmutablePair("tom", "album1"), + new ImmutablePair("bill", "album2"), new ImmutablePair("tom", "album2")); + } + + @Test + public void givenAListOfAlbums_whenFlatMap_thenGetListOfArtistAlbumjPairsBelowGivenCost() { + + int upperCost = 9; + List> artistAlbum = albums.stream() + .flatMap(album -> album.getArtists() + .stream() + .filter(artist -> upperCost > album.getAlbumCost()) + .map(artist -> new ImmutablePair(artist.getName(), album.getAlbumName()))) + .collect(toList()); + + assertTrue(artistAlbum.isEmpty()); + } + + @Test + public void givenAListOfAlbums_whenMapMulti_thenGetListOfArtistAlbumPairsBelowGivenCost() { + + int upperCost = 9; + List> artistAlbum = albums.stream() + .> mapMulti((album, consumer) -> { + if (album.getAlbumCost() < upperCost) { + for (Artist artist : album.getArtists()) { + consumer.accept(new ImmutablePair(artist.getName(), album.getAlbumName())); + } + } + }) + .collect(toList()); + + assertTrue(artistAlbum.isEmpty()); + } + + @Test + public void givenAListOfAlbums_whenMapMulti_thenGetPairsOfArtistMajorLabelsUsingMethodReference() { + + List> artistLabels = albums.stream() + .mapMulti(Album::artistAlbumPairsToMajorLabels) + .collect(toList()); + + assertThat(artistLabels).contains(new ImmutablePair("bob:album1", "label1,label3"), new ImmutablePair("tom:album1", "label2,label3"), + new ImmutablePair("bill:album2", "label2,label3"), new ImmutablePair("tom:album2", "label2,label4")); + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-16/src/test/java/com/baeldung/streams/StreamToListComparisonWithCollectorsToListUnitTest.java b/core-java-modules/core-java-16/src/test/java/com/baeldung/streams/StreamToListComparisonWithCollectorsToListUnitTest.java new file mode 100644 index 0000000000..e1330bb4f7 --- /dev/null +++ b/core-java-modules/core-java-16/src/test/java/com/baeldung/streams/StreamToListComparisonWithCollectorsToListUnitTest.java @@ -0,0 +1,128 @@ +package com.baeldung.streams; + +import java.util.List; +import java.util.Locale; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class StreamToListComparisonWithCollectorsToListUnitTest { + + @Test + public void whenAddingtoCollectToList_thenSuccess() { + + List result = Stream.of(Locale.getISOCountries()) + .collect(Collectors.toList()); + + Assertions.assertDoesNotThrow(() -> { + result.add("test"); + }); + } + + @Test + public void whenSortingtoCollectToList_thenSuccess() { + + List result = Stream.of(Locale.getISOCountries()) + .collect(Collectors.toList()); + + Assertions.assertDoesNotThrow(() -> { + result.sort(String::compareToIgnoreCase); + }); + } + + @Test + public void whenAddingCollectUnmodifiableToList_thenException() { + + List result = Stream.of(Locale.getISOCountries()) + .collect(Collectors.toUnmodifiableList()); + + Assertions.assertThrows(UnsupportedOperationException.class, () -> { + result.add("test"); + }); + } + + @Test + public void whenSortingCollectUnmodifiableToList_thenSortException() { + + List result = Stream.of(Locale.getISOCountries()) + .collect(Collectors.toUnmodifiableList()); + + Assertions.assertThrows(UnsupportedOperationException.class, () -> { + result.sort(String::compareToIgnoreCase); + }); + } + + @Test + public void whenAddingStreamToList_thenException() { + + List result = Stream.of(Locale.getISOCountries()) + .toList(); + + Assertions.assertThrows(UnsupportedOperationException.class, () -> { + result.add("test"); + }); + } + + @Test + public void whenSortingStreamToList_thenException() { + + List result = Stream.of(Locale.getISOCountries()) + .toList(); + + Assertions.assertThrows(UnsupportedOperationException.class, () -> { + result.sort(String::compareToIgnoreCase); + }); + } + + @Test + public void whenComparingStreamToList_withCollectToList_thenEqual() { + + List streamToList = Stream.of(Locale.getISOCountries()) + .toList(); + List collectToList = Stream.of(Locale.getISOCountries()) + .collect(Collectors.toList()); + + Assertions.assertEquals(streamToList, collectToList); + } + + @Test + public void whenComparingStreamToList_withUnmodifiedCollectToList_thenEqual() { + + List streamToList = Stream.of(Locale.getISOCountries()) + .toList(); + List collectToUnmodifiableList = Stream.of(Locale.getISOCountries()) + .collect(Collectors.toUnmodifiableList()); + + Assertions.assertEquals(streamToList, collectToUnmodifiableList); + } + + @Test + public void whenNullCollectorsToList_thenSuccess() { + + Assertions.assertDoesNotThrow(() -> { + Stream.of(null, null) + .collect(Collectors.toList()); + }); + } + + @Test + public void whenNullCollectorsUnmodifiableToList_thenException() { + + Assertions.assertThrows(NullPointerException.class, () -> { + Stream.of(null, null) + .collect(Collectors.toUnmodifiableList()); + }); + } + + @Test + public void whenNullStreamToList_thenSuccess() { + + Assertions.assertDoesNotThrow(() -> { + Stream.of(null, null) + .toList(); + }); + } + +} diff --git a/core-java-modules/core-java-8-2/pom.xml b/core-java-modules/core-java-8-2/pom.xml index e1a861a63c..f3e60f8d5f 100644 --- a/core-java-modules/core-java-8-2/pom.xml +++ b/core-java-modules/core-java-8-2/pom.xml @@ -7,7 +7,7 @@ 0.1.0-SNAPSHOT core-java-8-2 jar - + com.baeldung.core-java-modules core-java-modules diff --git a/core-java-modules/core-java-8-datetime-2/pom.xml b/core-java-modules/core-java-8-datetime-2/pom.xml index 9972122544..a5a0417374 100644 --- a/core-java-modules/core-java-8-datetime-2/pom.xml +++ b/core-java-modules/core-java-8-datetime-2/pom.xml @@ -7,7 +7,7 @@ ${project.parent.version} core-java-8-datetime-2 jar - + com.baeldung.core-java-modules core-java-modules diff --git a/core-java-modules/core-java-8-datetime/pom.xml b/core-java-modules/core-java-8-datetime/pom.xml index 48b2d062b0..a79d5d089b 100644 --- a/core-java-modules/core-java-8-datetime/pom.xml +++ b/core-java-modules/core-java-8-datetime/pom.xml @@ -7,7 +7,7 @@ ${project.parent.version} core-java-8-datetime jar - + com.baeldung.core-java-modules core-java-modules diff --git a/core-java-modules/core-java-8/README.md b/core-java-modules/core-java-8/README.md index 72bdafe5fa..ff4ceaf6db 100644 --- a/core-java-modules/core-java-8/README.md +++ b/core-java-modules/core-java-8/README.md @@ -4,7 +4,6 @@ This module contains articles about Java 8 core features ### Relevant Articles: - [New Features in Java 8](https://www.baeldung.com/java-8-new-features) -- [Guide to Java 8 groupingBy Collector](https://www.baeldung.com/java-groupingby-collector) - [Strategy Design Pattern in Java 8](https://www.baeldung.com/java-strategy-pattern) - [Guide to Java 8 Comparator.comparing()](https://www.baeldung.com/java-8-comparator-comparing) - [Guide to the Java 8 forEach](https://www.baeldung.com/foreach-java) diff --git a/core-java-modules/core-java-8/pom.xml b/core-java-modules/core-java-8/pom.xml index 13b2fbcf89..a7a2a1a0f8 100644 --- a/core-java-modules/core-java-8/pom.xml +++ b/core-java-modules/core-java-8/pom.xml @@ -7,7 +7,7 @@ 0.1.0-SNAPSHOT core-java-8 jar - + com.baeldung.core-java-modules core-java-modules diff --git a/core-java-modules/core-java-8/src/main/java/com/baeldung/java_8_features/groupingby/BlogPost.java b/core-java-modules/core-java-8/src/main/java/com/baeldung/java_8_features/groupingby/BlogPost.java deleted file mode 100644 index afc05e356a..0000000000 --- a/core-java-modules/core-java-8/src/main/java/com/baeldung/java_8_features/groupingby/BlogPost.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.baeldung.java_8_features.groupingby; - -public class BlogPost { - private String title; - private String author; - private BlogPostType type; - private int likes; - - public BlogPost(String title, String author, BlogPostType type, int likes) { - this.title = title; - this.author = author; - this.type = type; - this.likes = likes; - } - - public String getTitle() { - return title; - } - - public String getAuthor() { - return author; - } - - public BlogPostType getType() { - return type; - } - - public int getLikes() { - return likes; - } - - @Override - public String toString() { - return "BlogPost{" + "title='" + title + '\'' + ", type=" + type + ", likes=" + likes + '}'; - } -} diff --git a/core-java-modules/core-java-8/src/main/java/com/baeldung/java_8_features/groupingby/BlogPostType.java b/core-java-modules/core-java-8/src/main/java/com/baeldung/java_8_features/groupingby/BlogPostType.java deleted file mode 100644 index 2029784e91..0000000000 --- a/core-java-modules/core-java-8/src/main/java/com/baeldung/java_8_features/groupingby/BlogPostType.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.baeldung.java_8_features.groupingby; - -public enum BlogPostType { - NEWS, REVIEW, GUIDE -} diff --git a/core-java-modules/core-java-8/src/main/java/com/baeldung/java_8_features/groupingby/Tuple.java b/core-java-modules/core-java-8/src/main/java/com/baeldung/java_8_features/groupingby/Tuple.java deleted file mode 100644 index 82a84bb2d6..0000000000 --- a/core-java-modules/core-java-8/src/main/java/com/baeldung/java_8_features/groupingby/Tuple.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.baeldung.java_8_features.groupingby; - -import java.util.Objects; - -public class Tuple { - private final BlogPostType type; - private final String author; - - public Tuple(BlogPostType type, String author) { - this.type = type; - this.author = author; - } - - public BlogPostType getType() { - return type; - } - - public String getAuthor() { - return author; - } - - @Override - public boolean equals(Object o) { - if (this == o) - return true; - if (o == null || getClass() != o.getClass()) - return false; - Tuple tuple = (Tuple) o; - return type == tuple.type && author.equals(tuple.author); - } - - @Override - public int hashCode() { - return Objects.hash(type, author); - } - - @Override - public String toString() { - return "Tuple{" + "type=" + type + ", author='" + author + '\'' + '}'; - } -} diff --git a/core-java-modules/core-java-8/src/test/java/com/baeldung/java_8_features/groupingby/Java8GroupingByCollectorUnitTest.java b/core-java-modules/core-java-8/src/test/java/com/baeldung/java_8_features/groupingby/Java8GroupingByCollectorUnitTest.java deleted file mode 100644 index 1da705294e..0000000000 --- a/core-java-modules/core-java-8/src/test/java/com/baeldung/java_8_features/groupingby/Java8GroupingByCollectorUnitTest.java +++ /dev/null @@ -1,215 +0,0 @@ -package com.baeldung.java_8_features.groupingby; - -import static java.util.Comparator.comparingInt; -import static java.util.stream.Collectors.averagingInt; -import static java.util.stream.Collectors.counting; -import static java.util.stream.Collectors.groupingBy; -import static java.util.stream.Collectors.groupingByConcurrent; -import static java.util.stream.Collectors.joining; -import static java.util.stream.Collectors.mapping; -import static java.util.stream.Collectors.maxBy; -import static java.util.stream.Collectors.summarizingInt; -import static java.util.stream.Collectors.summingInt; -import static java.util.stream.Collectors.toList; -import static java.util.stream.Collectors.toSet; -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; - -import java.util.Arrays; -import java.util.EnumMap; -import java.util.IntSummaryStatistics; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.concurrent.ConcurrentMap; - -import org.junit.Test; - -public class Java8GroupingByCollectorUnitTest { - - private static final List posts = Arrays.asList(new BlogPost("News item 1", "Author 1", BlogPostType.NEWS, 15), new BlogPost("Tech review 1", "Author 2", BlogPostType.REVIEW, 5), - new BlogPost("Programming guide", "Author 1", BlogPostType.GUIDE, 20), new BlogPost("News item 2", "Author 2", BlogPostType.NEWS, 35), new BlogPost("Tech review 2", "Author 1", BlogPostType.REVIEW, 15)); - - @Test - public void givenAListOfPosts_whenGroupedByType_thenGetAMapBetweenTypeAndPosts() { - Map> postsPerType = posts.stream() - .collect(groupingBy(BlogPost::getType)); - - assertEquals(2, postsPerType.get(BlogPostType.NEWS) - .size()); - assertEquals(1, postsPerType.get(BlogPostType.GUIDE) - .size()); - assertEquals(2, postsPerType.get(BlogPostType.REVIEW) - .size()); - } - - @Test - public void givenAListOfPosts_whenGroupedByTypeAndTheirTitlesAreJoinedInAString_thenGetAMapBetweenTypeAndCsvTitles() { - Map postsPerType = posts.stream() - .collect(groupingBy(BlogPost::getType, mapping(BlogPost::getTitle, joining(", ", "Post titles: [", "]")))); - - assertEquals("Post titles: [News item 1, News item 2]", postsPerType.get(BlogPostType.NEWS)); - assertEquals("Post titles: [Programming guide]", postsPerType.get(BlogPostType.GUIDE)); - assertEquals("Post titles: [Tech review 1, Tech review 2]", postsPerType.get(BlogPostType.REVIEW)); - } - - @Test - public void givenAListOfPosts_whenGroupedByTypeAndSumTheLikes_thenGetAMapBetweenTypeAndPostLikes() { - Map likesPerType = posts.stream() - .collect(groupingBy(BlogPost::getType, summingInt(BlogPost::getLikes))); - - assertEquals(50, likesPerType.get(BlogPostType.NEWS) - .intValue()); - assertEquals(20, likesPerType.get(BlogPostType.REVIEW) - .intValue()); - assertEquals(20, likesPerType.get(BlogPostType.GUIDE) - .intValue()); - } - - @Test - public void givenAListOfPosts_whenGroupedByTypeInAnEnumMap_thenGetAnEnumMapBetweenTypeAndPosts() { - EnumMap> postsPerType = posts.stream() - .collect(groupingBy(BlogPost::getType, () -> new EnumMap<>(BlogPostType.class), toList())); - - assertEquals(2, postsPerType.get(BlogPostType.NEWS) - .size()); - assertEquals(1, postsPerType.get(BlogPostType.GUIDE) - .size()); - assertEquals(2, postsPerType.get(BlogPostType.REVIEW) - .size()); - } - - @Test - public void givenAListOfPosts_whenGroupedByTypeInSets_thenGetAMapBetweenTypesAndSetsOfPosts() { - Map> postsPerType = posts.stream() - .collect(groupingBy(BlogPost::getType, toSet())); - - assertEquals(2, postsPerType.get(BlogPostType.NEWS) - .size()); - assertEquals(1, postsPerType.get(BlogPostType.GUIDE) - .size()); - assertEquals(2, postsPerType.get(BlogPostType.REVIEW) - .size()); - } - - @Test - public void givenAListOfPosts_whenGroupedByTypeConcurrently_thenGetAMapBetweenTypeAndPosts() { - ConcurrentMap> postsPerType = posts.parallelStream() - .collect(groupingByConcurrent(BlogPost::getType)); - - assertEquals(2, postsPerType.get(BlogPostType.NEWS) - .size()); - assertEquals(1, postsPerType.get(BlogPostType.GUIDE) - .size()); - assertEquals(2, postsPerType.get(BlogPostType.REVIEW) - .size()); - } - - @Test - public void givenAListOfPosts_whenGroupedByTypeAndAveragingLikes_thenGetAMapBetweenTypeAndAverageNumberOfLikes() { - Map averageLikesPerType = posts.stream() - .collect(groupingBy(BlogPost::getType, averagingInt(BlogPost::getLikes))); - - assertEquals(25, averageLikesPerType.get(BlogPostType.NEWS) - .intValue()); - assertEquals(20, averageLikesPerType.get(BlogPostType.GUIDE) - .intValue()); - assertEquals(10, averageLikesPerType.get(BlogPostType.REVIEW) - .intValue()); - } - - @Test - public void givenAListOfPosts_whenGroupedByTypeAndCounted_thenGetAMapBetweenTypeAndNumberOfPosts() { - Map numberOfPostsPerType = posts.stream() - .collect(groupingBy(BlogPost::getType, counting())); - - assertEquals(2, numberOfPostsPerType.get(BlogPostType.NEWS) - .intValue()); - assertEquals(1, numberOfPostsPerType.get(BlogPostType.GUIDE) - .intValue()); - assertEquals(2, numberOfPostsPerType.get(BlogPostType.REVIEW) - .intValue()); - } - - @Test - public void givenAListOfPosts_whenGroupedByTypeAndMaxingLikes_thenGetAMapBetweenTypeAndMaximumNumberOfLikes() { - Map> maxLikesPerPostType = posts.stream() - .collect(groupingBy(BlogPost::getType, maxBy(comparingInt(BlogPost::getLikes)))); - - assertTrue(maxLikesPerPostType.get(BlogPostType.NEWS) - .isPresent()); - assertEquals(35, maxLikesPerPostType.get(BlogPostType.NEWS) - .get() - .getLikes()); - - assertTrue(maxLikesPerPostType.get(BlogPostType.GUIDE) - .isPresent()); - assertEquals(20, maxLikesPerPostType.get(BlogPostType.GUIDE) - .get() - .getLikes()); - - assertTrue(maxLikesPerPostType.get(BlogPostType.REVIEW) - .isPresent()); - assertEquals(15, maxLikesPerPostType.get(BlogPostType.REVIEW) - .get() - .getLikes()); - } - - @Test - public void givenAListOfPosts_whenGroupedByAuthorAndThenByType_thenGetAMapBetweenAuthorAndMapsBetweenTypeAndBlogPosts() { - Map>> map = posts.stream() - .collect(groupingBy(BlogPost::getAuthor, groupingBy(BlogPost::getType))); - - assertEquals(1, map.get("Author 1") - .get(BlogPostType.NEWS) - .size()); - assertEquals(1, map.get("Author 1") - .get(BlogPostType.GUIDE) - .size()); - assertEquals(1, map.get("Author 1") - .get(BlogPostType.REVIEW) - .size()); - - assertEquals(1, map.get("Author 2") - .get(BlogPostType.NEWS) - .size()); - assertEquals(1, map.get("Author 2") - .get(BlogPostType.REVIEW) - .size()); - assertNull(map.get("Author 2") - .get(BlogPostType.GUIDE)); - } - - @Test - public void givenAListOfPosts_whenGroupedByTypeAndSummarizingLikes_thenGetAMapBetweenTypeAndSummary() { - Map likeStatisticsPerType = posts.stream() - .collect(groupingBy(BlogPost::getType, summarizingInt(BlogPost::getLikes))); - - IntSummaryStatistics newsLikeStatistics = likeStatisticsPerType.get(BlogPostType.NEWS); - - assertEquals(2, newsLikeStatistics.getCount()); - assertEquals(50, newsLikeStatistics.getSum()); - assertEquals(25.0, newsLikeStatistics.getAverage(), 0.001); - assertEquals(35, newsLikeStatistics.getMax()); - assertEquals(15, newsLikeStatistics.getMin()); - } - - @Test - public void givenAListOfPosts_whenGroupedByComplexMapKeyType_thenGetAMapBetweenTupleAndList() { - Map> postsPerTypeAndAuthor = posts.stream() - .collect(groupingBy(post -> new Tuple(post.getType(), post.getAuthor()))); - - List result = postsPerTypeAndAuthor.get(new Tuple(BlogPostType.GUIDE, "Author 1")); - - assertThat(result.size()).isEqualTo(1); - - BlogPost blogPost = result.get(0); - - assertThat(blogPost.getTitle()).isEqualTo("Programming guide"); - assertThat(blogPost.getType()).isEqualTo(BlogPostType.GUIDE); - assertThat(blogPost.getAuthor()).isEqualTo("Author 1"); - } -} diff --git a/core-java-modules/core-java-9-new-features/pom.xml b/core-java-modules/core-java-9-new-features/pom.xml index 2f174002bb..00480a28e1 100644 --- a/core-java-modules/core-java-9-new-features/pom.xml +++ b/core-java-modules/core-java-9-new-features/pom.xml @@ -39,7 +39,7 @@ test - + incubator-features @@ -131,7 +131,7 @@ - + core-java-9-new-features 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 0e003b5cd9..f0d3d1fd93 100644 --- a/core-java-modules/core-java-arrays-operations-advanced/README.md +++ b/core-java-modules/core-java-arrays-operations-advanced/README.md @@ -10,3 +10,4 @@ This module contains articles about advanced operations on arrays in Java. They - [Intersection Between two Integer Arrays](https://www.baeldung.com/java-array-intersection) - [Comparing Arrays in Java](https://www.baeldung.com/java-comparing-arrays) - [Concatenate Two Arrays in Java](https://www.baeldung.com/java-concatenate-arrays) +- [Performance of System.arraycopy() vs. Arrays.copyOf()](https://www.baeldung.com/java-system-arraycopy-arrays-copyof-performance) diff --git a/core-java-modules/core-java-arrays-operations-advanced/pom.xml b/core-java-modules/core-java-arrays-operations-advanced/pom.xml index 5663a7d1ca..065f1930e2 100644 --- a/core-java-modules/core-java-arrays-operations-advanced/pom.xml +++ b/core-java-modules/core-java-arrays-operations-advanced/pom.xml @@ -26,10 +26,50 @@ ${assertj-core.version} test + + + org.openjdk.jmh + jmh-core + ${jmh.version} + + + + org.openjdk.jmh + jmh-generator-annprocess + ${jmh.version} + 3.10.0 + 1.33 + + + + maven-assembly-plugin + + + jar-with-dependencies + + + + com.baeldung.copyarraymethodsperformance.BenchmarkRunner + + + + + + make-assembly + package + + single + + + + + + + \ No newline at end of file diff --git a/core-java-modules/core-java-arrays-operations-advanced/src/main/java/com/baeldung/copyarraymethodsperformance/BenchmarkRunner.java b/core-java-modules/core-java-arrays-operations-advanced/src/main/java/com/baeldung/copyarraymethodsperformance/BenchmarkRunner.java new file mode 100644 index 0000000000..0adbcc1986 --- /dev/null +++ b/core-java-modules/core-java-arrays-operations-advanced/src/main/java/com/baeldung/copyarraymethodsperformance/BenchmarkRunner.java @@ -0,0 +1,11 @@ +package com.baeldung.copyarraymethodsperformance; + +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-arrays-operations-advanced/src/main/java/com/baeldung/copyarraymethodsperformance/ObjectsCopyBenchmark.java b/core-java-modules/core-java-arrays-operations-advanced/src/main/java/com/baeldung/copyarraymethodsperformance/ObjectsCopyBenchmark.java new file mode 100644 index 0000000000..6a492bf0d1 --- /dev/null +++ b/core-java-modules/core-java-arrays-operations-advanced/src/main/java/com/baeldung/copyarraymethodsperformance/ObjectsCopyBenchmark.java @@ -0,0 +1,42 @@ +package com.baeldung.copyarraymethodsperformance; + +import org.openjdk.jmh.annotations.*; + +import java.util.Arrays; +import java.util.Random; +import java.util.concurrent.TimeUnit; + +@BenchmarkMode(Mode.AverageTime) +@State(Scope.Thread) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@Warmup(iterations = 10) +@Fork(1) +@Measurement(iterations = 100) +public class ObjectsCopyBenchmark { + + @Param({ "10", "1000000" }) + public int SIZE; + Integer[] src; + + @Setup + public void setup() { + Random r = new Random(); + src = new Integer[SIZE]; + + for (int i = 0; i < SIZE; i++) { + src[i] = r.nextInt(); + } + } + + @Benchmark + public Integer[] systemArrayCopyBenchmark() { + Integer[] target = new Integer[SIZE]; + System.arraycopy(src, 0, target, 0, SIZE); + return target; + } + + @Benchmark + public Integer[] arraysCopyOfBenchmark() { + return Arrays.copyOf(src, SIZE); + } +} diff --git a/core-java-modules/core-java-arrays-operations-advanced/src/main/java/com/baeldung/copyarraymethodsperformance/PrimitivesCopyBenchmark.java b/core-java-modules/core-java-arrays-operations-advanced/src/main/java/com/baeldung/copyarraymethodsperformance/PrimitivesCopyBenchmark.java new file mode 100644 index 0000000000..767e91a350 --- /dev/null +++ b/core-java-modules/core-java-arrays-operations-advanced/src/main/java/com/baeldung/copyarraymethodsperformance/PrimitivesCopyBenchmark.java @@ -0,0 +1,43 @@ +package com.baeldung.copyarraymethodsperformance; + +import org.openjdk.jmh.annotations.*; + +import java.util.Arrays; +import java.util.Random; +import java.util.concurrent.TimeUnit; + +@BenchmarkMode(Mode.AverageTime) +@State(Scope.Thread) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@Warmup(iterations = 10) +@Fork(1) +@Measurement(iterations = 100) +public class PrimitivesCopyBenchmark { + + @Param({ "10", "1000000" }) + public int SIZE; + + int[] src; + + @Setup + public void setup() { + Random r = new Random(); + src = new int[SIZE]; + + for (int i = 0; i < SIZE; i++) { + src[i] = r.nextInt(); + } + } + + @Benchmark + public int[] systemArrayCopyBenchmark() { + int[] target = new int[SIZE]; + System.arraycopy(src, 0, target, 0, SIZE); + return target; + } + + @Benchmark + public int[] arraysCopyOfBenchmark() { + return Arrays.copyOf(src, SIZE); + } +} diff --git a/core-java-modules/core-java-arrays-sorting/pom.xml b/core-java-modules/core-java-arrays-sorting/pom.xml index d30e2bfabc..8c55204347 100644 --- a/core-java-modules/core-java-arrays-sorting/pom.xml +++ b/core-java-modules/core-java-arrays-sorting/pom.xml @@ -78,4 +78,5 @@ 28.2-jre 3.10.0 + \ No newline at end of file diff --git a/core-java-modules/core-java-char/pom.xml b/core-java-modules/core-java-char/pom.xml index ef356d9542..23156b5a22 100644 --- a/core-java-modules/core-java-char/pom.xml +++ b/core-java-modules/core-java-char/pom.xml @@ -7,7 +7,7 @@ 0.1.0-SNAPSHOT core-java-char jar - + com.baeldung.core-java-modules core-java-modules diff --git a/core-java-modules/core-java-collections-2/pom.xml b/core-java-modules/core-java-collections-2/pom.xml index 421ba9abac..ad76990af3 100644 --- a/core-java-modules/core-java-collections-2/pom.xml +++ b/core-java-modules/core-java-collections-2/pom.xml @@ -6,7 +6,7 @@ core-java-collections-2 core-java-collections-2 jar - + com.baeldung.core-java-modules core-java-modules diff --git a/core-java-modules/core-java-collections-3/pom.xml b/core-java-modules/core-java-collections-3/pom.xml index c7b1284d5c..40f1867738 100644 --- a/core-java-modules/core-java-collections-3/pom.xml +++ b/core-java-modules/core-java-collections-3/pom.xml @@ -7,7 +7,7 @@ 0.1.0-SNAPSHOT core-java-collections-3 jar - + com.baeldung.core-java-modules core-java-modules diff --git a/core-java-modules/core-java-collections-4/pom.xml b/core-java-modules/core-java-collections-4/pom.xml index 7eb8222211..9dc26cd5d5 100644 --- a/core-java-modules/core-java-collections-4/pom.xml +++ b/core-java-modules/core-java-collections-4/pom.xml @@ -1,31 +1,31 @@ - 4.0.0 - core-java-collections-4 - 0.1.0-SNAPSHOT - core-java-collections-4 - jar + 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 + core-java-collections-4 + 0.1.0-SNAPSHOT + core-java-collections-4 + jar - - com.baeldung.core-java-modules - core-java-modules - 0.0.1-SNAPSHOT - ../pom.xml - + + com.baeldung.core-java-modules + core-java-modules + 0.0.1-SNAPSHOT + ../pom.xml + - - - org.assertj - assertj-core - ${assertj.version} - test - - + + + org.assertj + assertj-core + ${assertj.version} + test + + - - 3.19.0 - + + 3.19.0 + \ No newline at end of file diff --git a/core-java-modules/core-java-collections-maps-3/README.md b/core-java-modules/core-java-collections-maps-3/README.md index 530a9310c2..68df2b9556 100644 --- a/core-java-modules/core-java-collections-maps-3/README.md +++ b/core-java-modules/core-java-collections-maps-3/README.md @@ -8,5 +8,5 @@ This module contains articles about Map data structures in Java. - [The Map.computeIfAbsent() Method](https://www.baeldung.com/java-map-computeifabsent) - [Collections.synchronizedMap vs. ConcurrentHashMap](https://www.baeldung.com/java-synchronizedmap-vs-concurrenthashmap) - [Java HashMap Load Factor](https://www.baeldung.com/java-hashmap-load-factor) -- [Converting java.util.Properties to HashMap](https://www.baeldung.com/java-convert-properties-to-hashmap) +- [Converting Java Properties to HashMap](https://www.baeldung.com/java-convert-properties-to-hashmap) - More articles: [[<-- prev]](/core-java-modules/core-java-collections-maps-2) diff --git a/core-java-modules/core-java-collections-maps-4/README.md b/core-java-modules/core-java-collections-maps-4/README.md new file mode 100644 index 0000000000..4449d3859b --- /dev/null +++ b/core-java-modules/core-java-collections-maps-4/README.md @@ -0,0 +1,6 @@ +## Java Collections Cookbooks and Examples + +This module contains articles about Map data structures in Java. + +### Relevant Articles: +- [Using a Custom Class as a Key in a Java HashMap](https://www.baeldung.com/custom-key-hashmap) diff --git a/core-java-modules/core-java-collections-maps-4/pom.xml b/core-java-modules/core-java-collections-maps-4/pom.xml new file mode 100644 index 0000000000..1835e3ceac --- /dev/null +++ b/core-java-modules/core-java-collections-maps-4/pom.xml @@ -0,0 +1,34 @@ + + + 4.0.0 + core-java-collections-maps-4 + 0.1.0-SNAPSHOT + core-java-collections-maps-4 + jar + + + com.baeldung.core-java-modules + core-java-modules + 0.0.1-SNAPSHOT + ../pom.xml + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 3.0.0-M5 + + + !performance + + + + + + + diff --git a/core-java-modules/core-java-collections-maps-4/src/main/java/com/baeldung/maps/CoordinateKey.java b/core-java-modules/core-java-collections-maps-4/src/main/java/com/baeldung/maps/CoordinateKey.java new file mode 100644 index 0000000000..34ae3d7952 --- /dev/null +++ b/core-java-modules/core-java-collections-maps-4/src/main/java/com/baeldung/maps/CoordinateKey.java @@ -0,0 +1,39 @@ +package com.baeldung.maps; + +import java.util.Objects; + +public class CoordinateKey { + + private final int x; + private final int y; + private final int hashCode; + + public CoordinateKey(int x, int y) { + this.x = x; + this.y = y; + this.hashCode = Objects.hash(x, y); + } + + public int getX() { + return x; + } + + public int getY() { + return y; + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + CoordinateKey that = (CoordinateKey) o; + return x == that.x && y == that.y; + } + + @Override + public int hashCode() { + return this.hashCode; + } +} diff --git a/core-java-modules/core-java-collections-maps-4/src/main/java/com/baeldung/maps/CoordinateMutableKey.java b/core-java-modules/core-java-collections-maps-4/src/main/java/com/baeldung/maps/CoordinateMutableKey.java new file mode 100644 index 0000000000..08b329de3d --- /dev/null +++ b/core-java-modules/core-java-collections-maps-4/src/main/java/com/baeldung/maps/CoordinateMutableKey.java @@ -0,0 +1,45 @@ +package com.baeldung.maps; + +import java.util.Objects; + +public class CoordinateMutableKey { + + private int x; + private int y; + + public CoordinateMutableKey(int x, int y) { + this.x = x; + this.y = y; + } + + public int getX() { + return x; + } + + public void setX(int x) { + this.x = x; + } + + public int getY() { + return y; + } + + public void setY(int y) { + this.y = y; + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + CoordinateMutableKey that = (CoordinateMutableKey) o; + return x == that.x && y == that.y; + } + + @Override + public int hashCode() { + return Objects.hash(x, y); + } +} diff --git a/core-java-modules/core-java-collections-maps-4/src/main/java/com/baeldung/maps/CoordinateSlowKey.java b/core-java-modules/core-java-collections-maps-4/src/main/java/com/baeldung/maps/CoordinateSlowKey.java new file mode 100644 index 0000000000..9fe54bd9ea --- /dev/null +++ b/core-java-modules/core-java-collections-maps-4/src/main/java/com/baeldung/maps/CoordinateSlowKey.java @@ -0,0 +1,13 @@ +package com.baeldung.maps; + +public class CoordinateSlowKey extends CoordinateKey { + + public CoordinateSlowKey(int x, int y) { + super(x, y); + } + + @Override + public int hashCode() { + return 1; + } +} diff --git a/core-java-modules/core-java-collections-maps-4/src/test/java/com/baeldung/maps/CoordinateKeyUnitTest.java b/core-java-modules/core-java-collections-maps-4/src/test/java/com/baeldung/maps/CoordinateKeyUnitTest.java new file mode 100644 index 0000000000..8ee68c4a3d --- /dev/null +++ b/core-java-modules/core-java-collections-maps-4/src/test/java/com/baeldung/maps/CoordinateKeyUnitTest.java @@ -0,0 +1,80 @@ +package com.baeldung.maps; + +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; + +import java.awt.*; +import java.util.HashMap; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +public class CoordinateKeyUnitTest { + + private Map pixels = new HashMap<>(); + + @Test + void testOptimalKey() { + // setup + CoordinateKey coord = new CoordinateKey(1, 2); + pixels.put(coord, Color.CYAN); + // read out color correctly + assertEquals(Color.CYAN, pixels.get(coord)); + } + + @Test + void testSlowKey() { + // setup + CoordinateKey coord = new CoordinateSlowKey(1, 2); + pixels.put(coord, Color.CYAN); + // read out color correctly + assertEquals(Color.CYAN, pixels.get(coord)); + } + + // Performance Test Parameters - change here + private static final int MAX_X = 100; + private static final int MAX_Y = 100; + private static final int COUNT_OF_QUERIES = 1000; + private static final int QUERY_X = 1; + private static final int QUERY_Y = 1; + + @Tag("performance") + @Test + void testKeyPerformance() { + // generate some sample keys and values + for (int x = 0; x < MAX_X; x++) { + for (int y = 0; y < MAX_Y; y++) { + pixels.put(new CoordinateKey(x, y), new Color(x % 255, y % 255, (x + y) % 255)); + } + } + // read out multiple times and measure time + CoordinateKey coord = new CoordinateKey(QUERY_X, QUERY_Y); + long t1 = System.currentTimeMillis(); + for (int i = 0; i < COUNT_OF_QUERIES; i++) { + assertNotNull(pixels.get(coord)); + } + long t2 = System.currentTimeMillis(); + System.out.printf("Optimal key performance: %d ms%n", t2 - t1); + } + + @Tag("performance") + @Test + void testSlowKeyPerformance() { + // generate some sample keys and values + for (int x = 0; x < MAX_X; x++) { + for (int y = 0; y < MAX_Y; y++) { + pixels.put(new CoordinateSlowKey(x, y), new Color(x % 255, y % 255, (x + y) % 255)); + } + } + // read out multiple times and measure time + CoordinateKey coord = new CoordinateSlowKey(QUERY_X, QUERY_Y); + long t1 = System.currentTimeMillis(); + for (int i = 0; i < COUNT_OF_QUERIES; i++) { + assertNotNull(pixels.get(coord)); + } + long t2 = System.currentTimeMillis(); + System.out.printf("Slow key performance: %d ms%n", t2 - t1); + } + +} diff --git a/core-java-modules/core-java-collections-maps-4/src/test/java/com/baeldung/maps/CoordinateMutableKeyUnitTest.java b/core-java-modules/core-java-collections-maps-4/src/test/java/com/baeldung/maps/CoordinateMutableKeyUnitTest.java new file mode 100644 index 0000000000..54a61be230 --- /dev/null +++ b/core-java-modules/core-java-collections-maps-4/src/test/java/com/baeldung/maps/CoordinateMutableKeyUnitTest.java @@ -0,0 +1,27 @@ +package com.baeldung.maps; + +import org.junit.jupiter.api.Test; + +import java.awt.*; +import java.util.HashMap; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + +public class CoordinateMutableKeyUnitTest { + + @Test + void testKeyMutable() { + // setup + Map pixels = new HashMap<>(); + CoordinateMutableKey coord = new CoordinateMutableKey(1, 2); + pixels.put(coord, Color.CYAN); + // read out color correctly + assertEquals(Color.CYAN, pixels.get(coord)); + // change key's hashcode should result in null value + coord.setX(10); + assertNull(pixels.get(coord)); + } + +} diff --git a/core-java-modules/core-java-collections-maps/pom.xml b/core-java-modules/core-java-collections-maps/pom.xml index 68e5c736cd..855f40c304 100644 --- a/core-java-modules/core-java-collections-maps/pom.xml +++ b/core-java-modules/core-java-collections-maps/pom.xml @@ -33,5 +33,5 @@ 4.1 3.6.1 - - + + \ No newline at end of file diff --git a/core-java-modules/core-java-collections/pom.xml b/core-java-modules/core-java-collections/pom.xml index 81bcdc74aa..38513c889a 100644 --- a/core-java-modules/core-java-collections/pom.xml +++ b/core-java-modules/core-java-collections/pom.xml @@ -7,7 +7,7 @@ 0.1.0-SNAPSHOT core-java-collections jar - + com.baeldung.core-java-modules core-java-modules diff --git a/core-java-modules/core-java-console/README.md b/core-java-modules/core-java-console/README.md index 0a31727588..9236e9cf99 100644 --- a/core-java-modules/core-java-console/README.md +++ b/core-java-modules/core-java-console/README.md @@ -3,6 +3,6 @@ ### Relevant Articles: - [Read and Write User Input in Java](http://www.baeldung.com/java-console-input-output) -- [Formatting with printf() in Java](https://www.baeldung.com/java-printstream-printf) +- [Formatting Output with printf() in Java](https://www.baeldung.com/java-printstream-printf) - [ASCII Art in Java](http://www.baeldung.com/ascii-art-in-java) - [System.console() vs. System.out](https://www.baeldung.com/java-system-console-vs-system-out) diff --git a/core-java-modules/core-java-date-operations-1/pom.xml b/core-java-modules/core-java-date-operations-1/pom.xml index 955cd910e9..7b7c68d1b6 100644 --- a/core-java-modules/core-java-date-operations-1/pom.xml +++ b/core-java-modules/core-java-date-operations-1/pom.xml @@ -26,7 +26,6 @@ commons-lang3 ${commons-lang3.version} - org.assertj assertj-core diff --git a/core-java-modules/core-java-datetime-string/README.md b/core-java-modules/core-java-datetime-string/README.md index cf00bdeb1f..aac123a884 100644 --- a/core-java-modules/core-java-datetime-string/README.md +++ b/core-java-modules/core-java-datetime-string/README.md @@ -11,3 +11,4 @@ This module contains articles about parsing and formatting Java date and time ob - [Display All Time Zones With GMT And UTC in Java](http://www.baeldung.com/java-time-zones) - [Convert between String and Timestamp](https://www.baeldung.com/java-string-to-timestamp) - [Convert String to Date in Java](http://www.baeldung.com/java-string-to-date) +- [Format a Milliseconds Duration to HH:MM:SS](https://www.baeldung.com/java-ms-to-hhmmss) diff --git a/core-java-modules/core-java-exceptions-3/pom.xml b/core-java-modules/core-java-exceptions-3/pom.xml index 6e35845c6a..c4c3c00b56 100644 --- a/core-java-modules/core-java-exceptions-3/pom.xml +++ b/core-java-modules/core-java-exceptions-3/pom.xml @@ -36,4 +36,5 @@ 3.10.0 + \ No newline at end of file diff --git a/core-java-modules/core-java-io-conversions/README.md b/core-java-modules/core-java-io-conversions/README.md index 1f12c87241..52f5222040 100644 --- a/core-java-modules/core-java-io-conversions/README.md +++ b/core-java-modules/core-java-io-conversions/README.md @@ -13,4 +13,5 @@ This module contains articles about core Java input/output(IO) conversions. - [Java – Write a Reader to File](https://www.baeldung.com/java-write-reader-to-file) - [Java – Reader to Byte Array](https://www.baeldung.com/java-convert-reader-to-byte-array) - [Java – Reader to InputStream](https://www.baeldung.com/java-convert-reader-to-inputstream) +- [Java String to InputStream](https://www.baeldung.com/convert-string-to-input-stream) - More articles: [[next -->]](/core-java-modules/core-java-io-conversions-2) diff --git a/core-java-modules/core-java-io/src/main/resources/logback.xml b/core-java-modules/core-java-io/src/main/resources/logback.xml index 56af2d397e..617917dca2 100644 --- a/core-java-modules/core-java-io/src/main/resources/logback.xml +++ b/core-java-modules/core-java-io/src/main/resources/logback.xml @@ -9,6 +9,7 @@ + diff --git a/core-java-modules/core-java-jar/pom.xml b/core-java-modules/core-java-jar/pom.xml index b638f81b0c..ae2333d721 100644 --- a/core-java-modules/core-java-jar/pom.xml +++ b/core-java-modules/core-java-jar/pom.xml @@ -76,6 +76,7 @@ org.apache.maven.plugins maven-dependency-plugin + ${maven-dependency-plugin.version} copy-dependencies @@ -106,6 +107,7 @@ org.apache.maven.plugins maven-assembly-plugin + ${maven-assembly-plugin.version} package @@ -383,6 +385,8 @@ 3.0.2 1.4.4 3.1.1 + 3.3.0 + 3.2.0 2.0.3.RELEASE 1.8 1.8 diff --git a/core-java-modules/core-java-lang-3/src/test/java/com/baeldung/isinstancevsisassignablefrom/IsInstanceIsAssignableFromUnitTest.java b/core-java-modules/core-java-lang-3/src/test/java/com/baeldung/isinstancevsisassignablefrom/IsInstanceIsAssignableFromUnitTest.java index e0ad264797..3e4ee0a1bb 100644 --- a/core-java-modules/core-java-lang-3/src/test/java/com/baeldung/isinstancevsisassignablefrom/IsInstanceIsAssignableFromUnitTest.java +++ b/core-java-modules/core-java-lang-3/src/test/java/com/baeldung/isinstancevsisassignablefrom/IsInstanceIsAssignableFromUnitTest.java @@ -6,57 +6,80 @@ import static org.junit.Assert.assertTrue; import org.junit.Test; public class IsInstanceIsAssignableFromUnitTest { - + @Test - public void whenUsingIsInstanceProperly_desiredResultsHappen() { + public void whenUsingInstanceOfProperly_thenDesiredResultsHappen() { + Shape shape = new Triangle(); + Triangle triangle = new Triangle(); + IsoscelesTriangle isoscelesTriangle = new IsoscelesTriangle(); + Shape nonspecificShape = null; + + assertTrue(shape instanceof Shape); + assertTrue(triangle instanceof Shape); + assertTrue(isoscelesTriangle instanceof Shape); + assertFalse(nonspecificShape instanceof Shape); + + assertTrue(shape instanceof Triangle); + assertTrue(triangle instanceof Triangle); + assertTrue(isoscelesTriangle instanceof Triangle); + assertFalse(nonspecificShape instanceof Triangle); + + assertFalse(shape instanceof IsoscelesTriangle); + assertFalse(triangle instanceof IsoscelesTriangle); + assertTrue(isoscelesTriangle instanceof IsoscelesTriangle); + assertFalse(nonspecificShape instanceof IsoscelesTriangle); + } + + @Test + public void whenUsingIsInstanceProperly_thenDesiredResultsHappen() { Shape shape = new Triangle(); Triangle triangle = new Triangle(); IsoscelesTriangle isoscelesTriangle = new IsoscelesTriangle(); Triangle isoscelesTriangle2 = new IsoscelesTriangle(); Shape nonspecificShape = null; - + assertTrue(Shape.class.isInstance(shape)); assertTrue(Shape.class.isInstance(triangle)); assertTrue(Shape.class.isInstance(isoscelesTriangle)); assertTrue(Shape.class.isInstance(isoscelesTriangle2)); assertFalse(Shape.class.isInstance(nonspecificShape)); - + assertTrue(Triangle.class.isInstance(shape)); assertTrue(Triangle.class.isInstance(triangle)); assertTrue(Triangle.class.isInstance(isoscelesTriangle)); assertTrue(Triangle.class.isInstance(isoscelesTriangle2)); - + assertFalse(IsoscelesTriangle.class.isInstance(shape)); assertFalse(IsoscelesTriangle.class.isInstance(triangle)); assertTrue(IsoscelesTriangle.class.isInstance(isoscelesTriangle)); - assertTrue(IsoscelesTriangle.class.isInstance(isoscelesTriangle2)); + assertTrue(IsoscelesTriangle.class.isInstance(isoscelesTriangle2)); } - + @Test - public void whenUsingIsAssignableFromProperly_desiredResultsHappen() { + public void whenUsingIsAssignableFromProperly_thenDesiredResultsHappen() { Shape shape = new Triangle(); Triangle triangle = new Triangle(); IsoscelesTriangle isoscelesTriangle = new IsoscelesTriangle(); Triangle isoscelesTriangle2 = new IsoscelesTriangle(); - + assertFalse(shape.getClass().isAssignableFrom(Shape.class)); assertTrue(shape.getClass().isAssignableFrom(shape.getClass())); assertTrue(shape.getClass().isAssignableFrom(triangle.getClass())); assertTrue(shape.getClass().isAssignableFrom(isoscelesTriangle.getClass())); assertTrue(shape.getClass().isAssignableFrom(isoscelesTriangle2.getClass())); - + assertFalse(triangle.getClass().isAssignableFrom(Shape.class)); assertTrue(triangle.getClass().isAssignableFrom(shape.getClass())); assertTrue(triangle.getClass().isAssignableFrom(triangle.getClass())); assertTrue(triangle.getClass().isAssignableFrom(isoscelesTriangle.getClass())); assertTrue(triangle.getClass().isAssignableFrom(isoscelesTriangle2.getClass())); - + assertFalse(isoscelesTriangle.getClass().isAssignableFrom(Shape.class)); assertFalse(isoscelesTriangle.getClass().isAssignableFrom(shape.getClass())); assertFalse(isoscelesTriangle.getClass().isAssignableFrom(triangle.getClass())); assertTrue(isoscelesTriangle.getClass().isAssignableFrom(isoscelesTriangle.getClass())); assertTrue(isoscelesTriangle.getClass().isAssignableFrom(isoscelesTriangle2.getClass())); - + assertFalse(isoscelesTriangle2.getClass().isAssignableFrom(Shape.class)); assertFalse(isoscelesTriangle2.getClass().isAssignableFrom(shape.getClass())); assertFalse(isoscelesTriangle2.getClass().isAssignableFrom(triangle.getClass())); @@ -64,4 +87,31 @@ public class IsInstanceIsAssignableFromUnitTest { assertTrue(isoscelesTriangle2.getClass().isAssignableFrom(isoscelesTriangle2.getClass())); } + @Test(expected = NullPointerException.class) + public void whenUsingNull_thenDesiredResultsHappen() { + assertFalse(null instanceof Shape); + assertFalse(Shape.class.isInstance(null)); + assertFalse(Shape.class.isAssignableFrom(null)); // NullPointerException + } + + @Test + public void whenUsingPrimitiveType_thenDesiredResultsHappen() { + //assertFalse(10 instanceof int); // illegal + assertFalse(int.class.isInstance(10)); + assertTrue(Integer.class.isInstance(10)); + assertTrue(int.class.isAssignableFrom(int.class)); + assertFalse(float.class.isAssignableFrom(int.class)); + } + + @Test + public void whenUsingClassInstanceVariable_thenDesiredResultsHappen() { + Shape shape = new Triangle(); + Triangle triangle = new Triangle(); + Class clazz = shape.getClass(); + + //assertFalse(triangle instanceof clazz); // illegal + assertTrue(clazz.isInstance(triangle)); + assertTrue(clazz.isAssignableFrom(triangle.getClass())); + } + } diff --git a/core-java-modules/core-java-lang-4/README.md b/core-java-modules/core-java-lang-4/README.md index 562be950c0..4546a00fe6 100644 --- a/core-java-modules/core-java-lang-4/README.md +++ b/core-java-modules/core-java-lang-4/README.md @@ -8,3 +8,4 @@ This module contains articles about core features in the Java language - [Java Objects.hash() vs Objects.hashCode()](https://www.baeldung.com/java-objects-hash-vs-objects-hashcode) - [Referencing a Method in Javadoc Comments](https://www.baeldung.com/java-method-in-javadoc) - [Tiered Compilation in JVM](https://www.baeldung.com/jvm-tiered-compilation) +- [Fixing the “Declared package does not match the expected package” Error](https://www.baeldung.com/java-declared-expected-package-error) diff --git a/core-java-modules/core-java-lang-4/src/main/java/com/baeldung/bookstore/Book.java b/core-java-modules/core-java-lang-4/src/main/java/com/baeldung/bookstore/Book.java new file mode 100644 index 0000000000..83ed76bab0 --- /dev/null +++ b/core-java-modules/core-java-lang-4/src/main/java/com/baeldung/bookstore/Book.java @@ -0,0 +1,21 @@ +// The next line is commented out to avoid the code to fail the build. +// package com.baeldung; + +/** +* If the below package declaration is commented out and the above incorrect package +* declaration is uncommented, then the problem will replicate. +*/ +package com.baeldung.bookstore; + +public class Book { + + private String title; + private String author; + private long isbn; + + public Book(String title, String author, long isbn) { + this.title = title; + this.author = author; + this.isbn = isbn; + } +} diff --git a/core-java-modules/core-java-lang-4/src/main/java/com/baeldung/bookstore/LibraryAdmin.java b/core-java-modules/core-java-lang-4/src/main/java/com/baeldung/bookstore/LibraryAdmin.java new file mode 100644 index 0000000000..9abd654589 --- /dev/null +++ b/core-java-modules/core-java-lang-4/src/main/java/com/baeldung/bookstore/LibraryAdmin.java @@ -0,0 +1,14 @@ +package com.baeldung.bookstore; + +import java.util.Random; + +public class LibraryAdmin { + + public Book createBook(String title, String author) { + + final long isbn = new Random().nextLong(); + + return new Book(title, author, isbn); + } + +} \ No newline at end of file diff --git a/core-java-modules/core-java-lang-oop-types/pom.xml b/core-java-modules/core-java-lang-oop-types/pom.xml index b770caf970..a5b492f5ca 100644 --- a/core-java-modules/core-java-lang-oop-types/pom.xml +++ b/core-java-modules/core-java-lang-oop-types/pom.xml @@ -25,6 +25,7 @@ ${commons-codec.version} + 1.15 diff --git a/core-java-modules/core-java-networking-3/README.md b/core-java-modules/core-java-networking-3/README.md index 2e76ab5d51..0dc9ad9f70 100644 --- a/core-java-modules/core-java-networking-3/README.md +++ b/core-java-modules/core-java-networking-3/README.md @@ -8,4 +8,5 @@ This module contains articles about networking in Java - [Downloading Email Attachments in Java](https://www.baeldung.com/java-download-email-attachments) - [Connection Timeout vs. Read Timeout for Java Sockets](https://www.baeldung.com/java-socket-connection-read-timeout) - [Find Whether an IP Address Is in the Specified Range or Not in Java](https://www.baeldung.com/java-check-ip-address-range) +- [Find the IP Address of a Client Connected to a Server](https://www.baeldung.com/java-client-get-ip-address) - [[<-- Prev]](/core-java-modules/core-java-networking-2) diff --git a/core-java-modules/core-java-networking-3/src/main/java/com/baeldung/clientaddress/ApplicationClient.java b/core-java-modules/core-java-networking-3/src/main/java/com/baeldung/clientaddress/ApplicationClient.java new file mode 100644 index 0000000000..498046904d --- /dev/null +++ b/core-java-modules/core-java-networking-3/src/main/java/com/baeldung/clientaddress/ApplicationClient.java @@ -0,0 +1,39 @@ +package com.baeldung.clientaddress; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.PrintWriter; +import java.net.Socket; + +public class ApplicationClient { + + private Socket clientSocket; + private PrintWriter out; + private BufferedReader in; + + public void connect(String ip, int port) throws IOException { + clientSocket = new Socket(ip, port); + out = new PrintWriter(clientSocket.getOutputStream(), true); + in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); + } + + public void sendGreetings(String msg) throws IOException { + out.println(msg); + String reply = in.readLine(); + System.out.println("Reply received from the server :: " + reply); + } + + public void disconnect() throws IOException { + in.close(); + out.close(); + clientSocket.close(); + } + + public static void main(String[] args) throws IOException { + ApplicationClient client = new ApplicationClient(); + client.connect(args[0], Integer.parseInt(args[1])); // IP address and port number of the server + client.sendGreetings(args[2]); // greetings message + client.disconnect(); + } +} diff --git a/core-java-modules/core-java-networking-3/src/main/java/com/baeldung/clientaddress/ApplicationServer.java b/core-java-modules/core-java-networking-3/src/main/java/com/baeldung/clientaddress/ApplicationServer.java new file mode 100644 index 0000000000..ded4482b9a --- /dev/null +++ b/core-java-modules/core-java-networking-3/src/main/java/com/baeldung/clientaddress/ApplicationServer.java @@ -0,0 +1,51 @@ +package com.baeldung.clientaddress; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.PrintWriter; +import java.net.InetSocketAddress; +import java.net.ServerSocket; +import java.net.Socket; + +public class ApplicationServer { + + private ServerSocket serverSocket; + private Socket connectedSocket; + private PrintWriter out; + private BufferedReader in; + + public void startServer(int port) throws IOException { + serverSocket = new ServerSocket(port); + connectedSocket = serverSocket.accept(); + + InetSocketAddress socketAddress = (InetSocketAddress) connectedSocket.getRemoteSocketAddress(); + String clientIpAddress = socketAddress.getAddress() + .getHostAddress(); + System.out.println("IP address of the connected client :: " + clientIpAddress); + + out = new PrintWriter(connectedSocket.getOutputStream(), true); + in = new BufferedReader(new InputStreamReader(connectedSocket.getInputStream())); + String msg = in.readLine(); + System.out.println("Message received from the client :: " + msg); + out.println("Hello Client !!"); + + closeIO(); + stopServer(); + } + + private void closeIO() throws IOException { + in.close(); + out.close(); + } + + private void stopServer() throws IOException { + connectedSocket.close(); + serverSocket.close(); + } + + public static void main(String[] args) throws IOException { + ApplicationServer server = new ApplicationServer(); + server.startServer(5000); + } +} diff --git a/core-java-modules/core-java-os/README.md b/core-java-modules/core-java-os/README.md index 10e04a8ba6..6d477de70a 100644 --- a/core-java-modules/core-java-os/README.md +++ b/core-java-modules/core-java-os/README.md @@ -13,5 +13,6 @@ This module contains articles about working with the operating system (OS) in Ja - [Pattern Search with Grep in Java](http://www.baeldung.com/grep-in-java) - [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) 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/pom.xml b/core-java-modules/core-java-os/pom.xml index 5f00b709e3..572000a714 100644 --- a/core-java-modules/core-java-os/pom.xml +++ b/core-java-modules/core-java-os/pom.xml @@ -1,93 +1,100 @@ - 4.0.0 - core-java-os - 0.1.0-SNAPSHOT - core-java-os - jar + 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 + core-java-os + 0.1.0-SNAPSHOT + core-java-os + jar - - com.baeldung.core-java-modules - core-java-modules - 0.0.1-SNAPSHOT - ../ - + + com.baeldung.core-java-modules + core-java-modules + 0.0.1-SNAPSHOT + ../ + - - - org.apache.commons - commons-collections4 - ${commons-collections4.version} - - - commons-io - commons-io - ${commons-io.version} - - - org.apache.commons - commons-lang3 - ${commons-lang3.version} - - - log4j - log4j - ${log4j.version} - - - - org.assertj - assertj-core - ${assertj.version} - test - - - org.unix4j - unix4j-command - ${unix4j.version} - - - com.googlecode.grep4j - grep4j - ${grep4j.version} - - + + + org.junit.jupiter + junit-jupiter-engine + ${junit-jupiter-engine.version} + test + + + org.apache.commons + commons-collections4 + ${commons-collections4.version} + + + commons-io + commons-io + ${commons-io.version} + + + org.apache.commons + commons-lang3 + ${commons-lang3.version} + + + log4j + log4j + ${log4j.version} + + + + org.assertj + assertj-core + ${assertj.version} + test + + + org.unix4j + unix4j-command + ${unix4j.version} + + + com.googlecode.grep4j + grep4j + ${grep4j.version} + + - - core-java-os - - - src/main/resources - true - - - - - org.apache.maven.plugins - maven-compiler-plugin - ${maven-compiler-plugin.version} - - ${maven.compiler.source} - ${maven.compiler.target} - - - - + + core-java-os + + + src/main/resources + true + + + + + org.apache.maven.plugins + maven-compiler-plugin + ${maven-compiler-plugin.version} + + ${maven.compiler.source} + ${maven.compiler.target} + + + + - - - 4.1 - 4.01 - - 3.6.1 - 1.8.9 - 1.9 - 1.9 - 25.1-jre - 0.4 - 1.8.7 - + + + 4.1 + 4.01 + + 3.6.1 + 1.8.9 + 1.9 + 1.9 + 25.1-jre + 0.4 + 1.8.7 + 5.7.2 + \ No newline at end of file diff --git a/core-java-modules/core-java-os/src/main/java/com/baeldung/example/soundapi/App.java b/core-java-modules/core-java-os/src/main/java/com/baeldung/example/soundapi/App.java new file mode 100644 index 0000000000..afd7687528 --- /dev/null +++ b/core-java-modules/core-java-os/src/main/java/com/baeldung/example/soundapi/App.java @@ -0,0 +1,34 @@ +package com.baeldung.example.soundapi; + +import javax.sound.sampled.AudioFileFormat; +import javax.sound.sampled.AudioFormat; + +public class App { + public static void main(String[] args) throws Exception { + + AudioFormat format = buildAudioFormatInstance(); + + SoundRecorder soundRecorder = new SoundRecorder(); + soundRecorder.build(format); + + System.out.println("Start recording ...."); + soundRecorder.start(); + Thread.sleep(20000); + soundRecorder.stop(); + + WaveDataUtil wd = new WaveDataUtil(); + Thread.sleep(3000); + wd.saveToFile("/SoundClip", AudioFileFormat.Type.WAVE, soundRecorder.getAudioInputStream()); + } + + public static AudioFormat buildAudioFormatInstance() { + ApplicationProperties aConstants = new ApplicationProperties(); + AudioFormat.Encoding encoding = aConstants.ENCODING; + float rate = aConstants.RATE; + int channels = aConstants.CHANNELS; + int sampleSize = aConstants.SAMPLE_SIZE; + boolean bigEndian = aConstants.BIG_ENDIAN; + + return new AudioFormat(encoding, rate, sampleSize, channels, (sampleSize / 8) * channels, rate, bigEndian); + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-os/src/main/java/com/baeldung/example/soundapi/ApplicationProperties.java b/core-java-modules/core-java-os/src/main/java/com/baeldung/example/soundapi/ApplicationProperties.java new file mode 100644 index 0000000000..985229b969 --- /dev/null +++ b/core-java-modules/core-java-os/src/main/java/com/baeldung/example/soundapi/ApplicationProperties.java @@ -0,0 +1,10 @@ +package com.baeldung.example.soundapi; +import javax.sound.sampled.AudioFormat; + +public class ApplicationProperties { + public final AudioFormat.Encoding ENCODING = AudioFormat.Encoding.PCM_SIGNED; + public final float RATE = 44100.0f; + public final int CHANNELS = 1; + public final int SAMPLE_SIZE = 16; + public final boolean BIG_ENDIAN = true; +} \ No newline at end of file diff --git a/core-java-modules/core-java-os/src/main/java/com/baeldung/example/soundapi/SoundRecorder.java b/core-java-modules/core-java-os/src/main/java/com/baeldung/example/soundapi/SoundRecorder.java new file mode 100644 index 0000000000..cae91ee74f --- /dev/null +++ b/core-java-modules/core-java-os/src/main/java/com/baeldung/example/soundapi/SoundRecorder.java @@ -0,0 +1,123 @@ +package com.baeldung.example.soundapi; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioInputStream; +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.DataLine; +import javax.sound.sampled.TargetDataLine; + +public class SoundRecorder implements Runnable { + private AudioInputStream audioInputStream; + private AudioFormat format; + public Thread thread; + private double duration; + + public SoundRecorder() { + super(); + } + + public SoundRecorder(AudioFormat format) { + this.format = format; + } + + public SoundRecorder build(AudioFormat format) { + this.format = format; + return this; + } + + public void start() { + thread = new Thread(this); + thread.setName("Capture Microphone"); + thread.start(); + } + + public void stop() { + thread = null; + } + + @Override + public void run() { + duration = 0; + + try (final ByteArrayOutputStream out = new ByteArrayOutputStream(); final TargetDataLine line = getTargetDataLineForRecord();) { + + int frameSizeInBytes = format.getFrameSize(); + int bufferLengthInFrames = line.getBufferSize() / 8; + final int bufferLengthInBytes = bufferLengthInFrames * frameSizeInBytes; + buildByteOutputStream(out, line, frameSizeInBytes, bufferLengthInBytes); + this.audioInputStream = new AudioInputStream(line); + setAudioInputStream(convertToAudioIStream(out, frameSizeInBytes)); + audioInputStream.reset(); + } catch (IOException ex) { + ex.printStackTrace(); + } catch (Exception ex) { + ex.printStackTrace(); + return; + } + } + + public void buildByteOutputStream(final ByteArrayOutputStream out, final TargetDataLine line, int frameSizeInBytes, final int bufferLengthInBytes) throws IOException { + final byte[] data = new byte[bufferLengthInBytes]; + int numBytesRead; + + line.start(); + while (thread != null) { + if ((numBytesRead = line.read(data, 0, bufferLengthInBytes)) == -1) { + break; + } + out.write(data, 0, numBytesRead); + } + } + + private void setAudioInputStream(AudioInputStream aStream) { + this.audioInputStream = aStream; + } + + public AudioInputStream convertToAudioIStream(final ByteArrayOutputStream out, int frameSizeInBytes) { + byte audioBytes[] = out.toByteArray(); + ByteArrayInputStream bais = new ByteArrayInputStream(audioBytes); + AudioInputStream audioStream = new AudioInputStream(bais, format, audioBytes.length / frameSizeInBytes); + long milliseconds = (long) ((audioInputStream.getFrameLength() * 1000) / format.getFrameRate()); + duration = milliseconds / 1000.0; + System.out.println("Recorded duration in seconds:" + duration); + return audioStream; + } + + public TargetDataLine getTargetDataLineForRecord() { + TargetDataLine line; + DataLine.Info info = new DataLine.Info(TargetDataLine.class, format); + if (!AudioSystem.isLineSupported(info)) { + return null; + } + try { + line = (TargetDataLine) AudioSystem.getLine(info); + line.open(format, line.getBufferSize()); + } catch (final Exception ex) { + return null; + } + return line; + } + + public AudioInputStream getAudioInputStream() { + return audioInputStream; + } + + public AudioFormat getFormat() { + return format; + } + + public void setFormat(AudioFormat format) { + this.format = format; + } + + public Thread getThread() { + return thread; + } + + public double getDuration() { + return duration; + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-os/src/main/java/com/baeldung/example/soundapi/WaveDataUtil.java b/core-java-modules/core-java-os/src/main/java/com/baeldung/example/soundapi/WaveDataUtil.java new file mode 100644 index 0000000000..7d63e66fdd --- /dev/null +++ b/core-java-modules/core-java-os/src/main/java/com/baeldung/example/soundapi/WaveDataUtil.java @@ -0,0 +1,34 @@ +package com.baeldung.example.soundapi; + +import java.io.File; + +import javax.sound.sampled.AudioFileFormat; +import javax.sound.sampled.AudioInputStream; +import javax.sound.sampled.AudioSystem; + +public class WaveDataUtil { + public boolean saveToFile(String name, AudioFileFormat.Type fileType, AudioInputStream audioInputStream) { + System.out.println("Saving..."); + if (null == name || null == fileType || audioInputStream == null) { + return false; + } + File myFile = new File(name + "." + fileType.getExtension()); + try { + audioInputStream.reset(); + } catch (Exception e) { + return false; + } + int i = 0; + while (myFile.exists()) { + String temp = "" + i + myFile.getName(); + myFile = new File(temp); + } + try { + AudioSystem.write(audioInputStream, fileType, myFile); + } catch (Exception ex) { + return false; + } + System.out.println("Saved " + myFile.getAbsolutePath()); + return true; + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-os/src/main/java/com/baeldung/java9/process/ProcessAPIEnhancements.java b/core-java-modules/core-java-os/src/main/java/com/baeldung/java9/process/ProcessAPIEnhancements.java new file mode 100644 index 0000000000..cb3c183062 --- /dev/null +++ b/core-java-modules/core-java-os/src/main/java/com/baeldung/java9/process/ProcessAPIEnhancements.java @@ -0,0 +1,101 @@ +package com.baeldung.java9.process; + +import java.io.IOException; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.stream.Stream; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ProcessAPIEnhancements { + + static Logger log = LoggerFactory.getLogger(ProcessAPIEnhancements.class); + + public static void main(String[] args) throws IOException, InterruptedException, ExecutionException { + infoOfCurrentProcess(); + infoOfLiveProcesses(); + infoOfSpawnProcess(); + infoOfExitCallback(); + infoOfChildProcess(); + } + + private static void infoOfCurrentProcess() { + ProcessHandle processHandle = ProcessHandle.current(); + ProcessHandle.Info processInfo = processHandle.info(); + + log.info("PID: " + processHandle.pid()); + log.info("Arguments: " + processInfo.arguments()); + log.info("Command: " + processInfo.command()); + log.info("Instant: " + processInfo.startInstant()); + log.info("Total CPU duration: " + processInfo.totalCpuDuration()); + log.info("User: " + processInfo.user()); + } + + private static void infoOfSpawnProcess() throws IOException { + + String javaCmd = ProcessUtils.getJavaCmd().getAbsolutePath(); + ProcessBuilder processBuilder = new ProcessBuilder(javaCmd, "-version"); + Process process = processBuilder.inheritIO().start(); + ProcessHandle processHandle = process.toHandle(); + ProcessHandle.Info processInfo = processHandle.info(); + + log.info("PID: " + processHandle.pid()); + log.info("Arguments: " + processInfo.arguments()); + log.info("Command: " + processInfo.command()); + log.info("Instant: " + processInfo.startInstant()); + log.info("Total CPU duration: " + processInfo.totalCpuDuration()); + log.info("User: " + processInfo.user()); + } + + private static void infoOfLiveProcesses() { + Stream liveProcesses = ProcessHandle.allProcesses(); + liveProcesses.filter(ProcessHandle::isAlive) + .forEach(ph -> { + log.info("PID: " + ph.pid()); + log.info("Instance: " + ph.info().startInstant()); + log.info("User: " + ph.info().user()); + }); + } + + private static void infoOfChildProcess() throws IOException { + int childProcessCount = 5; + for (int i = 0; i < childProcessCount; i++) { + String javaCmd = ProcessUtils.getJavaCmd() + .getAbsolutePath(); + ProcessBuilder processBuilder + = new ProcessBuilder(javaCmd, "-version"); + processBuilder.inheritIO().start(); + } + + Stream children = ProcessHandle.current() + .children(); + children.filter(ProcessHandle::isAlive) + .forEach(ph -> log.info("PID: {}, Cmd: {}", ph.pid(), ph.info() + .command())); + Stream descendants = ProcessHandle.current() + .descendants(); + descendants.filter(ProcessHandle::isAlive) + .forEach(ph -> log.info("PID: {}, Cmd: {}", ph.pid(), ph.info() + .command())); + } + + private static void infoOfExitCallback() throws IOException, InterruptedException, ExecutionException { + String javaCmd = ProcessUtils.getJavaCmd() + .getAbsolutePath(); + ProcessBuilder processBuilder + = new ProcessBuilder(javaCmd, "-version"); + Process process = processBuilder.inheritIO() + .start(); + ProcessHandle processHandle = process.toHandle(); + + log.info("PID: {} has started", processHandle.pid()); + CompletableFuture onProcessExit = processHandle.onExit(); + onProcessExit.get(); + log.info("Alive: " + processHandle.isAlive()); + onProcessExit.thenAccept(ph -> { + log.info("PID: {} has stopped", ph.pid()); + }); + } + +} diff --git a/core-java-modules/core-java-os/src/test/java/com/baeldung/example/soundapi/AppUnitTest.java b/core-java-modules/core-java-os/src/test/java/com/baeldung/example/soundapi/AppUnitTest.java new file mode 100644 index 0000000000..38f21320e3 --- /dev/null +++ b/core-java-modules/core-java-os/src/test/java/com/baeldung/example/soundapi/AppUnitTest.java @@ -0,0 +1,75 @@ +package com.baeldung.example.soundapi; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Assertions; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.fail; +import java.io.ByteArrayOutputStream; + +import javax.sound.sampled.AudioFileFormat; +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.TargetDataLine; + +public class AppUnitTest { + + AudioFormat af = App.buildAudioFormatInstance(); + SoundRecorder soundRecorder = new SoundRecorder(); + + @Test + public void Given_SoundRecorderObject_When_Run_Then_ThrowsNoException() { + + soundRecorder.build(af); + try { + soundRecorder.start(); + Thread.sleep(20000); + soundRecorder.stop(); + } catch (InterruptedException ex) { + fail("Exception: " + ex); + } + + } + + @Test + public void Given_AudioFormatObject_When_NotNull_Then_ReturnsTargetDataLine() { + soundRecorder.setFormat(af); + Assertions.assertDoesNotThrow(() -> soundRecorder.getTargetDataLineForRecord()); + } + + @Test + public void Given_TargetLineDataObject_When_Run_Then_GeneratesOutputStream() { + + soundRecorder.setFormat(af); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + TargetDataLine tLine = soundRecorder.getTargetDataLineForRecord(); + + int frameSizeInBytes = af.getFrameSize(); + int bufferLengthInFrames = tLine.getBufferSize() / 8; + final int bufferLengthInBytes = bufferLengthInFrames * frameSizeInBytes; + + Assertions.assertDoesNotThrow( + () -> soundRecorder.buildByteOutputStream(out, tLine, frameSizeInBytes, bufferLengthInBytes)); + } + + @Test + public void Given_AudioInputStream_When_NotNull_Then_SaveToWavFile() { + soundRecorder.setFormat(af); + soundRecorder.build(af); + try { + soundRecorder.start(); + Thread.sleep(20000); + soundRecorder.stop(); + WaveDataUtil wd = new WaveDataUtil(); + Thread.sleep(3000); + boolean saveFile = wd.saveToFile("/SoundClip", AudioFileFormat.Type.WAVE, + soundRecorder.getAudioInputStream()); + + assertEquals(saveFile, true); + + } catch (InterruptedException ex) { + fail("Exception: " + ex); + } + + } + +} diff --git a/core-java-modules/core-java-os/src/test/java/com/baeldung/java9/process/ProcessAPIEnhancementsUnitTest.java b/core-java-modules/core-java-os/src/test/java/com/baeldung/java9/process/ProcessAPIEnhancementsUnitTest.java deleted file mode 100644 index c81f060150..0000000000 --- a/core-java-modules/core-java-os/src/test/java/com/baeldung/java9/process/ProcessAPIEnhancementsUnitTest.java +++ /dev/null @@ -1,132 +0,0 @@ -package com.baeldung.java9.process; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; - -import java.io.IOException; -import java.util.concurrent.CompletableFuture; -import java.util.stream.Stream; - -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Created by sanaulla on 2/23/2017. - */ - -public class ProcessAPIEnhancementsUnitTest { - - Logger log = LoggerFactory.getLogger(ProcessAPIEnhancementsUnitTest.class); - - // @Test - // OS / Java version dependent - public void givenCurrentProcess_whenInvokeGetInfo_thenSuccess() throws IOException { - ProcessHandle processHandle = ProcessHandle.current(); - ProcessHandle.Info processInfo = processHandle.info(); - assertNotNull(processHandle.pid()); - assertEquals(true, processInfo.arguments() - .isPresent()); - assertEquals(true, processInfo.command() - .isPresent()); - assertTrue(processInfo.command() - .get() - .contains("java")); - - assertEquals(true, processInfo.startInstant() - .isPresent()); - assertEquals(true, processInfo.totalCpuDuration() - .isPresent()); - assertEquals(true, processInfo.user() - .isPresent()); - } - - // @Test - // OS / Java version dependent - public void givenSpawnProcess_whenInvokeGetInfo_thenSuccess() throws IOException { - - String javaCmd = ProcessUtils.getJavaCmd() - .getAbsolutePath(); - ProcessBuilder processBuilder = new ProcessBuilder(javaCmd, "-version"); - Process process = processBuilder.inheritIO() - .start(); - ProcessHandle processHandle = process.toHandle(); - ProcessHandle.Info processInfo = processHandle.info(); - assertNotNull(processHandle.pid()); - assertEquals(true, processInfo.arguments() - .isPresent()); - assertEquals(true, processInfo.command() - .isPresent()); - assertTrue(processInfo.command() - .get() - .contains("java")); - assertEquals(true, processInfo.startInstant() - .isPresent()); - assertEquals(false, processInfo.totalCpuDuration() - .isPresent()); - assertEquals(true, processInfo.user() - .isPresent()); - } - - // @Test - // OS / Java version dependent - public void givenLiveProcesses_whenInvokeGetInfo_thenSuccess() { - Stream liveProcesses = ProcessHandle.allProcesses(); - liveProcesses.filter(ProcessHandle::isAlive) - .forEach(ph -> { - assertNotNull(ph.pid()); - assertEquals(true, ph.info() - .startInstant() - .isPresent()); - assertEquals(true, ph.info() - .user() - .isPresent()); - }); - } - - // @Test - // OS / Java version dependent - public void givenProcess_whenGetChildProcess_thenSuccess() throws IOException { - int childProcessCount = 5; - for (int i = 0; i < childProcessCount; i++) { - String javaCmd = ProcessUtils.getJavaCmd() - .getAbsolutePath(); - ProcessBuilder processBuilder - = new ProcessBuilder(javaCmd, "-version"); - processBuilder.inheritIO().start(); - } - - Stream children = ProcessHandle.current() - .children(); - children.filter(ProcessHandle::isAlive) - .forEach(ph -> log.info("PID: {}, Cmd: {}", ph.pid(), ph.info() - .command())); - Stream descendants = ProcessHandle.current() - .descendants(); - descendants.filter(ProcessHandle::isAlive) - .forEach(ph -> log.info("PID: {}, Cmd: {}", ph.pid(), ph.info() - .command())); - } - - // @Test - // OS / Java version dependent - public void givenProcess_whenAddExitCallback_thenSuccess() throws Exception { - String javaCmd = ProcessUtils.getJavaCmd() - .getAbsolutePath(); - ProcessBuilder processBuilder - = new ProcessBuilder(javaCmd, "-version"); - Process process = processBuilder.inheritIO() - .start(); - ProcessHandle processHandle = process.toHandle(); - - log.info("PID: {} has started", processHandle.pid()); - CompletableFuture onProcessExit = processHandle.onExit(); - onProcessExit.get(); - assertEquals(false, processHandle.isAlive()); - onProcessExit.thenAccept(ph -> { - log.info("PID: {} has stopped", ph.pid()); - }); - } - -} diff --git a/core-java-modules/core-java-security-3/README.md b/core-java-modules/core-java-security-3/README.md index 970faaac88..a37719964b 100644 --- a/core-java-modules/core-java-security-3/README.md +++ b/core-java-modules/core-java-security-3/README.md @@ -5,4 +5,5 @@ This module contains articles about core Java Security ### Relevant Articles: - [Secret Key and String Conversion in Java](https://www.baeldung.com/java-secret-key-to-string) +- [Enabling Unlimited Strength Cryptography in Java](https://www.baeldung.com/jce-enable-unlimited-strength) - More articles: [[<-- prev]](/core-java-modules/core-java-security-2) diff --git a/core-java-modules/core-java-security-3/src/test/java/com/baeldung/cryptography/CryptographyStrengthUnitTest.java b/core-java-modules/core-java-security-3/src/test/java/com/baeldung/cryptography/CryptographyStrengthUnitTest.java new file mode 100644 index 0000000000..5d5c30dc34 --- /dev/null +++ b/core-java-modules/core-java-security-3/src/test/java/com/baeldung/cryptography/CryptographyStrengthUnitTest.java @@ -0,0 +1,17 @@ +package com.baeldung.cryptography; + +import org.junit.Test; + +import java.security.NoSuchAlgorithmException; + +import static org.assertj.core.api.Assertions.assertThat; + +public class CryptographyStrengthUnitTest { + private static final int UNLIMITED_KEY_SIZE = 2147483647; + + @Test + public void whenDefaultCheck_thenUnlimitedReturned() throws NoSuchAlgorithmException { + int maxKeySize = javax.crypto.Cipher.getMaxAllowedKeyLength("AES"); + assertThat(maxKeySize).isEqualTo(UNLIMITED_KEY_SIZE); + } +} 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 c7b17a6720..8d515b9aea 100644 --- a/core-java-modules/core-java-string-algorithms-3/README.md +++ b/core-java-modules/core-java-string-algorithms-3/README.md @@ -5,3 +5,4 @@ This module contains articles about string-related algorithms. ### Relevant Articles: - [Check if Two Strings are Anagrams in Java](https://www.baeldung.com/java-strings-anagrams) +- [Email Validation in Java](https://www.baeldung.com/java-email-validation-regex) diff --git a/core-java-modules/core-java-string-algorithms-3/pom.xml b/core-java-modules/core-java-string-algorithms-3/pom.xml index c8243258c1..6d1c0b0e48 100644 --- a/core-java-modules/core-java-string-algorithms-3/pom.xml +++ b/core-java-modules/core-java-string-algorithms-3/pom.xml @@ -32,6 +32,11 @@ junit-jupiter test + + commons-validator + commons-validator + ${validator.version} + @@ -59,6 +64,7 @@ 3.6.1 28.1-jre + 1.7 - \ No newline at end of file + diff --git a/core-java-modules/core-java-string-algorithms-3/src/main/java/com/baeldung/emailvalidation/EmailValidation.java b/core-java-modules/core-java-string-algorithms-3/src/main/java/com/baeldung/emailvalidation/EmailValidation.java new file mode 100644 index 0000000000..f80c87ea01 --- /dev/null +++ b/core-java-modules/core-java-string-algorithms-3/src/main/java/com/baeldung/emailvalidation/EmailValidation.java @@ -0,0 +1,12 @@ +package com.baeldung.emailvalidation; + +import java.util.regex.Pattern; + +public class EmailValidation { + + public static boolean patternMatches(String emailAddress, String regexPattern) { + return Pattern.compile(regexPattern) + .matcher(emailAddress) + .matches(); + } +} diff --git a/core-java-modules/core-java-string-algorithms-3/src/test/java/com/baeldung/emailvalidation/EmailValidationUnitTest.java b/core-java-modules/core-java-string-algorithms-3/src/test/java/com/baeldung/emailvalidation/EmailValidationUnitTest.java new file mode 100644 index 0000000000..e6bee0ce63 --- /dev/null +++ b/core-java-modules/core-java-string-algorithms-3/src/test/java/com/baeldung/emailvalidation/EmailValidationUnitTest.java @@ -0,0 +1,79 @@ +package com.baeldung.emailvalidation; + +import static org.junit.Assert.assertTrue; +import org.apache.commons.validator.routines.EmailValidator; +import org.junit.Test; + +public class EmailValidationUnitTest { + + private String emailAddress; + private String regexPattern; + + @Test + public void testUsingEmailValidator() { + emailAddress = "username@domain.com"; + assertTrue(EmailValidator.getInstance() + .isValid(emailAddress)); + } + + @Test + public void testUsingSimpleRegex() { + emailAddress = "username@domain.com"; + regexPattern = "^(.+)@(\\S+)$"; + assertTrue(EmailValidation.patternMatches(emailAddress, regexPattern)); + } + + @Test + public void testUsingStrictRegex() { + emailAddress = "username@domain.com"; + regexPattern = "^(?=.{1,64}@)[A-Za-z0-9_-]+(\\.[A-Za-z0-9_-]+)*@" + + "[^-][A-Za-z0-9-]+(\\.[A-Za-z0-9-]+)*(\\.[A-Za-z]{2,})$"; + assertTrue(EmailValidation.patternMatches(emailAddress, regexPattern)); + } + + @Test + public void testUsingUnicodeRegex() { + emailAddress = "用户名@领域.电脑"; + regexPattern = "^(?=.{1,64}@)[\\p{L}0-9_-]+(\\.[\\p{L}0-9_-]+)*@" + + "[^-][\\p{L}0-9-]+(\\.[\\p{L}0-9-]+)*(\\.[\\p{L}]{2,})$"; + assertTrue(EmailValidation.patternMatches(emailAddress, regexPattern)); + } + + @Test + public void testUsingRFC5322Regex() { + emailAddress = "username@domain.com"; + regexPattern = "^[a-zA-Z0-9_!#$%&'*+/=?`{|}~^.-]+@[a-zA-Z0-9.-]+$"; + assertTrue(EmailValidation.patternMatches(emailAddress, regexPattern)); + } + + @Test + public void testRestrictDots() { + emailAddress = "username@domain.com"; + regexPattern = "^[a-zA-Z0-9_!#$%&'*+/=?`{|}~^-]+(?:\\.[a-zA-Z0-9_!#$%&'*+/=?`{|}~^-]+)*@" + + "[a-zA-Z0-9-]+(?:\\.[a-zA-Z0-9-]+)*$"; + assertTrue(EmailValidation.patternMatches(emailAddress, regexPattern)); + } + + @Test + public void testOwaspValidation() { + emailAddress = "username@domain.com"; + regexPattern = "^[a-zA-Z0-9_+&*-]+(?:\\.[a-zA-Z0-9_+&*-]+)*@(?:[a-zA-Z0-9-]+\\.)+[a-zA-Z]{2,7}$"; + assertTrue(EmailValidation.patternMatches(emailAddress, regexPattern)); + } + + @Test + public void testTopLevelDomain() { + emailAddress = "username@domain.com"; + regexPattern = "^[\\w!#$%&'*+/=?`{|}~^-]+(?:\\.[\\w!#$%&'*+/=?`{|}~^-]+)*" + + "@(?:[a-zA-Z0-9-]+\\.)+[a-zA-Z]{2,6}$"; + assertTrue(EmailValidation.patternMatches(emailAddress, regexPattern)); + } + + @Test + public void testGmailSpecialCase() { + emailAddress = "username+something@domain.com"; + regexPattern = "^(?=.{1,64}@)[A-Za-z0-9\\+_-]+(\\.[A-Za-z0-9\\+_-]+)*@" + + "[^-][A-Za-z0-9\\+-]+(\\.[A-Za-z0-9\\+-]+)*(\\.[A-Za-z]{2,})$"; + assertTrue(EmailValidation.patternMatches(emailAddress, regexPattern)); + } +} diff --git a/core-java-modules/core-java-string-operations-3/README.md b/core-java-modules/core-java-string-operations-3/README.md index ff6ac51fab..f4cde6104f 100644 --- a/core-java-modules/core-java-string-operations-3/README.md +++ b/core-java-modules/core-java-string-operations-3/README.md @@ -5,3 +5,4 @@ - [Split Java String by Newline](https://www.baeldung.com/java-string-split-by-newline) - [Split a String in Java and Keep the Delimiters](https://www.baeldung.com/java-split-string-keep-delimiters) - [Validate String as Filename in Java](https://www.baeldung.com/java-validate-filename) +- [Count Spaces in a Java String](https://www.baeldung.com/java-string-count-spaces) diff --git a/core-java-modules/core-java-string-operations-3/pom.xml b/core-java-modules/core-java-string-operations-3/pom.xml index b73851f90c..642ade5ab3 100644 --- a/core-java-modules/core-java-string-operations-3/pom.xml +++ b/core-java-modules/core-java-string-operations-3/pom.xml @@ -16,6 +16,16 @@ + + org.springframework + spring-core + ${spring-core.version} + + + org.apache.commons + commons-lang3 + ${apache-commons-lang3.version} + org.assertj assertj-core @@ -68,10 +78,12 @@ 11 11 3.6.1 + 5.3.9 + 3.12.0 3.6.3 6.1.1 2.11.1 3.1.0 - \ No newline at end of file + diff --git a/core-java-modules/core-java-string-operations-3/src/test/java/com/baeldung/countspaces/CountSpacesInStringUnitTest.java b/core-java-modules/core-java-string-operations-3/src/test/java/com/baeldung/countspaces/CountSpacesInStringUnitTest.java new file mode 100644 index 0000000000..0432b7dd24 --- /dev/null +++ b/core-java-modules/core-java-string-operations-3/src/test/java/com/baeldung/countspaces/CountSpacesInStringUnitTest.java @@ -0,0 +1,65 @@ +package com.baeldung.countspaces; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import org.apache.commons.lang3.StringUtils; +import org.junit.jupiter.api.Test; + +class CountSpacesInStringUnitTest { + private static final String INPUT_STRING = " This string has nine spaces and a Tab:' '"; + private static final int EXPECTED_COUNT = 9; + + @Test + void givenString_whenCountSpaceByLooping_thenReturnsExpectedCount() { + int spaceCount = 0; + for (char c : INPUT_STRING.toCharArray()) { + if (c == ' ') { + spaceCount++; + } + } + assertThat(spaceCount).isEqualTo(EXPECTED_COUNT); + } + + @Test + void givenString_whenCountSpaceByJava8StreamFilter_thenReturnsExpectedCount() { + long spaceCount = INPUT_STRING.chars().filter(c -> c == (int) ' ').count(); + assertThat(spaceCount).isEqualTo(EXPECTED_COUNT); + } + + @Test + void givenString_whenCountSpaceByRegexMatcher_thenReturnsExpectedCount() { + Pattern pattern = Pattern.compile(" "); + Matcher matcher = pattern.matcher(INPUT_STRING); + int spaceCount = 0; + while (matcher.find()) { + spaceCount++; + } + assertThat(spaceCount).isEqualTo(EXPECTED_COUNT); + } + + @Test + void givenString_whenCountSpaceByReplaceAll_thenReturnsExpectedCount() { + int spaceCount = INPUT_STRING.replaceAll("[^ ]", "").length(); + assertThat(spaceCount).isEqualTo(EXPECTED_COUNT); + } + + @Test + void givenString_whenCountSpaceBySplit_thenReturnsExpectedCount() { + int spaceCount = INPUT_STRING.split(" ").length - 1; + assertThat(spaceCount).isEqualTo(EXPECTED_COUNT); + } + + @Test + void givenString_whenCountSpaceUsingApacheCommons_thenReturnsExpectedCount() { + int spaceCount = StringUtils.countMatches(INPUT_STRING, " "); + assertThat(spaceCount).isEqualTo(EXPECTED_COUNT); + } + + @Test + void givenString_whenCountSpaceUsingSpring_thenReturnsExpectedCount() { + int spaceCount = org.springframework.util.StringUtils.countOccurrencesOf(INPUT_STRING, " "); + assertThat(spaceCount).isEqualTo(EXPECTED_COUNT); + } +} diff --git a/core-java-modules/pom.xml b/core-java-modules/pom.xml index 13dd20b5da..5291c8c3ca 100644 --- a/core-java-modules/pom.xml +++ b/core-java-modules/pom.xml @@ -38,6 +38,7 @@ core-java-collections-maps core-java-collections-maps-2 core-java-collections-maps-3 + core-java-collections-maps-4 core-java-concurrency-2 core-java-concurrency-advanced core-java-concurrency-advanced-2 @@ -137,4 +138,5 @@ 2.22.2 5.6.2 - \ No newline at end of file + + diff --git a/deeplearning4j/pom.xml b/deeplearning4j/pom.xml index f1f9b9fa7b..c63e67d573 100644 --- a/deeplearning4j/pom.xml +++ b/deeplearning4j/pom.xml @@ -39,12 +39,12 @@ org.slf4j slf4j-api - ${slf4j.version} + ${org.slf4j.version} org.slf4j slf4j-log4j12 - ${slf4j.version} + ${org.slf4j.version} @@ -62,7 +62,6 @@ 0.9.1 4.3.5 - 1.7.5 \ No newline at end of file diff --git a/docker/README.md b/docker/README.md index f1b4181e64..ab3ddd35b7 100644 --- a/docker/README.md +++ b/docker/README.md @@ -1,6 +1,6 @@ ## Relevant Articles: -- [Introduction to Docker Compose](https://www.baeldung.com/docker-compose) +- [Introduction to Docker Compose](https://www.baeldung.com/ops/docker-compose) - [Reusing Docker Layers with Spring Boot](https://www.baeldung.com/docker-layers-spring-boot) - [Running Spring Boot with PostgreSQL in Docker Compose](https://www.baeldung.com/spring-boot-postgresql-docker) - [How To Configure Java Heap Size Inside a Docker Container](https://www.baeldung.com/ops/docker-jvm-heap-size) diff --git a/ethereum/pom.xml b/ethereum/pom.xml index 4283714b98..b9a3870702 100644 --- a/ethereum/pom.xml +++ b/ethereum/pom.xml @@ -99,7 +99,7 @@ org.slf4j jcl-over-slf4j - ${slf4j.version} + ${org.slf4j.version} ch.qos.logback @@ -204,8 +204,6 @@ 1.5.6.RELEASE 2.21.0 2.4.0 - 1.2.3 - 1.7.25 2.0.4.RELEASE 3.1 diff --git a/gradle/gradle-jacoco/README.md b/gradle/gradle-jacoco/README.md new file mode 100644 index 0000000000..0da51cc539 --- /dev/null +++ b/gradle/gradle-jacoco/README.md @@ -0,0 +1,3 @@ +### Relevant Articles: + +- [Exclusions from Jacoco Report](https://www.baeldung.com/jacoco-report-exclude) diff --git a/grpc/README.md b/grpc/README.md index d65dc03e54..e162681810 100644 --- a/grpc/README.md +++ b/grpc/README.md @@ -3,4 +3,6 @@ This module contains articles about gRPC ### Relevant Articles: + - [Introduction to gRPC](https://www.baeldung.com/grpc-introduction) +- [Streaming with gRPC in Java](https://www.baeldung.com/java-grpc-streaming) diff --git a/grpc/pom.xml b/grpc/pom.xml index 915777f3bd..77ec9be464 100644 --- a/grpc/pom.xml +++ b/grpc/pom.xml @@ -1,81 +1,82 @@ - 4.0.0 - grpc - 0.0.1-SNAPSHOT - grpc - jar + 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 + grpc + 0.0.1-SNAPSHOT + grpc + jar - - com.baeldung - parent-modules - 1.0.0-SNAPSHOT - + + com.baeldung + parent-modules + 1.0.0-SNAPSHOT + - - - io.grpc - grpc-netty - ${io.grpc.version} - - - io.grpc - grpc-protobuf - ${io.grpc.version} - - - io.grpc - grpc-stub - ${io.grpc.version} - - - junit - junit - ${junit.version} - test - - - - - - - kr.motd.maven - os-maven-plugin - ${os-maven-plugin.version} - - - - - org.xolstice.maven.plugins - protobuf-maven-plugin - ${protobuf-maven-plugin.version} - - - com.google.protobuf:protoc:3.3.0:exe:${os.detected.classifier} - - grpc-java - - io.grpc:protoc-gen-grpc-java:1.4.0:exe:${os.detected.classifier} - - - - - - compile - compile-custom - - - - - - - - - 1.16.1 - 1.6.1 - 0.6.1 - + + + io.grpc + grpc-netty-shaded + runtime + ${io.grpc.version} + + + io.grpc + grpc-protobuf + ${io.grpc.version} + + + io.grpc + grpc-stub + ${io.grpc.version} + + + junit + junit + ${junit.version} + test + + + javax.annotation + javax.annotation-api + 1.2 + + + + + + kr.motd.maven + os-maven-plugin + ${os-maven-plugin.version} + + + + + org.xolstice.maven.plugins + protobuf-maven-plugin + ${protobuf-maven-plugin.version} + + com.google.protobuf:protoc:${protoc.version}:exe:${os.detected.classifier} + grpc-java + io.grpc:protoc-gen-grpc-java:${io.grpc.version}:exe:${os.detected.classifier} + + + + + compile + compile-custom + + + + + + + + 1.40.1 + 3.17.2 + 1.6.2 + 0.6.1 + \ No newline at end of file diff --git a/grpc/src/main/java/com/baeldung/grpc/streaming/StockClient.java b/grpc/src/main/java/com/baeldung/grpc/streaming/StockClient.java new file mode 100644 index 0000000000..1850c975a2 --- /dev/null +++ b/grpc/src/main/java/com/baeldung/grpc/streaming/StockClient.java @@ -0,0 +1,183 @@ +package com.baeldung.grpc.streaming; + +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.logging.Level; +import java.util.logging.Logger; + +import com.baeldung.grpc.streaming.StockQuoteProviderGrpc.StockQuoteProviderBlockingStub; +import com.baeldung.grpc.streaming.StockQuoteProviderGrpc.StockQuoteProviderStub; + +import io.grpc.Channel; +import io.grpc.ManagedChannel; +import io.grpc.ManagedChannelBuilder; +import io.grpc.Status; +import io.grpc.StatusRuntimeException; +import io.grpc.stub.StreamObserver; + +public class StockClient { + private static final Logger logger = Logger.getLogger(StockClient.class.getName()); + + private final StockQuoteProviderBlockingStub blockingStub; + private final StockQuoteProviderStub nonBlockingStub; + private List stocks; + + public StockClient(Channel channel) { + + blockingStub = StockQuoteProviderGrpc.newBlockingStub(channel); + nonBlockingStub = StockQuoteProviderGrpc.newStub(channel); + initializeStocks(); + } + + public void serverSideStreamingListOfStockPrices() { + + logInfo("######START EXAMPLE######: ServerSideStreaming - list of Stock prices from a given stock"); + Stock request = Stock.newBuilder() + .setTickerSymbol("AU") + .setCompanyName("Austich") + .setDescription("server streaming example") + .build(); + Iterator stockQuotes; + try { + logInfo("REQUEST - ticker symbol {0}", request.getTickerSymbol()); + stockQuotes = blockingStub.serverSideStreamingGetListStockQuotes(request); + for (int i = 1; stockQuotes.hasNext(); i++) { + StockQuote stockQuote = stockQuotes.next(); + logInfo("RESPONSE - Price #" + i + ": {0}", stockQuote.getPrice()); + } + } catch (StatusRuntimeException e) { + logInfo("RPC failed: {0}", e.getStatus()); + } + } + + public void clientSideStreamingGetStatisticsOfStocks() throws InterruptedException { + + logInfo("######START EXAMPLE######: ClientSideStreaming - getStatisticsOfStocks from a list of stocks"); + final CountDownLatch finishLatch = new CountDownLatch(1); + StreamObserver responseObserver = new StreamObserver() { + @Override + public void onNext(StockQuote summary) { + logInfo("RESPONSE, got stock statistics - Average Price: {0}, description: {1}", summary.getPrice(), summary.getDescription()); + } + + @Override + public void onCompleted() { + logInfo("Finished clientSideStreamingGetStatisticsOfStocks"); + finishLatch.countDown(); + } + + @Override + public void onError(Throwable t) { + logWarning("Stock Statistics Failed: {0}", Status.fromThrowable(t)); + finishLatch.countDown(); + } + }; + + StreamObserver requestObserver = nonBlockingStub.clientSideStreamingGetStatisticsOfStocks(responseObserver); + try { + + for (Stock stock : stocks) { + logInfo("REQUEST: {0}, {1}", stock.getTickerSymbol(), stock.getCompanyName()); + requestObserver.onNext(stock); + if (finishLatch.getCount() == 0) { + return; + } + } + } catch (RuntimeException e) { + requestObserver.onError(e); + throw e; + } + requestObserver.onCompleted(); + if (!finishLatch.await(1, TimeUnit.MINUTES)) { + logWarning("clientSideStreamingGetStatisticsOfStocks can not finish within 1 minutes"); + } + } + + public void bidirectionalStreamingGetListsStockQuotes() throws InterruptedException{ + + logInfo("#######START EXAMPLE#######: BidirectionalStreaming - getListsStockQuotes from list of stocks"); + final CountDownLatch finishLatch = new CountDownLatch(1); + StreamObserver responseObserver = new StreamObserver() { + @Override + public void onNext(StockQuote stockQuote) { + logInfo("RESPONSE price#{0} : {1}, description:{2}", stockQuote.getOfferNumber(), stockQuote.getPrice(), stockQuote.getDescription()); + } + + @Override + public void onCompleted() { + logInfo("Finished bidirectionalStreamingGetListsStockQuotes"); + finishLatch.countDown(); + } + + @Override + public void onError(Throwable t) { + logWarning("bidirectionalStreamingGetListsStockQuotes Failed: {0}", Status.fromThrowable(t)); + finishLatch.countDown(); + } + }; + StreamObserver requestObserver = nonBlockingStub.bidirectionalStreamingGetListsStockQuotes(responseObserver); + try { + for (Stock stock : stocks) { + logInfo("REQUEST: {0}, {1}", stock.getTickerSymbol(), stock.getCompanyName()); + requestObserver.onNext(stock); + Thread.sleep(200); + if (finishLatch.getCount() == 0) { + return; + } + } + } catch (RuntimeException e) { + requestObserver.onError(e); + throw e; + } + requestObserver.onCompleted(); + + if (!finishLatch.await(1, TimeUnit.MINUTES)) { + logWarning("bidirectionalStreamingGetListsStockQuotes can not finish within 1 minute"); + } + + } + + public static void main(String[] args) throws InterruptedException { + String target = "localhost:8980"; + if (args.length > 0) { + target = args[0]; + } + + ManagedChannel channel = ManagedChannelBuilder.forTarget(target) + .usePlaintext() + .build(); + try { + StockClient client = new StockClient(channel); + + client.serverSideStreamingListOfStockPrices(); + + client.clientSideStreamingGetStatisticsOfStocks(); + + client.bidirectionalStreamingGetListsStockQuotes(); + + } finally { + channel.shutdownNow() + .awaitTermination(5, TimeUnit.SECONDS); + } + } + + private void initializeStocks() { + + this.stocks = Arrays.asList(Stock.newBuilder().setTickerSymbol("AU").setCompanyName("Auburn Corp").setDescription("Aptitude Intel").build() + , Stock.newBuilder().setTickerSymbol("BAS").setCompanyName("Bassel Corp").setDescription("Business Intel").build() + , Stock.newBuilder().setTickerSymbol("COR").setCompanyName("Corvine Corp").setDescription("Corporate Intel").build() + , Stock.newBuilder().setTickerSymbol("DIA").setCompanyName("Dialogic Corp").setDescription("Development Intel").build() + , Stock.newBuilder().setTickerSymbol("EUS").setCompanyName("Euskaltel Corp").setDescription("English Intel").build()); + } + + private void logInfo(String msg, Object... params) { + logger.log(Level.INFO, msg, params); + } + + private void logWarning(String msg, Object... params) { + logger.log(Level.WARNING, msg, params); + } +} diff --git a/grpc/src/main/java/com/baeldung/grpc/streaming/StockServer.java b/grpc/src/main/java/com/baeldung/grpc/streaming/StockServer.java new file mode 100644 index 0000000000..f4dc6c39ac --- /dev/null +++ b/grpc/src/main/java/com/baeldung/grpc/streaming/StockServer.java @@ -0,0 +1,147 @@ +package com.baeldung.grpc.streaming; + +import java.io.IOException; +import java.util.concurrent.ThreadLocalRandom; +import java.util.concurrent.TimeUnit; +import java.util.logging.Level; +import java.util.logging.Logger; + +import io.grpc.Server; +import io.grpc.ServerBuilder; +import io.grpc.stub.StreamObserver; + +public class StockServer { + + private static final Logger logger = Logger.getLogger(StockServer.class.getName()); + private final int port; + private final Server server; + + public StockServer(int port) throws IOException { + this.port = port; + server = ServerBuilder.forPort(port) + .addService(new StockService()) + .build(); + } + + public void start() throws IOException { + server.start(); + logger.info("Server started, listening on " + port); + Runtime.getRuntime() + .addShutdownHook(new Thread() { + @Override + public void run() { + System.err.println("shutting down server"); + try { + StockServer.this.stop(); + } catch (InterruptedException e) { + e.printStackTrace(System.err); + } + System.err.println("server shutted down"); + } + }); + } + + public void stop() throws InterruptedException { + if (server != null) { + server.shutdown() + .awaitTermination(30, TimeUnit.SECONDS); + } + } + + public static void main(String[] args) throws Exception { + StockServer stockServer = new StockServer(8980); + stockServer.start(); + if (stockServer.server != null) { + stockServer.server.awaitTermination(); + } + } + + private static class StockService extends StockQuoteProviderGrpc.StockQuoteProviderImplBase { + + StockService() { + } + + @Override + public void serverSideStreamingGetListStockQuotes(Stock request, StreamObserver responseObserver) { + + for (int i = 1; i <= 5; i++) { + + StockQuote stockQuote = StockQuote.newBuilder() + .setPrice(fetchStockPriceBid(request)) + .setOfferNumber(i) + .setDescription("Price for stock:" + request.getTickerSymbol()) + .build(); + responseObserver.onNext(stockQuote); + } + responseObserver.onCompleted(); + } + + @Override + public StreamObserver clientSideStreamingGetStatisticsOfStocks(final StreamObserver responseObserver) { + return new StreamObserver() { + int count; + double price = 0.0; + StringBuffer sb = new StringBuffer(); + + @Override + public void onNext(Stock stock) { + count++; + price = +fetchStockPriceBid(stock); + sb.append(":") + .append(stock.getTickerSymbol()); + } + + @Override + public void onCompleted() { + responseObserver.onNext(StockQuote.newBuilder() + .setPrice(price / count) + .setDescription("Statistics-" + sb.toString()) + .build()); + responseObserver.onCompleted(); + } + + @Override + public void onError(Throwable t) { + logger.log(Level.WARNING, "error:{0}", t.getMessage()); + } + }; + } + + @Override + public StreamObserver bidirectionalStreamingGetListsStockQuotes(final StreamObserver responseObserver) { + return new StreamObserver() { + @Override + public void onNext(Stock request) { + + for (int i = 1; i <= 5; i++) { + + StockQuote stockQuote = StockQuote.newBuilder() + .setPrice(fetchStockPriceBid(request)) + .setOfferNumber(i) + .setDescription("Price for stock:" + request.getTickerSymbol()) + .build(); + responseObserver.onNext(stockQuote); + } + } + + @Override + public void onCompleted() { + responseObserver.onCompleted(); + } + + @Override + public void onError(Throwable t) { + logger.log(Level.WARNING, "error:{0}", t.getMessage()); + } + }; + } + } + + private static double fetchStockPriceBid(Stock stock) { + + return stock.getTickerSymbol() + .length() + + ThreadLocalRandom.current() + .nextDouble(-0.1d, 0.1d); + } +} \ No newline at end of file diff --git a/grpc/src/main/proto/stock_quote.proto b/grpc/src/main/proto/stock_quote.proto new file mode 100644 index 0000000000..66891a5008 --- /dev/null +++ b/grpc/src/main/proto/stock_quote.proto @@ -0,0 +1,31 @@ +syntax = "proto3"; + +package stockquote; + +option java_multiple_files = true; +option java_package = "com.baeldung.grpc.streaming"; +option java_outer_classname = "StockQuoteProto"; +option objc_class_prefix = "RTG"; + +//basic setup ... + +service StockQuoteProvider { + + rpc serverSideStreamingGetListStockQuotes(Stock) returns (stream StockQuote) {} + + rpc clientSideStreamingGetStatisticsOfStocks(stream Stock) returns (StockQuote) {} + + rpc bidirectionalStreamingGetListsStockQuotes(stream Stock) returns (stream StockQuote) {} +} + +message Stock { + string ticker_symbol = 1; + string company_name = 2; + string description = 3; +} + +message StockQuote { + double price = 1; + int32 offer_number = 2; + string description = 3; +} diff --git a/jackson-modules/jackson-conversions-2/pom.xml b/jackson-modules/jackson-conversions-2/pom.xml index 799fcb106a..a498c8b4f8 100644 --- a/jackson-modules/jackson-conversions-2/pom.xml +++ b/jackson-modules/jackson-conversions-2/pom.xml @@ -24,7 +24,7 @@ com.fasterxml.jackson.datatype jackson-datatype-jsr310 - ${jackson-datatype.version} + ${jackson.version} @@ -52,7 +52,6 @@ 3.11.0 - 2.9.8 \ No newline at end of file diff --git a/jackson-modules/jackson/src/test/java/com/baeldung/jackson/inheritance/SubTypeHandlingUnitTest.java b/jackson-modules/jackson/src/test/java/com/baeldung/jackson/inheritance/SubTypeHandlingUnitTest.java index b5b81fa4a3..8d6bc9ad6a 100644 --- a/jackson-modules/jackson/src/test/java/com/baeldung/jackson/inheritance/SubTypeHandlingUnitTest.java +++ b/jackson-modules/jackson/src/test/java/com/baeldung/jackson/inheritance/SubTypeHandlingUnitTest.java @@ -1,14 +1,22 @@ package com.baeldung.jackson.inheritance; +import static org.hamcrest.CoreMatchers.instanceOf; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; import org.junit.Test; -import java.util.List; -import java.util.ArrayList; -import java.io.IOException; - +import com.baeldung.jackson.inheritance.SubTypeConstructorStructure.Car; +import com.baeldung.jackson.inheritance.SubTypeConstructorStructure.Fleet; +import com.baeldung.jackson.inheritance.SubTypeConstructorStructure.Truck; +import com.baeldung.jackson.inheritance.SubTypeConstructorStructure.Vehicle; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.jsontype.BasicPolymorphicTypeValidator; +import com.fasterxml.jackson.databind.jsontype.PolymorphicTypeValidator; public class SubTypeHandlingUnitTest { @Test @@ -23,21 +31,30 @@ public class SubTypeHandlingUnitTest { } @Test - public void givenSubType_whenNotUsingNoArgsConstructors_thenSucceed() throws IOException { + public void givenSubType_whenNotUsingNoArgsConstructors_thenSucceed() throws IOException { ObjectMapper mapper = new ObjectMapper(); - mapper.enableDefaultTyping(); + PolymorphicTypeValidator ptv = BasicPolymorphicTypeValidator.builder() + .allowIfSubType("com.baeldung.jackson.inheritance") + .allowIfSubType("java.util.ArrayList") + .build(); + mapper.activateDefaultTyping(ptv, ObjectMapper.DefaultTyping.NON_FINAL); + + Car car = new Car("Mercedes-Benz", "S500", 5, 250.0); + Truck truck = new Truck("Isuzu", "NQR", 7500.0); - SubTypeConstructorStructure.Car car = new SubTypeConstructorStructure.Car("Mercedes-Benz", "S500", 5, 250.0); - SubTypeConstructorStructure.Truck truck = new SubTypeConstructorStructure.Truck("Isuzu", "NQR", 7500.0); - - List vehicles = new ArrayList<>(); + List vehicles = new ArrayList<>(); vehicles.add(car); vehicles.add(truck); - SubTypeConstructorStructure.Fleet serializedFleet = new SubTypeConstructorStructure.Fleet(); + Fleet serializedFleet = new Fleet(); serializedFleet.setVehicles(vehicles); String jsonDataString = mapper.writeValueAsString(serializedFleet); - mapper.readValue(jsonDataString, SubTypeConstructorStructure.Fleet.class); + mapper.readValue(jsonDataString, Fleet.class); + + Fleet deserializedFleet = mapper.readValue(jsonDataString, Fleet.class); + + assertThat(deserializedFleet.getVehicles().get(0), instanceOf(Car.class)); + assertThat(deserializedFleet.getVehicles().get(1), instanceOf(Truck.class)); } } \ No newline at end of file diff --git a/jackson-modules/jackson/src/test/java/com/baeldung/jackson/inheritance/TypeInfoInclusionUnitTest.java b/jackson-modules/jackson/src/test/java/com/baeldung/jackson/inheritance/TypeInfoInclusionUnitTest.java index 02297b9ee8..ca057edadc 100644 --- a/jackson-modules/jackson/src/test/java/com/baeldung/jackson/inheritance/TypeInfoInclusionUnitTest.java +++ b/jackson-modules/jackson/src/test/java/com/baeldung/jackson/inheritance/TypeInfoInclusionUnitTest.java @@ -10,12 +10,18 @@ import java.util.ArrayList; import java.io.IOException; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.jsontype.BasicPolymorphicTypeValidator; +import com.fasterxml.jackson.databind.jsontype.PolymorphicTypeValidator; public class TypeInfoInclusionUnitTest { @Test public void givenTypeInfo_whenAnnotatingGlobally_thenTypesAreCorrectlyRecovered() throws IOException { ObjectMapper mapper = new ObjectMapper(); - mapper.enableDefaultTyping(); + PolymorphicTypeValidator ptv = BasicPolymorphicTypeValidator.builder() + .allowIfSubType("com.baeldung.jackson.inheritance") + .allowIfSubType("java.util.ArrayList") + .build(); + mapper.activateDefaultTyping(ptv, ObjectMapper.DefaultTyping.NON_FINAL); TypeInfoStructure.Car car = new TypeInfoStructure.Car("Mercedes-Benz", "S500", 5, 250.0); TypeInfoStructure.Truck truck = new TypeInfoStructure.Truck("Isuzu", "NQR", 7500.0); diff --git a/java-lite/pom.xml b/java-lite/pom.xml index c422e9a421..092063a110 100644 --- a/java-lite/pom.xml +++ b/java-lite/pom.xml @@ -21,13 +21,11 @@ activeweb ${activeweb.version} - mysql mysql-connector-java ${mysql.connector.java.version} - com.sun tools @@ -35,14 +33,12 @@ system ${java.home}/../lib/tools.jar - org.javalite activeweb-testing ${activeweb-testing.version} test - @@ -73,7 +69,6 @@ - org.javalite activejdbc-instrumentation diff --git a/javaxval/pom.xml b/javaxval/pom.xml index d684e9dfe2..f0093e0aa4 100644 --- a/javaxval/pom.xml +++ b/javaxval/pom.xml @@ -48,4 +48,5 @@ 5.0.2.RELEASE 3.11.1 + \ No newline at end of file diff --git a/jee-7/src/main/resources/logback.xml b/jee-7/src/main/resources/logback.xml index 7d900d8ea8..5c1b7ec771 100644 --- a/jee-7/src/main/resources/logback.xml +++ b/jee-7/src/main/resources/logback.xml @@ -7,6 +7,8 @@ + + diff --git a/jersey/pom.xml b/jersey/pom.xml index 9f57179065..c8a7de66ae 100644 --- a/jersey/pom.xml +++ b/jersey/pom.xml @@ -1,7 +1,7 @@ - + 4.0.0 jersey 0.0.1-SNAPSHOT diff --git a/jmeter/README.md b/jmeter/README.md index 53aca8d34b..6fdc79a2ce 100644 --- a/jmeter/README.md +++ b/jmeter/README.md @@ -51,5 +51,5 @@ Enjoy it :) ### Relevant Articles: - [Intro to Performance Testing using JMeter](https://www.baeldung.com/jmeter) -- [Configure Jenkins to Run and Show JMeter Tests](https://www.baeldung.com/jenkins-and-jmeter) +- [Configure Jenkins to Run and Show JMeter Tests](https://www.baeldung.com/ops/jenkins-and-jmeter) - [Write Extracted Data to a File Using JMeter](https://www.baeldung.com/jmeter-write-to-file) diff --git a/json-2/README.md b/json-2/README.md index 64ca7e6449..aebc42c472 100644 --- a/json-2/README.md +++ b/json-2/README.md @@ -7,3 +7,4 @@ This module contains articles about JSON. - [Introduction to Jsoniter](https://www.baeldung.com/java-jsoniter) - [Introduction to Moshi Json](https://www.baeldung.com/java-json-moshi) - [Hypermedia Serialization With JSON-LD](https://www.baeldung.com/json-linked-data) +- [Generate a Java Class From JSON](https://www.baeldung.com/java-generate-class-from-json) diff --git a/json-2/src/main/java/com/baeldung/jsontojavaclass/JsonToJavaClassConversion.java b/json-2/src/main/java/com/baeldung/jsontojavaclass/JsonToJavaClassConversion.java index 65eecd0d38..1b18463856 100644 --- a/json-2/src/main/java/com/baeldung/jsontojavaclass/JsonToJavaClassConversion.java +++ b/json-2/src/main/java/com/baeldung/jsontojavaclass/JsonToJavaClassConversion.java @@ -17,7 +17,22 @@ import com.sun.codemodel.JCodeModel; public class JsonToJavaClassConversion { - public Object convertJsonToJavaClass(URL inputJson, File outputJavaClassDirectory, String packageName, String className) throws IOException { + public static void main(String[] args) { + String packageName = "com.baeldung.jsontojavaclass.pojo"; + String basePath = "src/main/resources"; + File inputJson = new File(basePath + File.separator + "input.json"); + File outputPojoDirectory = new File(basePath + File.separator + "convertedPojo"); + outputPojoDirectory.mkdirs(); + try { + new JsonToJavaClassConversion().convertJsonToJavaClass(inputJson.toURI().toURL(), outputPojoDirectory, packageName, inputJson.getName().replace(".json", "")); + } catch (IOException e) { + System.out.println("Encountered issue while converting to pojo: " + e.getMessage()); + e.printStackTrace(); + } + } + + + public void convertJsonToJavaClass(URL inputJsonUrl, File outputJavaClassDirectory, String packageName, String javaClassName) throws IOException { JCodeModel jcodeModel = new JCodeModel(); GenerationConfig config = new DefaultGenerationConfig() { @@ -33,10 +48,9 @@ public class JsonToJavaClassConversion { }; SchemaMapper mapper = new SchemaMapper(new RuleFactory(config, new Jackson2Annotator(config), new SchemaStore()), new SchemaGenerator()); - mapper.generate(jcodeModel, className, packageName, inputJson); + mapper.generate(jcodeModel, javaClassName, packageName, inputJsonUrl); jcodeModel.build(outputJavaClassDirectory); - return mapper; } } diff --git a/json-2/src/main/java/com/baeldung/jsontojavaclass/pojo/SamplePojo.java b/json-2/src/main/java/com/baeldung/jsontojavaclass/pojo/SamplePojo.java index 4c8a719de0..38ebb8a0f8 100644 --- a/json-2/src/main/java/com/baeldung/jsontojavaclass/pojo/SamplePojo.java +++ b/json-2/src/main/java/com/baeldung/jsontojavaclass/pojo/SamplePojo.java @@ -5,9 +5,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; - import javax.annotation.Generated; - import com.fasterxml.jackson.annotation.JsonAnyGetter; import com.fasterxml.jackson.annotation.JsonAnySetter; import com.fasterxml.jackson.annotation.JsonIgnore; @@ -16,7 +14,14 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonPropertyOrder; @JsonInclude(JsonInclude.Include.NON_NULL) -@JsonPropertyOrder({ "name", "area", "author", "id", "salary", "topics" }) +@JsonPropertyOrder({ + "name", + "area", + "author", + "id", + "salary", + "topics" +}) @Generated("jsonschema2pojo") public class SamplePojo { @@ -143,40 +148,37 @@ public class SamplePojo { @Override public String toString() { StringBuilder sb = new StringBuilder(); - sb.append(SamplePojo.class.getName()) - .append('@') - .append(Integer.toHexString(System.identityHashCode(this))) - .append('['); + sb.append(SamplePojo.class.getName()).append('@').append(Integer.toHexString(System.identityHashCode(this))).append('['); sb.append("name"); sb.append('='); - sb.append(((this.name == null) ? "" : this.name)); + sb.append(((this.name == null)?"":this.name)); sb.append(','); sb.append("area"); sb.append('='); - sb.append(((this.area == null) ? "" : this.area)); + sb.append(((this.area == null)?"":this.area)); sb.append(','); sb.append("author"); sb.append('='); - sb.append(((this.author == null) ? "" : this.author)); + sb.append(((this.author == null)?"":this.author)); sb.append(','); sb.append("id"); sb.append('='); - sb.append(((this.id == null) ? "" : this.id)); + sb.append(((this.id == null)?"":this.id)); sb.append(','); sb.append("salary"); sb.append('='); - sb.append(((this.salary == null) ? "" : this.salary)); + sb.append(((this.salary == null)?"":this.salary)); sb.append(','); sb.append("topics"); sb.append('='); - sb.append(((this.topics == null) ? "" : this.topics)); + sb.append(((this.topics == null)?"":this.topics)); sb.append(','); sb.append("additionalProperties"); sb.append('='); - sb.append(((this.additionalProperties == null) ? "" : this.additionalProperties)); + sb.append(((this.additionalProperties == null)?"":this.additionalProperties)); sb.append(','); - if (sb.charAt((sb.length() - 1)) == ',') { - sb.setCharAt((sb.length() - 1), ']'); + if (sb.charAt((sb.length()- 1)) == ',') { + sb.setCharAt((sb.length()- 1), ']'); } else { sb.append(']'); } @@ -186,13 +188,13 @@ public class SamplePojo { @Override public int hashCode() { int result = 1; - result = ((result * 31) + ((this.area == null) ? 0 : this.area.hashCode())); - result = ((result * 31) + ((this.author == null) ? 0 : this.author.hashCode())); - result = ((result * 31) + ((this.topics == null) ? 0 : this.topics.hashCode())); - result = ((result * 31) + ((this.name == null) ? 0 : this.name.hashCode())); - result = ((result * 31) + ((this.id == null) ? 0 : this.id.hashCode())); - result = ((result * 31) + ((this.additionalProperties == null) ? 0 : this.additionalProperties.hashCode())); - result = ((result * 31) + ((this.salary == null) ? 0 : this.salary.hashCode())); + result = ((result* 31)+((this.area == null)? 0 :this.area.hashCode())); + result = ((result* 31)+((this.author == null)? 0 :this.author.hashCode())); + result = ((result* 31)+((this.topics == null)? 0 :this.topics.hashCode())); + result = ((result* 31)+((this.name == null)? 0 :this.name.hashCode())); + result = ((result* 31)+((this.id == null)? 0 :this.id.hashCode())); + result = ((result* 31)+((this.additionalProperties == null)? 0 :this.additionalProperties.hashCode())); + result = ((result* 31)+((this.salary == null)? 0 :this.salary.hashCode())); return result; } @@ -205,10 +207,7 @@ public class SamplePojo { return false; } SamplePojo rhs = ((SamplePojo) other); - return ((((((((this.area == rhs.area) || ((this.area != null) && this.area.equals(rhs.area))) && ((this.author == rhs.author) || ((this.author != null) && this.author.equals(rhs.author)))) - && ((this.topics == rhs.topics) || ((this.topics != null) && this.topics.equals(rhs.topics)))) && ((this.name == rhs.name) || ((this.name != null) && this.name.equals(rhs.name)))) - && ((this.id == rhs.id) || ((this.id != null) && this.id.equals(rhs.id)))) && ((this.additionalProperties == rhs.additionalProperties) || ((this.additionalProperties != null) && this.additionalProperties.equals(rhs.additionalProperties)))) - && ((this.salary == rhs.salary) || ((this.salary != null) && this.salary.equals(rhs.salary)))); + return ((((((((this.area == rhs.area)||((this.area!= null)&&this.area.equals(rhs.area)))&&((this.author == rhs.author)||((this.author!= null)&&this.author.equals(rhs.author))))&&((this.topics == rhs.topics)||((this.topics!= null)&&this.topics.equals(rhs.topics))))&&((this.name == rhs.name)||((this.name!= null)&&this.name.equals(rhs.name))))&&((this.id == rhs.id)||((this.id!= null)&&this.id.equals(rhs.id))))&&((this.additionalProperties == rhs.additionalProperties)||((this.additionalProperties!= null)&&this.additionalProperties.equals(rhs.additionalProperties))))&&((this.salary == rhs.salary)||((this.salary!= null)&&this.salary.equals(rhs.salary)))); } } diff --git a/json-2/src/main/resources/convertedPojo/com/baeldung/jsontojavaclass/pojo/Address.java b/json-2/src/main/resources/convertedPojo/com/baeldung/jsontojavaclass/pojo/Address.java new file mode 100644 index 0000000000..e3d901edf4 --- /dev/null +++ b/json-2/src/main/resources/convertedPojo/com/baeldung/jsontojavaclass/pojo/Address.java @@ -0,0 +1,119 @@ + +package com.baeldung.jsontojavaclass.pojo; + +import java.util.HashMap; +import java.util.Map; +import javax.annotation.Generated; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonPropertyOrder({ + "city", + "country" +}) +@Generated("jsonschema2pojo") +public class Address { + + @JsonProperty("city") + private String city; + @JsonProperty("country") + private String country; + @JsonIgnore + private Map additionalProperties = new HashMap(); + + @JsonProperty("city") + public String getCity() { + return city; + } + + @JsonProperty("city") + public void setCity(String city) { + this.city = city; + } + + public Address withCity(String city) { + this.city = city; + return this; + } + + @JsonProperty("country") + public String getCountry() { + return country; + } + + @JsonProperty("country") + public void setCountry(String country) { + this.country = country; + } + + public Address withCountry(String country) { + this.country = country; + return this; + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + @JsonAnySetter + public void setAdditionalProperty(String name, Object value) { + this.additionalProperties.put(name, value); + } + + public Address withAdditionalProperty(String name, Object value) { + this.additionalProperties.put(name, value); + return this; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(Address.class.getName()).append('@').append(Integer.toHexString(System.identityHashCode(this))).append('['); + sb.append("city"); + sb.append('='); + sb.append(((this.city == null)?"":this.city)); + sb.append(','); + sb.append("country"); + sb.append('='); + sb.append(((this.country == null)?"":this.country)); + sb.append(','); + sb.append("additionalProperties"); + sb.append('='); + sb.append(((this.additionalProperties == null)?"":this.additionalProperties)); + sb.append(','); + if (sb.charAt((sb.length()- 1)) == ',') { + sb.setCharAt((sb.length()- 1), ']'); + } else { + sb.append(']'); + } + return sb.toString(); + } + + @Override + public int hashCode() { + int result = 1; + result = ((result* 31)+((this.country == null)? 0 :this.country.hashCode())); + result = ((result* 31)+((this.additionalProperties == null)? 0 :this.additionalProperties.hashCode())); + result = ((result* 31)+((this.city == null)? 0 :this.city.hashCode())); + return result; + } + + @Override + public boolean equals(Object other) { + if (other == this) { + return true; + } + if ((other instanceof Address) == false) { + return false; + } + Address rhs = ((Address) other); + return ((((this.country == rhs.country)||((this.country!= null)&&this.country.equals(rhs.country)))&&((this.additionalProperties == rhs.additionalProperties)||((this.additionalProperties!= null)&&this.additionalProperties.equals(rhs.additionalProperties))))&&((this.city == rhs.city)||((this.city!= null)&&this.city.equals(rhs.city)))); + } + +} diff --git a/json-2/src/main/resources/convertedPojo/com/baeldung/jsontojavaclass/pojo/Input.java b/json-2/src/main/resources/convertedPojo/com/baeldung/jsontojavaclass/pojo/Input.java new file mode 100644 index 0000000000..19bee8db4d --- /dev/null +++ b/json-2/src/main/resources/convertedPojo/com/baeldung/jsontojavaclass/pojo/Input.java @@ -0,0 +1,213 @@ + +package com.baeldung.jsontojavaclass.pojo; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import javax.annotation.Generated; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonPropertyOrder({ + "name", + "area", + "author", + "id", + "topics", + "address" +}) +@Generated("jsonschema2pojo") +public class Input { + + @JsonProperty("name") + private String name; + @JsonProperty("area") + private String area; + @JsonProperty("author") + private String author; + @JsonProperty("id") + private Integer id; + @JsonProperty("topics") + private List topics = new ArrayList(); + @JsonProperty("address") + private Address address; + @JsonIgnore + private Map additionalProperties = new HashMap(); + + @JsonProperty("name") + public String getName() { + return name; + } + + @JsonProperty("name") + public void setName(String name) { + this.name = name; + } + + public Input withName(String name) { + this.name = name; + return this; + } + + @JsonProperty("area") + public String getArea() { + return area; + } + + @JsonProperty("area") + public void setArea(String area) { + this.area = area; + } + + public Input withArea(String area) { + this.area = area; + return this; + } + + @JsonProperty("author") + public String getAuthor() { + return author; + } + + @JsonProperty("author") + public void setAuthor(String author) { + this.author = author; + } + + public Input withAuthor(String author) { + this.author = author; + return this; + } + + @JsonProperty("id") + public Integer getId() { + return id; + } + + @JsonProperty("id") + public void setId(Integer id) { + this.id = id; + } + + public Input withId(Integer id) { + this.id = id; + return this; + } + + @JsonProperty("topics") + public List getTopics() { + return topics; + } + + @JsonProperty("topics") + public void setTopics(List topics) { + this.topics = topics; + } + + public Input withTopics(List topics) { + this.topics = topics; + return this; + } + + @JsonProperty("address") + public Address getAddress() { + return address; + } + + @JsonProperty("address") + public void setAddress(Address address) { + this.address = address; + } + + public Input withAddress(Address address) { + this.address = address; + return this; + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + @JsonAnySetter + public void setAdditionalProperty(String name, Object value) { + this.additionalProperties.put(name, value); + } + + public Input withAdditionalProperty(String name, Object value) { + this.additionalProperties.put(name, value); + return this; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(Input.class.getName()).append('@').append(Integer.toHexString(System.identityHashCode(this))).append('['); + sb.append("name"); + sb.append('='); + sb.append(((this.name == null)?"":this.name)); + sb.append(','); + sb.append("area"); + sb.append('='); + sb.append(((this.area == null)?"":this.area)); + sb.append(','); + sb.append("author"); + sb.append('='); + sb.append(((this.author == null)?"":this.author)); + sb.append(','); + sb.append("id"); + sb.append('='); + sb.append(((this.id == null)?"":this.id)); + sb.append(','); + sb.append("topics"); + sb.append('='); + sb.append(((this.topics == null)?"":this.topics)); + sb.append(','); + sb.append("address"); + sb.append('='); + sb.append(((this.address == null)?"":this.address)); + sb.append(','); + sb.append("additionalProperties"); + sb.append('='); + sb.append(((this.additionalProperties == null)?"":this.additionalProperties)); + sb.append(','); + if (sb.charAt((sb.length()- 1)) == ',') { + sb.setCharAt((sb.length()- 1), ']'); + } else { + sb.append(']'); + } + return sb.toString(); + } + + @Override + public int hashCode() { + int result = 1; + result = ((result* 31)+((this.area == null)? 0 :this.area.hashCode())); + result = ((result* 31)+((this.address == null)? 0 :this.address.hashCode())); + result = ((result* 31)+((this.author == null)? 0 :this.author.hashCode())); + result = ((result* 31)+((this.topics == null)? 0 :this.topics.hashCode())); + result = ((result* 31)+((this.name == null)? 0 :this.name.hashCode())); + result = ((result* 31)+((this.id == null)? 0 :this.id.hashCode())); + result = ((result* 31)+((this.additionalProperties == null)? 0 :this.additionalProperties.hashCode())); + return result; + } + + @Override + public boolean equals(Object other) { + if (other == this) { + return true; + } + if ((other instanceof Input) == false) { + return false; + } + Input rhs = ((Input) other); + return ((((((((this.area == rhs.area)||((this.area!= null)&&this.area.equals(rhs.area)))&&((this.address == rhs.address)||((this.address!= null)&&this.address.equals(rhs.address))))&&((this.author == rhs.author)||((this.author!= null)&&this.author.equals(rhs.author))))&&((this.topics == rhs.topics)||((this.topics!= null)&&this.topics.equals(rhs.topics))))&&((this.name == rhs.name)||((this.name!= null)&&this.name.equals(rhs.name))))&&((this.id == rhs.id)||((this.id!= null)&&this.id.equals(rhs.id))))&&((this.additionalProperties == rhs.additionalProperties)||((this.additionalProperties!= null)&&this.additionalProperties.equals(rhs.additionalProperties)))); + } + +} diff --git a/json-2/src/main/resources/input.json b/json-2/src/main/resources/input.json new file mode 100644 index 0000000000..22706ede53 --- /dev/null +++ b/json-2/src/main/resources/input.json @@ -0,0 +1,16 @@ +{ + "name": "Baeldung", + "area": "tech blogs", + "author": "Eugen", + "id": 32134, + "topics": [ + "java", + "kotlin", + "cs", + "linux" + ], + "address": { + "city": "Bucharest", + "country": "Romania" + } +} \ No newline at end of file diff --git a/json-2/src/test/java/com/baeldung/jsontojavaclass/JsonToJavaClassConversionUnitTest.java b/json-2/src/test/java/com/baeldung/jsontojavaclass/JsonToJavaClassConversionUnitTest.java index 8dbfb14b45..f8000fa6fb 100644 --- a/json-2/src/test/java/com/baeldung/jsontojavaclass/JsonToJavaClassConversionUnitTest.java +++ b/json-2/src/test/java/com/baeldung/jsontojavaclass/JsonToJavaClassConversionUnitTest.java @@ -3,6 +3,7 @@ package com.baeldung.jsontojavaclass; import java.io.File; import java.io.IOException; import java.net.MalformedURLException; +import java.util.Arrays; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -21,17 +22,16 @@ class JsonToJavaClassConversionUnitTest { File inputJson = new File(jsonPath + "sample_input.json"); // create the local directory for generating the Java Class file - String outputPath = "src/main/java/"; + String outputPath = "src/test/resources/"; File outputJavaClassDirectory = new File(outputPath); - outputJavaClassDirectory.mkdirs(); - String className = "SamplePojo"; + String javaClassName = "SamplePojo"; - Object object = jsonToJavaConversion.convertJsonToJavaClass(inputJson.toURI() - .toURL(), outputJavaClassDirectory, packageName, className); - System.out.println(object); + jsonToJavaConversion.convertJsonToJavaClass(inputJson.toURI() + .toURL(), outputJavaClassDirectory, packageName, javaClassName); - Assertions.assertNotNull(object); + File outputJavaClassPath = new File(outputPath + packageName.replace(".", "/")); + Assertions.assertTrue(Arrays.stream(outputJavaClassPath.listFiles()).peek(System.out::println).anyMatch(file -> (javaClassName+".java").equalsIgnoreCase(file.getName()))); } diff --git a/json-2/src/test/resources/com/baeldung/jsontojavaclass/pojo/SamplePojo.java b/json-2/src/test/resources/com/baeldung/jsontojavaclass/pojo/SamplePojo.java new file mode 100644 index 0000000000..38ebb8a0f8 --- /dev/null +++ b/json-2/src/test/resources/com/baeldung/jsontojavaclass/pojo/SamplePojo.java @@ -0,0 +1,213 @@ + +package com.baeldung.jsontojavaclass.pojo; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import javax.annotation.Generated; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonPropertyOrder({ + "name", + "area", + "author", + "id", + "salary", + "topics" +}) +@Generated("jsonschema2pojo") +public class SamplePojo { + + @JsonProperty("name") + private String name; + @JsonProperty("area") + private String area; + @JsonProperty("author") + private String author; + @JsonProperty("id") + private Integer id; + @JsonProperty("salary") + private Integer salary; + @JsonProperty("topics") + private List topics = new ArrayList(); + @JsonIgnore + private Map additionalProperties = new HashMap(); + + @JsonProperty("name") + public String getName() { + return name; + } + + @JsonProperty("name") + public void setName(String name) { + this.name = name; + } + + public SamplePojo withName(String name) { + this.name = name; + return this; + } + + @JsonProperty("area") + public String getArea() { + return area; + } + + @JsonProperty("area") + public void setArea(String area) { + this.area = area; + } + + public SamplePojo withArea(String area) { + this.area = area; + return this; + } + + @JsonProperty("author") + public String getAuthor() { + return author; + } + + @JsonProperty("author") + public void setAuthor(String author) { + this.author = author; + } + + public SamplePojo withAuthor(String author) { + this.author = author; + return this; + } + + @JsonProperty("id") + public Integer getId() { + return id; + } + + @JsonProperty("id") + public void setId(Integer id) { + this.id = id; + } + + public SamplePojo withId(Integer id) { + this.id = id; + return this; + } + + @JsonProperty("salary") + public Integer getSalary() { + return salary; + } + + @JsonProperty("salary") + public void setSalary(Integer salary) { + this.salary = salary; + } + + public SamplePojo withSalary(Integer salary) { + this.salary = salary; + return this; + } + + @JsonProperty("topics") + public List getTopics() { + return topics; + } + + @JsonProperty("topics") + public void setTopics(List topics) { + this.topics = topics; + } + + public SamplePojo withTopics(List topics) { + this.topics = topics; + return this; + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + @JsonAnySetter + public void setAdditionalProperty(String name, Object value) { + this.additionalProperties.put(name, value); + } + + public SamplePojo withAdditionalProperty(String name, Object value) { + this.additionalProperties.put(name, value); + return this; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(SamplePojo.class.getName()).append('@').append(Integer.toHexString(System.identityHashCode(this))).append('['); + sb.append("name"); + sb.append('='); + sb.append(((this.name == null)?"":this.name)); + sb.append(','); + sb.append("area"); + sb.append('='); + sb.append(((this.area == null)?"":this.area)); + sb.append(','); + sb.append("author"); + sb.append('='); + sb.append(((this.author == null)?"":this.author)); + sb.append(','); + sb.append("id"); + sb.append('='); + sb.append(((this.id == null)?"":this.id)); + sb.append(','); + sb.append("salary"); + sb.append('='); + sb.append(((this.salary == null)?"":this.salary)); + sb.append(','); + sb.append("topics"); + sb.append('='); + sb.append(((this.topics == null)?"":this.topics)); + sb.append(','); + sb.append("additionalProperties"); + sb.append('='); + sb.append(((this.additionalProperties == null)?"":this.additionalProperties)); + sb.append(','); + if (sb.charAt((sb.length()- 1)) == ',') { + sb.setCharAt((sb.length()- 1), ']'); + } else { + sb.append(']'); + } + return sb.toString(); + } + + @Override + public int hashCode() { + int result = 1; + result = ((result* 31)+((this.area == null)? 0 :this.area.hashCode())); + result = ((result* 31)+((this.author == null)? 0 :this.author.hashCode())); + result = ((result* 31)+((this.topics == null)? 0 :this.topics.hashCode())); + result = ((result* 31)+((this.name == null)? 0 :this.name.hashCode())); + result = ((result* 31)+((this.id == null)? 0 :this.id.hashCode())); + result = ((result* 31)+((this.additionalProperties == null)? 0 :this.additionalProperties.hashCode())); + result = ((result* 31)+((this.salary == null)? 0 :this.salary.hashCode())); + return result; + } + + @Override + public boolean equals(Object other) { + if (other == this) { + return true; + } + if ((other instanceof SamplePojo) == false) { + return false; + } + SamplePojo rhs = ((SamplePojo) other); + return ((((((((this.area == rhs.area)||((this.area!= null)&&this.area.equals(rhs.area)))&&((this.author == rhs.author)||((this.author!= null)&&this.author.equals(rhs.author))))&&((this.topics == rhs.topics)||((this.topics!= null)&&this.topics.equals(rhs.topics))))&&((this.name == rhs.name)||((this.name!= null)&&this.name.equals(rhs.name))))&&((this.id == rhs.id)||((this.id!= null)&&this.id.equals(rhs.id))))&&((this.additionalProperties == rhs.additionalProperties)||((this.additionalProperties!= null)&&this.additionalProperties.equals(rhs.additionalProperties))))&&((this.salary == rhs.salary)||((this.salary!= null)&&this.salary.equals(rhs.salary)))); + } + +} diff --git a/jta/pom.xml b/jta/pom.xml index 1937f55a20..e9f9364646 100644 --- a/jta/pom.xml +++ b/jta/pom.xml @@ -29,7 +29,6 @@ org.springframework.boot spring-boot-starter - org.hsqldb hsqldb diff --git a/ksqldb/pom.xml b/ksqldb/pom.xml index 13867b16e3..970e8c3788 100644 --- a/ksqldb/pom.xml +++ b/ksqldb/pom.xml @@ -28,34 +28,29 @@ ksqldb-api-client ${ksqldb.version} - org.projectlombok lombok ${lombok.version} - org.awaitility awaitility ${awaitility.version} test - org.assertj assertj-core ${assertj.version} test - org.testcontainers testcontainers ${testcontainers.version} test - org.testcontainers junit-jupiter @@ -71,4 +66,4 @@ 1.15.3 - + \ No newline at end of file diff --git a/kubernetes/k8s-admission-controller/README.md b/kubernetes/k8s-admission-controller/README.md index c446ab403d..9c824d76b3 100644 --- a/kubernetes/k8s-admission-controller/README.md +++ b/kubernetes/k8s-admission-controller/README.md @@ -1,3 +1,4 @@ ## Relevant Articles: - [Creating a Kubertes Admission Controller in Java](https://www.baeldung.com/java-kubernetes-admission-controller) +- [Access Control Models](https://www.baeldung.com/java-access-control-models) diff --git a/kubernetes/k8s-intro/README.md b/kubernetes/k8s-intro/README.md index 8c11f4d53e..bce7784aa1 100644 --- a/kubernetes/k8s-intro/README.md +++ b/kubernetes/k8s-intro/README.md @@ -18,3 +18,4 @@ If you get a valid response, then you're good to go. - [Using Watch with the Kubernetes API](https://www.baeldung.com/java-kubernetes-watch) - [Using Namespaces and Selectors With the Kubernetes Java API](https://www.baeldung.com/java-kubernetes-namespaces-selectors) - [Creating, Updating and Deleting Resources with the Java Kubernetes API](https://www.baeldung.com/java-kubernetes-api-crud) +- [A Quick Intro to the Kubernetes Java Client](https://www.baeldung.com/kubernetes-java-client) diff --git a/kubernetes/k8s-intro/pom.xml b/kubernetes/k8s-intro/pom.xml index 5da137ebb6..61722cb2c8 100644 --- a/kubernetes/k8s-intro/pom.xml +++ b/kubernetes/k8s-intro/pom.xml @@ -17,7 +17,6 @@ client-java 11.0.0 - ch.qos.logback logback-classic diff --git a/libraries-6/pom.xml b/libraries-6/pom.xml index d2ed06af6a..4b33df9a1d 100644 --- a/libraries-6/pom.xml +++ b/libraries-6/pom.xml @@ -111,9 +111,9 @@ - mulesoft - Mulesoft Repository - https://repository.mulesoft.org/nexus/content/repositories/public/ + bedatadriven + BeDataDriven repository + https://nexus.bedatadriven.com/content/groups/public/ @@ -144,7 +144,7 @@ 1.15 3.6 3.6.2 - RELEASE + 3.5-beta72 3.0 1.8.1 4.4 diff --git a/libraries-data-2/pom.xml b/libraries-data-2/pom.xml index cce2e57d22..75b2cc962d 100644 --- a/libraries-data-2/pom.xml +++ b/libraries-data-2/pom.xml @@ -104,12 +104,12 @@ org.slf4j slf4j-api - ${slf4j.version} + ${org.slf4j.version} org.slf4j slf4j-log4j12 - ${slf4j.version} + ${org.slf4j.version} com.univocity @@ -161,7 +161,6 @@ 4.0.0 1.1.0 3.6.2 - 1.7.25 3.0.0 2.8.4 29.0-jre diff --git a/libraries-data/pom.xml b/libraries-data/pom.xml index 717ee802db..c5ad08448f 100644 --- a/libraries-data/pom.xml +++ b/libraries-data/pom.xml @@ -108,7 +108,7 @@ org.slf4j slf4j-api - ${slf4j.version} + ${org.slf4j.version} org.apache.storm @@ -173,7 +173,6 @@ 3.8.4 0.15.0 2.2.0 - 1.7.25 1.6.0.1 diff --git a/libraries-io/src/main/java/com/baeldung/java/io/zip4j/CreateSplitZipFile.java b/libraries-io/src/main/java/com/baeldung/java/io/zip4j/CreateSplitZipFile.java index cc39bc9dd2..a7ecd7946e 100644 --- a/libraries-io/src/main/java/com/baeldung/java/io/zip4j/CreateSplitZipFile.java +++ b/libraries-io/src/main/java/com/baeldung/java/io/zip4j/CreateSplitZipFile.java @@ -1,22 +1,23 @@ package com.baeldung.java.io.zip4j; import net.lingala.zip4j.ZipFile; -import net.lingala.zip4j.exception.ZipException; import net.lingala.zip4j.model.ZipParameters; import net.lingala.zip4j.model.enums.EncryptionMethod; import java.io.File; +import java.io.IOException; import java.util.Arrays; public class CreateSplitZipFile { - public static void main(String[] args) throws ZipException { + public static void main(String[] args) throws IOException { ZipParameters zipParameters = new ZipParameters(); zipParameters.setEncryptFiles(true); zipParameters.setEncryptionMethod(EncryptionMethod.AES); ZipFile zipFile = new ZipFile("compressed.zip", "password".toCharArray()); - int splitLength = 1024 * 1024 * 10; //10MB + int splitLength = 1024 * 1024 * 10; // 10MB zipFile.createSplitZipFile(Arrays.asList(new File("aFile.txt")), zipParameters, true, splitLength); zipFile.createSplitZipFileFromFolder(new File("/users/folder_to_add"), zipParameters, true, splitLength); + zipFile.close(); } } diff --git a/libraries-io/src/main/java/com/baeldung/java/io/zip4j/ExtractAllFile.java b/libraries-io/src/main/java/com/baeldung/java/io/zip4j/ExtractAllFile.java index 10e7ddd339..924d80a921 100644 --- a/libraries-io/src/main/java/com/baeldung/java/io/zip4j/ExtractAllFile.java +++ b/libraries-io/src/main/java/com/baeldung/java/io/zip4j/ExtractAllFile.java @@ -1,12 +1,14 @@ package com.baeldung.java.io.zip4j; +import java.io.IOException; + import net.lingala.zip4j.ZipFile; -import net.lingala.zip4j.exception.ZipException; public class ExtractAllFile { - public static void main(String[] args) throws ZipException { + public static void main(String[] args) throws IOException { ZipFile zipFile = new ZipFile("compressed.zip", "password".toCharArray()); zipFile.extractAll("/destination_directory"); + zipFile.close(); } } diff --git a/libraries-io/src/main/java/com/baeldung/java/io/zip4j/ExtractSingleFile.java b/libraries-io/src/main/java/com/baeldung/java/io/zip4j/ExtractSingleFile.java index 4cf466d02b..ad79557a37 100644 --- a/libraries-io/src/main/java/com/baeldung/java/io/zip4j/ExtractSingleFile.java +++ b/libraries-io/src/main/java/com/baeldung/java/io/zip4j/ExtractSingleFile.java @@ -1,12 +1,14 @@ package com.baeldung.java.io.zip4j; +import java.io.IOException; + import net.lingala.zip4j.ZipFile; -import net.lingala.zip4j.exception.ZipException; public class ExtractSingleFile { - public static void main(String[] args) throws ZipException { + public static void main(String[] args) throws IOException { ZipFile zipFile = new ZipFile("compressed.zip", "password".toCharArray()); zipFile.extractFile("aFile.txt", "/destination_directory"); + zipFile.close(); } } diff --git a/libraries-io/src/main/java/com/baeldung/java/io/zip4j/ZipFolder.java b/libraries-io/src/main/java/com/baeldung/java/io/zip4j/ZipFolder.java index 4d89e8665f..ed25494083 100644 --- a/libraries-io/src/main/java/com/baeldung/java/io/zip4j/ZipFolder.java +++ b/libraries-io/src/main/java/com/baeldung/java/io/zip4j/ZipFolder.java @@ -1,19 +1,20 @@ package com.baeldung.java.io.zip4j; import net.lingala.zip4j.ZipFile; -import net.lingala.zip4j.exception.ZipException; import net.lingala.zip4j.model.ZipParameters; import net.lingala.zip4j.model.enums.EncryptionMethod; import java.io.File; +import java.io.IOException; public class ZipFolder { - public static void main(String[] args) throws ZipException { + public static void main(String[] args) throws IOException { ZipParameters zipParameters = new ZipParameters(); zipParameters.setEncryptFiles(true); zipParameters.setEncryptionMethod(EncryptionMethod.AES); ZipFile zipFile = new ZipFile("compressed.zip", "password".toCharArray()); zipFile.addFolder(new File("/users/folder_to_add"), zipParameters); + zipFile.close(); } } diff --git a/libraries-io/src/main/java/com/baeldung/java/io/zip4j/ZipMultiFile.java b/libraries-io/src/main/java/com/baeldung/java/io/zip4j/ZipMultiFile.java index dcb860ef92..081d207294 100644 --- a/libraries-io/src/main/java/com/baeldung/java/io/zip4j/ZipMultiFile.java +++ b/libraries-io/src/main/java/com/baeldung/java/io/zip4j/ZipMultiFile.java @@ -1,27 +1,34 @@ package com.baeldung.java.io.zip4j; import net.lingala.zip4j.ZipFile; -import net.lingala.zip4j.exception.ZipException; import net.lingala.zip4j.model.ZipParameters; import net.lingala.zip4j.model.enums.EncryptionMethod; import java.io.File; +import java.io.IOException; import java.util.Arrays; import java.util.List; public class ZipMultiFile { - public static void main(String[] args) throws ZipException { + public static void main(String[] args) throws IOException { ZipParameters zipParameters = new ZipParameters(); zipParameters.setEncryptFiles(true); zipParameters.setEncryptionMethod(EncryptionMethod.AES); - List filesToAdd = Arrays.asList( - new File("aFile.txt"), - new File("bFile.txt") - ); + File firstFile = new File("aFile.txt"); + File secondFile = new File("bFile.txt"); + if (!firstFile.exists()) { + firstFile.createNewFile(); + } + if (!secondFile.exists()) { + secondFile.createNewFile(); + } + + List filesToAdd = Arrays.asList(firstFile, secondFile); ZipFile zipFile = new ZipFile("compressed.zip", "password".toCharArray()); zipFile.addFiles(filesToAdd, zipParameters); + zipFile.close(); } } diff --git a/libraries-io/src/main/java/com/baeldung/java/io/zip4j/ZipSingleFile.java b/libraries-io/src/main/java/com/baeldung/java/io/zip4j/ZipSingleFile.java index a5f600df47..d0947afa2e 100644 --- a/libraries-io/src/main/java/com/baeldung/java/io/zip4j/ZipSingleFile.java +++ b/libraries-io/src/main/java/com/baeldung/java/io/zip4j/ZipSingleFile.java @@ -1,21 +1,27 @@ package com.baeldung.java.io.zip4j; import net.lingala.zip4j.ZipFile; -import net.lingala.zip4j.exception.ZipException; import net.lingala.zip4j.model.ZipParameters; import net.lingala.zip4j.model.enums.CompressionLevel; import net.lingala.zip4j.model.enums.EncryptionMethod; import java.io.File; +import java.io.IOException; public class ZipSingleFile { - public static void main(String[] args) throws ZipException { + public static void main(String[] args) throws IOException { ZipParameters zipParameters = new ZipParameters(); zipParameters.setEncryptFiles(true); zipParameters.setCompressionLevel(CompressionLevel.HIGHER); zipParameters.setEncryptionMethod(EncryptionMethod.AES); ZipFile zipFile = new ZipFile("compressed.zip", "password".toCharArray()); - zipFile.addFile(new File("aFile.txt")); + + File fileToAdd = new File("aFile.txt"); + if (!fileToAdd.exists()) { + fileToAdd.createNewFile(); + } + zipFile.addFile(fileToAdd); + zipFile.close(); } } diff --git a/libraries-security/pom.xml b/libraries-security/pom.xml index 0031b7bc06..46e12eb655 100644 --- a/libraries-security/pom.xml +++ b/libraries-security/pom.xml @@ -78,6 +78,29 @@ sshd-core ${apache-mina.version} + + org.xacml4j + xacml-core + ${xacml4j.version} + + + org.slf4j + slf4j-log4j12 + + + + + org.xacml4j + xacml-test + ${xacml4j.version} + test + + + org.slf4j + slf4j-log4j12 + + + @@ -90,6 +113,7 @@ 0.1.55 2.5.1 2.4.0.RELEASE + 1.4.0 \ No newline at end of file diff --git a/libraries-security/src/main/java/com/baeldung/scribejava/ScribejavaApplication.java b/libraries-security/src/main/java/com/baeldung/scribejava/ScribejavaApplication.java index bb86c497b0..5b18567b2d 100644 --- a/libraries-security/src/main/java/com/baeldung/scribejava/ScribejavaApplication.java +++ b/libraries-security/src/main/java/com/baeldung/scribejava/ScribejavaApplication.java @@ -2,9 +2,11 @@ package com.baeldung.scribejava; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.web.servlet.ServletComponentScan; @SpringBootApplication +@ServletComponentScan public class ScribejavaApplication { public static void main(String[] args) { diff --git a/libraries-security/src/main/java/com/baeldung/scribejava/controller/RBACController.java b/libraries-security/src/main/java/com/baeldung/scribejava/controller/RBACController.java new file mode 100644 index 0000000000..785f6228e8 --- /dev/null +++ b/libraries-security/src/main/java/com/baeldung/scribejava/controller/RBACController.java @@ -0,0 +1,27 @@ +package com.baeldung.scribejava.controller; + +import java.io.IOException; + +import javax.annotation.security.DeclareRoles; +import javax.annotation.security.RolesAllowed; +import javax.servlet.ServletException; +import javax.servlet.annotation.HttpConstraint; +import javax.servlet.annotation.ServletSecurity; +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +@WebServlet(name="rbac", urlPatterns = {"/protected"}) +@DeclareRoles("USER") +@ServletSecurity( + @HttpConstraint(rolesAllowed = "USER") +) +public class RBACController extends HttpServlet { + + private static final long serialVersionUID = 1L; + + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + resp.getWriter().println("Hello, USER"); + } +} diff --git a/libraries-security/src/test/java/com/baeldung/xacml4j/NightlyWithdrawalPolicyUnitTest.java b/libraries-security/src/test/java/com/baeldung/xacml4j/NightlyWithdrawalPolicyUnitTest.java new file mode 100644 index 0000000000..013c78370f --- /dev/null +++ b/libraries-security/src/test/java/com/baeldung/xacml4j/NightlyWithdrawalPolicyUnitTest.java @@ -0,0 +1,233 @@ +package com.baeldung.xacml4j; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.Test; +import org.xacml4j.v20.Xacml20TestUtility; +import org.xacml4j.v30.Attribute; +import org.xacml4j.v30.Categories; +import org.xacml4j.v30.Category; +import org.xacml4j.v30.CompositeDecisionRule; +import org.xacml4j.v30.Decision; +import org.xacml4j.v30.Entity; +import org.xacml4j.v30.RequestContext; +import org.xacml4j.v30.ResponseContext; +import org.xacml4j.v30.Result; +import org.xacml4j.v30.XacmlPolicyTestSupport; +import org.xacml4j.v30.pdp.PolicyDecisionPoint; +import org.xacml4j.v30.pdp.PolicyDecisionPointBuilder; +import org.xacml4j.v30.spi.combine.DecisionCombiningAlgorithmProviderBuilder; +import org.xacml4j.v30.spi.function.FunctionProviderBuilder; +import org.xacml4j.v30.spi.pip.PolicyInformationPointBuilder; +import org.xacml4j.v30.spi.repository.InMemoryPolicyRepository; +import org.xacml4j.v30.spi.repository.PolicyRepository; +import org.xacml4j.v30.types.DoubleExp; +import org.xacml4j.v30.types.StringExp; +import org.xacml4j.v30.types.TimeExp; + +public class NightlyWithdrawalPolicyUnitTest extends XacmlPolicyTestSupport { + + private static final String POLICY_SET = "xacml4j/NightlyWithdrawalsPolicy.xml"; + + @Test + public void testWhenNightlyWithdrawalOver500_thenFail() throws Exception { + + PolicyDecisionPoint pdp = buildPDP(POLICY_SET); + + // Action category + Attribute actionAttribute = Attribute.builder("urn:oasis:names:tc:xacml:1.0:action:action-id") + .value(StringExp.of("withdrawal")) + .build(); + Entity actionEntity = Entity.builder() + .attribute(actionAttribute) + .build(); + Category actionCategory = Category.builder(Categories.ACTION) + .entity(actionEntity) + .build(); + + // Environment Category + Attribute timeAttribute = Attribute.builder("urn:oasis:names:tc:xacml:1.0:environment:current-time") + .includeInResult(false) + .value(TimeExp.of("21:00:00")) + .build(); + Entity timeEntity = Entity.builder() + .attribute(timeAttribute) + .build(); + + Category environmentCategory = Category.builder(Categories.ENVIRONMENT) + .entity(timeEntity) + .build(); + + // ATM category + Attribute amountAttribute = Attribute.builder("urn:baeldung:atm:withdrawal:amount") + .value(DoubleExp.of("1200.00")) + .build(); + Entity atmEntity = Entity.builder() + .attribute(amountAttribute) + .build(); + + Category atmCategory = Category.builder(Categories.parse("urn:baeldung:atm:withdrawal")) + .entity(atmEntity) + .build(); + + RequestContext request = RequestContext.builder() + .attributes(actionCategory, environmentCategory, atmCategory) + .build(); + + ResponseContext response = pdp.decide(request); + assertNotNull(response); + assertTrue("Shoud have at least one result", response.getResults() != null && !response.getResults() + .isEmpty()); + + Result result = response.getResults() + .iterator() + .next(); + assertTrue("Evaluation should succeed", result.getStatus() + .isSuccess()); + assertEquals("Should DENY withdrawal", Decision.DENY, result.getDecision()); + + } + + @Test + public void testWhenNightlyWithdrawalUnder500_thenSuccess() throws Exception { + + PolicyDecisionPoint pdp = buildPDP(POLICY_SET); + + // Action category + Attribute actionAttribute = Attribute.builder("urn:oasis:names:tc:xacml:1.0:action:action-id") + .includeInResult(false) + .value(StringExp.of("withdrawal")) + .build(); + Entity actionEntity = Entity.builder() + .attribute(actionAttribute) + .build(); + Category actionCategory = Category.builder(Categories.ACTION) + .entity(actionEntity) + .build(); + + // Environment Category + Attribute timeAttribute = Attribute.builder("urn:oasis:names:tc:xacml:1.0:environment:current-time") + .includeInResult(false) + .value(TimeExp.of("21:00:00")) + .build(); + Entity timeEntity = Entity.builder() + .attribute(timeAttribute) + .build(); + Category environmentCategory = Category.builder(Categories.ENVIRONMENT) + .entity(timeEntity) + .build(); + + // ATM category + Attribute amountAttribute = Attribute.builder("urn:baeldung:atm:withdrawal:amount") + .value(DoubleExp.of("499.00")) + .build(); + Entity atmEntity = Entity.builder() + .attribute(amountAttribute) + .build(); + Category atmCategory = Category.builder(Categories.parse("urn:baeldung:atm:withdrawal")) + .entity(atmEntity) + .build(); + + RequestContext request = RequestContext.builder() + .attributes(actionCategory, environmentCategory, atmCategory) + .build(); + + ResponseContext response = pdp.decide(request); + assertNotNull(response); + assertTrue("Shoud have at least one result", + response.getResults() != null && !response.getResults().isEmpty()); + + Result result = response.getResults().iterator().next(); + assertTrue("Evaluation should succeed", result.getStatus().isSuccess()); + assertEquals("Should PERMIT withdrawal", Decision.PERMIT, result.getDecision()); + + } + + @Test + public void testWhenBusinessHoursWithdrawalOver500_thenSuccess() throws Exception { + + PolicyDecisionPoint pdp = buildPDP(POLICY_SET); + + // Action category + Attribute actionAttribute = Attribute.builder("urn:oasis:names:tc:xacml:1.0:action:action-id") + .includeInResult(false) + .value(StringExp.of("withdrawal")) + .build(); + Entity actionEntity = Entity.builder() + .attribute(actionAttribute) + .build(); + Category actionCategory = Category.builder(Categories.ACTION) + .entity(actionEntity) + .build(); + + // Environment Category + Attribute timeAttribute = Attribute.builder("urn:oasis:names:tc:xacml:1.0:environment:current-time") + .includeInResult(false) + .value(TimeExp.of("12:00:00")) + .build(); + Entity timeEntity = Entity.builder() + .attribute(timeAttribute) + .build(); + Category environmentCategory = Category.builder(Categories.ENVIRONMENT) + .entity(timeEntity) + .build(); + + // ATM category + Attribute amountAttribute = Attribute.builder("urn:baeldung:atm:withdrawal:amount") + .value(DoubleExp.of("2000.00")) + .build(); + Entity atmEntity = Entity.builder() + .attribute(amountAttribute) + .build(); + + Category atmCategory = Category.builder(Categories.parse("urn:baeldung:atm:withdrawal")) + .entity(atmEntity) + .build(); + + RequestContext request = RequestContext.builder() + .attributes(actionCategory, environmentCategory, atmCategory) + .build(); + + ResponseContext response = pdp.decide(request); + assertNotNull(response); + assertTrue("Shoud have at least one result", response.getResults() != null && !response.getResults() + .isEmpty()); + + Result result = response.getResults() + .iterator() + .next(); + assertTrue("Evaluation should succeed", result.getStatus().isSuccess()); + assertEquals("Should PERMIT withdrawal", Decision.PERMIT, result.getDecision()); + + } + + private PolicyDecisionPoint buildPDP(String... policyResources) throws Exception { + PolicyRepository repository = new InMemoryPolicyRepository("tes-repository", FunctionProviderBuilder.builder() + .defaultFunctions() + .build(), + DecisionCombiningAlgorithmProviderBuilder.builder() + .withDefaultAlgorithms() + .create()); + + List policies = new ArrayList(policyResources.length); + for (String policyResource : policyResources) { + CompositeDecisionRule policy = repository.importPolicy(Xacml20TestUtility.getClasspathResource(policyResource)); + log.info("Policy: {}", policy); + policies.add(policy); + } + + return PolicyDecisionPointBuilder.builder("testPdp") + .policyRepository(repository) + .pip(PolicyInformationPointBuilder.builder("testPip") + .defaultResolvers() + .build()) + .rootPolicy(policies.get(0)) + .build(); + } + +} diff --git a/libraries-security/src/test/resources/xacml4j/NightlyWithdrawalsPolicy.xml b/libraries-security/src/test/resources/xacml4j/NightlyWithdrawalsPolicy.xml new file mode 100644 index 0000000000..163df47f36 --- /dev/null +++ b/libraries-security/src/test/resources/xacml4j/NightlyWithdrawalsPolicy.xml @@ -0,0 +1,137 @@ + + + + Withdrawal policy example + + + + +Deny withdrawals over $500 between 20:00 and 08:00 + + + + + + withdrawal + + + + + + + + + + + + + 08:00:00 + 20:00:00 + + + + + + + 500.00 + + + + + + +Permit withdrawals under $500 between 20:00 and 08:00 + + + + + + withdrawal + + + + + + + + + + + + + 08:00:00 + 20:00:00 + + + + + + + 500.00 + + + + + + +Permit withdrawals of any value between 08:00 and 20:00 + + + + + + withdrawal + + + + + + + + + + + 08:00:00 + 20:00:00 + + + + + diff --git a/libraries-security/src/test/resources/xacml4j/Request.xml b/libraries-security/src/test/resources/xacml4j/Request.xml new file mode 100644 index 0000000000..105c7ad02f --- /dev/null +++ b/libraries-security/src/test/resources/xacml4j/Request.xml @@ -0,0 +1,30 @@ + + + + + + withdrawal + + + + + 21:00:00 + + + + + 1200 + + + \ No newline at end of file diff --git a/libraries-security/src/test/resources/xacml4j/Response.xml b/libraries-security/src/test/resources/xacml4j/Response.xml new file mode 100644 index 0000000000..f82b16080d --- /dev/null +++ b/libraries-security/src/test/resources/xacml4j/Response.xml @@ -0,0 +1,9 @@ + + + + NotApplicable + + + + + diff --git a/logging-modules/log4j/README.md b/logging-modules/log4j/README.md index 371d0246ce..a47d0ae89b 100644 --- a/logging-modules/log4j/README.md +++ b/logging-modules/log4j/README.md @@ -3,4 +3,4 @@ - [Introduction to SLF4J](http://www.baeldung.com/slf4j-with-log4j2-logback) - [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) +- [Log4j Warning: “No Appenders Could Be Found for Logger”](https://www.baeldung.com/log4j-no-appenders-found) diff --git a/logging-modules/logback/pom.xml b/logging-modules/logback/pom.xml index 6d32025d94..512dc9e5a3 100644 --- a/logging-modules/logback/pom.xml +++ b/logging-modules/logback/pom.xml @@ -69,7 +69,6 @@ - 1.2.3 0.1.5 3.3.5 1.4.7 diff --git a/mapstruct/pom.xml b/mapstruct/pom.xml index 1e7ce6cbfc..48687a73b9 100644 --- a/mapstruct/pom.xml +++ b/mapstruct/pom.xml @@ -1,7 +1,7 @@ - + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 4.0.0 mapstruct 1.0 @@ -90,4 +90,4 @@ 3.16.1 - \ No newline at end of file + \ No newline at end of file diff --git a/maven-modules/host-maven-repo-example/pom.xml b/maven-modules/host-maven-repo-example/pom.xml index 9434e4a3b3..bd58dddeda 100644 --- a/maven-modules/host-maven-repo-example/pom.xml +++ b/maven-modules/host-maven-repo-example/pom.xml @@ -1,28 +1,17 @@ + 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.maven.plugin host-maven-repo-example 1.0-SNAPSHOT - https://github.com/sgrverma23/host-maven-repo-example.git - - - github - 8 - 8 - - https://github.com/sgrverma23/host-maven-repo-example.git scm:git:git@github.com:sgrverma23/host-maven-repo-example.git scm:git:git@github.com:sgrverma23/host-maven-repo-example.git - - internal.repo @@ -30,6 +19,7 @@ file://${project.build.directory}/mvn-artifact + @@ -95,6 +85,7 @@ + PROJECT-REPO-URL @@ -105,4 +96,11 @@ + + + github + 8 + 8 + + \ No newline at end of file diff --git a/maven-modules/maven-dependency-management/README.md b/maven-modules/maven-dependency-management/README.md new file mode 100644 index 0000000000..0abf99d2d3 --- /dev/null +++ b/maven-modules/maven-dependency-management/README.md @@ -0,0 +1,3 @@ +### Relevant Articles: + +- [Maven dependencyManagement vs. dependencies Tags](https://www.baeldung.com/maven-dependencymanagement-vs-dependencies-tags) diff --git a/maven-modules/maven-dependency-management/pom.xml b/maven-modules/maven-dependency-management/pom.xml new file mode 100644 index 0000000000..fb2bdfe602 --- /dev/null +++ b/maven-modules/maven-dependency-management/pom.xml @@ -0,0 +1,45 @@ + + + 4.0.0 + + com.baeldung + maven-dependency + 1.0.0-SNAPSHOT + pom + + + maven-modules + com.baeldung + 0.0.1-SNAPSHOT + + + + + + + junit + junit + 4.13.2 + test + + + org.apache.commons + commons-lang3 + 3.12.0 + + + + + + + junit + junit + + + org.apache.commons + commons-lang3 + + + \ No newline at end of file diff --git a/maven-modules/maven-dependency-management/src/main/java/com/baeldung/Main.java b/maven-modules/maven-dependency-management/src/main/java/com/baeldung/Main.java new file mode 100644 index 0000000000..ea4451a41b --- /dev/null +++ b/maven-modules/maven-dependency-management/src/main/java/com/baeldung/Main.java @@ -0,0 +1,11 @@ +package com.baeldung; + +import org.apache.commons.lang3.StringUtils; + +public class Main { + + public static void main(String[] args) { + + StringUtils.isBlank(" "); + } +} diff --git a/maven-modules/maven-parent-pom-resolution/README.md b/maven-modules/maven-parent-pom-resolution/README.md new file mode 100644 index 0000000000..b315b2f626 --- /dev/null +++ b/maven-modules/maven-parent-pom-resolution/README.md @@ -0,0 +1,3 @@ +### Relevant Articles: + +- [Understanding Maven’s “relativePath” Tag for a Parent POM](https://www.baeldung.com/maven-relativepath) diff --git a/maven-modules/maven-parent-pom-resolution/aggregator/module1/pom.xml b/maven-modules/maven-parent-pom-resolution/aggregator/module1/pom.xml new file mode 100644 index 0000000000..e1f411db2f --- /dev/null +++ b/maven-modules/maven-parent-pom-resolution/aggregator/module1/pom.xml @@ -0,0 +1,16 @@ + + + 4.0.0 + module1 + pom + + + com.baeldung.maven-parent-pom-resolution + aggregator + 1.0.0-SNAPSHOT + + + + diff --git a/maven-modules/maven-parent-pom-resolution/aggregator/module2/module3/pom.xml b/maven-modules/maven-parent-pom-resolution/aggregator/module2/module3/pom.xml new file mode 100644 index 0000000000..d983f35e3e --- /dev/null +++ b/maven-modules/maven-parent-pom-resolution/aggregator/module2/module3/pom.xml @@ -0,0 +1,18 @@ + + + 4.0.0 + module3 + pom + + + com.baeldung.maven-parent-pom-resolution + aggregator + 1.0.0-SNAPSHOT + + + ../../pom.xml + + + diff --git a/maven-modules/maven-parent-pom-resolution/aggregator/module2/pom.xml b/maven-modules/maven-parent-pom-resolution/aggregator/module2/pom.xml new file mode 100644 index 0000000000..48c1ebab9d --- /dev/null +++ b/maven-modules/maven-parent-pom-resolution/aggregator/module2/pom.xml @@ -0,0 +1,21 @@ + + + 4.0.0 + module2 + pom + + + com.baeldung.maven-parent-pom-resolution + module1 + 1.0.0-SNAPSHOT + ../module1/pom.xml + + + + + module3 + + + diff --git a/maven-modules/maven-parent-pom-resolution/aggregator/pom.xml b/maven-modules/maven-parent-pom-resolution/aggregator/pom.xml new file mode 100644 index 0000000000..8f6e3453a5 --- /dev/null +++ b/maven-modules/maven-parent-pom-resolution/aggregator/pom.xml @@ -0,0 +1,22 @@ + + + 4.0.0 + com.baeldung.maven-parent-pom-resolution + aggregator + pom + + + com.baeldung + maven-parent-pom-resolution + 1.0.0-SNAPSHOT + + + + + module1 + module2 + + + diff --git a/maven-modules/maven-parent-pom-resolution/pom.xml b/maven-modules/maven-parent-pom-resolution/pom.xml new file mode 100644 index 0000000000..e5340032b7 --- /dev/null +++ b/maven-modules/maven-parent-pom-resolution/pom.xml @@ -0,0 +1,28 @@ + + + 4.0.0 + com.baeldung + maven-parent-pom-resolution + 1.0.0-SNAPSHOT + pom + + + aggregator + + + + + + + + org.apache.maven.plugins + maven-dependency-plugin + 3.2.0 + + + + + + \ No newline at end of file diff --git a/maven-modules/maven-printing-plugins/pom.xml b/maven-modules/maven-printing-plugins/pom.xml index b68c88dbee..07ddd8d1e8 100644 --- a/maven-modules/maven-printing-plugins/pom.xml +++ b/maven-modules/maven-printing-plugins/pom.xml @@ -53,7 +53,8 @@ Hello, world Embed a line break: ${line.separator} - ArtifactId is ${project.artifactId} + ArtifactId is + ${project.artifactId} INFO /logs/log-echo.txt @@ -76,7 +77,7 @@ log.info('Test message: {}', 'Hello, World!') log.info('Embed a line break {}', System.lineSeparator()) - log.info('ArtifactId is: ${project.artifactId}') + log.info('ArtifactId is: ${project.artifactId}') log.warn('Message only in debug mode') diff --git a/maven-modules/maven-properties/pom.xml b/maven-modules/maven-properties/pom.xml index 9454664c3f..f4c657c2e4 100644 --- a/maven-modules/maven-properties/pom.xml +++ b/maven-modules/maven-properties/pom.xml @@ -13,12 +13,12 @@ 1.0.0-SNAPSHOT ../.. - + junit junit - ${junit.version} + ${junit.version} @@ -46,7 +46,7 @@ ${project.name} property-from-pom - 4.13 + 4.13 - + \ No newline at end of file diff --git a/maven-modules/maven-surefire-plugin/pom.xml b/maven-modules/maven-surefire-plugin/pom.xml index 903adf3c11..98decc69e1 100644 --- a/maven-modules/maven-surefire-plugin/pom.xml +++ b/maven-modules/maven-surefire-plugin/pom.xml @@ -7,11 +7,11 @@ 0.0.1-SNAPSHOT maven-surefire-plugin jar + com.baeldung maven-modules 0.0.1-SNAPSHOT - diff --git a/maven-modules/pom.xml b/maven-modules/pom.xml index a0c45234d2..3f87c60406 100644 --- a/maven-modules/pom.xml +++ b/maven-modules/pom.xml @@ -36,6 +36,8 @@ host-maven-repo-example plugin-management maven-surefire-plugin + maven-parent-pom-resolution + maven-dependency-management - + \ No newline at end of file diff --git a/mesos-marathon/README.md b/mesos-marathon/README.md index 8e5b8e4974..6fb3e7782b 100644 --- a/mesos-marathon/README.md +++ b/mesos-marathon/README.md @@ -4,6 +4,6 @@ This module contains articles about Marathon and Mesos. ### Relevant articles -- [Simple Jenkins Pipeline with Marathon and Mesos](https://www.baeldung.com/jenkins-pipeline-with-marathon-mesos) +- [Simple Jenkins Pipeline with Marathon and Mesos](https://www.baeldung.com/ops/jenkins-pipeline-with-marathon-mesos) To run the pipeline, please modify the dockerise.sh file with your own username and password for docker login. diff --git a/micronaut/pom.xml b/micronaut/pom.xml index 196218d856..e9b5a0409f 100644 --- a/micronaut/pom.xml +++ b/micronaut/pom.xml @@ -61,7 +61,7 @@ ch.qos.logback logback-classic - ${lombok.version} + ${logback.version} runtime @@ -145,7 +145,6 @@ 1.0.0.RC2 1.8 1.3.2 - 1.2.3 3.1.6.RELEASE 3.7.0 3.1.0 diff --git a/netflix-modules/genie/README.md b/netflix-modules/genie/README.md index f6e15ba403..81b9d28dc4 100644 --- a/netflix-modules/genie/README.md +++ b/netflix-modules/genie/README.md @@ -1,3 +1,3 @@ ### Relevant Articles: -- [Introduction to Netflix Genie](https://www.baeldung.com/netflix-genie-intro) +- [Introduction to Netflix Genie](https://www.baeldung.com/ops/netflix-genie-intro) diff --git a/oauth2-framework-impl/oauth2-authorization-server/pom.xml b/oauth2-framework-impl/oauth2-authorization-server/pom.xml index f8ced851ba..c206fc2e55 100644 --- a/oauth2-framework-impl/oauth2-authorization-server/pom.xml +++ b/oauth2-framework-impl/oauth2-authorization-server/pom.xml @@ -1,7 +1,7 @@ - + xmlns="http://maven.apache.org/POM/4.0.0"> 4.0.0 oauth2-authorization-server oauth2-authorization-server diff --git a/oauth2-framework-impl/oauth2-client/pom.xml b/oauth2-framework-impl/oauth2-client/pom.xml index 814dabc664..715b7e729c 100644 --- a/oauth2-framework-impl/oauth2-client/pom.xml +++ b/oauth2-framework-impl/oauth2-client/pom.xml @@ -1,7 +1,7 @@ - + xmlns="http://maven.apache.org/POM/4.0.0"> 4.0.0 oauth2-client oauth2-client diff --git a/oauth2-framework-impl/oauth2-resource-server/pom.xml b/oauth2-framework-impl/oauth2-resource-server/pom.xml index 8f135055a2..d3af2cfd80 100644 --- a/oauth2-framework-impl/oauth2-resource-server/pom.xml +++ b/oauth2-framework-impl/oauth2-resource-server/pom.xml @@ -1,7 +1,7 @@ - + xmlns="http://maven.apache.org/POM/4.0.0"> 4.0.0 oauth2-resource-server oauth2-resource-server diff --git a/oauth2-framework-impl/pom.xml b/oauth2-framework-impl/pom.xml index 31983b08ad..5cfcb22fab 100644 --- a/oauth2-framework-impl/pom.xml +++ b/oauth2-framework-impl/pom.xml @@ -1,7 +1,7 @@ - + xmlns="http://maven.apache.org/POM/4.0.0"> 4.0.0 com.baeldung.oauth2 oauth2-framework-impl diff --git a/osgi/osgi-intro-sample-client/pom.xml b/osgi/osgi-intro-sample-client/pom.xml index b1b04aef78..7e679dd3a7 100644 --- a/osgi/osgi-intro-sample-client/pom.xml +++ b/osgi/osgi-intro-sample-client/pom.xml @@ -37,9 +37,7 @@ ${project.artifactId} ${project.version} com.baeldung.osgi.sample.client.Client - com.baeldung.osgi.sample.client - diff --git a/parent-boot-2/pom.xml b/parent-boot-2/pom.xml index accbc2df96..2e520640ec 100644 --- a/parent-boot-2/pom.xml +++ b/parent-boot-2/pom.xml @@ -81,7 +81,7 @@ 3.3.0 1.0.22.RELEASE - 2.5.1 + 2.5.4 1.9.1 3.4.0 diff --git a/patterns/design-patterns-architectural/README.md b/patterns/design-patterns-architectural/README.md index a8a5a98b88..bb11eea5e1 100644 --- a/patterns/design-patterns-architectural/README.md +++ b/patterns/design-patterns-architectural/README.md @@ -3,3 +3,4 @@ - [The DAO Pattern in Java](https://www.baeldung.com/java-dao-pattern) - [DAO vs Repository Patterns](https://www.baeldung.com/java-dao-vs-repository) - [Difference Between MVC and MVP Patterns](https://www.baeldung.com/mvc-vs-mvp-pattern) +- [The DTO Pattern (Data Transfer Object)](https://www.baeldung.com/java-dto-pattern) diff --git a/patterns/design-patterns-architectural/pom.xml b/patterns/design-patterns-architectural/pom.xml index 02716d7a10..11194a9c92 100644 --- a/patterns/design-patterns-architectural/pom.xml +++ b/patterns/design-patterns-architectural/pom.xml @@ -55,7 +55,6 @@ 6.0.6 2.5.3 3.3.0 - \ No newline at end of file diff --git a/patterns/design-patterns-cloud/pom.xml b/patterns/design-patterns-cloud/pom.xml index 950b6efb94..c3e2fcfc39 100644 --- a/patterns/design-patterns-cloud/pom.xml +++ b/patterns/design-patterns-cloud/pom.xml @@ -8,5 +8,4 @@ 1.0.0-SNAPSHOT design-patterns-cloud pom - \ No newline at end of file diff --git a/patterns/enterprise-patterns/wire-tap/README.md b/patterns/enterprise-patterns/wire-tap/README.md index 95cd1d585f..61d27f5c44 100644 --- a/patterns/enterprise-patterns/wire-tap/README.md +++ b/patterns/enterprise-patterns/wire-tap/README.md @@ -29,7 +29,5 @@ For more details, check out the AmqApplicationUnitTest.class. ### Relevant Articles: -- [Wire tap (Enterprise Integration Pattern)](https://drafts.baeldung.com/?p=103346&preview=true) -- [Intro to Apache camel](https://www.baeldung.com/apache-camel-intro) - [Wire Tap Enterprise Integration Pattern](https://www.baeldung.com/wiretap-pattern) diff --git a/patterns/simplehexagonalexample/pom.xml b/patterns/simplehexagonalexample/pom.xml index b73e81be44..d9b9b36831 100644 --- a/patterns/simplehexagonalexample/pom.xml +++ b/patterns/simplehexagonalexample/pom.xml @@ -1,31 +1,32 @@ - 4.0.0 - 1.0.0-SNAPSHOT - simple-hexagonal-example - simpleHexagonalExample + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> + 4.0.0 + 1.0.0-SNAPSHOT + simple-hexagonal-example + simpleHexagonalExample - - com.baeldung - parent-boot-2 - 0.0.1-SNAPSHOT - ../../parent-boot-2 - + + com.baeldung + parent-boot-2 + 0.0.1-SNAPSHOT + ../../parent-boot-2 + - - - org.springframework.boot - spring-boot-starter-web - - + + + org.springframework.boot + spring-boot-starter-web + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + - - - - org.springframework.boot - spring-boot-maven-plugin - - - \ No newline at end of file diff --git a/pdf/README.md b/pdf/README.md index bed468ad24..dd6931ba78 100644 --- a/pdf/README.md +++ b/pdf/README.md @@ -7,3 +7,4 @@ This module contains articles about PDF files. - [Creating PDF Files in Java](https://www.baeldung.com/java-pdf-creation) - [Generating PDF Files Using Thymeleaf](https://www.baeldung.com/thymeleaf-generate-pdf) - [Java Convert PDF to Base64](https://www.baeldung.com/java-convert-pdf-to-base64) +- [HTML to PDF Using OpenPDF](https://www.baeldung.com/java-html-to-pdf) diff --git a/pdf/pom.xml b/pdf/pom.xml index fb9508156e..6bd1d97402 100644 --- a/pdf/pom.xml +++ b/pdf/pom.xml @@ -71,6 +71,26 @@ flying-saucer-pdf ${flying-saucer-pdf.version} + + org.xhtmlrenderer + flying-saucer-pdf-openpdf + ${flying-saucer-pdf-openpdf.version} + + + org.jsoup + jsoup + ${jsoup.version} + + + com.openhtmltopdf + openhtmltopdf-core + ${open-html-pdf-core.version} + + + com.openhtmltopdf + openhtmltopdf-pdfbox + ${open-html-pdfbox.version} + @@ -93,6 +113,10 @@ 3.15 3.0.11.RELEASE 9.1.20 + 1.0.6 + 1.0.6 + 9.1.22 + 1.14.2 \ No newline at end of file diff --git a/pdf/src/main/java/com/baeldung/pdf/openpdf/CustomElementFactoryImpl.java b/pdf/src/main/java/com/baeldung/pdf/openpdf/CustomElementFactoryImpl.java new file mode 100644 index 0000000000..d8256a68f7 --- /dev/null +++ b/pdf/src/main/java/com/baeldung/pdf/openpdf/CustomElementFactoryImpl.java @@ -0,0 +1,56 @@ +package com.baeldung.pdf.openpdf; + +import java.io.FileInputStream; +import java.io.InputStream; + +import org.apache.commons.io.IOUtils; +import org.w3c.dom.Element; +import org.xhtmlrenderer.extend.FSImage; +import org.xhtmlrenderer.extend.ReplacedElement; +import org.xhtmlrenderer.extend.ReplacedElementFactory; +import org.xhtmlrenderer.extend.UserAgentCallback; +import org.xhtmlrenderer.layout.LayoutContext; +import org.xhtmlrenderer.pdf.ITextFSImage; +import org.xhtmlrenderer.pdf.ITextImageElement; +import org.xhtmlrenderer.render.BlockBox; +import org.xhtmlrenderer.simple.extend.FormSubmissionListener; + +import com.lowagie.text.Image; + +public class CustomElementFactoryImpl implements ReplacedElementFactory { + @Override + public ReplacedElement createReplacedElement(LayoutContext lc, BlockBox box, UserAgentCallback uac, int cssWidth, int cssHeight) { + Element e = box.getElement(); + String nodeName = e.getNodeName(); + if (nodeName.equals("img")) { + String imagePath = e.getAttribute("src"); + try { + InputStream input = new FileInputStream("src/main/resources/" + imagePath); + byte[] bytes = IOUtils.toByteArray(input); + Image image = Image.getInstance(bytes); + FSImage fsImage = new ITextFSImage(image); + if (cssWidth != -1 || cssHeight != -1) { + fsImage.scale(cssWidth, cssHeight); + } else { + fsImage.scale(2000, 1000); + } + return new ITextImageElement(fsImage); + } catch (Exception e1) { + e1.printStackTrace(); + } + } + return null; + } + + @Override + public void reset() { + } + + @Override + public void remove(Element e) { + } + + @Override + public void setFormSubmissionListener(FormSubmissionListener listener) { + } +} \ No newline at end of file diff --git a/pdf/src/main/java/com/baeldung/pdf/openpdf/Html2PdfUsingFlyingSaucer.java b/pdf/src/main/java/com/baeldung/pdf/openpdf/Html2PdfUsingFlyingSaucer.java new file mode 100644 index 0000000000..927d85a4cb --- /dev/null +++ b/pdf/src/main/java/com/baeldung/pdf/openpdf/Html2PdfUsingFlyingSaucer.java @@ -0,0 +1,53 @@ +package com.baeldung.pdf.openpdf; + +import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; +import org.xhtmlrenderer.layout.SharedContext; +import org.xhtmlrenderer.pdf.ITextRenderer; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +public class Html2PdfUsingFlyingSaucer { + + private static final String HTML_INPUT = "src/main/resources/htmlforopenpdf.html"; + private static final String PDF_OUTPUT = "src/main/resources/html2pdf.pdf"; + + public static void main(String[] args) { + try { + Html2PdfUsingFlyingSaucer htmlToPdf = new Html2PdfUsingFlyingSaucer(); + htmlToPdf.generateHtmlToPdf(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + private void generateHtmlToPdf() throws Exception { + File inputHTML = new File(HTML_INPUT); + Document inputHtml = createWellFormedHtml(inputHTML); + File outputPdf = new File(PDF_OUTPUT); + xhtmlToPdf(inputHtml, outputPdf); + } + + private Document createWellFormedHtml(File inputHTML) throws IOException { + Document document = Jsoup.parse(inputHTML, "UTF-8"); + document.outputSettings() + .syntax(Document.OutputSettings.Syntax.xml); + return document; + } + + private void xhtmlToPdf(Document xhtml, File outputPdf) throws Exception { + try (OutputStream outputStream = new FileOutputStream(outputPdf)) { + ITextRenderer renderer = new ITextRenderer(); + SharedContext sharedContext = renderer.getSharedContext(); + sharedContext.setPrint(true); + sharedContext.setInteractive(false); + sharedContext.setReplacedElementFactory(new CustomElementFactoryImpl()); + renderer.setDocumentFromString(xhtml.html()); + renderer.layout(); + renderer.createPDF(outputStream); + } + } +} diff --git a/pdf/src/main/java/com/baeldung/pdf/openpdf/Html2PdfUsingOpenHtml.java b/pdf/src/main/java/com/baeldung/pdf/openpdf/Html2PdfUsingOpenHtml.java new file mode 100644 index 0000000000..bc83da6102 --- /dev/null +++ b/pdf/src/main/java/com/baeldung/pdf/openpdf/Html2PdfUsingOpenHtml.java @@ -0,0 +1,55 @@ +package com.baeldung.pdf.openpdf; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.nio.file.FileSystems; + +import org.jsoup.Jsoup; +import org.jsoup.helper.W3CDom; +import org.jsoup.nodes.Document; + +import com.openhtmltopdf.pdfboxout.PdfRendererBuilder; + +public class Html2PdfUsingOpenHtml { + + private static final String HTML_INPUT = "src/main/resources/htmlforopenpdf.html"; + private static final String PDF_OUTPUT = "src/main/resources/html2pdf.pdf"; + + public static void main(String[] args) { + try { + Html2PdfUsingOpenHtml htmlToPdf = new Html2PdfUsingOpenHtml(); + htmlToPdf.generateHtmlToPdf(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + private void generateHtmlToPdf() throws IOException { + File inputHTML = new File(HTML_INPUT); + Document doc = createWellFormedHtml(inputHTML); + xhtmlToPdf(doc, PDF_OUTPUT); + } + + private Document createWellFormedHtml(File inputHTML) throws IOException { + Document document = Jsoup.parse(inputHTML, "UTF-8"); + document.outputSettings() + .syntax(Document.OutputSettings.Syntax.xml); + return document; + } + + private void xhtmlToPdf(Document doc, String outputPdf) throws IOException { + try (OutputStream os = new FileOutputStream(outputPdf)) { + String baseUri = FileSystems.getDefault() + .getPath("src/main/resources/") + .toUri() + .toString(); + PdfRendererBuilder builder = new PdfRendererBuilder(); + builder.withUri(outputPdf); + builder.toStream(os); + builder.withW3cDocument(new W3CDom().fromJsoup(doc), baseUri); + builder.run(); + } + } +} diff --git a/pdf/src/main/resources/html2pdf.pdf b/pdf/src/main/resources/html2pdf.pdf new file mode 100644 index 0000000000..877ff4cacd Binary files /dev/null and b/pdf/src/main/resources/html2pdf.pdf differ diff --git a/pdf/src/main/resources/htmlforopenpdf.html b/pdf/src/main/resources/htmlforopenpdf.html new file mode 100644 index 0000000000..ae39965c87 --- /dev/null +++ b/pdf/src/main/resources/htmlforopenpdf.html @@ -0,0 +1,26 @@ + + + + + + +
+

Hello Baeldung!

+ + +
+

This is the tutorial to convert html to pdf.

+
+
+ + \ No newline at end of file diff --git a/pdf/src/main/resources/style.css b/pdf/src/main/resources/style.css new file mode 100644 index 0000000000..381ffadf00 --- /dev/null +++ b/pdf/src/main/resources/style.css @@ -0,0 +1,6 @@ +.myclass{ + font-family: Helvetica, sans-serif; + font-size:25; + font-weight: normal; + color: blue; +} \ No newline at end of file diff --git a/persistence-modules/deltaspike/pom.xml b/persistence-modules/deltaspike/pom.xml index af02ba76c0..1255e5ab27 100644 --- a/persistence-modules/deltaspike/pom.xml +++ b/persistence-modules/deltaspike/pom.xml @@ -16,6 +16,38 @@ 1.0.0-SNAPSHOT
+ + + + + org.wildfly.bom + jboss-javaee-7.0-with-tools + ${jboss.bom.version} + pom + import + + + org.wildfly.bom + jboss-javaee-7.0-with-hibernate + ${jboss.bom.version} + pom + import + + + org.apache.deltaspike.distribution + distributions-bom + ${deltaspike.version} + pom + import + + + + @@ -245,38 +277,6 @@ - - - - - org.wildfly.bom - jboss-javaee-7.0-with-tools - ${jboss.bom.version} - pom - import - - - org.wildfly.bom - jboss-javaee-7.0-with-hibernate - ${jboss.bom.version} - pom - import - - - org.apache.deltaspike.distribution - distributions-bom - ${deltaspike.version} - pom - import - - - - 3.7.4 1.8.2 diff --git a/persistence-modules/hibernate-enterprise/pom.xml b/persistence-modules/hibernate-enterprise/pom.xml index dadfa211be..1d9ebfc156 100644 --- a/persistence-modules/hibernate-enterprise/pom.xml +++ b/persistence-modules/hibernate-enterprise/pom.xml @@ -1,7 +1,7 @@ - + 4.0.0 hibernate-enterprise 0.0.1-SNAPSHOT diff --git a/persistence-modules/hibernate-libraries/pom.xml b/persistence-modules/hibernate-libraries/pom.xml index 19537156aa..7d552b262d 100644 --- a/persistence-modules/hibernate-libraries/pom.xml +++ b/persistence-modules/hibernate-libraries/pom.xml @@ -77,7 +77,7 @@ org.slf4j slf4j-api - ${slf4j.version} + ${org.slf4j.version} provided true @@ -174,12 +174,10 @@ 3.27.0-GA 2.3.1 2.0.0 - 1.2.3 3.0.2 3.8.1 3.8.1 8.0.19 - 1.7.30 2.1.3.RELEASE diff --git a/persistence-modules/java-jpa-3/README.md b/persistence-modules/java-jpa-3/README.md index c024d7c540..202c97a830 100644 --- a/persistence-modules/java-jpa-3/README.md +++ b/persistence-modules/java-jpa-3/README.md @@ -13,3 +13,5 @@ This module contains articles about the Java Persistence API (JPA) in Java. - [Returning an Auto-Generated Id with JPA](https://www.baeldung.com/jpa-get-auto-generated-id) - [How to Return Multiple Entities In JPA Query](https://www.baeldung.com/jpa-return-multiple-entities) - [Defining Unique Constraints in JPA](https://www.baeldung.com/jpa-unique-constraints) +- [How to Check Field Existence in MongoDB?](https://www.baeldung.com/mongodb-check-field-exists) +- [Connecting to a Specific Schema in JDBC](https://www.baeldung.com/jdbc-connect-to-schema) diff --git a/persistence-modules/java-mongodb/pom.xml b/persistence-modules/java-mongodb/pom.xml index f708a54f46..03229e72bd 100644 --- a/persistence-modules/java-mongodb/pom.xml +++ b/persistence-modules/java-mongodb/pom.xml @@ -1,7 +1,7 @@ - + 4.0.0 java-mongodb 1.0-SNAPSHOT diff --git a/persistence-modules/redis/pom.xml b/persistence-modules/redis/pom.xml index 8079d56cbd..d1cb927c20 100644 --- a/persistence-modules/redis/pom.xml +++ b/persistence-modules/redis/pom.xml @@ -1,7 +1,7 @@ - + 4.0.0 redis 0.1-SNAPSHOT diff --git a/persistence-modules/spring-boot-persistence-2/pom.xml b/persistence-modules/spring-boot-persistence-2/pom.xml index b51ab17659..1a02b18e50 100644 --- a/persistence-modules/spring-boot-persistence-2/pom.xml +++ b/persistence-modules/spring-boot-persistence-2/pom.xml @@ -146,7 +146,7 @@ 3.9.1 2.1.8.RELEASE 0.9.5.2 - 19.6.0.0 + 21.1.0.0 \ No newline at end of file diff --git a/persistence-modules/spring-boot-persistence-2/src/main/java/com/baeldung/spring/oracle/pooling/configuration/OracleConfiguration.java b/persistence-modules/spring-boot-persistence-2/src/main/java/com/baeldung/spring/oracle/pooling/configuration/OracleConfiguration.java index 9cf7e27c99..e201c9eb76 100644 --- a/persistence-modules/spring-boot-persistence-2/src/main/java/com/baeldung/spring/oracle/pooling/configuration/OracleConfiguration.java +++ b/persistence-modules/spring-boot-persistence-2/src/main/java/com/baeldung/spring/oracle/pooling/configuration/OracleConfiguration.java @@ -20,7 +20,8 @@ public class OracleConfiguration { dataSource.setUser("books"); dataSource.setPassword("books"); dataSource.setURL("jdbc:oracle:thin:@//localhost:11521/ORCLPDB1"); - dataSource.setFastConnectionFailoverEnabled(true); + // Only with clients prior to v21 + // dataSource.setFastConnectionFailoverEnabled(true); dataSource.setImplicitCachingEnabled(true); // Only with clients prior to v11.2 // dataSource.setConnectionCachingEnabled(true); diff --git a/persistence-modules/spring-boot-persistence-2/src/main/java/com/baeldung/spring/oracle/pooling/configuration/OracleUCPConfiguration.java b/persistence-modules/spring-boot-persistence-2/src/main/java/com/baeldung/spring/oracle/pooling/configuration/OracleUCPConfiguration.java deleted file mode 100644 index b4c1544149..0000000000 --- a/persistence-modules/spring-boot-persistence-2/src/main/java/com/baeldung/spring/oracle/pooling/configuration/OracleUCPConfiguration.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.baeldung.spring.oracle.pooling.configuration; - -import java.sql.SQLException; - -import javax.sql.DataSource; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Profile; - -import oracle.ucp.jdbc.PoolDataSource; -import oracle.ucp.jdbc.PoolDataSourceFactory; - -@Configuration -@Profile("oracle-ucp") -public class OracleUCPConfiguration { - - @Bean - public DataSource dataSource() throws SQLException { - PoolDataSource dataSource = PoolDataSourceFactory.getPoolDataSource(); - dataSource.setUser("books"); - dataSource.setPassword("books"); - dataSource.setConnectionFactoryClassName("oracle.jdbc.pool.OracleDataSource"); - dataSource.setURL("jdbc:oracle:thin:@//localhost:11521/ORCLPDB1"); - - dataSource.setFastConnectionFailoverEnabled(true); - dataSource.setInitialPoolSize(5); - dataSource.setMinPoolSize(5); - dataSource.setMaxPoolSize(10); - return dataSource; - } -} diff --git a/persistence-modules/spring-boot-persistence-2/src/main/resources/application-oracle-pooling-basic.properties b/persistence-modules/spring-boot-persistence-2/src/main/resources/application-oracle-pooling-basic.properties index 9a1c7fc89d..9de2ee476b 100644 --- a/persistence-modules/spring-boot-persistence-2/src/main/resources/application-oracle-pooling-basic.properties +++ b/persistence-modules/spring-boot-persistence-2/src/main/resources/application-oracle-pooling-basic.properties @@ -21,6 +21,15 @@ spring.datasource.hikari.poolName=HikariPoolBooks spring.datasource.tomcat.maxActive=15 spring.datasource.tomcat.minIdle=5 +# UCP settings +#Note: These properties require JDBC version 21.0.0.0 +spring.datasource.ucp.connection-factory-class-name=oracle.jdbc.pool.OracleDataSource +spring.datasource.ucp.sql-for-validate-connection=select * from dual +spring.datasource.ucp.connection-pool-name=UcpPoolBooks +spring.datasource.ucp.initial-pool-size=5 +spring.datasource.ucp.min-pool-size=5 +spring.datasource.ucp.max-pool-size=10 + # JPA settings spring.jpa.database-platform=org.hibernate.dialect.Oracle12cDialect spring.jpa.hibernate.use-new-id-generator-mappings=false diff --git a/persistence-modules/spring-boot-persistence-2/src/test/java/com/baeldung/spring/oracle/pooling/SpringOraclePoolingApplicationOracleUCPLiveTest.java b/persistence-modules/spring-boot-persistence-2/src/test/java/com/baeldung/spring/oracle/pooling/SpringOraclePoolingApplicationOracleUCPLiveTest.java index 4fb6aa6bae..cf418b2cf4 100644 --- a/persistence-modules/spring-boot-persistence-2/src/test/java/com/baeldung/spring/oracle/pooling/SpringOraclePoolingApplicationOracleUCPLiveTest.java +++ b/persistence-modules/spring-boot-persistence-2/src/test/java/com/baeldung/spring/oracle/pooling/SpringOraclePoolingApplicationOracleUCPLiveTest.java @@ -9,11 +9,13 @@ 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.TestPropertySource; import org.springframework.test.context.junit4.SpringRunner; @RunWith(SpringRunner.class) @SpringBootTest(classes = {SpringOraclePoolingApplication.class}) -@ActiveProfiles({"oracle-pooling-basic", "oracle-ucp"}) +@ActiveProfiles({"oracle-pooling-basic"}) +@TestPropertySource(properties = "spring.datasource.type=oracle.ucp.jdbc.UCPDataSource") public class SpringOraclePoolingApplicationOracleUCPLiveTest { @Autowired @@ -21,7 +23,7 @@ public class SpringOraclePoolingApplicationOracleUCPLiveTest { @Test public void givenOracleUCPConfiguration_thenBuildsOraclePoolDataSource() { - assertTrue(dataSource instanceof oracle.ucp.jdbc.PoolDataSource); + assertTrue(dataSource instanceof oracle.ucp.jdbc.UCPDataSource); } } diff --git a/persistence-modules/spring-boot-persistence/src/main/resources/persistence-generic-entity.properties b/persistence-modules/spring-boot-persistence/src/main/resources/persistence-generic-entity.properties index b19304cb1f..3e018e9321 100644 --- a/persistence-modules/spring-boot-persistence/src/main/resources/persistence-generic-entity.properties +++ b/persistence-modules/spring-boot-persistence/src/main/resources/persistence-generic-entity.properties @@ -6,3 +6,5 @@ jdbc.pass=sa hibernate.dialect=org.hibernate.dialect.H2Dialect hibernate.show_sql=true hibernate.hbm2ddl.auto=create-drop + +spring.jpa.defer-datasource-initialization=true \ No newline at end of file diff --git a/persistence-modules/spring-data-arangodb/pom.xml b/persistence-modules/spring-data-arangodb/pom.xml index 562f06ae40..7303316edb 100644 --- a/persistence-modules/spring-data-arangodb/pom.xml +++ b/persistence-modules/spring-data-arangodb/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 spring-data-arangodb spring-data-arangodb @@ -18,7 +18,6 @@ org.springframework.boot spring-boot-starter - com.arangodb arangodb-spring-data diff --git a/persistence-modules/spring-data-cassandra-reactive/pom.xml b/persistence-modules/spring-data-cassandra-reactive/pom.xml index 5dd5ab4b69..cddb62186b 100644 --- a/persistence-modules/spring-data-cassandra-reactive/pom.xml +++ b/persistence-modules/spring-data-cassandra-reactive/pom.xml @@ -28,6 +28,10 @@ org.springframework.boot spring-boot-starter-web + + org.springframework.boot + spring-boot-starter-validation + org.projectlombok lombok @@ -52,8 +56,7 @@ - 2.2.6.RELEASE - 3.11.2.0 + 4.3.1.0 \ No newline at end of file diff --git a/persistence-modules/spring-data-cassandra-reactive/src/main/resources/application.properties b/persistence-modules/spring-data-cassandra-reactive/src/main/resources/application.properties index 7ed2f10131..5acbcdd5a3 100644 --- a/persistence-modules/spring-data-cassandra-reactive/src/main/resources/application.properties +++ b/persistence-modules/spring-data-cassandra-reactive/src/main/resources/application.properties @@ -1,2 +1,3 @@ spring.data.cassandra.keyspace-name=practice -spring.data.cassandra.port=9042 \ No newline at end of file +spring.data.cassandra.port=9042 +spring.data.cassandra.local-datacenter=datacenter1 \ No newline at end of file diff --git a/persistence-modules/spring-data-cassandra-test/pom.xml b/persistence-modules/spring-data-cassandra-test/pom.xml index f2cbc834de..5d9bcc63c2 100644 --- a/persistence-modules/spring-data-cassandra-test/pom.xml +++ b/persistence-modules/spring-data-cassandra-test/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 spring-data-cassandra-test spring-data-cassandra-test @@ -14,6 +14,50 @@ ../../parent-boot-2
+ + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-data-cassandra + ${spring-boot-starter-data-cassandra.version} + + + com.datastax.oss + java-driver-core + ${java-driver-core.version} + + + org.projectlombok + lombok + ${lombok.version} + + + com.datastax.oss + native-protocol + ${native-protocol.version} + + + org.springframework.boot + spring-boot-starter-test + test + + + org.testcontainers + testcontainers + ${testcontainers.version} + test + + + org.testcontainers + cassandra + ${testcontainers.version} + test + + + 2.5.3 1.18.18 @@ -23,55 +67,4 @@ 1.5.0 - - - org.springframework.boot - spring-boot-starter-web - - - - org.springframework.boot - spring-boot-starter-data-cassandra - ${spring-boot-starter-data-cassandra.version} - - - - com.datastax.oss - java-driver-core - ${java-driver-core.version} - - - - org.projectlombok - lombok - ${lombok.version} - - - - com.datastax.oss - native-protocol - ${native-protocol.version} - - - - org.springframework.boot - spring-boot-starter-test - test - - - - org.testcontainers - testcontainers - ${testcontainers.version} - test - - - - org.testcontainers - cassandra - ${testcontainers.version} - test - - - \ No newline at end of file diff --git a/persistence-modules/spring-data-jpa-crud/pom.xml b/persistence-modules/spring-data-jpa-crud/pom.xml index 8f9a3cc0e8..139632a42a 100644 --- a/persistence-modules/spring-data-jpa-crud/pom.xml +++ b/persistence-modules/spring-data-jpa-crud/pom.xml @@ -1,8 +1,7 @@ + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 spring-data-jpa-crud spring-data-jpa-crud diff --git a/persistence-modules/spring-data-jpa-crud/src/main/resources/application.properties b/persistence-modules/spring-data-jpa-crud/src/main/resources/application.properties index 3829f676d3..d7fb13da08 100644 --- a/persistence-modules/spring-data-jpa-crud/src/main/resources/application.properties +++ b/persistence-modules/spring-data-jpa-crud/src/main/resources/application.properties @@ -1,7 +1,6 @@ spring.jpa.properties.hibernate.jdbc.batch_size=4 spring.jpa.properties.hibernate.order_inserts=true spring.jpa.properties.hibernate.order_updates=true -spring.jpa.properties.hibernate.generate_statistics=true spring.jpa.database-platform=org.hibernate.dialect.H2Dialect diff --git a/persistence-modules/spring-data-jpa-crud/src/test/java/com/baeldung/batchinserts/BatchInsertIntegrationTest.java b/persistence-modules/spring-data-jpa-crud/src/test/java/com/baeldung/batchinserts/BatchInsertIntegrationTest.java index 7ddf36d3f0..f91c966e94 100644 --- a/persistence-modules/spring-data-jpa-crud/src/test/java/com/baeldung/batchinserts/BatchInsertIntegrationTest.java +++ b/persistence-modules/spring-data-jpa-crud/src/test/java/com/baeldung/batchinserts/BatchInsertIntegrationTest.java @@ -9,6 +9,7 @@ import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.setup.MockMvcBuilders; @@ -20,6 +21,7 @@ import com.baeldung.boot.web.controllers.CustomerController; @RunWith(SpringRunner.class) @SpringBootTest(classes=Application.class) @AutoConfigureMockMvc +@ActiveProfiles("stats") public class BatchInsertIntegrationTest { @Autowired @@ -35,6 +37,6 @@ public class BatchInsertIntegrationTest { public void whenInsertingCustomers_thenCustomersAreCreated() throws Exception { this.mockMvc.perform(post("/customers")) .andExpect(status().isOk()); - } - + } + } \ No newline at end of file diff --git a/persistence-modules/spring-data-jpa-crud/src/test/resources/application-batchinserts.properties b/persistence-modules/spring-data-jpa-crud/src/test/resources/application-batchinserts.properties index 4141f5668e..bc9c9a832c 100644 --- a/persistence-modules/spring-data-jpa-crud/src/test/resources/application-batchinserts.properties +++ b/persistence-modules/spring-data-jpa-crud/src/test/resources/application-batchinserts.properties @@ -3,4 +3,6 @@ spring.jpa.show-sql=false spring.jpa.properties.hibernate.jdbc.batch_size=5 spring.jpa.properties.hibernate.order_inserts=true spring.jpa.properties.hibernate.order_updates=true -spring.jpa.properties.hibernate.batch_versioned_data=true \ No newline at end of file +spring.jpa.properties.hibernate.batch_versioned_data=true + +spring.jpa.properties.hibernate.generate_statistics=true \ No newline at end of file diff --git a/persistence-modules/spring-data-jpa-crud/src/test/resources/application-stats.properties b/persistence-modules/spring-data-jpa-crud/src/test/resources/application-stats.properties new file mode 100644 index 0000000000..97bc170ca0 --- /dev/null +++ b/persistence-modules/spring-data-jpa-crud/src/test/resources/application-stats.properties @@ -0,0 +1,5 @@ +spring.jpa.properties.hibernate.jdbc.batch_size=4 +spring.jpa.properties.hibernate.order_inserts=true +spring.jpa.properties.hibernate.order_updates=true + +spring.jpa.properties.hibernate.generate_statistics=true \ No newline at end of file diff --git a/persistence-modules/spring-data-jpa-repo/src/test/java/com/baeldung/boot/daos/InventoryRepositoryIntegrationTest.java b/persistence-modules/spring-data-jpa-repo/src/test/java/com/baeldung/boot/daos/InventoryRepositoryIntegrationTest.java index 22e2c81739..e4bd3dabff 100644 --- a/persistence-modules/spring-data-jpa-repo/src/test/java/com/baeldung/boot/daos/InventoryRepositoryIntegrationTest.java +++ b/persistence-modules/spring-data-jpa-repo/src/test/java/com/baeldung/boot/daos/InventoryRepositoryIntegrationTest.java @@ -3,20 +3,23 @@ package com.baeldung.boot.daos; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; import java.math.BigDecimal; +import java.util.Optional; 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.junit4.SpringRunner; +import org.springframework.transaction.annotation.Transactional; import com.baeldung.Application; import com.baeldung.boot.domain.MerchandiseEntity; @RunWith(SpringRunner.class) -@SpringBootTest(classes=Application.class) +@SpringBootTest(classes = Application.class) public class InventoryRepositoryIntegrationTest { private static final String ORIGINAL_TITLE = "Pair of Pants"; @@ -58,4 +61,28 @@ public class InventoryRepositoryIntegrationTest { assertEquals(BigDecimal.TEN, result.getPrice()); assertEquals(UPDATED_BRAND, result.getBrand()); } + + @Test + @Transactional + public void shouldUpdateExistingEntryInDBWithoutSave() { + MerchandiseEntity pants = new MerchandiseEntity(ORIGINAL_TITLE, BigDecimal.ONE); + pants = repository.save(pants); + + Long originalId = pants.getId(); + + // Update using setters + pants.setTitle(UPDATED_TITLE); + pants.setPrice(BigDecimal.TEN); + pants.setBrand(UPDATED_BRAND); + + Optional resultOp = repository.findById(originalId); + + assertTrue(resultOp.isPresent()); + MerchandiseEntity result = resultOp.get(); + + assertEquals(originalId, result.getId()); + assertEquals(UPDATED_TITLE, result.getTitle()); + assertEquals(BigDecimal.TEN, result.getPrice()); + assertEquals(UPDATED_BRAND, result.getBrand()); + } } diff --git a/persistence-modules/spring-data-mongodb-reactive/README.md b/persistence-modules/spring-data-mongodb-reactive/README.md index 0931161700..0d80fc8b92 100644 --- a/persistence-modules/spring-data-mongodb-reactive/README.md +++ b/persistence-modules/spring-data-mongodb-reactive/README.md @@ -7,6 +7,4 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring ### Relevant Articles - [Spring Data Reactive Repositories with MongoDB](https://www.baeldung.com/spring-data-mongodb-reactive) -- [Spring Data MongoDB Tailable Cursors](https://www.baeldung.com/spring-data-mongodb-tailable-cursors) -- [A Quick Look at R2DBC with Spring Data](https://www.baeldung.com/spring-data-r2dbc) -- [Spring Data Reactive Repositories with Couchbase](https://www.baeldung.com/spring-data-reactive-couchbase) +- [Spring Data MongoDB Tailable Cursors](https://www.baeldung.com/spring-data-mongodb-tailable-cursors) \ No newline at end of file diff --git a/persistence-modules/spring-data-mongodb-reactive/pom.xml b/persistence-modules/spring-data-mongodb-reactive/pom.xml index 9fb22b6033..eabcc77352 100644 --- a/persistence-modules/spring-data-mongodb-reactive/pom.xml +++ b/persistence-modules/spring-data-mongodb-reactive/pom.xml @@ -147,10 +147,7 @@ 1.4.200 1.5.23 3.3.1.RELEASE - + 2.2.6.RELEASE diff --git a/podman/README.md b/podman/README.md index 3102036f04..24c5aa2653 100644 --- a/podman/README.md +++ b/podman/README.md @@ -1,3 +1,3 @@ ### Relevant Articles: -- [An Introduction to Podman](https://www.baeldung.com/podman-intro) +- [An Introduction to Podman](https://www.baeldung.com/ops/podman-intro) diff --git a/pom.xml b/pom.xml index 059c6dae25..f5ac14a009 100644 --- a/pom.xml +++ b/pom.xml @@ -1356,6 +1356,7 @@ core-java-modules/core-java-time-measurements core-java-modules/multimodulemavenproject core-java-modules/core-java-strings + quarkus-vs-springboot @@ -1410,7 +1411,7 @@ 1.2 2.3.1 1.2 - 2.11.1 + 2.12.4 1.4 1.2.0 5.2.0 diff --git a/quarkus-vs-springboot/README.md b/quarkus-vs-springboot/README.md new file mode 100644 index 0000000000..35fc8eb5eb --- /dev/null +++ b/quarkus-vs-springboot/README.md @@ -0,0 +1,95 @@ +# Spring Boot vs Quarkus + +To follow this tutorial, you will need the following things: +- GRAALVM (https://www.graalvm.org/) +- VisualVM (https://visualvm.github.io/) +- Maven (Embedded, IDE, or local installation) +- Docker (https://www.docker.com/) +- Jmeter (https://jmeter.apache.org/) + +To create this test, I used some custom features from Jmeter. You can install the Jmeter plugin manager here: +https://loadium.com/blog/how-to-install-use-jmeter-plugin. After that, please install the following plugins: +- https://jmeter-plugins.org/?search=jpgc-casutg + +The test file is `load_test.jmx` in case of any change need. You can open it with the Jmeter GUI. For example, to run the start, you can execute the file `run_test.sh` or run the comment bellow: + +``` +$jmeter_home/bin/jmeter -n -t load_test.jmx -l log.csv -e -o ./report +``` + +Just remember to change the variable `jmeter_home` with the path to the JMeter folder. The path to the data files is relative, so either keep them in the same folder as the test or use Jmeter GUI to change it. + +Open the VisualVM application and select your application to start monitoring before running the test, and of course, start the sample application first. + +## Spring Boot +To build the application, you only need to run the following command in the Spring project root: +``` +./mvnw package -f pom.xml +``` +Or this one in case you want to build the native one: +``` +./mvnw -DskipTests package -Pnative -f pom.xml +``` +In this case, you will need to have the `GRAALVM_HOME` env variable defined. You only need this if you want to build the image locally. Otherwise, you can build it using docker by leveraging the Spring Boot maven plugin. It will pull a docker image of the GraalVM, and with that, it will create the native image of the app. To do that, run: +``` +./mvnw spring-boot:build-image +``` +You can also create a docker image with the JVM version of the app running the script `build_jvm_docker.sh` or: +``` +docker build -f src/main/docker/Dockerfile.jvm -t spring-project:0.1-SNAPSHOT . +``` + +You can execute the script `start_app.sh` or `start_jvm.sh` to run the application locally. In this case, you will need the Postgres DB. You can run it in docker with the command: +``` +docker run -e POSTGRES_PASSWORD=example -p 5432:5432 postgres +``` +You can also run both application and DB from docker, using: +``` +docker-compose -f src/main/docker/spring.yml up +``` +But remember to rebuild the image to switch between native and JVM versions. + +## Quarkus +The process to build and run the Quarkus application is very similar to the Spring Boot one. First, to create the native image, you also need either the GRAALVM installed and the `GRAALVM_HOME` env variable set, or we can use docker to build the native image. + +To build the native version locally, run the command: +``` +./mvnw package -Pnative -f pom.xml +``` +Or this one to build using docker: +``` +./mvnw package -Pnative -Dquarkus.native.container-build=true -f pom.xml +``` +And to the JVM version: +``` +./mvnw package -f pom.xml +``` + +To start the application locally, use either the scripts `start_app.sh` and `start_jvm.sh` with the docker DB: +``` +docker run -e POSTGRES_PASSWORD=example -p 5432:5432 postgres +``` +Or use the script to build the docker image of the application, running: +```bash +./build.sh + +## script content +## ./mvnw quarkus:add-extension -Dextensions=container-image-docker +## ./mvnw package -Dquarkus.container-build=true -f pom.xml && +## docker build -f src/main/docker/Dockerfile.jvm -t quarkus-project:0.1-SNAPSHOT . +``` +To build the docker image of the JVM version, and running the following command to the native version: +```bash +./build.sh native + +## script content +## ./mvnw quarkus:add-extension -Dextensions=container-image-docker +## ./mvnw package -Pnative -Dquarkus.native.container-build=true -f pom.xml && +## docker build -f src/main/docker/Dockerfile.native -t quarkus-project:0.1-SNAPSHOT . +``` +Then, once again, you can also run both application and DB from docker, using: +``` +docker-compose -f src/main/docker/quarkus.yml up +``` + +Now you have all you need to reproduce the tests with your machine. \ No newline at end of file diff --git a/quarkus-vs-springboot/cities.csv b/quarkus-vs-springboot/cities.csv new file mode 100644 index 0000000000..3b7016f3b5 --- /dev/null +++ b/quarkus-vs-springboot/cities.csv @@ -0,0 +1,136 @@ +Holtsville +Adjuntas +Aguada +Aguadilla +Maricao +Anasco +Angeles +Arecibo +Bajadero +Barceloneta +Boqueron +Cabo Rojo +Penuelas +Camuy +Castaner +Rosario +Sabana Grande +Ciales +Utuado +Dorado +Ensenada +Florida +Garrochales +Guanica +Guayanilla +Hatillo +Hormigueros +Isabela +Jayuya +Lajas +Lares +Las Marias +Manati +Moca +Rincon +Quebradillas +Mayaguez +San German +San Sebastian +Morovis +Sabana Hoyos +San Antonio +Vega Alta +Vega Baja +Yauco +Aguas Buenas +Aguirre +Aibonito +Maunabo +Arroyo +Mercedita +Ponce +Naguabo +Naranjito +Orocovis +Palmer +Patillas +Caguas +Canovanas +Ceiba +Cayey +Fajardo +Cidra +Puerto Real +Punta Santiago +Roosevelt Roads +Rio Blanco +Rio Grande +Salinas +San Lorenzo +Santa Isabel +Vieques +Villalba +Yabucoa +Coamo +Las Piedras +Loiza +Luquillo +Culebra +Juncos +Gurabo +Coto Laurel +Comerio +Corozal +Guayama +La Plata +Humacao +Barranquitas +Juana Diaz +St Thomas +Christiansted +St John +Frederiksted +Kingshill +San Juan +Fort Buchanan +Toa Baja +Sabana Seca +Toa Alta +Bayamon +Catano +Guaynabo +Trujillo Alto +Saint Just +Carolina +Agawam +Amherst +Barre +Belchertown +Blandford +Bondsville +Brimfield +Chester +Chesterfield +Chicopee +Cummington +Easthampton +East Longmeadow +East Otis +Feeding Hills +Gilbertville +Goshen +Granby +Granville +Hadley +Hampden +Hardwick +Hatfield +Haydenville +Holyoke +Huntington +Leeds +Leverett +Ludlow +Monson +North Amherst \ No newline at end of file diff --git a/quarkus-vs-springboot/load_test.jmx b/quarkus-vs-springboot/load_test.jmx new file mode 100644 index 0000000000..7da984343b --- /dev/null +++ b/quarkus-vs-springboot/load_test.jmx @@ -0,0 +1,384 @@ + + + + + + false + true + false + + + + + + + + continue + + false + -1 + + 500 + 150 + true + 300 + + true + + + + , + + zip_code_database.csv + true + true + false + shareMode.group + true + zip,type,decommissioned,primary_city,acceptable_cities,unacceptable_cities,state,county,timezone,area_codes,world_region,country,latitude,longitude,irs_estimated_population + + + + true + + + + false + { + "zip":"${zip}", + "type":"${type}", + "city":"${primary_city}", + "state":"${state}", + "county":"${country}", + "timezone":"${timezone}" +} + = + + + + localhost + 8080 + + UTF-8 + zipcode + POST + true + false + true + false + + + + + + + + + Content-Type + application/json + + + Accept + */* + + + Cache-Control + no-cache + + + + + + + false + + saveConfig + + + true + true + true + + true + true + true + true + false + true + true + false + false + false + true + false + false + false + true + 0 + true + true + true + true + true + true + + + + + + + + + + 25 + 30 + 15 + 255 + + + + 125 + 30 + 15 + 255 + + + + 125 + 60 + 15 + 225 + + + + 225 + 150 + 30 + 120 + + + + + false + -1 + + continue + + + + , + + zip_code_database.csv + true + true + false + shareMode.group + true + zip,type,decommissioned,primary_city,acceptable_cities,unacceptable_cities,state,county,timezone,area_codes,world_region,country,latitude,longitude,irs_estimated_population + + + + + + + localhost + 8080 + + UTF-8 + zipcode/${zip} + GET + true + false + true + false + + + + + + + + + Content-Type + application/json + + + Accept + */* + + + Cache-Control + no-cache + + + + + + + false + + saveConfig + + + true + true + true + + true + true + true + true + false + true + true + false + false + false + true + false + false + false + true + 0 + true + true + true + true + true + true + + + + + + + + + + 25 + 30 + 15 + 255 + + + + 125 + 30 + 15 + 255 + + + + 125 + 60 + 15 + 225 + + + + 225 + 150 + 30 + 120 + + + + + false + -1 + + continue + + + + , + + cities.csv + false + false + true + shareMode.group + false + city + + + + + + + localhost + 8080 + + UTF-8 + zipcode/by_city?city=${city} + GET + true + false + true + false + + + + + + + + + Content-Type + application/json + + + Accept + */* + + + Cache-Control + no-cache + + + + + + + false + + saveConfig + + + true + true + true + + true + true + true + true + false + true + true + false + false + false + true + false + false + false + true + 0 + true + true + true + true + true + true + + + + + + + + + + + diff --git a/quarkus-vs-springboot/pom.xml b/quarkus-vs-springboot/pom.xml new file mode 100644 index 0000000000..cf1cbb5d85 --- /dev/null +++ b/quarkus-vs-springboot/pom.xml @@ -0,0 +1,22 @@ + + + + parent-modules + com.baeldung + 1.0.0-SNAPSHOT + + + 1.0-SNAPSHOT + quarkus-vs-springboot + quarkus-vs-springboot + pom + 4.0.0 + + + quarkus-project + spring-project + + + \ No newline at end of file diff --git a/quarkus-vs-springboot/quarkus-project/build.sh b/quarkus-vs-springboot/quarkus-project/build.sh new file mode 100755 index 0000000000..85761adab0 --- /dev/null +++ b/quarkus-vs-springboot/quarkus-project/build.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +SCRIPTPATH="$( cd -- "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" + +./mvnw quarkus:add-extension -Dextensions=container-image-docker + +if [ "$1" = "native" ]; then + ./mvnw package -Pnative -Dquarkus.native.container-build=true -f $SCRIPTPATH/pom.xml && + docker build -f $SCRIPTPATH/src/main/docker/Dockerfile.native -t quarkus-project:0.1-SNAPSHOT $SCRIPTPATH/. +else + ./mvnw package -Dquarkus.container-build=true -f $SCRIPTPATH/pom.xml && + docker build -f $SCRIPTPATH/src/main/docker/Dockerfile.jvm -t quarkus-project:0.1-SNAPSHOT $SCRIPTPATH/. +fi \ No newline at end of file diff --git a/quarkus-vs-springboot/quarkus-project/pom.xml b/quarkus-vs-springboot/quarkus-project/pom.xml new file mode 100644 index 0000000000..c9eae79a88 --- /dev/null +++ b/quarkus-vs-springboot/quarkus-project/pom.xml @@ -0,0 +1,149 @@ + + + 4.0.0 + + com.baeldung + quarkus-vs-springboot + 1.0-SNAPSHOT + + quarkus-project + 0.1-SNAPSHOT + + 3.8.1 + true + 11 + 11 + UTF-8 + UTF-8 + quarkus-bom + io.quarkus.platform + 2.2.2.Final + 3.0.0-M4 + + + + + ${quarkus.platform.group-id} + ${quarkus.platform.artifact-id} + ${quarkus.platform.version} + pom + import + + + + + + io.quarkus + quarkus-hibernate-reactive-panache + + + io.quarkus + quarkus-resteasy-reactive + + + io.quarkus + quarkus-resteasy-reactive-jackson + + + io.quarkus + quarkus-reactive-pg-client + + + io.quarkus + quarkus-arc + + + io.quarkus + quarkus-container-image-docker + + + io.quarkus + quarkus-junit5 + test + + + io.rest-assured + rest-assured + test + + + junit + junit + 4.8.2 + test + + + + + + ${quarkus.platform.group-id} + quarkus-maven-plugin + ${quarkus.platform.version} + true + + + + build + generate-code + generate-code-tests + + + + + + maven-compiler-plugin + ${compiler-plugin.version} + + ${maven.compiler.parameters} + + + + maven-surefire-plugin + ${surefire-plugin.version} + + false + + org.jboss.logmanager.LogManager + + + + + + + + native + + + native + + + + + + maven-failsafe-plugin + ${surefire-plugin.version} + + + + integration-test + verify + + + + ${project.build.directory}/${project.build.finalName}-runner + org.jboss.logmanager.LogManager + + + + + + + + + -H:+AllowVMInspection + native + + + + diff --git a/quarkus-vs-springboot/quarkus-project/src/main/docker/Dockerfile.jvm b/quarkus-vs-springboot/quarkus-project/src/main/docker/Dockerfile.jvm new file mode 100644 index 0000000000..e5d6d4d851 --- /dev/null +++ b/quarkus-vs-springboot/quarkus-project/src/main/docker/Dockerfile.jvm @@ -0,0 +1,55 @@ +#### +# This Dockerfile is used in order to build a container that runs the Quarkus application in JVM mode +# +# Before building the container image run: +# +# ./mvnw package +# +# Then, build the image with: +# +# docker build -f src/main/docker/Dockerfile.jvm -t quarkus/code-with-quarkus-jvm . +# +# Then run the container using: +# +# docker run -i --rm -p 8080:8080 quarkus/code-with-quarkus-jvm +# +# If you want to include the debug port into your docker image +# you will have to expose the debug port (default 5005) like this : EXPOSE 8080 5005 +# +# Then run the container using : +# +# docker run -i --rm -p 8080:8080 -p 5005:5005 -e JAVA_ENABLE_DEBUG="true" quarkus/code-with-quarkus-jvm +# +### +FROM registry.access.redhat.com/ubi8/ubi-minimal:8.4 + +ARG JAVA_PACKAGE=java-11-openjdk-headless +ARG RUN_JAVA_VERSION=1.3.8 +ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en' +# Install java and the run-java script +# Also set up permissions for user `1001` +RUN microdnf install curl ca-certificates ${JAVA_PACKAGE} \ + && microdnf update \ + && microdnf clean all \ + && mkdir /deployments \ + && chown 1001 /deployments \ + && chmod "g+rwX" /deployments \ + && chown 1001:root /deployments \ + && curl https://repo1.maven.org/maven2/io/fabric8/run-java-sh/${RUN_JAVA_VERSION}/run-java-sh-${RUN_JAVA_VERSION}-sh.sh -o /deployments/run-java.sh \ + && chown 1001 /deployments/run-java.sh \ + && chmod 540 /deployments/run-java.sh \ + && echo "securerandom.source=file:/dev/urandom" >> /etc/alternatives/jre/conf/security/java.security + +# Configure the JAVA_OPTIONS, you can add -XshowSettings:vm to also display the heap size. +ENV JAVA_OPTIONS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager" +# We make four distinct layers so if there are application changes the library layers can be re-used +COPY --chown=1001 target/quarkus-app/lib/ /deployments/lib/ +COPY --chown=1001 target/quarkus-app/*.jar /deployments/ +COPY --chown=1001 target/quarkus-app/app/ /deployments/app/ +COPY --chown=1001 target/quarkus-app/quarkus/ /deployments/quarkus/ + +EXPOSE 8080 +USER 1001 + +ENTRYPOINT [ "/deployments/run-java.sh" ] + diff --git a/quarkus-vs-springboot/quarkus-project/src/main/docker/Dockerfile.legacy-jar b/quarkus-vs-springboot/quarkus-project/src/main/docker/Dockerfile.legacy-jar new file mode 100644 index 0000000000..da0fe018f6 --- /dev/null +++ b/quarkus-vs-springboot/quarkus-project/src/main/docker/Dockerfile.legacy-jar @@ -0,0 +1,51 @@ +#### +# This Dockerfile is used in order to build a container that runs the Quarkus application in JVM mode +# +# Before building the container image run: +# +# ./mvnw package -Dquarkus.package.type=legacy-jar +# +# Then, build the image with: +# +# docker build -f src/main/docker/Dockerfile.legacy-jar -t quarkus/code-with-quarkus-legacy-jar . +# +# Then run the container using: +# +# docker run -i --rm -p 8080:8080 quarkus/code-with-quarkus-legacy-jar +# +# If you want to include the debug port into your docker image +# you will have to expose the debug port (default 5005) like this : EXPOSE 8080 5005 +# +# Then run the container using : +# +# docker run -i --rm -p 8080:8080 -p 5005:5005 -e JAVA_ENABLE_DEBUG="true" quarkus/code-with-quarkus-legacy-jar +# +### +FROM registry.access.redhat.com/ubi8/ubi-minimal:8.4 + +ARG JAVA_PACKAGE=java-11-openjdk-headless +ARG RUN_JAVA_VERSION=1.3.8 +ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en' +# Install java and the run-java script +# Also set up permissions for user `1001` +RUN microdnf install curl ca-certificates ${JAVA_PACKAGE} \ + && microdnf update \ + && microdnf clean all \ + && mkdir /deployments \ + && chown 1001 /deployments \ + && chmod "g+rwX" /deployments \ + && chown 1001:root /deployments \ + && curl https://repo1.maven.org/maven2/io/fabric8/run-java-sh/${RUN_JAVA_VERSION}/run-java-sh-${RUN_JAVA_VERSION}-sh.sh -o /deployments/run-java.sh \ + && chown 1001 /deployments/run-java.sh \ + && chmod 540 /deployments/run-java.sh \ + && echo "securerandom.source=file:/dev/urandom" >> /etc/alternatives/jre/conf/security/java.security + +# Configure the JAVA_OPTIONS, you can add -XshowSettings:vm to also display the heap size. +ENV JAVA_OPTIONS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager" +COPY target/lib/* /deployments/lib/ +COPY target/*-runner.jar /deployments/app.jar + +EXPOSE 8080 +USER 1001 + +ENTRYPOINT [ "/deployments/run-java.sh" ] diff --git a/quarkus-vs-springboot/quarkus-project/src/main/docker/Dockerfile.native b/quarkus-vs-springboot/quarkus-project/src/main/docker/Dockerfile.native new file mode 100644 index 0000000000..33698500f6 --- /dev/null +++ b/quarkus-vs-springboot/quarkus-project/src/main/docker/Dockerfile.native @@ -0,0 +1,27 @@ +#### +# This Dockerfile is used in order to build a container that runs the Quarkus application in native (no JVM) mode +# +# Before building the container image run: +# +# ./mvnw package -Pnative +# +# Then, build the image with: +# +# docker build -f src/main/docker/Dockerfile.native -t quarkus/code-with-quarkus . +# +# Then run the container using: +# +# docker run -i --rm -p 8080:8080 quarkus/code-with-quarkus +# +### +FROM registry.access.redhat.com/ubi8/ubi-minimal:8.4 +WORKDIR /work/ +RUN chown 1001 /work \ + && chmod "g+rwX" /work \ + && chown 1001:root /work +COPY --chown=1001:root target/*-runner /work/application + +EXPOSE 8080 +USER 1001 + +CMD ["./application", "-Dquarkus.http.host=0.0.0.0"] diff --git a/quarkus-vs-springboot/quarkus-project/src/main/docker/Dockerfile.native-distroless b/quarkus-vs-springboot/quarkus-project/src/main/docker/Dockerfile.native-distroless new file mode 100644 index 0000000000..5fda989696 --- /dev/null +++ b/quarkus-vs-springboot/quarkus-project/src/main/docker/Dockerfile.native-distroless @@ -0,0 +1,23 @@ +#### +# This Dockerfile is used in order to build a distroless container that runs the Quarkus application in native (no JVM) mode +# +# Before building the container image run: +# +# ./mvnw package -Pnative +# +# Then, build the image with: +# +# docker build -f src/main/docker/Dockerfile.native-distroless -t quarkus/code-with-quarkus . +# +# Then run the container using: +# +# docker run -i --rm -p 8080:8080 quarkus/code-with-quarkus +# +### +FROM quay.io/quarkus/quarkus-distroless-image:1.0 +COPY target/*-runner /application + +EXPOSE 8080 +USER nonroot + +CMD ["./application", "-Dquarkus.http.host=0.0.0.0"] diff --git a/quarkus-vs-springboot/quarkus-project/src/main/docker/quarkus.yml b/quarkus-vs-springboot/quarkus-project/src/main/docker/quarkus.yml new file mode 100644 index 0000000000..00bdcf9292 --- /dev/null +++ b/quarkus-vs-springboot/quarkus-project/src/main/docker/quarkus.yml @@ -0,0 +1,23 @@ +version: '3.1' + +services: + db: + image: postgres + ports: + - '5432:5432' + environment: + POSTGRES_PASSWORD: example + app: + image: quarkus-project:0.1-SNAPSHOT + ports: + - '8080:8080' + environment: + DB_URL: postgresql://db:5432/postgres + links: + - "db" + depends_on: + - "db" +networks: + default: + driver: bridge + diff --git a/quarkus-vs-springboot/quarkus-project/src/main/java/com/baeldung/quarkus_project/ReactiveGreetingResource.java b/quarkus-vs-springboot/quarkus-project/src/main/java/com/baeldung/quarkus_project/ReactiveGreetingResource.java new file mode 100644 index 0000000000..b885e828c7 --- /dev/null +++ b/quarkus-vs-springboot/quarkus-project/src/main/java/com/baeldung/quarkus_project/ReactiveGreetingResource.java @@ -0,0 +1,17 @@ +package com.baeldung.quarkus_project; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; + +@Path("/hello") +public class ReactiveGreetingResource { + + @GET + @Produces(MediaType.TEXT_PLAIN) + public String hello() { + return "Hello RESTEasy Reactive"; + } + +} \ No newline at end of file diff --git a/quarkus-vs-springboot/quarkus-project/src/main/java/com/baeldung/quarkus_project/ZipCode.java b/quarkus-vs-springboot/quarkus-project/src/main/java/com/baeldung/quarkus_project/ZipCode.java new file mode 100644 index 0000000000..6764c510bf --- /dev/null +++ b/quarkus-vs-springboot/quarkus-project/src/main/java/com/baeldung/quarkus_project/ZipCode.java @@ -0,0 +1,68 @@ +package com.baeldung.quarkus_project; + +import io.quarkus.hibernate.reactive.panache.PanacheEntityBase; +import io.quarkus.runtime.annotations.RegisterForReflection; + +import javax.persistence.Entity; +import javax.persistence.Id; + +@Entity +@RegisterForReflection +public class ZipCode extends PanacheEntityBase { + + @Id + private String zip; + private String type; + private String city; + private String state; + private String county; + private String timezone; + + public String getZip() { + return zip; + } + + public void setZip(String zip) { + this.zip = zip; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getCity() { + return city; + } + + public void setCity(String city) { + this.city = city; + } + + public String getState() { + return state; + } + + public void setState(String state) { + this.state = state; + } + + public String getCounty() { + return county; + } + + public void setCounty(String county) { + this.county = county; + } + + public String getTimezone() { + return timezone; + } + + public void setTimezone(String timezone) { + this.timezone = timezone; + } +} diff --git a/quarkus-vs-springboot/quarkus-project/src/main/java/com/baeldung/quarkus_project/ZipCodeRepo.java b/quarkus-vs-springboot/quarkus-project/src/main/java/com/baeldung/quarkus_project/ZipCodeRepo.java new file mode 100644 index 0000000000..74f46c33ea --- /dev/null +++ b/quarkus-vs-springboot/quarkus-project/src/main/java/com/baeldung/quarkus_project/ZipCodeRepo.java @@ -0,0 +1,19 @@ +package com.baeldung.quarkus_project; + +import io.quarkus.hibernate.reactive.panache.PanacheRepositoryBase; +import io.smallrye.mutiny.Multi; +import io.smallrye.mutiny.Uni; + +import javax.enterprise.context.ApplicationScoped; + +@ApplicationScoped +public class ZipCodeRepo implements PanacheRepositoryBase { + + public Multi findByCity(String city) { + return find("city = ?1", city).stream(); + } + + public Uni save(ZipCode zipCode) { + return zipCode.persistAndFlush(); + } +} diff --git a/quarkus-vs-springboot/quarkus-project/src/main/java/com/baeldung/quarkus_project/ZipCodeResource.java b/quarkus-vs-springboot/quarkus-project/src/main/java/com/baeldung/quarkus_project/ZipCodeResource.java new file mode 100644 index 0000000000..b4d41fd855 --- /dev/null +++ b/quarkus-vs-springboot/quarkus-project/src/main/java/com/baeldung/quarkus_project/ZipCodeResource.java @@ -0,0 +1,46 @@ +package com.baeldung.quarkus_project; + +import io.smallrye.mutiny.Multi; +import io.smallrye.mutiny.Uni; +import org.jboss.logging.Logger; + +import javax.transaction.Transactional; +import javax.ws.rs.*; +import javax.ws.rs.core.MediaType; + +@Path("/zipcode") +@Produces(MediaType.APPLICATION_JSON) +@Consumes(MediaType.APPLICATION_JSON) +public class ZipCodeResource { + + private ZipCodeRepo zipRepo; + + public ZipCodeResource(ZipCodeRepo zipRepo) { + this.zipRepo = zipRepo; + } + + @GET + @Path("/{zipcode}") + public Uni findById(@PathParam("zipcode") String zipcode) { + return zipRepo.findById(zipcode); + } + + @GET + @Path("/by_city") + public Multi postZipCode(@QueryParam("city") String city) { + return zipRepo.findByCity(city); + } + + @POST + @Transactional + public Uni create(ZipCode zipCode) { + return zipRepo.findById(zipCode.getZip()) + .onItem() + .ifNull() + .switchTo(createZipCode(zipCode)); + } + + private Uni createZipCode(ZipCode zipCode) { + return Uni.createFrom().deferred(() -> zipRepo.save(zipCode)); + } +} \ No newline at end of file diff --git a/quarkus-vs-springboot/quarkus-project/src/main/resources/application.properties b/quarkus-vs-springboot/quarkus-project/src/main/resources/application.properties new file mode 100644 index 0000000000..918a129500 --- /dev/null +++ b/quarkus-vs-springboot/quarkus-project/src/main/resources/application.properties @@ -0,0 +1,9 @@ +quarkus.datasource.db-kind=postgresql +quarkus.datasource.username=postgres +quarkus.datasource.password=example + +quarkus.datasource.reactive.url=${DB_URL:postgresql://localhost:5432/postgres} +quarkus.datasource.reactive.max-size=20 + +#quarkus.hibernate-orm.log.sql=true +quarkus.hibernate-orm.database.generation=drop-and-create diff --git a/quarkus-vs-springboot/quarkus-project/src/test/java/com/baeldung/quarkus_project/NativeGreetingResourceIT.java b/quarkus-vs-springboot/quarkus-project/src/test/java/com/baeldung/quarkus_project/NativeGreetingResourceIT.java new file mode 100644 index 0000000000..99b91ea5a8 --- /dev/null +++ b/quarkus-vs-springboot/quarkus-project/src/test/java/com/baeldung/quarkus_project/NativeGreetingResourceIT.java @@ -0,0 +1,21 @@ +package com.baeldung.quarkus_project; + +import io.quarkus.test.junit.NativeImageTest; +import io.quarkus.test.junit.QuarkusTest; +import org.junit.jupiter.api.Test; + +import static io.restassured.RestAssured.given; + +@NativeImageTest +@QuarkusTest +public class NativeGreetingResourceIT { + + @Test + void testEndpoint() { + given() + .when().get("/hello") + .then() + .statusCode(200); + } + +} \ No newline at end of file diff --git a/quarkus-vs-springboot/quarkus-project/start_app.sh b/quarkus-vs-springboot/quarkus-project/start_app.sh new file mode 100755 index 0000000000..ddffe29736 --- /dev/null +++ b/quarkus-vs-springboot/quarkus-project/start_app.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +SCRIPTPATH="$( cd -- "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" + +$SCRIPTPATH/target/quarkus-project-0.1-SNAPSHOT-runner -XX:+FlightRecorder -XX:StartFlightRecording="filename=$SCRIPTPATH/recording.jfr,name=Profiling quarkus" \ No newline at end of file diff --git a/quarkus-vs-springboot/quarkus-project/start_jvm.sh b/quarkus-vs-springboot/quarkus-project/start_jvm.sh new file mode 100755 index 0000000000..e7a7039154 --- /dev/null +++ b/quarkus-vs-springboot/quarkus-project/start_jvm.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +SCRIPTPATH="$( cd -- "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" + +java -jar $SCRIPTPATH/target/quarkus-app/quarkus-run.jar \ No newline at end of file diff --git a/quarkus-vs-springboot/run_test.sh b/quarkus-vs-springboot/run_test.sh new file mode 100755 index 0000000000..a2d31c8587 --- /dev/null +++ b/quarkus-vs-springboot/run_test.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +$Jmeter_home/bin/jmeter -n -t load_test.jmx -l log.csv -e -o ./report \ No newline at end of file diff --git a/quarkus-vs-springboot/spring-project/build_jvm_docker.sh b/quarkus-vs-springboot/spring-project/build_jvm_docker.sh new file mode 100755 index 0000000000..c7ee730ec7 --- /dev/null +++ b/quarkus-vs-springboot/spring-project/build_jvm_docker.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +SCRIPTPATH="$( cd -- "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" + +docker build -f $SCRIPTPATH/src/main/docker/Dockerfile.jvm -t spring-project:0.1-SNAPSHOT $SCRIPTPATH/. + diff --git a/quarkus-vs-springboot/spring-project/pom.xml b/quarkus-vs-springboot/spring-project/pom.xml new file mode 100644 index 0000000000..be5cc57765 --- /dev/null +++ b/quarkus-vs-springboot/spring-project/pom.xml @@ -0,0 +1,171 @@ + + + + + org.springframework.boot + spring-boot-starter-parent + 2.5.4 + + + + 4.0.0 + spring-project + com.baeldung + 0.1-SNAPSHOT + + + 11 + + 0.10.3 + + + + + org.springframework.boot + spring-boot-starter-data-r2dbc + + + org.springframework.boot + spring-boot-starter-webflux + + + org.springframework.experimental + spring-native + ${spring-native.version} + + + io.r2dbc + r2dbc-postgresql + runtime + + + org.postgresql + postgresql + runtime + + + org.springframework.boot + spring-boot-starter-test + test + + + io.projectreactor + reactor-test + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + ${repackage.classifier} + + paketobuildpacks/builder:tiny + + true + + + + + + org.springframework.experimental + spring-aot-maven-plugin + ${spring-native.version} + + + test-generate + + test-generate + + + + generate + + generate + + + + + + + + + + spring-releases + Spring Releases + https://repo.spring.io/release + + false + + + + + + spring-releases + Spring Releases + https://repo.spring.io/release + + false + + + + + + + native + + exec + 0.9.3 + + + + org.graalvm.buildtools + junit-platform-native + ${native-buildtools.version} + + + + + + org.graalvm.buildtools + native-maven-plugin + ${native-buildtools.version} + + + -H:+AllowVMInspection + + + + + test-native + test + + test + + + + build-native + package + + build + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + -DspringAot=true -agentlib:native-image-agent=access-filter-file=src/test/resources/access-filter.json,config-merge-dir=target/classes/META-INF/native-image + + + + + + + \ No newline at end of file diff --git a/quarkus-vs-springboot/spring-project/src/main/docker/Dockerfile.jvm b/quarkus-vs-springboot/spring-project/src/main/docker/Dockerfile.jvm new file mode 100644 index 0000000000..ca3f3cca76 --- /dev/null +++ b/quarkus-vs-springboot/spring-project/src/main/docker/Dockerfile.jvm @@ -0,0 +1,12 @@ +FROM openjdk:11 + +ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en' + +COPY --chown=1001 target/spring-project-0.1-SNAPSHOT-exec.jar /spring-app/ + +WORKDIR /spring-app + +EXPOSE 8080 +USER 1001 + +ENTRYPOINT ["java", "-jar", "spring-project-0.1-SNAPSHOT-exec.jar" ] \ No newline at end of file diff --git a/quarkus-vs-springboot/spring-project/src/main/docker/spring.yml b/quarkus-vs-springboot/spring-project/src/main/docker/spring.yml new file mode 100644 index 0000000000..2214e0a898 --- /dev/null +++ b/quarkus-vs-springboot/spring-project/src/main/docker/spring.yml @@ -0,0 +1,22 @@ +version: '3.1' + +services: + db: + image: postgres + ports: + - '5432:5432' + environment: + POSTGRES_PASSWORD: example + app: + image: spring-project:0.1-SNAPSHOT + ports: + - '8080:8080' + environment: + DB_URL: r2dbc:postgresql://db:5432/postgres + links: + - "db" + depends_on: + - "db" +networks: + default: + driver: bridge \ No newline at end of file diff --git a/quarkus-vs-springboot/spring-project/src/main/java/com/baeldung/spring_project/Startup.java b/quarkus-vs-springboot/spring-project/src/main/java/com/baeldung/spring_project/Startup.java new file mode 100644 index 0000000000..48cf7e8ed1 --- /dev/null +++ b/quarkus-vs-springboot/spring-project/src/main/java/com/baeldung/spring_project/Startup.java @@ -0,0 +1,37 @@ +package com.baeldung.spring_project; + +import com.baeldung.spring_project.domain.ZIPRepo; +import io.r2dbc.spi.ConnectionFactory; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; +import org.springframework.core.io.ByteArrayResource; +import org.springframework.r2dbc.connection.R2dbcTransactionManager; +import org.springframework.r2dbc.connection.init.ConnectionFactoryInitializer; +import org.springframework.r2dbc.connection.init.ResourceDatabasePopulator; +import org.springframework.transaction.ReactiveTransactionManager; + +@SpringBootApplication +public class Startup { + + public static void main(String[] args) { + SpringApplication.run(Startup.class, args).getBean(ZIPRepo.class).findById(""); + } + + @Bean + ConnectionFactoryInitializer initializer(ConnectionFactory connectionFactory) { + + var initializer = new ConnectionFactoryInitializer(); + initializer.setConnectionFactory(connectionFactory); + initializer.setDatabasePopulator(new ResourceDatabasePopulator(new ByteArrayResource(("" + + "DROP TABLE IF EXISTS zipcode;" + + "CREATE TABLE zipcode (zip VARCHAR(100) PRIMARY KEY, type VARCHAR(255) NULL, city VARCHAR(255) NULL, state VARCHAR(255) NULL, county VARCHAR(255) NULL, timezone VARCHAR(255) NULL);") + .getBytes()))); + + return initializer; + } + + @Bean ReactiveTransactionManager transactionManager(ConnectionFactory connectionFactory) { + return new R2dbcTransactionManager(connectionFactory); + } +} diff --git a/quarkus-vs-springboot/spring-project/src/main/java/com/baeldung/spring_project/ZipCodeApi.java b/quarkus-vs-springboot/spring-project/src/main/java/com/baeldung/spring_project/ZipCodeApi.java new file mode 100644 index 0000000000..263ce67e21 --- /dev/null +++ b/quarkus-vs-springboot/spring-project/src/main/java/com/baeldung/spring_project/ZipCodeApi.java @@ -0,0 +1,44 @@ +package com.baeldung.spring_project; + +import com.baeldung.spring_project.domain.ZIPRepo; +import com.baeldung.spring_project.domain.ZipCode; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.bind.annotation.*; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.util.function.Supplier; + +@RestController +@RequestMapping(value = "/zipcode") +public class ZipCodeApi { + + private ZIPRepo zipRepo; + + public ZipCodeApi(ZIPRepo zipRepo) { + this.zipRepo = zipRepo; + } + + @GetMapping("/{zipcode}") + public Mono findById(@PathVariable String zipcode) { + return zipRepo.findById(zipcode); + } + + @GetMapping("/by_city") + public Flux postZipCode(@RequestParam String city) { + return zipRepo.findByCity(city); + } + + @Transactional + @PostMapping + public Mono create(@RequestBody ZipCode zipCode) { + return zipRepo.findById(zipCode.getZip()).switchIfEmpty(Mono.defer(createZipCode(zipCode))); + } + + private Supplier> createZipCode(ZipCode zipCode) { + return () -> { + zipCode.setId(zipCode.getZip()); + return zipRepo.save(zipCode); + }; + } +} diff --git a/quarkus-vs-springboot/spring-project/src/main/java/com/baeldung/spring_project/domain/ZIPRepo.java b/quarkus-vs-springboot/spring-project/src/main/java/com/baeldung/spring_project/domain/ZIPRepo.java new file mode 100644 index 0000000000..59d3fb4293 --- /dev/null +++ b/quarkus-vs-springboot/spring-project/src/main/java/com/baeldung/spring_project/domain/ZIPRepo.java @@ -0,0 +1,11 @@ +package com.baeldung.spring_project.domain; + +import org.springframework.data.r2dbc.repository.Query; +import org.springframework.data.repository.reactive.ReactiveCrudRepository; +import reactor.core.publisher.Flux; + +public interface ZIPRepo extends ReactiveCrudRepository { + + @Query("SELECT * FROM zipcode WHERE city = :city") + Flux findByCity(String city); +} diff --git a/quarkus-vs-springboot/spring-project/src/main/java/com/baeldung/spring_project/domain/ZipCode.java b/quarkus-vs-springboot/spring-project/src/main/java/com/baeldung/spring_project/domain/ZipCode.java new file mode 100644 index 0000000000..b2ef7b17a8 --- /dev/null +++ b/quarkus-vs-springboot/spring-project/src/main/java/com/baeldung/spring_project/domain/ZipCode.java @@ -0,0 +1,86 @@ +package com.baeldung.spring_project.domain; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import org.springframework.data.annotation.Id; +import org.springframework.data.annotation.Transient; +import org.springframework.data.domain.Persistable; +import org.springframework.data.relational.core.mapping.Table; + +@Table(value = "zipcode") +public class ZipCode implements Persistable { + + @Id + private String zip; + private String type; + private String city; + private String state; + private String county; + private String timezone; + + @Transient + private boolean persisted; + + public String getZip() { + return zip; + } + + void setZip(String zip) { + this.zip = zip; + this.persisted = true; + } + + public void setId(String zip) { + this.zip = zip; + this.persisted = false; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getCity() { + return city; + } + + public void setCity(String city) { + this.city = city; + } + + public String getState() { + return state; + } + + public void setState(String state) { + this.state = state; + } + + public String getCounty() { + return county; + } + + public void setCounty(String county) { + this.county = county; + } + + public String getTimezone() { + return timezone; + } + + public void setTimezone(String timezone) { + this.timezone = timezone; + } + + @JsonIgnore + @Override public String getId() { + return zip; + } + + @JsonIgnore + @Override public boolean isNew() { + return !persisted; + } +} diff --git a/quarkus-vs-springboot/spring-project/src/main/resources/application.properties b/quarkus-vs-springboot/spring-project/src/main/resources/application.properties new file mode 100644 index 0000000000..adc2f8b0b4 --- /dev/null +++ b/quarkus-vs-springboot/spring-project/src/main/resources/application.properties @@ -0,0 +1,5 @@ +spring.r2dbc.url=${DB_URL:'r2dbc:postgresql://localhost:5432/postgres'} +spring.r2dbc.username=postgres +spring.r2dbc.password=example +spring.r2dbc.pool.enabled=true +spring.r2dbc.pool.maxSize=20 \ No newline at end of file diff --git a/quarkus-vs-springboot/spring-project/src/test/java/com/baeldung/spring_project/StartupIT.java b/quarkus-vs-springboot/spring-project/src/test/java/com/baeldung/spring_project/StartupIT.java new file mode 100644 index 0000000000..7487e5aa7f --- /dev/null +++ b/quarkus-vs-springboot/spring-project/src/test/java/com/baeldung/spring_project/StartupIT.java @@ -0,0 +1,13 @@ +package com.baeldung.spring_project; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class StartupIT { + + @Test + void contextLoads() { + } + +} diff --git a/quarkus-vs-springboot/spring-project/src/test/resources/access-filter.json b/quarkus-vs-springboot/spring-project/src/test/resources/access-filter.json new file mode 100644 index 0000000000..9718fed1c6 --- /dev/null +++ b/quarkus-vs-springboot/spring-project/src/test/resources/access-filter.json @@ -0,0 +1,11 @@ +{ "rules": [ + {"excludeClasses": "org.apache.maven.surefire.**"}, + {"excludeClasses": "net.bytebuddy.**"}, + {"excludeClasses": "org.apiguardian.**"}, + {"excludeClasses": "org.junit.**"}, + {"excludeClasses": "org.mockito.**"}, + {"excludeClasses": "org.springframework.test.**"}, + {"excludeClasses": "org.springframework.boot.test.**"}, + {"excludeClasses": "com.example.demo.test.**"} +] +} \ No newline at end of file diff --git a/quarkus-vs-springboot/spring-project/start_app.sh b/quarkus-vs-springboot/spring-project/start_app.sh new file mode 100755 index 0000000000..f596213c4c --- /dev/null +++ b/quarkus-vs-springboot/spring-project/start_app.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +SCRIPTPATH="$( cd -- "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" + +$SCRIPTPATH/target/spring-project -XX:+FlightRecorder -XX:StartFlightRecording="filename=$SCRIPTPATH/recording.jfr,name=Profiling spring" + diff --git a/quarkus-vs-springboot/spring-project/start_jvm.sh b/quarkus-vs-springboot/spring-project/start_jvm.sh new file mode 100755 index 0000000000..f62762fcca --- /dev/null +++ b/quarkus-vs-springboot/spring-project/start_jvm.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +SCRIPTPATH="$( cd -- "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" + +java -jar $SCRIPTPATH/target/spring-project-0.1-SNAPSHOT-exec.jar + diff --git a/reactor-core/README.md b/reactor-core/README.md index f7c36f5897..a4ced49096 100644 --- a/reactor-core/README.md +++ b/reactor-core/README.md @@ -11,3 +11,4 @@ This module contains articles about Reactor Core. - [How to Convert Mono> Into Flux](https://www.baeldung.com/java-mono-list-to-flux) - [Project Reactor: map() vs flatMap()](https://www.baeldung.com/java-reactor-map-flatmap) - [What Does Mono.defer() Do?](https://www.baeldung.com/java-mono-defer) +- [Handling Exceptions in Project Reactor](https://www.baeldung.com/reactor-exceptions) diff --git a/reactor-core/pom.xml b/reactor-core/pom.xml index c13dda63d5..420b1b028a 100644 --- a/reactor-core/pom.xml +++ b/reactor-core/pom.xml @@ -45,4 +45,4 @@ 3.6.1 - + \ No newline at end of file diff --git a/restx/pom.xml b/restx/pom.xml index ee25c88047..83dd2afd58 100644 --- a/restx/pom.xml +++ b/restx/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 restx 0.1-SNAPSHOT @@ -99,7 +99,7 @@ ch.qos.logback logback-classic - ${logback-classic.version} + ${logback.version} io.restx @@ -123,10 +123,8 @@ attach-docs - + prepare-package jar @@ -149,7 +147,6 @@ 0.35-rc4 - 1.2.3 - + \ No newline at end of file diff --git a/spf4j/spf4j-aspects-app/pom.xml b/spf4j/spf4j-aspects-app/pom.xml index a44ee805fb..c4940b9c97 100644 --- a/spf4j/spf4j-aspects-app/pom.xml +++ b/spf4j/spf4j-aspects-app/pom.xml @@ -99,7 +99,6 @@ 8.9.0 - 1.7.21 3.8.0 3.1.1 diff --git a/spf4j/spf4j-core-app/pom.xml b/spf4j/spf4j-core-app/pom.xml index 1f9be97854..28c104afe1 100644 --- a/spf4j/spf4j-core-app/pom.xml +++ b/spf4j/spf4j-core-app/pom.xml @@ -105,7 +105,6 @@ 8.9.0 - 1.7.21 3.8.0 3.1.1 diff --git a/spring-5-data-reactive/README.md b/spring-5-data-reactive/README.md index 0931161700..ecb6d01267 100644 --- a/spring-5-data-reactive/README.md +++ b/spring-5-data-reactive/README.md @@ -6,7 +6,5 @@ This module contains articles about reactive Spring 5 Data The "REST With Spring" Classes: http://bit.ly/restwithspring ### Relevant Articles -- [Spring Data Reactive Repositories with MongoDB](https://www.baeldung.com/spring-data-mongodb-reactive) -- [Spring Data MongoDB Tailable Cursors](https://www.baeldung.com/spring-data-mongodb-tailable-cursors) - [A Quick Look at R2DBC with Spring Data](https://www.baeldung.com/spring-data-r2dbc) - [Spring Data Reactive Repositories with Couchbase](https://www.baeldung.com/spring-data-reactive-couchbase) diff --git a/spring-5-data-reactive/pom.xml b/spring-5-data-reactive/pom.xml index dffd4be99b..3a9651de39 100644 --- a/spring-5-data-reactive/pom.xml +++ b/spring-5-data-reactive/pom.xml @@ -138,10 +138,7 @@ 1.4.200 1.5.23 3.3.1.RELEASE - + 2.2.6.RELEASE diff --git a/spring-5-data-reactive/src/test/java/com/baeldung/SpringContextTest.java b/spring-5-data-reactive/src/test/java/com/baeldung/SpringContextTest.java new file mode 100644 index 0000000000..dc7bcd1e37 --- /dev/null +++ b/spring-5-data-reactive/src/test/java/com/baeldung/SpringContextTest.java @@ -0,0 +1,17 @@ +package com.baeldung; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +import com.baeldung.r2dbc.R2dbcApplication; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = R2dbcApplication.class) +public class SpringContextTest { + + @Test + public void whenSpringContextIsBootstrapped_thenNoExceptions() { + } +} diff --git a/spring-5-reactive-client/README.md b/spring-5-reactive-client/README.md index 154a3cab0b..e485897d27 100644 --- a/spring-5-reactive-client/README.md +++ b/spring-5-reactive-client/README.md @@ -11,3 +11,4 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring - [Mocking a WebClient in Spring](https://www.baeldung.com/spring-mocking-webclient) - [Spring WebClient Filters](https://www.baeldung.com/spring-webclient-filters) - [Get List of JSON Objects with WebClient](https://www.baeldung.com/spring-webclient-json-list) +- [Upload a File with WebClient](https://www.baeldung.com/spring-webclient-upload-file) diff --git a/spring-5-reactive-client/src/main/java/com/baeldung/reactive/controller/UploadController.java b/spring-5-reactive-client/src/main/java/com/baeldung/reactive/controller/UploadController.java new file mode 100644 index 0000000000..08d6ff55ef --- /dev/null +++ b/spring-5-reactive-client/src/main/java/com/baeldung/reactive/controller/UploadController.java @@ -0,0 +1,30 @@ +package com.baeldung.reactive.controller; + + +import com.baeldung.reactive.service.ReactiveUploadService; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; +import reactor.core.publisher.Mono; + + +@RestController +public class UploadController { + final ReactiveUploadService uploadService; + + public UploadController(ReactiveUploadService uploadService) { + this.uploadService = uploadService; + } + + @PostMapping(path = "/upload") + @ResponseBody + public Mono uploadPdf(@RequestParam("file") final MultipartFile multipartFile) { + return uploadService.uploadPdf(multipartFile.getResource()); + } + + @PostMapping(path = "/upload/multipart") + @ResponseBody + public Mono uploadMultipart(@RequestParam("file") final MultipartFile multipartFile) { + return uploadService.uploadMultipart(multipartFile); + } +} diff --git a/spring-5-reactive-client/src/main/java/com/baeldung/reactive/exception/ServiceException.java b/spring-5-reactive-client/src/main/java/com/baeldung/reactive/exception/ServiceException.java new file mode 100644 index 0000000000..cd639ec1f9 --- /dev/null +++ b/spring-5-reactive-client/src/main/java/com/baeldung/reactive/exception/ServiceException.java @@ -0,0 +1,8 @@ +package com.baeldung.reactive.exception; + +public class ServiceException extends RuntimeException{ + + public ServiceException(String message) { + super(message); + } +} diff --git a/spring-5-reactive-client/src/main/java/com/baeldung/reactive/service/ReactiveUploadService.java b/spring-5-reactive-client/src/main/java/com/baeldung/reactive/service/ReactiveUploadService.java new file mode 100644 index 0000000000..a12d54960a --- /dev/null +++ b/spring-5-reactive-client/src/main/java/com/baeldung/reactive/service/ReactiveUploadService.java @@ -0,0 +1,66 @@ +package com.baeldung.reactive.service; + + +import com.baeldung.reactive.exception.ServiceException; +import org.springframework.core.io.Resource; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.client.MultipartBodyBuilder; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; +import org.springframework.web.reactive.function.BodyInserters; +import org.springframework.web.reactive.function.client.WebClient; +import org.springframework.web.util.UriComponentsBuilder; +import reactor.core.publisher.Mono; + +import java.net.URI; + +@Service +public class ReactiveUploadService { + + private final WebClient webClient; + private static final String EXTERNAL_UPLOAD_URL = "http://localhost:8080/external/upload"; + + public ReactiveUploadService(final WebClient webClient) { + this.webClient = webClient; + } + + + public Mono uploadPdf(final Resource resource) { + + final URI url = UriComponentsBuilder.fromHttpUrl(EXTERNAL_UPLOAD_URL).build().toUri(); + Mono httpStatusMono = webClient.post() + .uri(url) + .contentType(MediaType.APPLICATION_PDF) + .body(BodyInserters.fromResource(resource)) + .exchangeToMono(response -> { + if (response.statusCode().equals(HttpStatus.OK)) { + return response.bodyToMono(HttpStatus.class).thenReturn(response.statusCode()); + } else { + throw new ServiceException("Error uploading file"); + } + }); + return httpStatusMono; + } + + + public Mono uploadMultipart(final MultipartFile multipartFile) { + final URI url = UriComponentsBuilder.fromHttpUrl(EXTERNAL_UPLOAD_URL).build().toUri(); + + final MultipartBodyBuilder builder = new MultipartBodyBuilder(); + builder.part("file", multipartFile.getResource()); + + Mono httpStatusMono = webClient.post() + .uri(url) + .contentType(MediaType.MULTIPART_FORM_DATA) + .body(BodyInserters.fromMultipartData(builder.build())) + .exchangeToMono(response -> { + if (response.statusCode().equals(HttpStatus.OK)) { + return response.bodyToMono(HttpStatus.class).thenReturn(response.statusCode()); + } else { + throw new ServiceException("Error uploading file"); + } + }); + return httpStatusMono; + } +} diff --git a/spring-5-reactive-client/src/test/java/com/baeldung/reactive/service/ReactiveUploadServiceUnitTest.java b/spring-5-reactive-client/src/test/java/com/baeldung/reactive/service/ReactiveUploadServiceUnitTest.java new file mode 100644 index 0000000000..40c1e40d92 --- /dev/null +++ b/spring-5-reactive-client/src/test/java/com/baeldung/reactive/service/ReactiveUploadServiceUnitTest.java @@ -0,0 +1,48 @@ +package com.baeldung.reactive.service; + +import org.junit.jupiter.api.Test; +import org.springframework.core.io.Resource; +import org.springframework.http.HttpStatus; +import org.springframework.web.multipart.MultipartFile; +import org.springframework.web.reactive.function.client.ClientResponse; +import org.springframework.web.reactive.function.client.WebClient; +import reactor.core.publisher.Mono; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +class ReactiveUploadServiceUnitTest { + + private static final String BASE_URL = "http://localhost:8080/external/upload"; + + final WebClient webClientMock = WebClient.builder().baseUrl(BASE_URL) + .exchangeFunction(clientRequest -> Mono.just(ClientResponse.create(HttpStatus.OK) + .header("content-type", "application/json") + .build())) + .build(); + + private final ReactiveUploadService tested = new ReactiveUploadService(webClientMock); + + @Test + void givenAPdf_whenUploadingWithWebClient_thenOK() { + final Resource file = mock(Resource.class); + + final Mono result = tested.uploadPdf(file); + final HttpStatus status = result.block(); + + assertThat(status).isEqualTo(HttpStatus.OK); + } + + @Test + void givenAMultipartPdf_whenUploadingWithWebClient_thenOK() { + final Resource file = mock(Resource.class); + final MultipartFile multipartFile = mock(MultipartFile.class); + when(multipartFile.getResource()).thenReturn(file); + + final Mono result = tested.uploadMultipart(multipartFile); + final HttpStatus status = result.block(); + + assertThat(status).isEqualTo(HttpStatus.OK); + } +} \ No newline at end of file diff --git a/spring-5-webflux/pom.xml b/spring-5-webflux/pom.xml index ad1a66943c..b37e93ded8 100644 --- a/spring-5-webflux/pom.xml +++ b/spring-5-webflux/pom.xml @@ -65,8 +65,4 @@
- - 2.3.3.RELEASE - - \ No newline at end of file diff --git a/spring-5-webflux/src/main/java/com/baeldung/spring/rsocket/client/ClientConfiguration.java b/spring-5-webflux/src/main/java/com/baeldung/spring/rsocket/client/ClientConfiguration.java index abfe2e7807..2e2c309240 100644 --- a/spring-5-webflux/src/main/java/com/baeldung/spring/rsocket/client/ClientConfiguration.java +++ b/spring-5-webflux/src/main/java/com/baeldung/spring/rsocket/client/ClientConfiguration.java @@ -1,30 +1,29 @@ package com.baeldung.spring.rsocket.client; -import io.rsocket.RSocket; -import io.rsocket.RSocketFactory; -import io.rsocket.frame.decoder.PayloadDecoder; -import io.rsocket.transport.netty.client.TcpClientTransport; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.messaging.rsocket.RSocketRequester; -import org.springframework.messaging.rsocket.RSocketStrategies; import org.springframework.util.MimeTypeUtils; +import reactor.util.retry.Retry; + +import java.time.Duration; @Configuration public class ClientConfiguration { @Bean - public RSocket rSocket() { - return RSocketFactory.connect() - .mimeType(MimeTypeUtils.APPLICATION_JSON_VALUE, MimeTypeUtils.APPLICATION_JSON_VALUE) - .frameDecoder(PayloadDecoder.ZERO_COPY) - .transport(TcpClientTransport.create(7000)) - .start() - .block(); - } + public RSocketRequester getRSocketRequester(){ - @Bean - RSocketRequester rSocketRequester(RSocketStrategies rSocketStrategies) { - return RSocketRequester.wrap(rSocket(), MimeTypeUtils.APPLICATION_JSON, MimeTypeUtils.APPLICATION_JSON, rSocketStrategies); + RSocketRequester.Builder builder = RSocketRequester.builder(); + + return builder + .rsocketConnector( + rSocketConnector -> + rSocketConnector.reconnect( + Retry.fixedDelay(2, Duration.ofSeconds(2)) + ) + ) + .dataMimeType(MimeTypeUtils.APPLICATION_JSON) + .tcp("localhost", 7000); } } diff --git a/spring-5-webflux/src/main/java/com/baeldung/spring/serverconfig/CustomNettyWebServerFactory.java b/spring-5-webflux/src/main/java/com/baeldung/spring/serverconfig/CustomNettyWebServerFactory.java index f9de3b4006..2d11a51160 100644 --- a/spring-5-webflux/src/main/java/com/baeldung/spring/serverconfig/CustomNettyWebServerFactory.java +++ b/spring-5-webflux/src/main/java/com/baeldung/spring/serverconfig/CustomNettyWebServerFactory.java @@ -25,12 +25,9 @@ public class CustomNettyWebServerFactory { @Override public HttpServer apply(HttpServer httpServer) { - EventLoopGroup parentGroup = new NioEventLoopGroup(); - EventLoopGroup childGroup = new NioEventLoopGroup(); - return httpServer - .tcpConfiguration(tcpServer -> tcpServer.bootstrap( - serverBootstrap -> serverBootstrap.group(parentGroup, childGroup).channel(NioServerSocketChannel.class) - )); + EventLoopGroup eventLoopGroup = new NioEventLoopGroup(); + eventLoopGroup.register(new NioServerSocketChannel()); + return httpServer.runOn(eventLoopGroup); } } } diff --git a/spring-5-webflux/src/test/java/com/baeldung/spring/rsocket/server/MarketDataRSocketControllerLiveTest.java b/spring-5-webflux/src/test/java/com/baeldung/spring/rsocket/server/MarketDataRSocketControllerLiveTest.java index 40ddc732ac..98d604b178 100644 --- a/spring-5-webflux/src/test/java/com/baeldung/spring/rsocket/server/MarketDataRSocketControllerLiveTest.java +++ b/spring-5-webflux/src/test/java/com/baeldung/spring/rsocket/server/MarketDataRSocketControllerLiveTest.java @@ -1,15 +1,8 @@ package com.baeldung.spring.rsocket.server; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.verify; - import com.baeldung.spring.rsocket.model.MarketData; import com.baeldung.spring.rsocket.model.MarketDataRequest; import io.rsocket.RSocket; -import io.rsocket.RSocketFactory; -import io.rsocket.frame.decoder.PayloadDecoder; -import io.rsocket.transport.netty.client.TcpClientTransport; -import java.time.Duration; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; @@ -23,6 +16,12 @@ import org.springframework.messaging.rsocket.RSocketStrategies; import org.springframework.test.context.TestPropertySource; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.util.MimeTypeUtils; +import reactor.util.retry.Retry; + +import java.time.Duration; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.verify; @RunWith(SpringRunner.class) @SpringBootTest @@ -81,12 +80,16 @@ public class MarketDataRSocketControllerLiveTest { @Bean @Lazy public RSocket rSocket() { - return RSocketFactory.connect() - .mimeType(MimeTypeUtils.APPLICATION_JSON_VALUE, MimeTypeUtils.APPLICATION_JSON_VALUE) - .frameDecoder(PayloadDecoder.ZERO_COPY) - .transport(TcpClientTransport.create(7000)) - .start() - .block(); + + RSocketRequester.Builder builder = RSocketRequester.builder(); + + return builder + .rsocketConnector( + rSocketConnector -> + rSocketConnector.reconnect(Retry.fixedDelay(2, Duration.ofSeconds(2)))) + .dataMimeType(MimeTypeUtils.APPLICATION_JSON) + .tcp("localhost", 7000) + .rsocket(); } @Bean diff --git a/spring-5/README.md b/spring-5/README.md index 2ddd9fa94f..952daa40d2 100644 --- a/spring-5/README.md +++ b/spring-5/README.md @@ -11,5 +11,4 @@ This module contains articles about Spring 5 - [Spring Assert Statements](https://www.baeldung.com/spring-assert) - [Difference between \ vs \](https://www.baeldung.com/spring-contextannotation-contextcomponentscan) - [Finding the Spring Version](https://www.baeldung.com/spring-find-version) -- [Spring 5 Testing with @EnabledIf Annotation](https://www.baeldung.com/spring-5-enabledIf) - [Configuring a Hikari Connection Pool with Spring Boot](https://www.baeldung.com/spring-boot-hikari) diff --git a/spring-aop/README.md b/spring-aop/README.md index 707e0fbf81..b49c2bd457 100644 --- a/spring-aop/README.md +++ b/spring-aop/README.md @@ -13,3 +13,4 @@ This module contains articles about Spring aspect oriented programming (AOP) - [When Does Java Throw UndeclaredThrowableException?](https://www.baeldung.com/java-undeclaredthrowableexception) - [Get Advised Method Info in Spring AOP](https://www.baeldung.com/spring-aop-get-advised-method-info) - [Advise Methods on Annotated Classes With AspectJ](https://www.baeldung.com/aspectj-advise-methods) +- [Joinpoint vs. ProceedingJoinPoint in AspectJ](https://www.baeldung.com/aspectj-joinpoint-proceedingjoinpoint) diff --git a/spring-aop/src/main/java/com/baeldung/joinpoint/ArticleService.java b/spring-aop/src/main/java/com/baeldung/joinpoint/ArticleService.java new file mode 100644 index 0000000000..5a6b5ce63a --- /dev/null +++ b/spring-aop/src/main/java/com/baeldung/joinpoint/ArticleService.java @@ -0,0 +1,32 @@ +package com.baeldung.joinpoint; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +import java.util.Arrays; +import java.util.List; + +import static java.util.stream.Collectors.toList; + +@Service +public class ArticleService { + + public List getArticleList() { + return Arrays.asList( + "Article 1", + "Article 2" + ); + } + + public List getArticleList(String startsWithFilter) { + if (StringUtils.isBlank(startsWithFilter)) { + throw new IllegalArgumentException("startsWithFilter can't be blank"); + } + + return getArticleList() + .stream() + .filter(a -> a.startsWith(startsWithFilter)) + .collect(toList()); + } + +} diff --git a/spring-aop/src/main/java/com/baeldung/joinpoint/JoinPointAfterThrowingAspect.java b/spring-aop/src/main/java/com/baeldung/joinpoint/JoinPointAfterThrowingAspect.java new file mode 100644 index 0000000000..a1f991e90d --- /dev/null +++ b/spring-aop/src/main/java/com/baeldung/joinpoint/JoinPointAfterThrowingAspect.java @@ -0,0 +1,27 @@ +package com.baeldung.joinpoint; + +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.AfterThrowing; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Pointcut; +import org.springframework.stereotype.Component; + +import java.util.logging.Logger; + +@Aspect +@Component +public class JoinPointAfterThrowingAspect { + + private static final java.util.logging.Logger log = Logger.getLogger(JoinPointAfterThrowingAspect.class.getName()); + + @Pointcut("execution(* com.baeldung.joinpoint.ArticleService.getArticleList(..))") + public void articleListPointcut() { } + + @AfterThrowing( + pointcut = "articleListPointcut()", + throwing = "e" + ) + public void logExceptions(JoinPoint jp, Exception e) { + log.severe(e.getMessage()); + } +} diff --git a/spring-aop/src/main/java/com/baeldung/joinpoint/JoinPointAroundCacheAspect.java b/spring-aop/src/main/java/com/baeldung/joinpoint/JoinPointAroundCacheAspect.java new file mode 100644 index 0000000000..dbf2b2e1e4 --- /dev/null +++ b/spring-aop/src/main/java/com/baeldung/joinpoint/JoinPointAroundCacheAspect.java @@ -0,0 +1,30 @@ +package com.baeldung.joinpoint; + +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Pointcut; +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.Map; + +@Aspect +@Component +public class JoinPointAroundCacheAspect { + + public final static Map CACHE = new HashMap<>(); + + @Pointcut("execution(* com.baeldung.joinpoint.ArticleService.getArticleList(..))") + public void articleListPointcut() { } + + @Around("articleListPointcut()") + public Object aroundAdviceCache(ProceedingJoinPoint pjp) throws Throwable { + Object articles = CACHE.get(pjp.getArgs()); + if (articles == null) { + articles = pjp.proceed(pjp.getArgs()); + CACHE.put(pjp.getArgs(), articles); + } + return articles; + } +} diff --git a/spring-aop/src/main/java/com/baeldung/joinpoint/JoinPointAroundExceptionAspect.java b/spring-aop/src/main/java/com/baeldung/joinpoint/JoinPointAroundExceptionAspect.java new file mode 100644 index 0000000000..8d15de150d --- /dev/null +++ b/spring-aop/src/main/java/com/baeldung/joinpoint/JoinPointAroundExceptionAspect.java @@ -0,0 +1,30 @@ +package com.baeldung.joinpoint; + +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Pointcut; +import org.springframework.stereotype.Component; + +import java.util.logging.Logger; + +@Aspect +@Component +public class JoinPointAroundExceptionAspect { + + private static final java.util.logging.Logger log = Logger.getLogger(JoinPointAroundExceptionAspect.class.getName()); + + @Pointcut("execution(* com.baeldung.joinpoint.ArticleService.getArticleList(..))") + public void articleListPointcut() { } + + @Around("articleListPointcut()") + public Object aroundAdviceException(ProceedingJoinPoint pjp) throws Throwable { + try { + return pjp.proceed(pjp.getArgs()); + } catch (Throwable e) { + log.severe(e.getMessage()); + log.info("Retrying operation"); + return pjp.proceed(pjp.getArgs()); + } + } +} diff --git a/spring-aop/src/main/java/com/baeldung/joinpoint/JoinPointBeforeAspect.java b/spring-aop/src/main/java/com/baeldung/joinpoint/JoinPointBeforeAspect.java new file mode 100644 index 0000000000..4485363ff9 --- /dev/null +++ b/spring-aop/src/main/java/com/baeldung/joinpoint/JoinPointBeforeAspect.java @@ -0,0 +1,32 @@ +package com.baeldung.joinpoint; + +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; +import org.aspectj.lang.annotation.Pointcut; +import org.springframework.stereotype.Component; + +import java.util.Arrays; +import java.util.logging.Logger; + +import static java.lang.String.format; + +@Aspect +@Component +public class JoinPointBeforeAspect { + + private static final Logger log = Logger.getLogger(JoinPointBeforeAspect.class.getName()); + + @Pointcut("execution(* com.baeldung.joinpoint.ArticleService.getArticleList(..))") + public void articleListPointcut() { } + + @Before("articleListPointcut()") + public void beforeAdvice(JoinPoint joinPoint) { + log.info( + format("Method %s executed with %s arguments", + joinPoint.getStaticPart().getSignature(), + Arrays.toString(joinPoint.getArgs()) + ) + ); + } +} diff --git a/spring-aop/src/test/java/com/baeldung/joinpoint/ArticleServiceIntegrationTest.java b/spring-aop/src/test/java/com/baeldung/joinpoint/ArticleServiceIntegrationTest.java new file mode 100644 index 0000000000..a67b843262 --- /dev/null +++ b/spring-aop/src/test/java/com/baeldung/joinpoint/ArticleServiceIntegrationTest.java @@ -0,0 +1,39 @@ +package com.baeldung.joinpoint; + +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.junit4.SpringJUnit4ClassRunner; + +import java.util.List; + +import static org.junit.Assert.assertFalse; + +@RunWith(SpringJUnit4ClassRunner.class) +@SpringBootTest +public class ArticleServiceIntegrationTest { + + @Autowired + private ArticleService articleService; + + @Test + public void shouldGetNotEmptyArticleList() { + List articleList = articleService.getArticleList(); + + assertFalse(articleList.isEmpty()); + } + + @Test + public void shouldGetNotEmptyArticleListWithStartsWithFilter() { + List articleList = articleService.getArticleList("Article"); + + assertFalse(articleList.isEmpty()); + } + + @Test(expected = IllegalArgumentException.class) + public void shouldThrowExceptionIfStartsWithFilterIsBlank() { + articleService.getArticleList(" "); + } + +} diff --git a/spring-aop/src/test/java/com/baeldung/joinpoint/JoinPointAfterThrowingAspectIntegrationTest.java b/spring-aop/src/test/java/com/baeldung/joinpoint/JoinPointAfterThrowingAspectIntegrationTest.java new file mode 100644 index 0000000000..cdef76ac0d --- /dev/null +++ b/spring-aop/src/test/java/com/baeldung/joinpoint/JoinPointAfterThrowingAspectIntegrationTest.java @@ -0,0 +1,60 @@ +package com.baeldung.joinpoint; + +import org.junit.Before; +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.context.annotation.EnableAspectJAutoProxy; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Handler; +import java.util.logging.LogRecord; +import java.util.logging.Logger; + +import static org.hamcrest.Matchers.hasSize; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; + +@RunWith(SpringJUnit4ClassRunner.class) +@SpringBootTest +@EnableAspectJAutoProxy +public class JoinPointAfterThrowingAspectIntegrationTest { + + private final List messages = new ArrayList<>(); + + @Before + public void setUp() { + Handler logEventHandler = new Handler() { + @Override + public void publish(LogRecord record) { + messages.add(record.getLevel().getName() + " " + record.getMessage()); + } + + @Override + public void flush() { + } + + @Override + public void close() throws SecurityException { + } + }; + + Logger logger = Logger.getLogger(JoinPointAfterThrowingAspect.class.getName()); + logger.addHandler(logEventHandler); + } + + @Autowired + private ArticleService articleService; + + @Test(expected = IllegalArgumentException.class) + public void shouldLogMethodSignatureBeforeExecution() { + articleService.getArticleList(" "); + + assertThat(messages, hasSize(1)); + assertTrue(messages.contains("SEVERE startsWithFilter can't be blank")); + } + +} diff --git a/spring-aop/src/test/java/com/baeldung/joinpoint/JoinPointAroundCacheAspectIntegrationTest.java b/spring-aop/src/test/java/com/baeldung/joinpoint/JoinPointAroundCacheAspectIntegrationTest.java new file mode 100644 index 0000000000..4bd8f2ad8e --- /dev/null +++ b/spring-aop/src/test/java/com/baeldung/joinpoint/JoinPointAroundCacheAspectIntegrationTest.java @@ -0,0 +1,35 @@ +package com.baeldung.joinpoint; + +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.context.annotation.EnableAspectJAutoProxy; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import java.util.List; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +@RunWith(SpringJUnit4ClassRunner.class) +@SpringBootTest +@EnableAspectJAutoProxy +public class JoinPointAroundCacheAspectIntegrationTest { + + @Autowired + private ArticleService articleService; + + @Test + public void shouldPopulateCache() { + assertTrue(JoinPointAroundCacheAspect.CACHE.isEmpty()); + + List articles = articleService.getArticleList(); + + assertFalse(JoinPointAroundCacheAspect.CACHE.isEmpty()); + assertEquals(JoinPointAroundCacheAspect.CACHE.size(), 1); + assertEquals(JoinPointAroundCacheAspect.CACHE.values().iterator().next(), articles); + } + +} diff --git a/spring-aop/src/test/java/com/baeldung/joinpoint/JoinPointAroundExceptionAspectIntegrationTest.java b/spring-aop/src/test/java/com/baeldung/joinpoint/JoinPointAroundExceptionAspectIntegrationTest.java new file mode 100644 index 0000000000..dbdda30c15 --- /dev/null +++ b/spring-aop/src/test/java/com/baeldung/joinpoint/JoinPointAroundExceptionAspectIntegrationTest.java @@ -0,0 +1,60 @@ +package com.baeldung.joinpoint; + +import org.junit.Before; +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.context.annotation.EnableAspectJAutoProxy; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Handler; +import java.util.logging.LogRecord; +import java.util.logging.Logger; + +import static org.hamcrest.Matchers.hasSize; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; + +@RunWith(SpringJUnit4ClassRunner.class) +@SpringBootTest +@EnableAspectJAutoProxy +public class JoinPointAroundExceptionAspectIntegrationTest { + + private final List messages = new ArrayList<>(); + + @Before + public void setUp() { + Handler logEventHandler = new Handler() { + @Override + public void publish(LogRecord record) { + messages.add(record.getLevel().getName() + " " + record.getMessage()); + } + + @Override + public void flush() { + } + + @Override + public void close() throws SecurityException { + } + }; + + Logger logger = Logger.getLogger(JoinPointAroundExceptionAspect.class.getName()); + logger.addHandler(logEventHandler); + } + + @Autowired + private ArticleService articleService; + + @Test(expected = IllegalArgumentException.class) + public void shouldLogMethodSignatureBeforeExecution() { + articleService.getArticleList(" "); + + assertThat(messages, hasSize(1)); + assertTrue(messages.contains("INFO Retrying operation")); + } + +} diff --git a/spring-aop/src/test/java/com/baeldung/joinpoint/JoinPointBeforeAspectIntegrationTest.java b/spring-aop/src/test/java/com/baeldung/joinpoint/JoinPointBeforeAspectIntegrationTest.java new file mode 100644 index 0000000000..631852d57f --- /dev/null +++ b/spring-aop/src/test/java/com/baeldung/joinpoint/JoinPointBeforeAspectIntegrationTest.java @@ -0,0 +1,60 @@ +package com.baeldung.joinpoint; + +import org.junit.Before; +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.context.annotation.EnableAspectJAutoProxy; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Handler; +import java.util.logging.LogRecord; +import java.util.logging.Logger; + +import static org.hamcrest.Matchers.hasSize; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; + +@RunWith(SpringJUnit4ClassRunner.class) +@SpringBootTest +@EnableAspectJAutoProxy +public class JoinPointBeforeAspectIntegrationTest { + + private final List messages = new ArrayList<>(); + + @Before + public void setUp() { + Handler logEventHandler = new Handler() { + @Override + public void publish(LogRecord record) { + messages.add(record.getLevel().getName() + " " + record.getMessage()); + } + + @Override + public void flush() { + } + + @Override + public void close() throws SecurityException { + } + }; + + Logger logger = Logger.getLogger(JoinPointBeforeAspect.class.getName()); + logger.addHandler(logEventHandler); + } + + @Autowired + private ArticleService articleService; + + @Test + public void shouldLogMethodSignatureBeforeExecution() { + articleService.getArticleList(); + + assertThat(messages, hasSize(1)); + assertTrue(messages.contains("INFO Method List com.baeldung.joinpoint.ArticleService.getArticleList() executed with [] arguments")); + } + +} diff --git a/spring-boot-modules/spring-boot-bootstrap/README.md b/spring-boot-modules/spring-boot-bootstrap/README.md index 146cd04551..02ec52f755 100644 --- a/spring-boot-modules/spring-boot-bootstrap/README.md +++ b/spring-boot-modules/spring-boot-bootstrap/README.md @@ -10,4 +10,4 @@ This module contains articles about bootstrapping Spring Boot applications. - [Deploy a Spring Boot Application to OpenShift](https://www.baeldung.com/spring-boot-deploy-openshift) - [Deploy a Spring Boot Application to AWS Beanstalk](https://www.baeldung.com/spring-boot-deploy-aws-beanstalk) - [Guide to @SpringBootConfiguration in Spring Boot](https://www.baeldung.com/springbootconfiguration-annotation) -- [Implement Health Checks in OpenShift](https://www.baeldung.com/openshift-health-checks) +- [Implement Health Checks in OpenShift](https://www.baeldung.com/ops/openshift-health-checks) diff --git a/spring-boot-modules/spring-boot-custom-starter/parent-multi-module/application/pom.xml b/spring-boot-modules/spring-boot-custom-starter/parent-multi-module/application/pom.xml index 948482b21b..1c26ec32d3 100644 --- a/spring-boot-modules/spring-boot-custom-starter/parent-multi-module/application/pom.xml +++ b/spring-boot-modules/spring-boot-custom-starter/parent-multi-module/application/pom.xml @@ -34,4 +34,5 @@ + \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-environment/pom.xml b/spring-boot-modules/spring-boot-environment/pom.xml index 5327825409..d4b260ee3d 100644 --- a/spring-boot-modules/spring-boot-environment/pom.xml +++ b/spring-boot-modules/spring-boot-environment/pom.xml @@ -4,8 +4,8 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 spring-boot-environment - war spring-boot-environment + war Demo project for Spring Boot diff --git a/spring-boot-modules/spring-boot-exceptions/pom.xml b/spring-boot-modules/spring-boot-exceptions/pom.xml index 9866c418be..cec1bab4ff 100644 --- a/spring-boot-modules/spring-boot-exceptions/pom.xml +++ b/spring-boot-modules/spring-boot-exceptions/pom.xml @@ -4,8 +4,8 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 spring-boot-exceptions - jar spring-boot-exceptions + jar Demo project for working with Spring Boot exceptions diff --git a/spring-boot-modules/spring-boot-flowable/pom.xml b/spring-boot-modules/spring-boot-flowable/pom.xml index fee4d9fdfc..320a684880 100644 --- a/spring-boot-modules/spring-boot-flowable/pom.xml +++ b/spring-boot-modules/spring-boot-flowable/pom.xml @@ -4,8 +4,8 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 spring-boot-flowable - war spring-boot-flowable + war Spring Boot Flowable Module diff --git a/spring-boot-modules/spring-boot-jasypt/pom.xml b/spring-boot-modules/spring-boot-jasypt/pom.xml index 1032500de7..0a37c545ac 100644 --- a/spring-boot-modules/spring-boot-jasypt/pom.xml +++ b/spring-boot-modules/spring-boot-jasypt/pom.xml @@ -5,8 +5,8 @@ 4.0.0 com.example.jasypt spring-boot-jasypt - jar spring-boot-jasypt + jar Demo project for Spring Boot diff --git a/spring-boot-modules/spring-boot-keycloak/pom.xml b/spring-boot-modules/spring-boot-keycloak/pom.xml index 505d486509..b80dbfa191 100644 --- a/spring-boot-modules/spring-boot-keycloak/pom.xml +++ b/spring-boot-modules/spring-boot-keycloak/pom.xml @@ -77,8 +77,6 @@ 13.0.1 - - 2.5.3 \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-mvc-2/pom.xml b/spring-boot-modules/spring-boot-mvc-2/pom.xml index 43e1f12efc..d347b36b3b 100644 --- a/spring-boot-modules/spring-boot-mvc-2/pom.xml +++ b/spring-boot-modules/spring-boot-mvc-2/pom.xml @@ -4,8 +4,8 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 spring-boot-mvc-2 - jar spring-boot-mvc-2 + jar Module For Spring Boot MVC Web Fn diff --git a/spring-boot-modules/spring-boot-mvc-birt/pom.xml b/spring-boot-modules/spring-boot-mvc-birt/pom.xml index 54a5091559..16b07000f8 100644 --- a/spring-boot-modules/spring-boot-mvc-birt/pom.xml +++ b/spring-boot-modules/spring-boot-mvc-birt/pom.xml @@ -5,8 +5,8 @@ 4.0.0 spring-boot-mvc-birt 0.0.1-SNAPSHOT - jar spring-boot-mvc-birt + jar Module For Spring Boot Integration with BIRT 4.0.0 com.baeldung @@ -627,4 +627,4 @@ 1.2.0 - + \ No newline at end of file diff --git a/spring-security-modules/pom.xml b/spring-security-modules/pom.xml index 917360dc3e..e482a67a0e 100644 --- a/spring-security-modules/pom.xml +++ b/spring-security-modules/pom.xml @@ -49,4 +49,4 @@ spring-social-login - + \ No newline at end of file diff --git a/spring-security-modules/spring-5-security-oauth/pom.xml b/spring-security-modules/spring-5-security-oauth/pom.xml index 03e1880431..194ace35b0 100644 --- a/spring-security-modules/spring-5-security-oauth/pom.xml +++ b/spring-security-modules/spring-5-security-oauth/pom.xml @@ -68,6 +68,8 @@ + + 2.5.2 com.baeldung.oauth2.SpringOAuthApplication diff --git a/spring-security-modules/spring-security-saml/src/main/java/com/baeldung/saml/config/SamlSecurityConfig.java b/spring-security-modules/spring-security-saml/src/main/java/com/baeldung/saml/config/SamlSecurityConfig.java index 378db478cf..10e37b346f 100644 --- a/spring-security-modules/spring-security-saml/src/main/java/com/baeldung/saml/config/SamlSecurityConfig.java +++ b/spring-security-modules/spring-security-saml/src/main/java/com/baeldung/saml/config/SamlSecurityConfig.java @@ -5,10 +5,13 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Timer; import org.opensaml.saml2.metadata.provider.FilesystemMetadataProvider; import org.opensaml.saml2.metadata.provider.MetadataProvider; import org.opensaml.saml2.metadata.provider.MetadataProviderException; +import org.opensaml.saml2.metadata.provider.ResourceBackedMetadataProvider; +import org.opensaml.util.resource.ClasspathResource; import org.opensaml.util.resource.ResourceException; import org.opensaml.xml.parse.StaticBasicParserPool; import org.springframework.beans.factory.annotation.Qualifier; @@ -141,13 +144,19 @@ public class SamlSecurityConfig { @Bean @Qualifier("okta") public ExtendedMetadataDelegate oktaExtendedMetadataProvider() throws MetadataProviderException { - File metadata = null; - try { - metadata = new File("./src/main/resources/saml/metadata/sso.xml"); - } catch (Exception e) { - e.printStackTrace(); - } - FilesystemMetadataProvider provider = new FilesystemMetadataProvider(metadata); + // Use the Spring Security SAML resource mechanism to load + // metadata from the Java classpath. This works from Spring Boot + // self contained JAR file. + org.opensaml.util.resource.Resource resource = null; + + try { + resource = new ClasspathResource("/saml/metadata/sso.xml"); + } catch (ResourceException e) { + e.printStackTrace(); + } + + Timer timer = new Timer("saml-metadata"); + ResourceBackedMetadataProvider provider = new ResourceBackedMetadataProvider(timer,resource); provider.setParserPool(parserPool()); return new ExtendedMetadataDelegate(provider, extendedMetadata()); } diff --git a/spring-security-modules/spring-security-saml/src/main/resources/application.properties b/spring-security-modules/spring-security-saml/src/main/resources/application.properties index f9d6a5df3c..1d93a12737 100644 --- a/spring-security-modules/spring-security-saml/src/main/resources/application.properties +++ b/spring-security-modules/spring-security-saml/src/main/resources/application.properties @@ -1,6 +1,8 @@ saml.keystore.location=classpath:/saml/samlKeystore.jks +# Password for Java keystore and item therein saml.keystore.password= saml.keystore.alias= +# SAML Entity ID extracted from top of SAML metadata file saml.idp= saml.sp=http://localhost:8080/saml/metadata \ No newline at end of file diff --git a/spring-security-modules/spring-security-web-boot-3/pom.xml b/spring-security-modules/spring-security-web-boot-3/pom.xml index 1fff259c16..9d09d60611 100644 --- a/spring-security-modules/spring-security-web-boot-3/pom.xml +++ b/spring-security-modules/spring-security-web-boot-3/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 spring-security-web-boot-3 0.0.1-SNAPSHOT @@ -25,6 +25,20 @@ org.springframework.boot spring-boot-starter-web + + org.springframework.boot + spring-boot-starter-test + test + + + org.apache.commons + commons-lang3 + + + org.springframework.security + spring-security-test + test + \ No newline at end of file diff --git a/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/httpfirewall/HttpFirewallApplication.java b/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/httpfirewall/HttpFirewallApplication.java new file mode 100644 index 0000000000..e7d6d823a6 --- /dev/null +++ b/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/httpfirewall/HttpFirewallApplication.java @@ -0,0 +1,15 @@ +package com.baeldung.httpfirewall; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class HttpFirewallApplication { + + public static void main(String[] args) { + SpringApplication application = new SpringApplication(HttpFirewallApplication.class); + application.setAdditionalProfiles("httpfirewall"); + application.run(args); + } + +} diff --git a/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/httpfirewall/HttpFirewallConfiguration.java b/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/httpfirewall/HttpFirewallConfiguration.java new file mode 100644 index 0000000000..3147b962a3 --- /dev/null +++ b/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/httpfirewall/HttpFirewallConfiguration.java @@ -0,0 +1,48 @@ +package com.baeldung.httpfirewall; + +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.WebSecurityConfigurerAdapter; +import org.springframework.security.web.firewall.HttpFirewall; +import org.springframework.security.web.firewall.HttpStatusRequestRejectedHandler; +import org.springframework.security.web.firewall.RequestRejectedHandler; +import org.springframework.security.web.firewall.StrictHttpFirewall; + +import java.util.Arrays; + +@Configuration +public class HttpFirewallConfiguration extends WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) throws Exception { + //@formatter:off + http + .csrf() + .disable() + .authorizeRequests() + .antMatchers("/error") + .permitAll() + .anyRequest() + .authenticated() + .and() + .httpBasic(); + //@formatter:on + } + + @Bean + public HttpFirewall configureFirewall() { + StrictHttpFirewall strictHttpFirewall = new StrictHttpFirewall(); + strictHttpFirewall.setAllowedHttpMethods(Arrays.asList("GET", "POST", "DELETE", "OPTIONS")); // Allow only HTTP GET, POST, DELETE and OPTIONS methods + return strictHttpFirewall; + } + + /* + Use this bean if you are using Spring Security 5.4 and above + */ + @Bean + public RequestRejectedHandler requestRejectedHandler() { + return new HttpStatusRequestRejectedHandler(); // Default status code is 400. Can be customized + } + +} diff --git a/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/httpfirewall/api/UserApi.java b/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/httpfirewall/api/UserApi.java new file mode 100644 index 0000000000..9bed81bb8f --- /dev/null +++ b/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/httpfirewall/api/UserApi.java @@ -0,0 +1,59 @@ +package com.baeldung.httpfirewall.api; + +import com.baeldung.httpfirewall.model.Response; +import com.baeldung.httpfirewall.model.User; +import com.baeldung.httpfirewall.service.UserServiceImpl; +import org.apache.commons.lang3.StringUtils; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.DeleteMapping; +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 org.springframework.web.server.ResponseStatusException; + +import java.net.URI; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +@RestController +@RequestMapping("/api/v1/users") +public class UserApi { + + private final UserServiceImpl userServiceImpl; + + public UserApi(UserServiceImpl userServiceImpl) { + this.userServiceImpl = userServiceImpl; + } + + @PostMapping + public ResponseEntity createUser(@RequestBody User user) { + if (StringUtils.isBlank(user.getId())) { + user.setId(UUID.randomUUID().toString()); + } + userServiceImpl.saveUser(user); + Response response = new Response(HttpStatus.CREATED.value(), "User created successfully", System.currentTimeMillis()); + URI location = URI.create("/users/" + user.getId()); + return ResponseEntity.created(location).body(response); + } + + @GetMapping("/{userId}") + public User getUser(@PathVariable("userId") String userId) { + return userServiceImpl.findById(userId).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "No user exists with the given Id")); + } + + @GetMapping() + public List getAllUsers() { + return userServiceImpl.findAll().orElse(new ArrayList<>()); + } + + @DeleteMapping("/{userId}") + public ResponseEntity deleteUser(@PathVariable("userId") String userId) { + userServiceImpl.deleteUser(userId); + return ResponseEntity.ok(new Response(200, "The user has been deleted successfully", System.currentTimeMillis())); + } +} diff --git a/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/httpfirewall/dao/InMemoryUserDao.java b/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/httpfirewall/dao/InMemoryUserDao.java new file mode 100644 index 0000000000..fb89abf17d --- /dev/null +++ b/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/httpfirewall/dao/InMemoryUserDao.java @@ -0,0 +1,65 @@ +package com.baeldung.httpfirewall.dao; + +import com.baeldung.httpfirewall.model.User; +import org.springframework.stereotype.Repository; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +@Repository +public class InMemoryUserDao { + private Map map = new HashMap<>(); + + /** + * Persists the user. The user is store in an In-Memory store (a HashMap) + * The default implementation is an In-Memory persistence + * @param user The user that should be persisted + */ + + public void save(User user) { + map.put(user.getId(), user); + } + + /** + * Finds the user from the in-memory data store. + * The default implementation is an In-Memory persistence + * + * @param userId The ID of the user that has to be fetched + * @return An optional of the requested user + */ + public Optional findById(String userId) { + return Optional.ofNullable(map.get(userId)); + } + + /** + * Finds all the users from the in-memory data store + * The default implementation is an In-Memory persistence + */ + + public Optional> findAll() { + return Optional.of(new ArrayList<>(map.values())); + } + + /** + * Delete the user from the data store + * The default implementation is an In-Memory persistence + * @param userId The user that has to be deleted + */ + + public void delete(String userId) { + map.remove(userId); + } + + /** + * Checks if the user exists + * The default implementation is an In-Memory persistence + * @param userId The user that has to be checked for + */ + + public boolean isExists(String userId) { + return map.containsKey(userId); + } +} diff --git a/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/httpfirewall/model/Response.java b/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/httpfirewall/model/Response.java new file mode 100644 index 0000000000..ba1c8d5dea --- /dev/null +++ b/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/httpfirewall/model/Response.java @@ -0,0 +1,40 @@ +package com.baeldung.httpfirewall.model; + +public class Response { + private int code; + private String message; + private long timestamp; + + public Response() { + } + + public Response(int code, String message, long timestamp) { + this.code = code; + this.message = message; + this.timestamp = timestamp; + } + + public int getCode() { + return code; + } + + public void setCode(int code) { + this.code = code; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public long getTimestamp() { + return timestamp; + } + + public void setTimestamp(long timestamp) { + this.timestamp = timestamp; + } +} diff --git a/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/httpfirewall/model/User.java b/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/httpfirewall/model/User.java new file mode 100644 index 0000000000..5807a990e7 --- /dev/null +++ b/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/httpfirewall/model/User.java @@ -0,0 +1,41 @@ +package com.baeldung.httpfirewall.model; + +public class User { + private String id; + private String username; + private String email; + + public User() { + } + + public User(String id, String username, String email) { + this.id = id; + this.username = username; + this.email = email; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + +} diff --git a/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/httpfirewall/service/UserServiceImpl.java b/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/httpfirewall/service/UserServiceImpl.java new file mode 100644 index 0000000000..d3d3f20f3d --- /dev/null +++ b/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/httpfirewall/service/UserServiceImpl.java @@ -0,0 +1,51 @@ +package com.baeldung.httpfirewall.service; + +import com.baeldung.httpfirewall.dao.InMemoryUserDao; +import com.baeldung.httpfirewall.model.User; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Optional; + +@Service +public class UserServiceImpl { + + private final InMemoryUserDao inMemoryUserDao; + + public UserServiceImpl(InMemoryUserDao inMemoryUserDao) { + this.inMemoryUserDao = inMemoryUserDao; + } + + /** + * Creates a user. Checks if the user already exists and then persists the user + * @param user The user that is to be persisted into the store + */ + public void saveUser(User user) { + inMemoryUserDao.save(user); + } + + /** + * Get a user. Returns a user + * + * @param userId The user that has to be fetched form the repository + */ + public Optional findById(String userId) { + return inMemoryUserDao.findById(userId); + } + + /** + * Fetch all the users in the store + * @return A list of all the users + */ + public Optional> findAll() { + return inMemoryUserDao.findAll(); + } + + /** + * Delete the user with a given id + * @param userId The identifier of the user + */ + public void deleteUser(String userId) { + inMemoryUserDao.delete(userId); + } +} diff --git a/spring-security-modules/spring-security-web-boot-3/src/main/resources/application-httpfirewall.properties b/spring-security-modules/spring-security-web-boot-3/src/main/resources/application-httpfirewall.properties new file mode 100644 index 0000000000..cb7e159bf3 --- /dev/null +++ b/spring-security-modules/spring-security-web-boot-3/src/main/resources/application-httpfirewall.properties @@ -0,0 +1,2 @@ +spring.security.user.name=user +spring.security.user.password=password \ No newline at end of file diff --git a/spring-security-modules/spring-security-web-boot-3/src/test/java/com/baeldung/httpfirewall/api/UserApiLiveTest.java b/spring-security-modules/spring-security-web-boot-3/src/test/java/com/baeldung/httpfirewall/api/UserApiLiveTest.java new file mode 100644 index 0000000000..4b4a9a40ce --- /dev/null +++ b/spring-security-modules/spring-security-web-boot-3/src/test/java/com/baeldung/httpfirewall/api/UserApiLiveTest.java @@ -0,0 +1,114 @@ +package com.baeldung.httpfirewall.api; + +import com.baeldung.httpfirewall.model.User; + +import com.baeldung.httpfirewall.service.UserServiceImpl; +import com.baeldung.httpfirewall.utility.UserTestUtility; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.HttpStatus; +import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.MvcResult; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header; + +@SpringBootTest +@AutoConfigureMockMvc +@DisplayName("User API Live Tests") +class UserApiLiveTest { + + private final String userId = "1"; + + @Autowired + private MockMvc mockMvc; + @Autowired + private ObjectMapper objectMapper; + + @BeforeEach + void setup() throws Exception { + //@formatter:off + mockMvc + .perform(post("/api/v1/users") + .content(objectMapper.writeValueAsString(UserTestUtility.createUserWithId(userId))) + .contentType("application/json")); + //@formatter:on + } + + @Test + @WithMockUser + @DisplayName("LiveTest User Creation") + void givenCredentials_whenHttpPost_thenReturn201() throws Exception { + // @formatter:off + MvcResult result = mockMvc + .perform(post("/api/v1/users") + .content(objectMapper.writeValueAsString(UserTestUtility.createUserWithId("200"))) + .contentType("application/json")) + .andDo(print()) + .andExpect(header().exists("Location")).andReturn(); + + assertEquals(HttpStatus.CREATED.value(), result.getResponse().getStatus()); + // @formatter:on + mockMvc.perform(delete("/api/v1/users/" + 200).contentType("application/json")); + } + + @Test + @WithMockUser + @DisplayName("LiveTest Get User") + void givenCredentials_whenHttpGetById_thenReturnUser() throws Exception { + // @formatter:off + MvcResult result=mockMvc + .perform(get("/api/v1/users/"+userId) + .contentType("application/json")).andReturn(); + // @formatter:on + assertEquals(HttpStatus.OK.value(), result.getResponse().getStatus()); + assertNotNull(result.getResponse()); + assertEquals(userId, objectMapper.readValue(result.getResponse().getContentAsString(), User.class).getId()); + } + + @Test + @WithMockUser + @DisplayName("LiveTest Get All Users") + void givenCredentials_whenHttpGet_thenReturnAllUsers() throws Exception { + // @formatter:off + MvcResult result=mockMvc + .perform(get("/api/v1/users/") + .contentType("application/json")).andReturn(); + // @formatter:on + assertEquals(HttpStatus.OK.value(), result.getResponse().getStatus()); + assertNotNull(result.getResponse()); + assertNotNull(result.getResponse().getContentAsString()); + + List users = objectMapper.readValue(result.getResponse().getContentAsString(), objectMapper.getTypeFactory().constructCollectionType(List.class, User.class)); + + assertEquals(1, users.size()); + } + + @Test + @WithMockUser + @DisplayName("LiveTest Delete User") + void givenCredentials_whenHttpDelete_thenDeleteUser() throws Exception { + // @formatter:off + MvcResult result=mockMvc + .perform(delete("/api/v1/users/"+userId) + .contentType("application/json")).andReturn(); + // @formatter:on + assertEquals(HttpStatus.OK.value(), result.getResponse().getStatus()); + assertNotNull(result.getResponse()); + assertNotNull(result.getResponse().getContentAsString()); + } + +} diff --git a/spring-security-modules/spring-security-web-boot-3/src/test/java/com/baeldung/httpfirewall/api/UserApiUnitTest.java b/spring-security-modules/spring-security-web-boot-3/src/test/java/com/baeldung/httpfirewall/api/UserApiUnitTest.java new file mode 100644 index 0000000000..4f6217ade2 --- /dev/null +++ b/spring-security-modules/spring-security-web-boot-3/src/test/java/com/baeldung/httpfirewall/api/UserApiUnitTest.java @@ -0,0 +1,161 @@ +package com.baeldung.httpfirewall.api; + +import com.baeldung.httpfirewall.model.User; +import com.baeldung.httpfirewall.service.UserServiceImpl; +import com.baeldung.httpfirewall.utility.UserTestUtility; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.HttpStatus; +import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.MvcResult; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header; + +@WebMvcTest +@AutoConfigureMockMvc +@DisplayName("User API Unit Tests") +class UserApiUnitTest { + + @Autowired + private MockMvc mockMvc; + + @MockBean + private UserServiceImpl userService; + + @Autowired + private ObjectMapper objectMapper; + + @Test + @DisplayName("Test to Check Authentication") + void whenNoAuthentication_thenThrow401() throws Exception { + // @formatter:off + MvcResult result = mockMvc + .perform(post("/api/v1/users") + .content(objectMapper.writeValueAsString(UserTestUtility.createUser())) + .contentType("application/json")) + .andReturn(); + assertEquals(HttpStatus.UNAUTHORIZED.value(), result.getResponse().getStatus()); + // @formatter:off + } + + @Test + @WithMockUser + @DisplayName("Test Malicious URL") + void givenCredentials_whenMaliciousUrl_thenThrowRequestRejectedException() throws Exception { + // @formatter:off + MvcResult result = mockMvc + .perform(post("/api/v1\\users") + .content(objectMapper.writeValueAsString(UserTestUtility.createUser())) + .contentType("application/json")) + .andDo(print()) + .andReturn(); + assertEquals(HttpStatus.BAD_REQUEST.value(), result.getResponse().getStatus()); + // @formatter:on + } + + @Test + @WithMockUser + @DisplayName("Test User Create") + void givenCredentials_whenHttpPost_thenReturn201() throws Exception { + // @formatter:off + doNothing().when(userService).saveUser(new User()); + + MvcResult result=mockMvc + .perform(post("/api/v1/users") + .content(objectMapper.writeValueAsString(UserTestUtility.createUser())) + .contentType("application/json")) + .andDo(print()) + .andExpect(header().exists("Location")).andReturn(); + assertEquals(HttpStatus.CREATED.value(), result.getResponse().getStatus()); + // @formatter:on + } + + @Test + @WithMockUser + @DisplayName("Test User Create Without ID") + void givenCredentials_whenHttpPostWithId_thenReturn201() throws Exception { + // @formatter:off + doNothing().when(userService).saveUser(new User()); + + MvcResult result = mockMvc + .perform(post("/api/v1/users") + .content(objectMapper.writeValueAsString(UserTestUtility.createUserWithoutId())) + .contentType("application/json")) + .andDo(print()) + .andExpect(header().exists("Location")).andReturn(); + assertEquals(HttpStatus.CREATED.value(), result.getResponse().getStatus()); + // @formatter:on + } + + @Test + @WithMockUser + @DisplayName("Test Get User") + void givenCredentials_whenHttpGetWithId_thenReturnUser() throws Exception { + String userId = "1"; + // @formatter:off + when(userService.findById("1")).thenReturn(UserTestUtility.createUserWithId(userId)); + + MvcResult result = mockMvc + .perform(get("/api/v1/users/"+userId) + .accept("application/json")) + .andDo(print()) + .andReturn(); + assertEquals(HttpStatus.OK.value(), result.getResponse().getStatus()); + assertNotNull(result.getResponse()); + assertEquals("jhondoe",objectMapper.readValue(result.getResponse().getContentAsString(), User.class).getUsername()); + + // @formatter:on + } + + @Test + @WithMockUser + @DisplayName("Test Get All Users") + void givenCredentials_whenHttpGetWithoutId_thenReturnAllUsers() throws Exception { + // @formatter:off + when(userService.findAll()).thenReturn(UserTestUtility.createUsers()); + + MvcResult result = mockMvc + .perform(get("/api/v1/users/") + .accept("application/json")) + .andDo(print()) + .andReturn(); + assertEquals(HttpStatus.OK.value(), result.getResponse().getStatus()); + assertNotNull(result.getResponse()); + assertTrue(result.getResponse().getContentAsString().contains("jane.doe")); + // @formatter:on + } + + @Test + @WithMockUser + @DisplayName("Test Delete a User") + void givenCredentials_whenHttpDelete_thenDeleteUser() throws Exception { + String userId = "1"; + doNothing().when(userService).deleteUser(userId); + // @formatter:off + MvcResult result = mockMvc + .perform(delete("/api/v1/users/"+userId) + .accept("application/json")) + .andDo(print()) + .andReturn(); + assertEquals(HttpStatus.OK.value(), result.getResponse().getStatus()); + assertNotNull(result.getResponse()); + assertTrue(result.getResponse().getContentAsString().contains("The user has been deleted successfully")); + // @formatter:on + } + +} diff --git a/spring-security-modules/spring-security-web-boot-3/src/test/java/com/baeldung/httpfirewall/service/UserServiceUnitTest.java b/spring-security-modules/spring-security-web-boot-3/src/test/java/com/baeldung/httpfirewall/service/UserServiceUnitTest.java new file mode 100644 index 0000000000..4a58312c0f --- /dev/null +++ b/spring-security-modules/spring-security-web-boot-3/src/test/java/com/baeldung/httpfirewall/service/UserServiceUnitTest.java @@ -0,0 +1,92 @@ +package com.baeldung.httpfirewall.service; + +import com.baeldung.httpfirewall.dao.InMemoryUserDao; + +import com.baeldung.httpfirewall.model.User; +import com.baeldung.httpfirewall.utility.UserTestUtility; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import static org.junit.jupiter.api.Assertions.assertThrows; + +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@DisplayName("UserService Unit Tests") +class UserServiceUnitTest { + + @InjectMocks + private UserServiceImpl userService; + + @Mock + private InMemoryUserDao userDao; + + @BeforeEach + void setup() { + MockitoAnnotations.openMocks(this); + } + + @Test + @DisplayName("Check Create User") + void whenCalledCreateUser_thenVerify() { + User user = UserTestUtility.createUser(); + doNothing().when(userDao).save(user); + + userService.saveUser(user); + verify(userDao, times(1)).save(user); + } + + + + @Test + @DisplayName("Check Get User") + void givenUserId_whenCalledFindById_thenReturnUser() { + User user = UserTestUtility.createUserWithId("1").orElse(new User("1", "jhondoe", "jhon.doe@gmail.com")); + + when(userDao.findById(user.getId())).thenReturn(Optional.of(user)); + + User actualUser = userService.findById("1").get(); + + assertNotNull(actualUser); + assertEquals("jhondoe", actualUser.getUsername()); + verify(userDao, times(1)).findById(user.getId()); + } + + @Test + @DisplayName("Check Get All Users") + void whenCalledFindAll_thenReturnAllUsers() { + List users = UserTestUtility.createUsers().orElse(new ArrayList<>()); + + when(userDao.findAll()).thenReturn(Optional.of(users)); + + Optional> actualUsers = userService.findAll(); + + assertNotNull(actualUsers); + assertEquals(2, users.size()); + verify(userDao, times(1)).findAll(); + } + + @Test + @DisplayName("Check Delete Users") + void givenId_whenCalledDeleteUser_thenDeleteUser() { + User user = UserTestUtility.createUserWithId("1").orElse(new User()); + + doNothing().when(userDao).delete(user.getId()); + userService.deleteUser(user.getId()); + verify(userDao, times(1)).delete(user.getId()); + } + +} diff --git a/spring-security-modules/spring-security-web-boot-3/src/test/java/com/baeldung/httpfirewall/utility/UserTestUtility.java b/spring-security-modules/spring-security-web-boot-3/src/test/java/com/baeldung/httpfirewall/utility/UserTestUtility.java new file mode 100644 index 0000000000..77953a5176 --- /dev/null +++ b/spring-security-modules/spring-security-web-boot-3/src/test/java/com/baeldung/httpfirewall/utility/UserTestUtility.java @@ -0,0 +1,33 @@ +package com.baeldung.httpfirewall.utility; + +import com.baeldung.httpfirewall.model.User; + +import java.util.Arrays; +import java.util.List; +import java.util.Optional; +import java.util.UUID; + +public class UserTestUtility { + public static User createUser() { + return new User(UUID.randomUUID().toString(),"jhondoe", "jhondoe@gmail.com"); + } + + public static User createUserWithoutId() { + return new User("","jhondoe", "jhondoe@gmail.com"); + } + + public static Optional createUserWithId(String id) { + // @formatter:off + return Optional.of(new User(id, "jhondoe", "jhon.doe@gmail.com")); + // @formatter:on + } + + public static Optional> createUsers() { + // @formatter:off + return Optional.of(Arrays.asList( + new User(UUID.randomUUID().toString(), "jhondoe","jhon.doe@gmail.com" ), + new User(UUID.randomUUID().toString(), "janedoe","jane.doe@gmail.com" )) + ); + // @formatter:on + } +} diff --git a/spring-security-modules/spring-security-web-react/pom.xml b/spring-security-modules/spring-security-web-react/pom.xml index 61df563edd..a31fafc5ad 100644 --- a/spring-security-modules/spring-security-web-react/pom.xml +++ b/spring-security-modules/spring-security-web-react/pom.xml @@ -108,41 +108,17 @@ - - + + org.eclipse.jetty jetty-maven-plugin @@ -152,61 +128,17 @@ - - + + diff --git a/spring-security-modules/spring-security-web-sockets/README.md b/spring-security-modules/spring-security-web-sockets/README.md index 76717e2fe6..34e06fa832 100644 --- a/spring-security-modules/spring-security-web-sockets/README.md +++ b/spring-security-modules/spring-security-web-sockets/README.md @@ -10,8 +10,8 @@ This module contains articles about WebSockets with Spring Security ### Running This Project: -To build the project, run the command: mvn clean install. This will build a war file in the target folder that you can deploye on a server like Tomcat. +To build the project, run the command: `mvn clean install`. This will build a war file in the target folder that you can deploy on a server like Tomcat. -Alternatively, run the project from an IDE. +Alternatively, run the project from an IDE, with the maven goal `org.codehaus.cargo:cargo-maven2-plugin:run` To login, use credentials from the data.sql file in src/main/resource, eg: user/password. diff --git a/spring-security-modules/spring-security-web-sockets/pom.xml b/spring-security-modules/spring-security-web-sockets/pom.xml index b1536e88ea..802c894612 100644 --- a/spring-security-modules/spring-security-web-sockets/pom.xml +++ b/spring-security-modules/spring-security-web-sockets/pom.xml @@ -103,7 +103,7 @@ ch.qos.logback logback-classic - ${logback-classic.version} + ${logback.version} @@ -155,11 +155,14 @@ spring-security-web-sockets - org.apache.tomcat.maven - tomcat7-maven-plugin - 2.2 + org.codehaus.cargo + cargo-maven2-plugin + ${cargo-maven2-plugin.version} - /spring-security-mvc-socket + + tomcat9x + embedded + @@ -177,8 +180,8 @@ 5.2.10.Final 1.11.3.RELEASE - 1.2.3 1.5.10.RELEASE + 1.7.6 \ No newline at end of file diff --git a/spring-web-modules/spring-mvc-views/pom.xml b/spring-web-modules/spring-mvc-views/pom.xml index 7e48175ff2..ac2215f983 100644 --- a/spring-web-modules/spring-mvc-views/pom.xml +++ b/spring-web-modules/spring-mvc-views/pom.xml @@ -4,8 +4,8 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 spring-mvc-views - war spring-mvc-views + war com.baeldung diff --git a/spring-web-modules/spring-mvc-xml/src/test/java/com/baeldung/geoip/GeoIpIntegrationTest.java b/spring-web-modules/spring-mvc-xml/src/test/java/com/baeldung/geoip/GeoIpManualTest.java similarity index 66% rename from spring-web-modules/spring-mvc-xml/src/test/java/com/baeldung/geoip/GeoIpIntegrationTest.java rename to spring-web-modules/spring-mvc-xml/src/test/java/com/baeldung/geoip/GeoIpManualTest.java index 0aa23842b1..99a76099b2 100644 --- a/spring-web-modules/spring-mvc-xml/src/test/java/com/baeldung/geoip/GeoIpIntegrationTest.java +++ b/spring-web-modules/spring-mvc-xml/src/test/java/com/baeldung/geoip/GeoIpManualTest.java @@ -10,13 +10,18 @@ import com.maxmind.geoip2.DatabaseReader; import com.maxmind.geoip2.exception.GeoIp2Exception; import com.maxmind.geoip2.model.CityResponse; -public class GeoIpIntegrationTest { +public class GeoIpManualTest { @Test public void givenIP_whenFetchingCity_thenReturnsCityData() throws IOException, GeoIp2Exception { ClassLoader classLoader = getClass().getClassLoader(); - File database = new File(classLoader.getResource("GeoLite2-City.mmdb").getFile()); + /** + * Download the db file as shown in the article https://www.baeldung.com/geolocation-by-ip-with-maxmind, + * then replace the "your-path-to-db-file" string in the test with the file path before running the test + * HINT : Copy the downloaded file at spring-web-modules/spring-mvc-xml/src/test/resources/GeoLite2-City.mmdb + * **/ + File database = new File("your-path-to-db-file"); DatabaseReader dbReader = new DatabaseReader.Builder(database).build(); InetAddress ipAddress = InetAddress.getByName("google.com"); diff --git a/spring-websockets/README.md b/spring-websockets/README.md index 9cc84f0fda..7d69c21b78 100644 --- a/spring-websockets/README.md +++ b/spring-websockets/README.md @@ -6,3 +6,4 @@ This module contains articles about Spring WebSockets. - [Intro to WebSockets with Spring](https://www.baeldung.com/websockets-spring) - [A Quick Example of Spring Websockets’ @SendToUser Annotation](https://www.baeldung.com/spring-websockets-sendtouser) - [Scheduled WebSocket Push with Spring Boot](https://www.baeldung.com/spring-boot-scheduled-websocket) +- [Test WebSocket APIs With Postman](https://www.baeldung.com/postman-websocket-apis) diff --git a/spring-websockets/src/main/java/com/baeldung/rawwebsocket/ServerWebSocketConfig.java b/spring-websockets/src/main/java/com/baeldung/rawwebsocket/ServerWebSocketConfig.java new file mode 100644 index 0000000000..5218140d2c --- /dev/null +++ b/spring-websockets/src/main/java/com/baeldung/rawwebsocket/ServerWebSocketConfig.java @@ -0,0 +1,23 @@ +package com.baeldung.rawwebsocket; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.socket.WebSocketHandler; +import org.springframework.web.socket.config.annotation.EnableWebSocket; +import org.springframework.web.socket.config.annotation.WebSocketConfigurer; +import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry; + +@Configuration +@EnableWebSocket +public class ServerWebSocketConfig implements WebSocketConfigurer { + + @Override + public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { + registry.addHandler(webSocketHandler(), "/websocket"); + } + + @Bean + public WebSocketHandler webSocketHandler() { + return new ServerWebSocketHandler(); + } +} diff --git a/spring-websockets/src/main/java/com/baeldung/rawwebsocket/ServerWebSocketHandler.java b/spring-websockets/src/main/java/com/baeldung/rawwebsocket/ServerWebSocketHandler.java new file mode 100644 index 0000000000..ed1ac8edc3 --- /dev/null +++ b/spring-websockets/src/main/java/com/baeldung/rawwebsocket/ServerWebSocketHandler.java @@ -0,0 +1,72 @@ +package com.baeldung.rawwebsocket; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.web.socket.CloseStatus; +import org.springframework.web.socket.SubProtocolCapable; +import org.springframework.web.socket.TextMessage; +import org.springframework.web.socket.WebSocketSession; +import org.springframework.web.socket.handler.TextWebSocketHandler; +import org.springframework.web.util.HtmlUtils; + +import java.io.IOException; +import java.time.LocalTime; +import java.util.Collections; +import java.util.List; +import java.util.Set; +import java.util.concurrent.CopyOnWriteArraySet; + +public class ServerWebSocketHandler extends TextWebSocketHandler implements SubProtocolCapable { + + private static final Logger logger = LoggerFactory.getLogger(ServerWebSocketHandler.class); + + private final Set sessions = new CopyOnWriteArraySet<>(); + + @Override + public void afterConnectionEstablished(WebSocketSession session) throws Exception { + logger.info("Server connection opened"); + sessions.add(session); + + TextMessage message = new TextMessage("one-time message from server"); + logger.info("Server sends: {}", message); + session.sendMessage(message); + } + + @Override + public void afterConnectionClosed(WebSocketSession session, CloseStatus status) { + logger.info("Server connection closed: {}", status); + sessions.remove(session); + } + + @Scheduled(fixedRate = 10000) + void sendPeriodicMessages() throws IOException { + for (WebSocketSession session : sessions) { + if (session.isOpen()) { + String broadcast = "server periodic message " + LocalTime.now(); + logger.info("Server sends: {}", broadcast); + session.sendMessage(new TextMessage(broadcast)); + } + } + } + + @Override + public void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception { + String request = message.getPayload(); + logger.info("Server received: {}", request); + + String response = String.format("response from server to '%s'", HtmlUtils.htmlEscape(request)); + logger.info("Server sends: {}", response); + session.sendMessage(new TextMessage(response)); + } + + @Override + public void handleTransportError(WebSocketSession session, Throwable exception) { + logger.info("Server transport error: {}", exception.getMessage()); + } + + @Override + public List getSubProtocols() { + return Collections.singletonList("subprotocol.demo.websocket"); + } +} diff --git a/testing-modules/gatling/README.md b/testing-modules/gatling/README.md index 7352479d1b..b99fafce15 100644 --- a/testing-modules/gatling/README.md +++ b/testing-modules/gatling/README.md @@ -1,6 +1,6 @@ ### Relevant Articles: - [Intro to Gatling](http://www.baeldung.com/introduction-to-gatling) -- [Run Gatling Tests From Jenkins](https://www.baeldung.com/jenkins-run-gatling-tests) +- [Run Gatling Tests From Jenkins](https://www.baeldung.com/ops/jenkins-run-gatling-tests) ### Running a simualtion - To run a simulation use "simulation" profile, command - `mvn install -Psimulation -Dgib.enabled=false` diff --git a/testing-modules/junit-4/README.md b/testing-modules/junit-4/README.md index cf20c8da91..cb5def7144 100644 --- a/testing-modules/junit-4/README.md +++ b/testing-modules/junit-4/README.md @@ -6,3 +6,4 @@ - [Running JUnit Tests Programmatically, from a Java Application](https://www.baeldung.com/junit-tests-run-programmatically-from-java) - [Introduction to Lambda Behave](https://www.baeldung.com/lambda-behave) - [Conditionally Run or Ignore Tests in JUnit 4](https://www.baeldung.com/junit-conditional-assume) +- [JUnit 4 on How to Ignore a Base Test Class](https://www.baeldung.com/junit-ignore-base-test-class) diff --git a/testing-modules/junit-4/src/test/java/com/baeldung/ignore/BaseUnitTest.java b/testing-modules/junit-4/src/test/java/com/baeldung/ignore/BaseUnitTest.java new file mode 100644 index 0000000000..0138184cc3 --- /dev/null +++ b/testing-modules/junit-4/src/test/java/com/baeldung/ignore/BaseUnitTest.java @@ -0,0 +1,8 @@ +package com.baeldung.ignore; + +public abstract class BaseUnitTest { + + public void helperMethod() { + + } +} diff --git a/testing-modules/junit-4/src/test/java/com/baeldung/ignore/BaseUnitTestHelper.java b/testing-modules/junit-4/src/test/java/com/baeldung/ignore/BaseUnitTestHelper.java new file mode 100644 index 0000000000..73ad19ed13 --- /dev/null +++ b/testing-modules/junit-4/src/test/java/com/baeldung/ignore/BaseUnitTestHelper.java @@ -0,0 +1,8 @@ +package com.baeldung.ignore; + +public class BaseUnitTestHelper { + + public void helperMethod() { + + } +} diff --git a/testing-modules/junit-4/src/test/java/com/baeldung/ignore/ExtendedBaseUnitTest.java b/testing-modules/junit-4/src/test/java/com/baeldung/ignore/ExtendedBaseUnitTest.java new file mode 100644 index 0000000000..3b88ff6ff9 --- /dev/null +++ b/testing-modules/junit-4/src/test/java/com/baeldung/ignore/ExtendedBaseUnitTest.java @@ -0,0 +1,11 @@ +package com.baeldung.ignore; + +import org.junit.Test; + +public class ExtendedBaseUnitTest extends BaseUnitTest { + + @Test + public void whenDoTest_thenAssert() { + + } +} diff --git a/testing-modules/junit-4/src/test/java/com/baeldung/ignore/IgnoreClassUnitTest.java b/testing-modules/junit-4/src/test/java/com/baeldung/ignore/IgnoreClassUnitTest.java new file mode 100644 index 0000000000..43ada14e8f --- /dev/null +++ b/testing-modules/junit-4/src/test/java/com/baeldung/ignore/IgnoreClassUnitTest.java @@ -0,0 +1,13 @@ +package com.baeldung.ignore; + +import org.junit.Ignore; +import org.junit.Test; + +@Ignore("Class not ready for tests") +public class IgnoreClassUnitTest { + + @Test + public void whenDoTest_thenAssert() { + + } +} diff --git a/testing-modules/junit-4/src/test/java/com/baeldung/ignore/IgnoreMethodUnitTest.java b/testing-modules/junit-4/src/test/java/com/baeldung/ignore/IgnoreMethodUnitTest.java new file mode 100644 index 0000000000..c49e95eed9 --- /dev/null +++ b/testing-modules/junit-4/src/test/java/com/baeldung/ignore/IgnoreMethodUnitTest.java @@ -0,0 +1,13 @@ +package com.baeldung.ignore; + +import org.junit.Ignore; +import org.junit.Test; + +public class IgnoreMethodUnitTest { + + @Ignore("This test method not ready yet") + @Test + public void whenMethodIsIgnored_thenTestsDoNotRun() { + + } +} diff --git a/testing-modules/junit-5-basics/pom.xml b/testing-modules/junit-5-basics/pom.xml index 0358f0c29a..cf39068ae7 100644 --- a/testing-modules/junit-5-basics/pom.xml +++ b/testing-modules/junit-5-basics/pom.xml @@ -99,7 +99,6 @@ maven-surefire-plugin ${maven-surefire-plugin.version} - **/*IntegrationTest.java diff --git a/testing-modules/rest-assured/pom.xml b/testing-modules/rest-assured/pom.xml index 3bb351f123..0658094efd 100644 --- a/testing-modules/rest-assured/pom.xml +++ b/testing-modules/rest-assured/pom.xml @@ -12,7 +12,6 @@ parent-boot-2 0.0.1-SNAPSHOT ../../parent-boot-2 - diff --git a/vertx-and-rxjava/pom.xml b/vertx-and-rxjava/pom.xml index fb04ba784c..1793cff1e7 100644 --- a/vertx-and-rxjava/pom.xml +++ b/vertx-and-rxjava/pom.xml @@ -47,7 +47,6 @@ 3.5.0.Beta1 - 1.2.3 \ No newline at end of file diff --git a/vraptor/pom.xml b/vraptor/pom.xml index ab78c0d97a..fad17e7aae 100644 --- a/vraptor/pom.xml +++ b/vraptor/pom.xml @@ -68,7 +68,7 @@ org.slf4j slf4j-log4j12 - ${slf4j-log4j12.version} + ${org.slf4j.version} br.com.caelum.vraptor @@ -117,7 +117,6 @@ 2.1.2.Final 2.2 5.1.1.Final - 1.7.5 4.1.0-RC3 4.0.4 8.0.8-dmr