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/annotations/annotation-processing/pom.xml b/annotations/annotation-processing/pom.xml index 59dffb963d..14bbc409e5 100644 --- a/annotations/annotation-processing/pom.xml +++ b/annotations/annotation-processing/pom.xml @@ -10,7 +10,6 @@ com.baeldung 1.0.0-SNAPSHOT annotations - ../ diff --git a/annotations/annotation-user/pom.xml b/annotations/annotation-user/pom.xml index 4743f22e95..37a2e36f61 100644 --- a/annotations/annotation-user/pom.xml +++ b/annotations/annotation-user/pom.xml @@ -10,7 +10,6 @@ com.baeldung annotations 1.0.0-SNAPSHOT - ../ diff --git a/apache-kafka/README.md b/apache-kafka/README.md index 3e817b2fa6..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) 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/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/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..af26289db8 100644 --- a/core-java-modules/core-java-8-2/pom.xml +++ b/core-java-modules/core-java-8-2/pom.xml @@ -7,12 +7,11 @@ 0.1.0-SNAPSHOT core-java-8-2 jar - + com.baeldung.core-java-modules core-java-modules 0.0.1-SNAPSHOT - ../ 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..e662ba400c 100644 --- a/core-java-modules/core-java-8-datetime-2/pom.xml +++ b/core-java-modules/core-java-8-datetime-2/pom.xml @@ -7,12 +7,11 @@ ${project.parent.version} core-java-8-datetime-2 jar - + com.baeldung.core-java-modules core-java-modules 0.0.1-SNAPSHOT - ../ diff --git a/core-java-modules/core-java-8-datetime/pom.xml b/core-java-modules/core-java-8-datetime/pom.xml index 48b2d062b0..f58557df7f 100644 --- a/core-java-modules/core-java-8-datetime/pom.xml +++ b/core-java-modules/core-java-8-datetime/pom.xml @@ -7,12 +7,11 @@ ${project.parent.version} core-java-8-datetime jar - + com.baeldung.core-java-modules core-java-modules 0.0.1-SNAPSHOT - ../ 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..987ba2e568 100644 --- a/core-java-modules/core-java-8/pom.xml +++ b/core-java-modules/core-java-8/pom.xml @@ -7,12 +7,11 @@ 0.1.0-SNAPSHOT core-java-8 jar - + com.baeldung.core-java-modules core-java-modules 0.0.1-SNAPSHOT - ../ 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/README.md b/core-java-modules/core-java-9-new-features/README.md index 4045a37d9d..09890bb677 100644 --- a/core-java-modules/core-java-9-new-features/README.md +++ b/core-java-modules/core-java-9-new-features/README.md @@ -6,7 +6,6 @@ This module contains articles about core Java features that have been introduced - [New Features in Java 9](https://www.baeldung.com/new-java-9) - [Java 9 Variable Handles Demystified](http://www.baeldung.com/java-variable-handles) -- [Exploring the New HTTP Client in Java 9 and 11](http://www.baeldung.com/java-9-http-client) - [Multi-Release Jar Files](https://www.baeldung.com/java-multi-release-jar) - [Ahead of Time Compilation (AoT)](https://www.baeldung.com/ahead-of-time-compilation) - [Introduction to Java 9 StackWalking API](https://www.baeldung.com/java-9-stackwalking-api) 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-9-new-features/src/modules/com.baeldung.httpclient/com/baeldung/httpclient/HttpClientExample.java b/core-java-modules/core-java-9-new-features/src/modules/com.baeldung.httpclient/com/baeldung/httpclient/HttpClientExample.java deleted file mode 100644 index de08c2164e..0000000000 --- a/core-java-modules/core-java-9-new-features/src/modules/com.baeldung.httpclient/com/baeldung/httpclient/HttpClientExample.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package com.baeldung.httpclient; - -import java.io.File; -import java.io.IOException; -import java.net.URI; -import java.net.URISyntaxException; -import java.nio.file.Paths; -import java.util.Arrays; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import java.util.stream.Collectors; -import jdk.incubator.http.HttpClient; -import jdk.incubator.http.HttpRequest; -import jdk.incubator.http.HttpRequest.BodyProcessor; -import jdk.incubator.http.HttpResponse; -import jdk.incubator.http.HttpResponse.BodyHandler; - -/** - * - * @author pkaria - */ -public class HttpClientExample { - - public static void main(String[] args) throws Exception { - httpGetRequest(); - httpPostRequest(); - asynchronousRequest(); - asynchronousMultipleRequests(); - } - - public static void httpGetRequest() throws URISyntaxException, IOException, InterruptedException { - HttpClient client = HttpClient.newHttpClient(); - URI httpURI = new URI("http://jsonplaceholder.typicode.com/posts/1"); - HttpRequest request = HttpRequest.newBuilder(httpURI).GET() - .headers("Accept-Enconding", "gzip, deflate").build(); - HttpResponse response = client.send(request, HttpResponse.BodyHandler.asString()); - String responseBody = response.body(); - int responseStatusCode = response.statusCode(); - System.out.println(responseBody); - } - - public static void httpPostRequest() throws URISyntaxException, IOException, InterruptedException { - HttpClient client = HttpClient - .newBuilder() - .build(); - HttpRequest request = HttpRequest - .newBuilder(new URI("http://jsonplaceholder.typicode.com/posts")) - .POST(BodyProcessor.fromString("Sample Post Request")) - .build(); - HttpResponse response - = client.send(request, HttpResponse.BodyHandler.asString()); - String responseBody = response.body(); - System.out.println(responseBody); - } - - public static void asynchronousRequest() throws URISyntaxException { - HttpClient client = HttpClient.newHttpClient(); - URI httpURI = new URI("http://jsonplaceholder.typicode.com/posts/1"); - HttpRequest request = HttpRequest.newBuilder(httpURI).GET().build(); - CompletableFuture> futureResponse = client.sendAsync(request, - HttpResponse.BodyHandler.asString()); - } - - public static void asynchronousMultipleRequests() throws URISyntaxException { - List targets = Arrays.asList(new URI("http://jsonplaceholder.typicode.com/posts/1"), new URI("http://jsonplaceholder.typicode.com/posts/2")); - HttpClient client = HttpClient.newHttpClient(); - List> futures = targets - .stream() - .map(target -> client - .sendAsync( - HttpRequest.newBuilder(target) - .GET() - .build(), - BodyHandler.asFile(Paths.get("base", target.getPath()))) - .thenApply(response -> response.body()) - .thenApply(path -> path.toFile())) - .collect(Collectors.toList()); - } -} diff --git a/core-java-modules/core-java-9-new-features/src/modules/com.baeldung.httpclient/module-info.java b/core-java-modules/core-java-9-new-features/src/modules/com.baeldung.httpclient/module-info.java deleted file mode 100644 index 205c9ea725..0000000000 --- a/core-java-modules/core-java-9-new-features/src/modules/com.baeldung.httpclient/module-info.java +++ /dev/null @@ -1,3 +0,0 @@ -module com.baeldung.httpclient { - requires jdk.incubator.httpclient; -} diff --git a/core-java-modules/core-java-9-new-features/src/test/java/com/baeldung/java9/httpclient/HttpClientIntegrationTest.java b/core-java-modules/core-java-9-new-features/src/test/java/com/baeldung/java9/httpclient/HttpClientIntegrationTest.java deleted file mode 100644 index fc59ae8d8d..0000000000 --- a/core-java-modules/core-java-9-new-features/src/test/java/com/baeldung/java9/httpclient/HttpClientIntegrationTest.java +++ /dev/null @@ -1,218 +0,0 @@ -package com.baeldung.java9.httpclient; - -import jdk.incubator.http.HttpClient; -import jdk.incubator.http.HttpRequest; -import jdk.incubator.http.HttpResponse; -import org.junit.Test; - -import java.io.IOException; -import java.net.*; -import java.util.Arrays; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.stream.Collectors; - -import static org.hamcrest.CoreMatchers.containsString; -import static org.hamcrest.CoreMatchers.equalTo; -import static org.hamcrest.collection.IsEmptyCollection.empty; -import static org.hamcrest.core.IsNot.not; -import static org.junit.Assert.assertThat; - -/** - * Created by adam. - */ -public class HttpClientIntegrationTest { - - @Test - public void shouldReturnSampleDataContentWhenConnectViaSystemProxy() throws IOException, InterruptedException, URISyntaxException { - HttpRequest request = HttpRequest.newBuilder() - .uri(new URI("https://postman-echo.com/post")) - .headers("Content-Type", "text/plain;charset=UTF-8") - .POST(HttpRequest.BodyProcessor.fromString("Sample body")) - .build(); - - HttpResponse response = HttpClient.newBuilder() - .proxy(ProxySelector.getDefault()) - .build() - .send(request, HttpResponse.BodyHandler.asString()); - - assertThat(response.statusCode(), equalTo(HttpURLConnection.HTTP_OK)); - assertThat(response.body(), containsString("Sample body")); - } - - @Test - public void shouldNotFollowRedirectWhenSetToDefaultNever() throws IOException, InterruptedException, URISyntaxException { - HttpRequest request = HttpRequest.newBuilder() - .uri(new URI("http://stackoverflow.com")) - .version(HttpClient.Version.HTTP_1_1) - .GET() - .build(); - HttpResponse response = HttpClient.newBuilder() - .build() - .send(request, HttpResponse.BodyHandler.asString()); - - assertThat(response.statusCode(), equalTo(HttpURLConnection.HTTP_MOVED_PERM)); - assertThat(response.body(), containsString("")); - } - - @Test - public void shouldFollowRedirectWhenSetToAlways() throws IOException, InterruptedException, URISyntaxException { - HttpRequest request = HttpRequest.newBuilder() - .uri(new URI("http://stackoverflow.com")) - .version(HttpClient.Version.HTTP_1_1) - .GET() - .build(); - HttpResponse response = HttpClient.newBuilder() - .followRedirects(HttpClient.Redirect.ALWAYS) - .build() - .send(request, HttpResponse.BodyHandler.asString()); - - assertThat(response.statusCode(), equalTo(HttpURLConnection.HTTP_OK)); - assertThat(response.finalRequest() - .uri() - .toString(), equalTo("https://stackoverflow.com/")); - } - - @Test - public void shouldReturnOKStatusForAuthenticatedAccess() throws URISyntaxException, IOException, InterruptedException { - HttpRequest request = HttpRequest.newBuilder() - .uri(new URI("https://postman-echo.com/basic-auth")) - .GET() - .build(); - HttpResponse response = HttpClient.newBuilder() - .authenticator(new Authenticator() { - @Override - protected PasswordAuthentication getPasswordAuthentication() { - return new PasswordAuthentication("postman", "password".toCharArray()); - } - }) - .build() - .send(request, HttpResponse.BodyHandler.asString()); - - assertThat(response.statusCode(), equalTo(HttpURLConnection.HTTP_OK)); - } - - @Test - public void shouldSendRequestAsync() throws URISyntaxException, InterruptedException, ExecutionException { - HttpRequest request = HttpRequest.newBuilder() - .uri(new URI("https://postman-echo.com/post")) - .headers("Content-Type", "text/plain;charset=UTF-8") - .POST(HttpRequest.BodyProcessor.fromString("Sample body")) - .build(); - CompletableFuture> response = HttpClient.newBuilder() - .build() - .sendAsync(request, HttpResponse.BodyHandler.asString()); - - assertThat(response.get() - .statusCode(), equalTo(HttpURLConnection.HTTP_OK)); - } - - @Test - public void shouldUseJustTwoThreadWhenProcessingSendAsyncRequest() throws URISyntaxException, InterruptedException, ExecutionException { - HttpRequest request = HttpRequest.newBuilder() - .uri(new URI("https://postman-echo.com/get")) - .GET() - .build(); - - ExecutorService executorService = Executors.newFixedThreadPool(2); - - CompletableFuture> response1 = HttpClient.newBuilder() - .executor(executorService) - .build() - .sendAsync(request, HttpResponse.BodyHandler.asString()); - - CompletableFuture> response2 = HttpClient.newBuilder() - .executor(executorService) - .build() - .sendAsync(request, HttpResponse.BodyHandler.asString()); - - CompletableFuture> response3 = HttpClient.newBuilder() - .executor(executorService) - .build() - .sendAsync(request, HttpResponse.BodyHandler.asString()); - - CompletableFuture.allOf(response1, response2, response3) - .join(); - - assertThat(response1.get() - .statusCode(), equalTo(HttpURLConnection.HTTP_OK)); - assertThat(response2.get() - .statusCode(), equalTo(HttpURLConnection.HTTP_OK)); - assertThat(response3.get() - .statusCode(), equalTo(HttpURLConnection.HTTP_OK)); - } - - @Test - public void shouldNotStoreCookieWhenPolicyAcceptNone() throws URISyntaxException, IOException, InterruptedException { - HttpRequest request = HttpRequest.newBuilder() - .uri(new URI("https://postman-echo.com/get")) - .GET() - .build(); - - HttpClient httpClient = HttpClient.newBuilder() - .cookieManager(new CookieManager(null, CookiePolicy.ACCEPT_NONE)) - .build(); - - httpClient.send(request, HttpResponse.BodyHandler.asString()); - - assertThat(httpClient.cookieManager() - .get() - .getCookieStore() - .getCookies(), empty()); - } - - @Test - public void shouldStoreCookieWhenPolicyAcceptAll() throws URISyntaxException, IOException, InterruptedException { - HttpRequest request = HttpRequest.newBuilder() - .uri(new URI("https://postman-echo.com/get")) - .GET() - .build(); - - HttpClient httpClient = HttpClient.newBuilder() - .cookieManager(new CookieManager(null, CookiePolicy.ACCEPT_ALL)) - .build(); - - httpClient.send(request, HttpResponse.BodyHandler.asString()); - - assertThat(httpClient.cookieManager() - .get() - .getCookieStore() - .getCookies(), not(empty())); - } - - @Test - public void shouldProcessMultipleRequestViaStream() throws URISyntaxException, ExecutionException, InterruptedException { - List targets = Arrays.asList(new URI("https://postman-echo.com/get?foo1=bar1"), new URI("https://postman-echo.com/get?foo2=bar2")); - - HttpClient client = HttpClient.newHttpClient(); - - List> futures = targets.stream() - .map(target -> client.sendAsync(HttpRequest.newBuilder(target) - .GET() - .build(), HttpResponse.BodyHandler.asString()) - .thenApply(response -> response.body())) - .collect(Collectors.toList()); - - CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])) - .join(); - - if (futures.get(0) - .get() - .contains("foo1")) { - assertThat(futures.get(0) - .get(), containsString("bar1")); - assertThat(futures.get(1) - .get(), containsString("bar2")); - } else { - assertThat(futures.get(1) - .get(), containsString("bar2")); - assertThat(futures.get(1) - .get(), containsString("bar1")); - } - - } - -} diff --git a/core-java-modules/core-java-9-new-features/src/test/java/com/baeldung/java9/httpclient/HttpRequestIntegrationTest.java b/core-java-modules/core-java-9-new-features/src/test/java/com/baeldung/java9/httpclient/HttpRequestIntegrationTest.java deleted file mode 100644 index 17af7bd8ba..0000000000 --- a/core-java-modules/core-java-9-new-features/src/test/java/com/baeldung/java9/httpclient/HttpRequestIntegrationTest.java +++ /dev/null @@ -1,171 +0,0 @@ -package com.baeldung.java9.httpclient; - -import jdk.incubator.http.HttpClient; -import jdk.incubator.http.HttpRequest; -import jdk.incubator.http.HttpResponse; -import org.junit.Test; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.net.HttpURLConnection; -import java.net.URI; -import java.net.URISyntaxException; -import java.nio.file.Paths; -import java.security.NoSuchAlgorithmException; -import java.time.Duration; - -import static java.time.temporal.ChronoUnit.SECONDS; -import static org.hamcrest.CoreMatchers.containsString; -import static org.hamcrest.CoreMatchers.equalTo; -import static org.junit.Assert.assertThat; - -/** - * Created by adam. - */ -public class HttpRequestIntegrationTest { - - @Test - public void shouldReturnStatusOKWhenSendGetRequest() throws IOException, InterruptedException, URISyntaxException { - HttpRequest request = HttpRequest.newBuilder() - .uri(new URI("https://postman-echo.com/get")) - .GET() - .build(); - - HttpResponse response = HttpClient.newHttpClient() - .send(request, HttpResponse.BodyHandler.asString()); - - assertThat(response.statusCode(), equalTo(HttpURLConnection.HTTP_OK)); - } - - @Test - public void shouldUseHttp2WhenWebsiteUsesHttp2() throws IOException, InterruptedException, URISyntaxException { - HttpRequest request = HttpRequest.newBuilder() - .uri(new URI("https://stackoverflow.com")) - .version(HttpClient.Version.HTTP_2) - .GET() - .build(); - HttpResponse response = HttpClient.newHttpClient() - .send(request, HttpResponse.BodyHandler.asString()); - - assertThat(response.statusCode(), equalTo(HttpURLConnection.HTTP_OK)); - assertThat(response.version(), equalTo(HttpClient.Version.HTTP_2)); - } - - @Test - public void shouldFallbackToHttp1_1WhenWebsiteDoesNotUseHttp2() throws IOException, InterruptedException, URISyntaxException, NoSuchAlgorithmException { - HttpRequest request = HttpRequest.newBuilder() - .uri(new URI("https://postman-echo.com/get")) - .version(HttpClient.Version.HTTP_2) - .GET() - .build(); - - HttpResponse response = HttpClient.newHttpClient() - .send(request, HttpResponse.BodyHandler.asString()); - - assertThat(response.version(), equalTo(HttpClient.Version.HTTP_1_1)); - } - - @Test - public void shouldReturnStatusOKWhenSendGetRequestWithDummyHeaders() throws IOException, InterruptedException, URISyntaxException { - HttpRequest request = HttpRequest.newBuilder() - .uri(new URI("https://postman-echo.com/get")) - .headers("key1", "value1", "key2", "value2") - .GET() - .build(); - - HttpResponse response = HttpClient.newHttpClient() - .send(request, HttpResponse.BodyHandler.asString()); - - assertThat(response.statusCode(), equalTo(HttpURLConnection.HTTP_OK)); - } - - @Test - public void shouldReturnStatusOKWhenSendGetRequestTimeoutSet() throws IOException, InterruptedException, URISyntaxException { - HttpRequest request = HttpRequest.newBuilder() - .uri(new URI("https://postman-echo.com/get")) - .timeout(Duration.of(10, SECONDS)) - .GET() - .build(); - - HttpResponse response = HttpClient.newHttpClient() - .send(request, HttpResponse.BodyHandler.asString()); - - assertThat(response.statusCode(), equalTo(HttpURLConnection.HTTP_OK)); - } - - @Test - public void shouldReturnNoContentWhenPostWithNoBody() throws IOException, InterruptedException, URISyntaxException { - HttpRequest request = HttpRequest.newBuilder() - .uri(new URI("https://postman-echo.com/post")) - .POST(HttpRequest.noBody()) - .build(); - - HttpResponse response = HttpClient.newHttpClient() - .send(request, HttpResponse.BodyHandler.asString()); - - assertThat(response.statusCode(), equalTo(HttpURLConnection.HTTP_OK)); - } - - @Test - public void shouldReturnSampleDataContentWhenPostWithBodyText() throws IOException, InterruptedException, URISyntaxException { - HttpRequest request = HttpRequest.newBuilder() - .uri(new URI("https://postman-echo.com/post")) - .headers("Content-Type", "text/plain;charset=UTF-8") - .POST(HttpRequest.BodyProcessor.fromString("Sample request body")) - .build(); - - HttpResponse response = HttpClient.newHttpClient() - .send(request, HttpResponse.BodyHandler.asString()); - - assertThat(response.statusCode(), equalTo(HttpURLConnection.HTTP_OK)); - assertThat(response.body(), containsString("Sample request body")); - } - - @Test - public void shouldReturnSampleDataContentWhenPostWithInputStream() throws IOException, InterruptedException, URISyntaxException { - byte[] sampleData = "Sample request body".getBytes(); - HttpRequest request = HttpRequest.newBuilder() - .uri(new URI("https://postman-echo.com/post")) - .headers("Content-Type", "text/plain;charset=UTF-8") - .POST(HttpRequest.BodyProcessor.fromInputStream(() -> new ByteArrayInputStream(sampleData))) - .build(); - - HttpResponse response = HttpClient.newHttpClient() - .send(request, HttpResponse.BodyHandler.asString()); - - assertThat(response.statusCode(), equalTo(HttpURLConnection.HTTP_OK)); - assertThat(response.body(), containsString("Sample request body")); - } - - @Test - public void shouldReturnSampleDataContentWhenPostWithByteArrayProcessorStream() throws IOException, InterruptedException, URISyntaxException { - byte[] sampleData = "Sample request body".getBytes(); - HttpRequest request = HttpRequest.newBuilder() - .uri(new URI("https://postman-echo.com/post")) - .headers("Content-Type", "text/plain;charset=UTF-8") - .POST(HttpRequest.BodyProcessor.fromByteArray(sampleData)) - .build(); - - HttpResponse response = HttpClient.newHttpClient() - .send(request, HttpResponse.BodyHandler.asString()); - - assertThat(response.statusCode(), equalTo(HttpURLConnection.HTTP_OK)); - assertThat(response.body(), containsString("Sample request body")); - } - - @Test - public void shouldReturnSampleDataContentWhenPostWithFileProcessorStream() throws IOException, InterruptedException, URISyntaxException { - HttpRequest request = HttpRequest.newBuilder() - .uri(new URI("https://postman-echo.com/post")) - .headers("Content-Type", "text/plain;charset=UTF-8") - .POST(HttpRequest.BodyProcessor.fromFile(Paths.get("src/test/resources/sample.txt"))) - .build(); - - HttpResponse response = HttpClient.newHttpClient() - .send(request, HttpResponse.BodyHandler.asString()); - - assertThat(response.statusCode(), equalTo(HttpURLConnection.HTTP_OK)); - assertThat(response.body(), containsString("Sample file content")); - } - -} diff --git a/core-java-modules/core-java-9-new-features/src/test/java/com/baeldung/java9/httpclient/HttpResponseIntegrationTest.java b/core-java-modules/core-java-9-new-features/src/test/java/com/baeldung/java9/httpclient/HttpResponseIntegrationTest.java deleted file mode 100644 index 5c6f9c8a52..0000000000 --- a/core-java-modules/core-java-9-new-features/src/test/java/com/baeldung/java9/httpclient/HttpResponseIntegrationTest.java +++ /dev/null @@ -1,55 +0,0 @@ -package com.baeldung.java9.httpclient; - -import jdk.incubator.http.HttpClient; -import jdk.incubator.http.HttpRequest; -import jdk.incubator.http.HttpResponse; -import org.junit.Test; - -import java.io.IOException; -import java.net.HttpURLConnection; -import java.net.URI; -import java.net.URISyntaxException; - -import static org.hamcrest.CoreMatchers.equalTo; -import static org.hamcrest.Matchers.isEmptyString; -import static org.hamcrest.core.IsNot.not; -import static org.junit.Assert.assertThat; - -/** - * Created by adam. - */ -public class HttpResponseIntegrationTest { - - @Test - public void shouldReturnStatusOKWhenSendGetRequest() throws IOException, InterruptedException, URISyntaxException { - HttpRequest request = HttpRequest.newBuilder() - .uri(new URI("https://postman-echo.com/get")) - .GET() - .build(); - - HttpResponse response = HttpClient.newHttpClient() - .send(request, HttpResponse.BodyHandler.asString()); - - assertThat(response.statusCode(), equalTo(HttpURLConnection.HTTP_OK)); - assertThat(response.body(), not(isEmptyString())); - } - - @Test - public void shouldResponseURIDifferentThanRequestUIRWhenRedirect() throws IOException, InterruptedException, URISyntaxException { - HttpRequest request = HttpRequest.newBuilder() - .uri(new URI("http://stackoverflow.com")) - .version(HttpClient.Version.HTTP_1_1) - .GET() - .build(); - HttpResponse response = HttpClient.newBuilder() - .followRedirects(HttpClient.Redirect.ALWAYS) - .build() - .send(request, HttpResponse.BodyHandler.asString()); - - assertThat(request.uri() - .toString(), equalTo("http://stackoverflow.com")); - assertThat(response.uri() - .toString(), equalTo("https://stackoverflow.com/")); - } - -} diff --git a/core-java-modules/core-java-annotations/pom.xml b/core-java-modules/core-java-annotations/pom.xml index 6c35aea668..a718c43eef 100644 --- a/core-java-modules/core-java-annotations/pom.xml +++ b/core-java-modules/core-java-annotations/pom.xml @@ -12,7 +12,6 @@ com.baeldung.core-java-modules core-java-modules 0.0.1-SNAPSHOT - ../ 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..e9946d46ed 100644 --- a/core-java-modules/core-java-arrays-sorting/pom.xml +++ b/core-java-modules/core-java-arrays-sorting/pom.xml @@ -11,7 +11,6 @@ core-java-modules com.baeldung.core-java-modules 0.0.1-SNAPSHOT - ../ @@ -78,4 +77,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..009197a1d0 100644 --- a/core-java-modules/core-java-char/pom.xml +++ b/core-java-modules/core-java-char/pom.xml @@ -7,12 +7,11 @@ 0.1.0-SNAPSHOT core-java-char jar - + com.baeldung.core-java-modules core-java-modules 0.0.1-SNAPSHOT - ../ diff --git a/core-java-modules/core-java-collections-2/pom.xml b/core-java-modules/core-java-collections-2/pom.xml index 421ba9abac..4e171eed48 100644 --- a/core-java-modules/core-java-collections-2/pom.xml +++ b/core-java-modules/core-java-collections-2/pom.xml @@ -6,12 +6,11 @@ core-java-collections-2 core-java-collections-2 jar - + com.baeldung.core-java-modules core-java-modules 0.0.1-SNAPSHOT - ../ diff --git a/core-java-modules/core-java-collections-3/pom.xml b/core-java-modules/core-java-collections-3/pom.xml index c7b1284d5c..4ca4bda1ee 100644 --- a/core-java-modules/core-java-collections-3/pom.xml +++ b/core-java-modules/core-java-collections-3/pom.xml @@ -7,12 +7,11 @@ 0.1.0-SNAPSHOT core-java-collections-3 jar - + com.baeldung.core-java-modules core-java-modules 0.0.1-SNAPSHOT - ../ diff --git a/core-java-modules/core-java-collections-4/pom.xml b/core-java-modules/core-java-collections-4/pom.xml index 7eb8222211..d86b04644c 100644 --- a/core-java-modules/core-java-collections-4/pom.xml +++ b/core-java-modules/core-java-collections-4/pom.xml @@ -1,31 +1,30 @@ - 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 + - - - 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-array-list/pom.xml b/core-java-modules/core-java-collections-array-list/pom.xml index 2e4ab30b8a..c14e59bac0 100644 --- a/core-java-modules/core-java-collections-array-list/pom.xml +++ b/core-java-modules/core-java-collections-array-list/pom.xml @@ -12,7 +12,6 @@ com.baeldung.core-java-modules core-java-modules 0.0.1-SNAPSHOT - ../ diff --git a/core-java-modules/core-java-collections-list-2/pom.xml b/core-java-modules/core-java-collections-list-2/pom.xml index abddeb9014..51e66fc0c2 100644 --- a/core-java-modules/core-java-collections-list-2/pom.xml +++ b/core-java-modules/core-java-collections-list-2/pom.xml @@ -12,7 +12,6 @@ com.baeldung.core-java-modules core-java-modules 0.0.1-SNAPSHOT - ../ diff --git a/core-java-modules/core-java-collections-list-3/pom.xml b/core-java-modules/core-java-collections-list-3/pom.xml index b05fc46928..efe79509c1 100644 --- a/core-java-modules/core-java-collections-list-3/pom.xml +++ b/core-java-modules/core-java-collections-list-3/pom.xml @@ -12,7 +12,6 @@ com.baeldung.core-java-modules core-java-modules 0.0.1-SNAPSHOT - ../ diff --git a/core-java-modules/core-java-collections-list/pom.xml b/core-java-modules/core-java-collections-list/pom.xml index f1b6bc3965..ae1e1561c6 100644 --- a/core-java-modules/core-java-collections-list/pom.xml +++ b/core-java-modules/core-java-collections-list/pom.xml @@ -12,7 +12,6 @@ com.baeldung.core-java-modules core-java-modules 0.0.1-SNAPSHOT - ../ diff --git a/core-java-modules/core-java-collections-maps-2/pom.xml b/core-java-modules/core-java-collections-maps-2/pom.xml index 3ae1437054..772cf30416 100644 --- a/core-java-modules/core-java-collections-maps-2/pom.xml +++ b/core-java-modules/core-java-collections-maps-2/pom.xml @@ -12,7 +12,6 @@ com.baeldung.core-java-modules core-java-modules 0.0.1-SNAPSHOT - ../ 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-3/pom.xml b/core-java-modules/core-java-collections-maps-3/pom.xml index 892d0443c5..c534c1d5ca 100644 --- a/core-java-modules/core-java-collections-maps-3/pom.xml +++ b/core-java-modules/core-java-collections-maps-3/pom.xml @@ -12,7 +12,6 @@ com.baeldung.core-java-modules core-java-modules 0.0.1-SNAPSHOT - ../ 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..245c4b04bb 100644 --- a/core-java-modules/core-java-collections-maps/pom.xml +++ b/core-java-modules/core-java-collections-maps/pom.xml @@ -12,7 +12,6 @@ com.baeldung.core-java-modules core-java-modules 0.0.1-SNAPSHOT - ../ @@ -33,5 +32,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..8fbc6e8de7 100644 --- a/core-java-modules/core-java-collections/pom.xml +++ b/core-java-modules/core-java-collections/pom.xml @@ -7,12 +7,11 @@ 0.1.0-SNAPSHOT core-java-collections jar - + com.baeldung.core-java-modules core-java-modules 0.0.1-SNAPSHOT - ../ diff --git a/core-java-modules/core-java-concurrency-2/pom.xml b/core-java-modules/core-java-concurrency-2/pom.xml index 71c73f5dff..5196872e21 100644 --- a/core-java-modules/core-java-concurrency-2/pom.xml +++ b/core-java-modules/core-java-concurrency-2/pom.xml @@ -12,7 +12,6 @@ com.baeldung.core-java-modules core-java-modules 0.0.1-SNAPSHOT - ../ diff --git a/core-java-modules/core-java-concurrency-advanced-2/pom.xml b/core-java-modules/core-java-concurrency-advanced-2/pom.xml index f975dd41a4..93c23ccae7 100644 --- a/core-java-modules/core-java-concurrency-advanced-2/pom.xml +++ b/core-java-modules/core-java-concurrency-advanced-2/pom.xml @@ -12,7 +12,6 @@ com.baeldung.core-java-modules core-java-modules 0.0.1-SNAPSHOT - ../ diff --git a/core-java-modules/core-java-concurrency-advanced-3/pom.xml b/core-java-modules/core-java-concurrency-advanced-3/pom.xml index 7a85672779..915aa8d912 100644 --- a/core-java-modules/core-java-concurrency-advanced-3/pom.xml +++ b/core-java-modules/core-java-concurrency-advanced-3/pom.xml @@ -12,7 +12,6 @@ com.baeldung.core-java-modules core-java-modules 0.0.1-SNAPSHOT - ../ diff --git a/core-java-modules/core-java-concurrency-advanced-4/pom.xml b/core-java-modules/core-java-concurrency-advanced-4/pom.xml index 7f4a573664..5bd7ccfa07 100644 --- a/core-java-modules/core-java-concurrency-advanced-4/pom.xml +++ b/core-java-modules/core-java-concurrency-advanced-4/pom.xml @@ -12,7 +12,6 @@ com.baeldung.core-java-modules core-java-modules 0.0.1-SNAPSHOT - ../ diff --git a/core-java-modules/core-java-concurrency-advanced/pom.xml b/core-java-modules/core-java-concurrency-advanced/pom.xml index 52a2e67e70..3c21b49ae5 100644 --- a/core-java-modules/core-java-concurrency-advanced/pom.xml +++ b/core-java-modules/core-java-concurrency-advanced/pom.xml @@ -12,7 +12,6 @@ com.baeldung.core-java-modules core-java-modules 0.0.1-SNAPSHOT - ../ diff --git a/core-java-modules/core-java-concurrency-basic-2/pom.xml b/core-java-modules/core-java-concurrency-basic-2/pom.xml index 99c8cee0f2..9ca12da7fb 100644 --- a/core-java-modules/core-java-concurrency-basic-2/pom.xml +++ b/core-java-modules/core-java-concurrency-basic-2/pom.xml @@ -12,7 +12,6 @@ com.baeldung.core-java-modules core-java-modules 0.0.1-SNAPSHOT - ../ diff --git a/core-java-modules/core-java-concurrency-basic/pom.xml b/core-java-modules/core-java-concurrency-basic/pom.xml index 5df379efb2..7212a2dcb1 100644 --- a/core-java-modules/core-java-concurrency-basic/pom.xml +++ b/core-java-modules/core-java-concurrency-basic/pom.xml @@ -12,7 +12,6 @@ com.baeldung.core-java-modules core-java-modules 0.0.1-SNAPSHOT - ../ diff --git a/core-java-modules/core-java-concurrency-collections-2/pom.xml b/core-java-modules/core-java-concurrency-collections-2/pom.xml index 0a31c64728..8de0e1bef7 100644 --- a/core-java-modules/core-java-concurrency-collections-2/pom.xml +++ b/core-java-modules/core-java-concurrency-collections-2/pom.xml @@ -11,7 +11,6 @@ com.baeldung.core-java-modules core-java-modules 0.0.1-SNAPSHOT - ../ diff --git a/core-java-modules/core-java-concurrency-collections/pom.xml b/core-java-modules/core-java-concurrency-collections/pom.xml index edb5a71e39..f22da1c848 100644 --- a/core-java-modules/core-java-concurrency-collections/pom.xml +++ b/core-java-modules/core-java-concurrency-collections/pom.xml @@ -12,7 +12,6 @@ com.baeldung.core-java-modules core-java-modules 0.0.1-SNAPSHOT - ../ 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-console/pom.xml b/core-java-modules/core-java-console/pom.xml index 6f9288f1a5..673c5d4dff 100644 --- a/core-java-modules/core-java-console/pom.xml +++ b/core-java-modules/core-java-console/pom.xml @@ -12,7 +12,6 @@ com.baeldung.core-java-modules core-java-modules 0.0.1-SNAPSHOT - ../ 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-date-operations-2/pom.xml b/core-java-modules/core-java-date-operations-2/pom.xml index bb0435a92a..1d283851ca 100644 --- a/core-java-modules/core-java-date-operations-2/pom.xml +++ b/core-java-modules/core-java-date-operations-2/pom.xml @@ -12,7 +12,6 @@ com.baeldung.core-java-modules core-java-modules 0.0.1-SNAPSHOT - ../ diff --git a/core-java-modules/core-java-exceptions-2/pom.xml b/core-java-modules/core-java-exceptions-2/pom.xml index ce95553021..af7a778b23 100644 --- a/core-java-modules/core-java-exceptions-2/pom.xml +++ b/core-java-modules/core-java-exceptions-2/pom.xml @@ -12,7 +12,6 @@ com.baeldung.core-java-modules core-java-modules 0.0.1-SNAPSHOT - ../ diff --git a/core-java-modules/core-java-exceptions-3/pom.xml b/core-java-modules/core-java-exceptions-3/pom.xml index 6e35845c6a..bdee998e8d 100644 --- a/core-java-modules/core-java-exceptions-3/pom.xml +++ b/core-java-modules/core-java-exceptions-3/pom.xml @@ -13,7 +13,6 @@ com.baeldung.core-java-modules core-java-modules 0.0.1-SNAPSHOT - ../ @@ -36,4 +35,5 @@ 3.10.0 + \ No newline at end of file diff --git a/core-java-modules/core-java-exceptions/pom.xml b/core-java-modules/core-java-exceptions/pom.xml index f2c6d001be..1f15dabe36 100644 --- a/core-java-modules/core-java-exceptions/pom.xml +++ b/core-java-modules/core-java-exceptions/pom.xml @@ -13,7 +13,6 @@ com.baeldung.core-java-modules core-java-modules 0.0.1-SNAPSHOT - ../ diff --git a/core-java-modules/core-java-function/pom.xml b/core-java-modules/core-java-function/pom.xml index 1cdcfe47db..cc44ba5a7c 100644 --- a/core-java-modules/core-java-function/pom.xml +++ b/core-java-modules/core-java-function/pom.xml @@ -12,7 +12,6 @@ com.baeldung.core-java-modules core-java-modules 0.0.1-SNAPSHOT - ../ diff --git a/core-java-modules/core-java-functional/pom.xml b/core-java-modules/core-java-functional/pom.xml index 3eeec71a5a..52d74035a5 100644 --- a/core-java-modules/core-java-functional/pom.xml +++ b/core-java-modules/core-java-functional/pom.xml @@ -12,7 +12,6 @@ com.baeldung.core-java-modules core-java-modules 0.0.1-SNAPSHOT - ../ \ No newline at end of file diff --git a/core-java-modules/core-java-io-2/pom.xml b/core-java-modules/core-java-io-2/pom.xml index 19f34d6da1..924248f4f9 100644 --- a/core-java-modules/core-java-io-2/pom.xml +++ b/core-java-modules/core-java-io-2/pom.xml @@ -12,7 +12,6 @@ com.baeldung.core-java-modules core-java-modules 0.0.1-SNAPSHOT - ../ diff --git a/core-java-modules/core-java-io-3/pom.xml b/core-java-modules/core-java-io-3/pom.xml index f1b6412249..017b56f03f 100644 --- a/core-java-modules/core-java-io-3/pom.xml +++ b/core-java-modules/core-java-io-3/pom.xml @@ -12,7 +12,6 @@ com.baeldung.core-java-modules core-java-modules 0.0.1-SNAPSHOT - ../ diff --git a/core-java-modules/core-java-io-4/pom.xml b/core-java-modules/core-java-io-4/pom.xml index 8327764c9f..0501bb4a66 100644 --- a/core-java-modules/core-java-io-4/pom.xml +++ b/core-java-modules/core-java-io-4/pom.xml @@ -12,7 +12,6 @@ com.baeldung.core-java-modules core-java-modules 0.0.1-SNAPSHOT - ../ diff --git a/core-java-modules/core-java-io-apis/pom.xml b/core-java-modules/core-java-io-apis/pom.xml index 9d0f3196ab..f2a574ed89 100644 --- a/core-java-modules/core-java-io-apis/pom.xml +++ b/core-java-modules/core-java-io-apis/pom.xml @@ -12,7 +12,6 @@ com.baeldung.core-java-modules core-java-modules 0.0.1-SNAPSHOT - ../ 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-conversions/pom.xml b/core-java-modules/core-java-io-conversions/pom.xml index 2dd21a80e8..8d5a47a1ac 100644 --- a/core-java-modules/core-java-io-conversions/pom.xml +++ b/core-java-modules/core-java-io-conversions/pom.xml @@ -12,7 +12,6 @@ com.baeldung.core-java-modules core-java-modules 0.0.1-SNAPSHOT - ../ 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..3c5a1b35bf 100644 --- a/core-java-modules/core-java-jar/pom.xml +++ b/core-java-modules/core-java-jar/pom.xml @@ -12,7 +12,6 @@ com.baeldung.core-java-modules core-java-modules 0.0.1-SNAPSHOT - ../ @@ -76,6 +75,7 @@ org.apache.maven.plugins maven-dependency-plugin + ${maven-dependency-plugin.version} copy-dependencies @@ -106,6 +106,7 @@ org.apache.maven.plugins maven-assembly-plugin + ${maven-assembly-plugin.version} package @@ -383,6 +384,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-jvm-2/pom.xml b/core-java-modules/core-java-jvm-2/pom.xml index f1d0a292c6..5bc5b5e3a5 100644 --- a/core-java-modules/core-java-jvm-2/pom.xml +++ b/core-java-modules/core-java-jvm-2/pom.xml @@ -12,7 +12,6 @@ com.baeldung.core-java-modules core-java-modules 0.0.1-SNAPSHOT - ../ diff --git a/core-java-modules/core-java-lambdas/pom.xml b/core-java-modules/core-java-lambdas/pom.xml index 87b315490a..f1e61ab8bf 100644 --- a/core-java-modules/core-java-lambdas/pom.xml +++ b/core-java-modules/core-java-lambdas/pom.xml @@ -12,7 +12,6 @@ com.baeldung.core-java-modules core-java-modules 0.0.1-SNAPSHOT - ../ diff --git a/core-java-modules/core-java-lang-2/pom.xml b/core-java-modules/core-java-lang-2/pom.xml index d32f382506..d1a8d68075 100644 --- a/core-java-modules/core-java-lang-2/pom.xml +++ b/core-java-modules/core-java-lang-2/pom.xml @@ -12,7 +12,6 @@ com.baeldung.core-java-modules core-java-modules 0.0.1-SNAPSHOT - ../ diff --git a/core-java-modules/core-java-lang-3/pom.xml b/core-java-modules/core-java-lang-3/pom.xml index c9005e51ae..0eda5dd16b 100644 --- a/core-java-modules/core-java-lang-3/pom.xml +++ b/core-java-modules/core-java-lang-3/pom.xml @@ -12,7 +12,6 @@ com.baeldung.core-java-modules core-java-modules 0.0.1-SNAPSHOT - ../ 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/pom.xml b/core-java-modules/core-java-lang-4/pom.xml index 824194cc07..de67ddf55a 100644 --- a/core-java-modules/core-java-lang-4/pom.xml +++ b/core-java-modules/core-java-lang-4/pom.xml @@ -12,7 +12,6 @@ com.baeldung.core-java-modules core-java-modules 0.0.1-SNAPSHOT - ../ 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-math-2/pom.xml b/core-java-modules/core-java-lang-math-2/pom.xml index c825ecdef8..4411d313db 100644 --- a/core-java-modules/core-java-lang-math-2/pom.xml +++ b/core-java-modules/core-java-lang-math-2/pom.xml @@ -11,7 +11,6 @@ com.baeldung.core-java-modules core-java-modules 0.0.1-SNAPSHOT - ../ diff --git a/core-java-modules/core-java-lang-math-3/pom.xml b/core-java-modules/core-java-lang-math-3/pom.xml index e1a650a18f..b9d09dba8c 100644 --- a/core-java-modules/core-java-lang-math-3/pom.xml +++ b/core-java-modules/core-java-lang-math-3/pom.xml @@ -11,7 +11,6 @@ com.baeldung.core-java-modules core-java-modules 0.0.1-SNAPSHOT - ../ diff --git a/core-java-modules/core-java-lang-math/pom.xml b/core-java-modules/core-java-lang-math/pom.xml index 0facdf2d8b..2cc9b90fa4 100644 --- a/core-java-modules/core-java-lang-math/pom.xml +++ b/core-java-modules/core-java-lang-math/pom.xml @@ -12,7 +12,6 @@ com.baeldung.core-java-modules core-java-modules 0.0.1-SNAPSHOT - ../ 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-lang-operators-2/pom.xml b/core-java-modules/core-java-lang-operators-2/pom.xml index 1e7e659e6d..1779b7384c 100644 --- a/core-java-modules/core-java-lang-operators-2/pom.xml +++ b/core-java-modules/core-java-lang-operators-2/pom.xml @@ -12,7 +12,6 @@ com.baeldung.core-java-modules core-java-modules 0.0.1-SNAPSHOT - ../ diff --git a/core-java-modules/core-java-lang-operators/pom.xml b/core-java-modules/core-java-lang-operators/pom.xml index 2d669bfa55..63f42917b8 100644 --- a/core-java-modules/core-java-lang-operators/pom.xml +++ b/core-java-modules/core-java-lang-operators/pom.xml @@ -12,7 +12,6 @@ com.baeldung.core-java-modules core-java-modules 0.0.1-SNAPSHOT - ../ diff --git a/core-java-modules/core-java-lang-syntax-2/pom.xml b/core-java-modules/core-java-lang-syntax-2/pom.xml index 9ca06e8fba..fdb0503174 100644 --- a/core-java-modules/core-java-lang-syntax-2/pom.xml +++ b/core-java-modules/core-java-lang-syntax-2/pom.xml @@ -12,7 +12,6 @@ com.baeldung.core-java-modules core-java-modules 0.0.1-SNAPSHOT - ../ diff --git a/core-java-modules/core-java-lang-syntax/pom.xml b/core-java-modules/core-java-lang-syntax/pom.xml index 70b0600580..da7d56de7b 100644 --- a/core-java-modules/core-java-lang-syntax/pom.xml +++ b/core-java-modules/core-java-lang-syntax/pom.xml @@ -12,7 +12,6 @@ com.baeldung.core-java-modules core-java-modules 0.0.1-SNAPSHOT - ../ diff --git a/core-java-modules/core-java-lang/pom.xml b/core-java-modules/core-java-lang/pom.xml index 6a14cab242..4989c6a5a7 100644 --- a/core-java-modules/core-java-lang/pom.xml +++ b/core-java-modules/core-java-lang/pom.xml @@ -12,7 +12,6 @@ com.baeldung.core-java-modules core-java-modules 0.0.1-SNAPSHOT - ../ diff --git a/core-java-modules/core-java-networking-2/pom.xml b/core-java-modules/core-java-networking-2/pom.xml index 893db2d85c..0035b9c0b7 100644 --- a/core-java-modules/core-java-networking-2/pom.xml +++ b/core-java-modules/core-java-networking-2/pom.xml @@ -11,7 +11,6 @@ com.baeldung.core-java-modules core-java-modules 0.0.1-SNAPSHOT - ../ 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/pom.xml b/core-java-modules/core-java-networking-3/pom.xml index d3b2398b75..de2408ec0d 100644 --- a/core-java-modules/core-java-networking-3/pom.xml +++ b/core-java-modules/core-java-networking-3/pom.xml @@ -11,7 +11,6 @@ com.baeldung.core-java-modules core-java-modules 0.0.1-SNAPSHOT - ../pom.xml diff --git a/core-java-modules/core-java-networking/pom.xml b/core-java-modules/core-java-networking/pom.xml index 3e69e03dcb..9974134eae 100644 --- a/core-java-modules/core-java-networking/pom.xml +++ b/core-java-modules/core-java-networking/pom.xml @@ -12,7 +12,6 @@ com.baeldung.core-java-modules core-java-modules 0.0.1-SNAPSHOT - ../ diff --git a/core-java-modules/core-java-nio-2/pom.xml b/core-java-modules/core-java-nio-2/pom.xml index 0f4107d536..f9cf1f3060 100644 --- a/core-java-modules/core-java-nio-2/pom.xml +++ b/core-java-modules/core-java-nio-2/pom.xml @@ -12,7 +12,6 @@ com.baeldung.core-java-modules core-java-modules 0.0.1-SNAPSHOT - ../ diff --git a/core-java-modules/core-java-nio/pom.xml b/core-java-modules/core-java-nio/pom.xml index 1d267245a9..9e1c529a65 100644 --- a/core-java-modules/core-java-nio/pom.xml +++ b/core-java-modules/core-java-nio/pom.xml @@ -12,7 +12,6 @@ com.baeldung.core-java-modules core-java-modules 0.0.1-SNAPSHOT - ../ \ No newline at end of file diff --git a/core-java-modules/core-java-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/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-perf/pom.xml b/core-java-modules/core-java-perf/pom.xml index 636de00d8f..f6f3ef795c 100644 --- a/core-java-modules/core-java-perf/pom.xml +++ b/core-java-modules/core-java-perf/pom.xml @@ -12,7 +12,6 @@ com.baeldung.core-java-modules core-java-modules 0.0.1-SNAPSHOT - ../ \ No newline at end of file diff --git a/core-java-modules/core-java-reflection-2/pom.xml b/core-java-modules/core-java-reflection-2/pom.xml index 5b04b8e8db..75168936a7 100644 --- a/core-java-modules/core-java-reflection-2/pom.xml +++ b/core-java-modules/core-java-reflection-2/pom.xml @@ -12,7 +12,6 @@ com.baeldung.core-java-modules core-java-modules 0.0.1-SNAPSHOT - ../ diff --git a/core-java-modules/core-java-reflection/pom.xml b/core-java-modules/core-java-reflection/pom.xml index 67922eec5b..b28ecccb80 100644 --- a/core-java-modules/core-java-reflection/pom.xml +++ b/core-java-modules/core-java-reflection/pom.xml @@ -12,7 +12,6 @@ com.baeldung.core-java-modules core-java-modules 0.0.1-SNAPSHOT - ../ diff --git a/core-java-modules/core-java-regex-2/pom.xml b/core-java-modules/core-java-regex-2/pom.xml index 9e081c2228..a47c0ff357 100644 --- a/core-java-modules/core-java-regex-2/pom.xml +++ b/core-java-modules/core-java-regex-2/pom.xml @@ -12,7 +12,6 @@ com.baeldung.core-java-modules core-java-modules 0.0.1-SNAPSHOT - ../ diff --git a/core-java-modules/core-java-regex/pom.xml b/core-java-modules/core-java-regex/pom.xml index fc8c1a8385..3fb63fb42a 100644 --- a/core-java-modules/core-java-regex/pom.xml +++ b/core-java-modules/core-java-regex/pom.xml @@ -12,7 +12,6 @@ com.baeldung.core-java-modules core-java-modules 0.0.1-SNAPSHOT - ../ diff --git a/core-java-modules/core-java-security-2/pom.xml b/core-java-modules/core-java-security-2/pom.xml index 2520cee7f8..8de12c0c46 100644 --- a/core-java-modules/core-java-security-2/pom.xml +++ b/core-java-modules/core-java-security-2/pom.xml @@ -12,7 +12,6 @@ com.baeldung.core-java-modules core-java-modules 0.0.1-SNAPSHOT - ../ 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-security/pom.xml b/core-java-modules/core-java-security/pom.xml index 7b49d08a37..daba990776 100644 --- a/core-java-modules/core-java-security/pom.xml +++ b/core-java-modules/core-java-security/pom.xml @@ -12,7 +12,6 @@ com.baeldung.core-java-modules core-java-modules 0.0.1-SNAPSHOT - ../ diff --git a/core-java-modules/core-java-streams-2/pom.xml b/core-java-modules/core-java-streams-2/pom.xml index f875e910db..5f25a2d9fb 100644 --- a/core-java-modules/core-java-streams-2/pom.xml +++ b/core-java-modules/core-java-streams-2/pom.xml @@ -12,7 +12,6 @@ com.baeldung.core-java-modules core-java-modules 0.0.1-SNAPSHOT - ../ diff --git a/core-java-modules/core-java-streams-3/pom.xml b/core-java-modules/core-java-streams-3/pom.xml index 01b83f229a..b384ef7e0e 100644 --- a/core-java-modules/core-java-streams-3/pom.xml +++ b/core-java-modules/core-java-streams-3/pom.xml @@ -12,7 +12,6 @@ com.baeldung.core-java-modules core-java-modules 0.0.1-SNAPSHOT - ../ diff --git a/core-java-modules/core-java-streams-4/pom.xml b/core-java-modules/core-java-streams-4/pom.xml index 8cb3786776..110ec50b8c 100644 --- a/core-java-modules/core-java-streams-4/pom.xml +++ b/core-java-modules/core-java-streams-4/pom.xml @@ -12,7 +12,6 @@ com.baeldung.core-java-modules core-java-modules 0.0.1-SNAPSHOT - ../ diff --git a/core-java-modules/core-java-streams/pom.xml b/core-java-modules/core-java-streams/pom.xml index 3d5de7cebe..4862672c8a 100644 --- a/core-java-modules/core-java-streams/pom.xml +++ b/core-java-modules/core-java-streams/pom.xml @@ -12,7 +12,6 @@ com.baeldung.core-java-modules core-java-modules 0.0.1-SNAPSHOT - ../ diff --git a/core-java-modules/core-java-string-algorithms-2/pom.xml b/core-java-modules/core-java-string-algorithms-2/pom.xml index e263c1c79c..4b0d55508f 100644 --- a/core-java-modules/core-java-string-algorithms-2/pom.xml +++ b/core-java-modules/core-java-string-algorithms-2/pom.xml @@ -12,7 +12,6 @@ com.baeldung.core-java-modules core-java-modules 0.0.1-SNAPSHOT - ../ 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..6376bfa677 100644 --- a/core-java-modules/core-java-string-algorithms-3/pom.xml +++ b/core-java-modules/core-java-string-algorithms-3/pom.xml @@ -11,7 +11,6 @@ com.baeldung.core-java-modules core-java-modules 0.0.1-SNAPSHOT - ../ @@ -32,6 +31,11 @@ junit-jupiter test + + commons-validator + commons-validator + ${validator.version} + @@ -59,6 +63,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-algorithms/pom.xml b/core-java-modules/core-java-string-algorithms/pom.xml index 0ad9ec4c66..9fea569b29 100644 --- a/core-java-modules/core-java-string-algorithms/pom.xml +++ b/core-java-modules/core-java-string-algorithms/pom.xml @@ -12,7 +12,6 @@ com.baeldung.core-java-modules core-java-modules 0.0.1-SNAPSHOT - ../ diff --git a/core-java-modules/core-java-string-apis/pom.xml b/core-java-modules/core-java-string-apis/pom.xml index b09d59fc10..6a382c3c57 100644 --- a/core-java-modules/core-java-string-apis/pom.xml +++ b/core-java-modules/core-java-string-apis/pom.xml @@ -12,7 +12,6 @@ com.baeldung.core-java-modules core-java-modules 0.0.1-SNAPSHOT - ../ diff --git a/core-java-modules/core-java-string-conversions-2/pom.xml b/core-java-modules/core-java-string-conversions-2/pom.xml index 700b4394c6..44968678f2 100644 --- a/core-java-modules/core-java-string-conversions-2/pom.xml +++ b/core-java-modules/core-java-string-conversions-2/pom.xml @@ -12,7 +12,6 @@ com.baeldung.core-java-modules core-java-modules 0.0.1-SNAPSHOT - ../ diff --git a/core-java-modules/core-java-string-conversions/pom.xml b/core-java-modules/core-java-string-conversions/pom.xml index ccbeb69768..1047e3e7c3 100644 --- a/core-java-modules/core-java-string-conversions/pom.xml +++ b/core-java-modules/core-java-string-conversions/pom.xml @@ -12,7 +12,6 @@ com.baeldung.core-java-modules core-java-modules 0.0.1-SNAPSHOT - ../ diff --git a/core-java-modules/core-java-string-operations-2/pom.xml b/core-java-modules/core-java-string-operations-2/pom.xml index b7187d2fdf..db8f78da70 100644 --- a/core-java-modules/core-java-string-operations-2/pom.xml +++ b/core-java-modules/core-java-string-operations-2/pom.xml @@ -12,7 +12,6 @@ com.baeldung.core-java-modules core-java-modules 0.0.1-SNAPSHOT - ../ 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/core-java-string-operations/pom.xml b/core-java-modules/core-java-string-operations/pom.xml index a7f75f37e2..67ce43277e 100644 --- a/core-java-modules/core-java-string-operations/pom.xml +++ b/core-java-modules/core-java-string-operations/pom.xml @@ -12,7 +12,6 @@ com.baeldung.core-java-modules core-java-modules 0.0.1-SNAPSHOT - ../ @@ -61,7 +60,7 @@ 3.6.1 - 1.10 + 1.15 \ No newline at end of file diff --git a/core-java-modules/core-java/pom.xml b/core-java-modules/core-java/pom.xml index 504ec321f2..db2b1edc70 100644 --- a/core-java-modules/core-java/pom.xml +++ b/core-java-modules/core-java/pom.xml @@ -12,7 +12,6 @@ com.baeldung.core-java-modules core-java-modules 0.0.1-SNAPSHOT - ../ 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..50700b0785 100644 --- a/grpc/pom.xml +++ b/grpc/pom.xml @@ -1,81 +1,88 @@ - 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} + + + io.grpc + grpc-testing + ${io.grpc.version} + test + + + 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/errorhandling/CommodityClient.java b/grpc/src/main/java/com/baeldung/grpc/errorhandling/CommodityClient.java new file mode 100644 index 0000000000..8680abe6f3 --- /dev/null +++ b/grpc/src/main/java/com/baeldung/grpc/errorhandling/CommodityClient.java @@ -0,0 +1,127 @@ +package com.baeldung.grpc.errorhandling; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.baeldung.grpc.errorhandling.CommodityPriceProviderGrpc.CommodityPriceProviderStub; +import com.google.protobuf.Any; +import com.google.protobuf.InvalidProtocolBufferException; +import com.google.rpc.Code; +import com.google.rpc.ErrorInfo; + +import io.grpc.Channel; +import io.grpc.ManagedChannel; +import io.grpc.ManagedChannelBuilder; +import io.grpc.Status; +import io.grpc.stub.StreamObserver; + +public class CommodityClient { + + private static final Logger logger = LoggerFactory.getLogger(CommodityClient.class.getName()); + + private final CommodityPriceProviderStub nonBlockingStub; + + public CommodityClient(Channel channel) { + + nonBlockingStub = CommodityPriceProviderGrpc.newStub(channel); + } + + public void getBidirectionalCommodityPriceLists() throws InterruptedException { + + logger.info("#######START EXAMPLE#######: BidirectionalStreaming - getCommodityPriceLists from list of commodities"); + final CountDownLatch finishLatch = new CountDownLatch(1); + StreamObserver responseObserver = new StreamObserver() { + @Override + public void onNext(StreamingCommodityQuote streamingCommodityQuote) { + + switch (streamingCommodityQuote.getMessageCase()) { + case COMODITY_QUOTE: + CommodityQuote commodityQuote = streamingCommodityQuote.getComodityQuote(); + logger.info("RESPONSE producer:" + commodityQuote.getCommodityName() + " price:" + commodityQuote.getPrice()); + break; + case STATUS: + com.google.rpc.Status status = streamingCommodityQuote.getStatus(); + logger.info("RESPONSE status error:"); + logger.info("Status code:" + Code.forNumber(status.getCode())); + logger.info("Status message:" + status.getMessage()); + for (Any any : status.getDetailsList()) { + if (any.is(ErrorInfo.class)) { + ErrorInfo errorInfo; + try { + errorInfo = any.unpack(ErrorInfo.class); + logger.info("Reason:" + errorInfo.getReason()); + logger.info("Domain:" + errorInfo.getDomain()); + logger.info("Insert Token:" + errorInfo.getMetadataMap() + .get("insertToken")); + } catch (InvalidProtocolBufferException e) { + logger.error(e.getMessage()); + } + } + } + break; + default: + logger.info("Unknow message case"); + } + } + + @Override + public void onCompleted() { + logger.info("Finished getBidirectionalCommodityPriceLists"); + finishLatch.countDown(); + } + + @Override + public void onError(Throwable t) { + logger.error("getBidirectionalCommodityPriceLists Failed:" + Status.fromThrowable(t)); + finishLatch.countDown(); + } + }; + StreamObserver requestObserver = nonBlockingStub.bidirectionalListOfPrices(responseObserver); + try { + for (int i = 1; i <= 2; i++) { + Commodity request = Commodity.newBuilder() + .setCommodityName("Commodity" + i) + .setAccessToken(i + "23validToken") + .build(); + logger.info("REQUEST - commodity:" + request.getCommodityName()); + requestObserver.onNext(request); + Thread.sleep(200); + if (finishLatch.getCount() == 0) { + return; + } + } + } catch (RuntimeException e) { + requestObserver.onError(e); + throw e; + } + requestObserver.onCompleted(); + + if (!finishLatch.await(1, TimeUnit.MINUTES)) { + logger.info("getBidirectionalCommodityPriceLists can not finish within 1 minute"); + } + } + + public static void main(String[] args) throws InterruptedException, InvalidProtocolBufferException { + + String target = "localhost:8980"; + if (args.length > 0) { + target = args[0]; + } + + ManagedChannel channel = ManagedChannelBuilder.forTarget(target) + .usePlaintext() + .build(); + try { + CommodityClient client = new CommodityClient(channel); + + client.getBidirectionalCommodityPriceLists(); + + } finally { + channel.shutdownNow() + .awaitTermination(5, TimeUnit.SECONDS); + } + } +} diff --git a/grpc/src/main/java/com/baeldung/grpc/errorhandling/CommodityServer.java b/grpc/src/main/java/com/baeldung/grpc/errorhandling/CommodityServer.java new file mode 100644 index 0000000000..567c0815e5 --- /dev/null +++ b/grpc/src/main/java/com/baeldung/grpc/errorhandling/CommodityServer.java @@ -0,0 +1,182 @@ +package com.baeldung.grpc.errorhandling; + +import java.io.IOException; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ThreadLocalRandom; +import java.util.concurrent.TimeUnit; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.protobuf.Any; +import com.google.rpc.Code; +import com.google.rpc.ErrorInfo; + +import io.grpc.Metadata; +import io.grpc.Server; +import io.grpc.ServerBuilder; +import io.grpc.Status; +import io.grpc.protobuf.ProtoUtils; +import io.grpc.protobuf.StatusProto; +import io.grpc.stub.StreamObserver; + +public class CommodityServer { + + private static final Logger logger = LoggerFactory.getLogger(CommodityServer.class.getName()); + private final int port; + private final Server server; + private static Map commodityLookupBasePrice; + static { + commodityLookupBasePrice = new ConcurrentHashMap<>(); + commodityLookupBasePrice.put("Commodity1", 5.0); + commodityLookupBasePrice.put("Commodity2", 6.0); + } + + public static void main(String[] args) throws Exception { + + CommodityServer commodityServer = new CommodityServer(8980); + commodityServer.start(); + if (commodityServer.server != null) { + commodityServer.server.awaitTermination(); + } + } + + public CommodityServer(int port) throws IOException { + this.port = port; + server = ServerBuilder.forPort(port) + .addService(new CommodityService()) + .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 { + CommodityServer.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 class CommodityService extends CommodityPriceProviderGrpc.CommodityPriceProviderImplBase { + + @Override + public void getBestCommodityPrice(Commodity request, StreamObserver responseObserver) { + + if (commodityLookupBasePrice.get(request.getCommodityName()) == null) { + + Metadata.Key errorResponseKey = ProtoUtils.keyForProto(ErrorResponse.getDefaultInstance()); + ErrorResponse errorResponse = ErrorResponse.newBuilder() + .setCommodityName(request.getCommodityName()) + .setAccessToken(request.getAccessToken()) + .setExpectedValue("Only Commodity1, Commodity2 are supported") + .build(); + Metadata metadata = new Metadata(); + metadata.put(errorResponseKey, errorResponse); + responseObserver.onError(Status.INVALID_ARGUMENT.withDescription("The commodity is not supported") + .asRuntimeException(metadata)); + } else if (request.getAccessToken().equals("123validToken") == false) { + + com.google.rpc.Status status = com.google.rpc.Status.newBuilder() + .setCode(Code.NOT_FOUND.getNumber()) + .setMessage("The access token not found") + .addDetails(Any.pack(ErrorInfo.newBuilder() + .setReason("Invalid Token") + .setDomain("com.baeldung.grpc.errorhandling") + .putMetadata("insertToken", "123validToken") + .build())) + .build(); + responseObserver.onError(StatusProto.toStatusRuntimeException(status)); + } else { + CommodityQuote commodityQuote = CommodityQuote.newBuilder() + .setPrice(fetchBestPriceBid(request)) + .setCommodityName(request.getCommodityName()) + .setProducerName("Best Producer with best price") + .build(); + responseObserver.onNext(commodityQuote); + responseObserver.onCompleted(); + } + } + + @Override + public StreamObserver bidirectionalListOfPrices(StreamObserver responseObserver) { + + return new StreamObserver() { + @Override + public void onNext(Commodity request) { + + logger.info("Access token:{}", request.getAccessToken()); + if (request.getAccessToken() + .equals("123validToken") == false) { + + com.google.rpc.Status status = com.google.rpc.Status.newBuilder() + .setCode(Code.NOT_FOUND.getNumber()) + .setMessage("The access token not found") + .addDetails(Any.pack(ErrorInfo.newBuilder() + .setReason("Invalid Token") + .setDomain("com.baeldung.grpc.errorhandling") + .putMetadata("insertToken", "123validToken") + .build())) + .build(); + StreamingCommodityQuote streamingCommodityQuote = StreamingCommodityQuote.newBuilder() + .setStatus(status) + .build(); + responseObserver.onNext(streamingCommodityQuote); + } else { + + for (int i = 1; i <= 5; i++) { + CommodityQuote commodityQuote = CommodityQuote.newBuilder() + .setPrice(fetchProviderPriceBid(request, "producer:" + i)) + .setCommodityName(request.getCommodityName()) + .setProducerName("producer:" + i) + .build(); + StreamingCommodityQuote streamingCommodityQuote = StreamingCommodityQuote.newBuilder() + .setComodityQuote(commodityQuote) + .build(); + responseObserver.onNext(streamingCommodityQuote); + } + } + } + + @Override + public void onCompleted() { + responseObserver.onCompleted(); + } + + @Override + public void onError(Throwable t) { + logger.info("error:{}", t.getMessage()); + } + }; + } + + } + + private static double fetchBestPriceBid(Commodity commodity) { + + return commodityLookupBasePrice.get(commodity.getCommodityName()) + ThreadLocalRandom.current() + .nextDouble(-0.2d, 0.2d); + } + + private static double fetchProviderPriceBid(Commodity commodity, String providerName) { + + return commodityLookupBasePrice.get(commodity.getCommodityName()) + providerName.length() + ThreadLocalRandom.current() + .nextDouble(-0.2d, 0.2d); + } +} 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..e2b670458e --- /dev/null +++ b/grpc/src/main/java/com/baeldung/grpc/streaming/StockClient.java @@ -0,0 +1,176 @@ +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 org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +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 = LoggerFactory.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() { + + logger.info("######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 { + logger.info("REQUEST - ticker symbol {}", request.getTickerSymbol()); + stockQuotes = blockingStub.serverSideStreamingGetListStockQuotes(request); + for (int i = 1; stockQuotes.hasNext(); i++) { + StockQuote stockQuote = stockQuotes.next(); + logger.info("RESPONSE - Price #" + i + ": {}", stockQuote.getPrice()); + } + } catch (StatusRuntimeException e) { + logger.info("RPC failed: {}", e.getStatus()); + } + } + + public void clientSideStreamingGetStatisticsOfStocks() throws InterruptedException { + + logger.info("######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) { + logger.info("RESPONSE, got stock statistics - Average Price: {}, description: {}", summary.getPrice(), summary.getDescription()); + } + + @Override + public void onCompleted() { + logger.info("Finished clientSideStreamingGetStatisticsOfStocks"); + finishLatch.countDown(); + } + + @Override + public void onError(Throwable t) { + logger.warn("Stock Statistics Failed: {}", Status.fromThrowable(t)); + finishLatch.countDown(); + } + }; + + StreamObserver requestObserver = nonBlockingStub.clientSideStreamingGetStatisticsOfStocks(responseObserver); + try { + + for (Stock stock : stocks) { + logger.info("REQUEST: {}, {}", 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)) { + logger.warn("clientSideStreamingGetStatisticsOfStocks can not finish within 1 minutes"); + } + } + + public void bidirectionalStreamingGetListsStockQuotes() throws InterruptedException{ + + logger.info("#######START EXAMPLE#######: BidirectionalStreaming - getListsStockQuotes from list of stocks"); + final CountDownLatch finishLatch = new CountDownLatch(1); + StreamObserver responseObserver = new StreamObserver() { + @Override + public void onNext(StockQuote stockQuote) { + logger.info("RESPONSE price#{} : {}, description:{}", stockQuote.getOfferNumber(), stockQuote.getPrice(), stockQuote.getDescription()); + } + + @Override + public void onCompleted() { + logger.info("Finished bidirectionalStreamingGetListsStockQuotes"); + finishLatch.countDown(); + } + + @Override + public void onError(Throwable t) { + logger.warn("bidirectionalStreamingGetListsStockQuotes Failed: {0}", Status.fromThrowable(t)); + finishLatch.countDown(); + } + }; + StreamObserver requestObserver = nonBlockingStub.bidirectionalStreamingGetListsStockQuotes(responseObserver); + try { + for (Stock stock : stocks) { + logger.info("REQUEST: {}, {}", 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)) { + logger.warn("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()); + } +} 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..952c9f26fd --- /dev/null +++ b/grpc/src/main/java/com/baeldung/grpc/streaming/StockServer.java @@ -0,0 +1,148 @@ +package com.baeldung.grpc.streaming; + +import java.io.IOException; +import java.util.concurrent.ThreadLocalRandom; +import java.util.concurrent.TimeUnit; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.grpc.Server; +import io.grpc.ServerBuilder; +import io.grpc.stub.StreamObserver; + +public class StockServer { + + private static final Logger logger = LoggerFactory.getLogger(StockClient.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.warn("error:{}", 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.warn("error:{}", 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/commodity_price.proto b/grpc/src/main/proto/commodity_price.proto new file mode 100644 index 0000000000..c5d6247df5 --- /dev/null +++ b/grpc/src/main/proto/commodity_price.proto @@ -0,0 +1,42 @@ +syntax = "proto3"; + +import "google/rpc/status.proto"; + +package commodityprice; + +option java_multiple_files = true; +option java_package = "com.baeldung.grpc.errorhandling"; +option java_outer_classname = "CommodityPriceProto"; +option objc_class_prefix = "RTG"; + +service CommodityPriceProvider { + + rpc getBestCommodityPrice(Commodity) returns (CommodityQuote) {} + + rpc bidirectionalListOfPrices(stream Commodity) returns (stream StreamingCommodityQuote) {} +} + +message Commodity { + string access_token = 1; + string commodity_name = 2; +} + +message CommodityQuote { + string commodity_name = 1; + string producer_name = 2; + double price = 3; +} + +message ErrorResponse { + string commodity_name = 1; + string access_token = 2; + string expected_token = 3; + string expected_value = 4; +} + +message StreamingCommodityQuote{ + oneof message{ + CommodityQuote comodity_quote = 1; + google.rpc.Status status = 2; + } +} diff --git a/grpc/src/main/proto/google/protobuf/any.proto b/grpc/src/main/proto/google/protobuf/any.proto new file mode 100644 index 0000000000..1c6a465c72 --- /dev/null +++ b/grpc/src/main/proto/google/protobuf/any.proto @@ -0,0 +1,158 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto3"; + +package google.protobuf; + +option csharp_namespace = "Google.Protobuf.WellKnownTypes"; +option go_package = "google.golang.org/protobuf/types/known/anypb"; +option java_package = "com.google.protobuf"; +option java_outer_classname = "AnyProto"; +option java_multiple_files = true; +option objc_class_prefix = "GPB"; + +// `Any` contains an arbitrary serialized protocol buffer message along with a +// URL that describes the type of the serialized message. +// +// Protobuf library provides support to pack/unpack Any values in the form +// of utility functions or additional generated methods of the Any type. +// +// Example 1: Pack and unpack a message in C++. +// +// Foo foo = ...; +// Any any; +// any.PackFrom(foo); +// ... +// if (any.UnpackTo(&foo)) { +// ... +// } +// +// Example 2: Pack and unpack a message in Java. +// +// Foo foo = ...; +// Any any = Any.pack(foo); +// ... +// if (any.is(Foo.class)) { +// foo = any.unpack(Foo.class); +// } +// +// Example 3: Pack and unpack a message in Python. +// +// foo = Foo(...) +// any = Any() +// any.Pack(foo) +// ... +// if any.Is(Foo.DESCRIPTOR): +// any.Unpack(foo) +// ... +// +// Example 4: Pack and unpack a message in Go +// +// foo := &pb.Foo{...} +// any, err := anypb.New(foo) +// if err != nil { +// ... +// } +// ... +// foo := &pb.Foo{} +// if err := any.UnmarshalTo(foo); err != nil { +// ... +// } +// +// The pack methods provided by protobuf library will by default use +// 'type.googleapis.com/full.type.name' as the type URL and the unpack +// methods only use the fully qualified type name after the last '/' +// in the type URL, for example "foo.bar.com/x/y.z" will yield type +// name "y.z". +// +// +// JSON +// ==== +// The JSON representation of an `Any` value uses the regular +// representation of the deserialized, embedded message, with an +// additional field `@type` which contains the type URL. Example: +// +// package google.profile; +// message Person { +// string first_name = 1; +// string last_name = 2; +// } +// +// { +// "@type": "type.googleapis.com/google.profile.Person", +// "firstName": , +// "lastName": +// } +// +// If the embedded message type is well-known and has a custom JSON +// representation, that representation will be embedded adding a field +// `value` which holds the custom JSON in addition to the `@type` +// field. Example (for message [google.protobuf.Duration][]): +// +// { +// "@type": "type.googleapis.com/google.protobuf.Duration", +// "value": "1.212s" +// } +// +message Any { + // A URL/resource name that uniquely identifies the type of the serialized + // protocol buffer message. This string must contain at least + // one "/" character. The last segment of the URL's path must represent + // the fully qualified name of the type (as in + // `path/google.protobuf.Duration`). The name should be in a canonical form + // (e.g., leading "." is not accepted). + // + // In practice, teams usually precompile into the binary all types that they + // expect it to use in the context of Any. However, for URLs which use the + // scheme `http`, `https`, or no scheme, one can optionally set up a type + // server that maps type URLs to message definitions as follows: + // + // * If no scheme is provided, `https` is assumed. + // * An HTTP GET on the URL must yield a [google.protobuf.Type][] + // value in binary format, or produce an error. + // * Applications are allowed to cache lookup results based on the + // URL, or have them precompiled into a binary to avoid any + // lookup. Therefore, binary compatibility needs to be preserved + // on changes to types. (Use versioned type names to manage + // breaking changes.) + // + // Note: this functionality is not currently available in the official + // protobuf release, and it is not used for type URLs beginning with + // type.googleapis.com. + // + // Schemes other than `http`, `https` (or the empty scheme) might be + // used with implementation specific semantics. + // + string type_url = 1; + + // Must be a valid serialized protocol buffer of the above specified type. + bytes value = 2; +} \ No newline at end of file diff --git a/grpc/src/main/proto/google/rpc/status.proto b/grpc/src/main/proto/google/rpc/status.proto new file mode 100644 index 0000000000..5bd51aa2f3 --- /dev/null +++ b/grpc/src/main/proto/google/rpc/status.proto @@ -0,0 +1,47 @@ +// Copyright 2020 Google LLC +// +// Licensed 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. + +syntax = "proto3"; + +package google.rpc; + +import "google/protobuf/any.proto"; + +option cc_enable_arenas = true; +option go_package = "google.golang.org/genproto/googleapis/rpc/status;status"; +option java_multiple_files = true; +option java_outer_classname = "StatusProto"; +option java_package = "com.google.rpc"; +option objc_class_prefix = "RPC"; + +// The `Status` type defines a logical error model that is suitable for +// different programming environments, including REST APIs and RPC APIs. It is +// used by [gRPC](https://github.com/grpc). Each `Status` message contains +// three pieces of data: error code, error message, and error details. +// +// You can find out more about this error model and how to work with it in the +// [API Design Guide](https://cloud.google.com/apis/design/errors). +message Status { + // The status code, which should be an enum value of [google.rpc.Code][google.rpc.Code]. + int32 code = 1; + + // A developer-facing error message, which should be in English. Any + // user-facing error message should be localized and sent in the + // [google.rpc.Status.details][google.rpc.Status.details] field, or localized by the client. + string message = 2; + + // A list of messages that carry the error details. There is a common set of + // message types for APIs to use. + repeated google.protobuf.Any details = 3; +} \ 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..b1197886ee --- /dev/null +++ b/grpc/src/main/proto/stock_quote.proto @@ -0,0 +1,29 @@ +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"; + +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/grpc/src/test/java/com/baeldung/grpc/errorhandling/CommodityServerUnitTest.java b/grpc/src/test/java/com/baeldung/grpc/errorhandling/CommodityServerUnitTest.java new file mode 100644 index 0000000000..7148831e51 --- /dev/null +++ b/grpc/src/test/java/com/baeldung/grpc/errorhandling/CommodityServerUnitTest.java @@ -0,0 +1,102 @@ +package com.baeldung.grpc.errorhandling; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import org.junit.Rule; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import com.baeldung.grpc.errorhandling.CommodityServer.CommodityService; +import com.google.protobuf.Any; +import com.google.rpc.Code; +import com.google.rpc.ErrorInfo; + +import io.grpc.Metadata; +import io.grpc.Status; +import io.grpc.StatusRuntimeException; +import io.grpc.inprocess.InProcessChannelBuilder; +import io.grpc.inprocess.InProcessServerBuilder; +import io.grpc.protobuf.ProtoUtils; +import io.grpc.protobuf.StatusProto; +import io.grpc.testing.GrpcCleanupRule; + +public class CommodityServerUnitTest { + + CommodityPriceProviderGrpc.CommodityPriceProviderBlockingStub blockingStub; + + @Rule + public final GrpcCleanupRule grpcCleanup = new GrpcCleanupRule(); + + @BeforeEach + public void setup() throws Exception{ + + String serverName = InProcessServerBuilder.generateName(); + + grpcCleanup.register(InProcessServerBuilder.forName(serverName) + .directExecutor() + .addService(new CommodityService()) + .build() + .start()); + + blockingStub = CommodityPriceProviderGrpc.newBlockingStub(grpcCleanup.register(InProcessChannelBuilder.forName(serverName) + .directExecutor() + .build())); + } + + @Test + public void whenUsingValidRequest_thenReturnResponse() throws Exception { + + CommodityQuote reply = blockingStub.getBestCommodityPrice(Commodity.newBuilder() + .setCommodityName("Commodity1") + .setAccessToken("123validToken") + .build()); + + assertEquals("Commodity1", reply.getCommodityName()); + } + + @Test + public void whenUsingInvalidRequestToken_thenReturnExceptionGoogleRPCStatus() throws Exception { + + Commodity request = Commodity.newBuilder() + .setAccessToken("invalidToken") + .setCommodityName("Commodity1") + .build(); + + StatusRuntimeException thrown = Assertions.assertThrows(StatusRuntimeException.class, () -> blockingStub.getBestCommodityPrice(request)); + + com.google.rpc.Status status = StatusProto.fromThrowable(thrown); + assertNotNull(status); + assertEquals("NOT_FOUND", Code.forNumber(status.getCode()).toString()); + assertEquals("The access token not found", status.getMessage()); + for (Any any : status.getDetailsList()) { + if (any.is(ErrorInfo.class)) { + ErrorInfo errorInfo = any.unpack(ErrorInfo.class); + assertEquals("Invalid Token", errorInfo.getReason()); + assertEquals("com.baeldung.grpc.errorhandling", errorInfo.getDomain()); + assertEquals("123validToken", errorInfo.getMetadataMap().get("insertToken")); + } + } + } + + @Test + public void whenUsingInvalidCommodityName_thenReturnExceptionIoRpcStatus() throws Exception { + + Commodity request = Commodity.newBuilder() + .setAccessToken("123validToken") + .setCommodityName("Commodity5") + .build(); + + StatusRuntimeException thrown = Assertions.assertThrows(StatusRuntimeException.class, () -> blockingStub.getBestCommodityPrice(request)); + + assertEquals("INVALID_ARGUMENT", thrown.getStatus().getCode().toString()); + assertEquals("INVALID_ARGUMENT: The commodity is not supported", thrown.getMessage()); + Metadata metadata = Status.trailersFromThrowable(thrown); + ErrorResponse errorResponse = metadata.get(ProtoUtils.keyForProto(ErrorResponse.getDefaultInstance())); + assertEquals("Commodity5",errorResponse.getCommodityName()); + assertEquals("123validToken", errorResponse.getAccessToken()); + assertEquals("Only Commodity1, Commodity2 are supported", errorResponse.getExpectedValue()); + } + +} 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/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 index 6f72b5e70b..b315b2f626 100644 --- a/maven-modules/maven-parent-pom-resolution/README.md +++ b/maven-modules/maven-parent-pom-resolution/README.md @@ -1,3 +1,3 @@ ### Relevant Articles: -- [Understanding the "relativePath" Tag - Maven Parent POM Resolution At A Glance](https://www.baeldung.com/maven-relativepath) +- [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 index 01b522748f..e1f411db2f 100644 --- a/maven-modules/maven-parent-pom-resolution/aggregator/module1/pom.xml +++ b/maven-modules/maven-parent-pom-resolution/aggregator/module1/pom.xml @@ -4,12 +4,13 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 module1 + pom + com.baeldung.maven-parent-pom-resolution aggregator 1.0.0-SNAPSHOT - pom 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 index da0193be10..d983f35e3e 100644 --- a/maven-modules/maven-parent-pom-resolution/aggregator/module2/module3/pom.xml +++ b/maven-modules/maven-parent-pom-resolution/aggregator/module2/module3/pom.xml @@ -4,6 +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 module3 + pom + com.baeldung.maven-parent-pom-resolution aggregator @@ -12,6 +14,5 @@ ../../pom.xml - pom diff --git a/maven-modules/maven-parent-pom-resolution/aggregator/module2/pom.xml b/maven-modules/maven-parent-pom-resolution/aggregator/module2/pom.xml index bf9c89ecf4..48c1ebab9d 100644 --- a/maven-modules/maven-parent-pom-resolution/aggregator/module2/pom.xml +++ b/maven-modules/maven-parent-pom-resolution/aggregator/module2/pom.xml @@ -4,6 +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 module2 + pom + com.baeldung.maven-parent-pom-resolution module1 @@ -11,7 +13,6 @@ ../module1/pom.xml - pom module3 diff --git a/maven-modules/maven-parent-pom-resolution/aggregator/pom.xml b/maven-modules/maven-parent-pom-resolution/aggregator/pom.xml index 0067dfc009..8f6e3453a5 100644 --- a/maven-modules/maven-parent-pom-resolution/aggregator/pom.xml +++ b/maven-modules/maven-parent-pom-resolution/aggregator/pom.xml @@ -5,13 +5,14 @@ 4.0.0 com.baeldung.maven-parent-pom-resolution aggregator + pom + com.baeldung maven-parent-pom-resolution 1.0.0-SNAPSHOT - pom module1 diff --git a/maven-modules/maven-parent-pom-resolution/pom.xml b/maven-modules/maven-parent-pom-resolution/pom.xml index d5a96c0998..e5340032b7 100644 --- a/maven-modules/maven-parent-pom-resolution/pom.xml +++ b/maven-modules/maven-parent-pom-resolution/pom.xml @@ -25,4 +25,4 @@ - + \ 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 fe3bbd2653..3f87c60406 100644 --- a/maven-modules/pom.xml +++ b/maven-modules/pom.xml @@ -37,6 +37,7 @@ 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/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-exceptions/src/main/java/com/baeldung/hibernate/exception/transientobject/HibernateUtil.java b/persistence-modules/hibernate-exceptions/src/main/java/com/baeldung/hibernate/exception/transientobject/HibernateUtil.java new file mode 100644 index 0000000000..a40279661f --- /dev/null +++ b/persistence-modules/hibernate-exceptions/src/main/java/com/baeldung/hibernate/exception/transientobject/HibernateUtil.java @@ -0,0 +1,51 @@ +package com.baeldung.hibernate.exception.transientobject; + +import java.util.Properties; + +import com.baeldung.hibernate.exception.transientobject.entity.Address; +import com.baeldung.hibernate.exception.transientobject.entity.Department; +import com.baeldung.hibernate.exception.transientobject.entity.Author; +import com.baeldung.hibernate.exception.transientobject.entity.Book; +import com.baeldung.hibernate.exception.transientobject.entity.Employee; +import com.baeldung.hibernate.exception.transientobject.entity.User; +import org.hibernate.SessionFactory; +import org.hibernate.boot.registry.StandardServiceRegistryBuilder; +import org.hibernate.cfg.Configuration; +import org.hibernate.cfg.Environment; +import org.hibernate.service.ServiceRegistry; + +public class HibernateUtil { + private static SessionFactory sessionFactory; + + public static SessionFactory getSessionFactory() { + if (sessionFactory == null) { + try { + Configuration configuration = new Configuration(); + Properties settings = new Properties(); + settings.put(Environment.DRIVER, "org.hsqldb.jdbcDriver"); + settings.put(Environment.URL, "jdbc:hsqldb:mem:transient"); + settings.put(Environment.USER, "sa"); + settings.put(Environment.PASS, ""); + settings.put(Environment.DIALECT, "org.hibernate.dialect.HSQLDialect"); + settings.put(Environment.SHOW_SQL, "true"); + settings.put(Environment.USE_SQL_COMMENTS, "true"); + settings.put(Environment.HBM2DDL_AUTO, "update"); + configuration.setProperties(settings); + configuration.addAnnotatedClass(User.class); + configuration.addAnnotatedClass(Address.class); + configuration.addAnnotatedClass(Department.class); + configuration.addAnnotatedClass(Employee.class); + configuration.addAnnotatedClass(Book.class); + configuration.addAnnotatedClass(Author.class); + + + ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder() + .applySettings(configuration.getProperties()).build(); + sessionFactory = configuration.buildSessionFactory(serviceRegistry); + } catch (Exception e) { + e.printStackTrace(); + } + } + return sessionFactory; + } +} \ No newline at end of file diff --git a/persistence-modules/hibernate-exceptions/src/main/java/com/baeldung/hibernate/exception/transientobject/entity/Address.java b/persistence-modules/hibernate-exceptions/src/main/java/com/baeldung/hibernate/exception/transientobject/entity/Address.java new file mode 100644 index 0000000000..e450fc3c18 --- /dev/null +++ b/persistence-modules/hibernate-exceptions/src/main/java/com/baeldung/hibernate/exception/transientobject/entity/Address.java @@ -0,0 +1,74 @@ +package com.baeldung.hibernate.exception.transientobject.entity; + +import java.io.Serializable; +import java.util.HashSet; +import java.util.Set; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.OneToMany; +import javax.persistence.OneToOne; +import javax.persistence.Table; + +@Entity +@Table(name = "address") +public class Address { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + private Long id; + + @Column(name = "city") + private String city; + + @Column(name = "street") + private String street; + + @OneToOne(mappedBy = "address") + private User user; + + public Address() { + } + + public Address(String city, String street) { + this.city = city; + this.street = street; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getCity() { + return city; + } + + public void setCity(String city) { + this.city = city; + } + + public String getStreet() { + return street; + } + + public void setStreet(String street) { + this.street = street; + } + + public User getUser() { + return user; + } + + public void setUser(User user) { + this.user = user; + } +} \ No newline at end of file diff --git a/persistence-modules/hibernate-exceptions/src/main/java/com/baeldung/hibernate/exception/transientobject/entity/Author.java b/persistence-modules/hibernate-exceptions/src/main/java/com/baeldung/hibernate/exception/transientobject/entity/Author.java new file mode 100644 index 0000000000..f1a88daa36 --- /dev/null +++ b/persistence-modules/hibernate-exceptions/src/main/java/com/baeldung/hibernate/exception/transientobject/entity/Author.java @@ -0,0 +1,71 @@ +package com.baeldung.hibernate.exception.transientobject.entity; + +import org.hibernate.annotations.Cascade; +import org.hibernate.annotations.CascadeType; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToMany; +import javax.persistence.ManyToOne; +import javax.persistence.Table; +import java.util.HashSet; +import java.util.Set; + +@Entity +@Table(name = "author") +public class Author { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + private int id; + + @Column(name = "name") + private String name; + + @ManyToMany + @Cascade({ CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.PERSIST}) + @JoinColumn(name = "book_id") + private Set books = new HashSet<>(); + + public void addBook(Book book) { + books.add(book); + } + + // standard getters and setters + + public Author() { + } + + public Author(String name) { + this.name = name; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Set getBooks() { + return books; + } + + public void setBooks(Set books) { + this.books = books; + } +} diff --git a/persistence-modules/hibernate-exceptions/src/main/java/com/baeldung/hibernate/exception/transientobject/entity/Book.java b/persistence-modules/hibernate-exceptions/src/main/java/com/baeldung/hibernate/exception/transientobject/entity/Book.java new file mode 100644 index 0000000000..91728430ea --- /dev/null +++ b/persistence-modules/hibernate-exceptions/src/main/java/com/baeldung/hibernate/exception/transientobject/entity/Book.java @@ -0,0 +1,72 @@ +package com.baeldung.hibernate.exception.transientobject.entity; + + +import org.hibernate.annotations.Cascade; +import org.hibernate.annotations.CascadeType; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToMany; +import javax.persistence.OneToMany; +import javax.persistence.Table; +import java.util.HashSet; +import java.util.Set; + +@Entity +@Table(name = "book") +public class Book { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + private int id; + + @Column(name = "title") + private String title; + + @ManyToMany + @Cascade({ CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.PERSIST}) + @JoinColumn(name = "author_id") + private Set authors = new HashSet<>(); + + public void addAuthor(Author author) { + authors.add(author); + } + + // standard getters and setters + + public Book() { + } + + public Book(String title) { + this.title = title; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public Set getAuthors() { + return authors; + } + + public void setAuthors(Set authors) { + this.authors = authors; + } +} diff --git a/persistence-modules/hibernate-exceptions/src/main/java/com/baeldung/hibernate/exception/transientobject/entity/Department.java b/persistence-modules/hibernate-exceptions/src/main/java/com/baeldung/hibernate/exception/transientobject/entity/Department.java new file mode 100644 index 0000000000..4b8fa69964 --- /dev/null +++ b/persistence-modules/hibernate-exceptions/src/main/java/com/baeldung/hibernate/exception/transientobject/entity/Department.java @@ -0,0 +1,70 @@ +package com.baeldung.hibernate.exception.transientobject.entity; + +import javax.persistence.CascadeType; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.OneToMany; +import javax.persistence.Table; +import java.util.HashSet; +import java.util.Set; + +@Entity +@Table(name = "department") +public class Department { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + private int id; + + @Column(name = "name") + private String name; + + @OneToMany(mappedBy = "department", cascade = CascadeType.ALL, orphanRemoval = true) + private Set employees = new HashSet<>(); + + public void addEmployee(Employee employee) { + employees.add(employee); + } + + // standard getters and setters + + public Department() { + } + + public Department(int id) { + this.id = id; + } + + public Department(int id, String name) { + this.id = id; + this.name = name; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Set getEmployees() { + return employees; + } + + public void setEmployees(Set employees) { + this.employees = employees; + } +} diff --git a/persistence-modules/hibernate-exceptions/src/main/java/com/baeldung/hibernate/exception/transientobject/entity/Employee.java b/persistence-modules/hibernate-exceptions/src/main/java/com/baeldung/hibernate/exception/transientobject/entity/Employee.java new file mode 100644 index 0000000000..56443cce70 --- /dev/null +++ b/persistence-modules/hibernate-exceptions/src/main/java/com/baeldung/hibernate/exception/transientobject/entity/Employee.java @@ -0,0 +1,66 @@ +package com.baeldung.hibernate.exception.transientobject.entity; + + +import org.hibernate.annotations.Cascade; +import org.hibernate.annotations.CascadeType; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.Table; + +@Entity +@Table(name = "employee") +public class Employee { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + private int id; + + @Column(name = "name") + private String name; + + @ManyToOne + @Cascade(CascadeType.SAVE_UPDATE) + @JoinColumn(name = "department_id") + private Department department; + + // standard getters and setters + + public Employee() { + } + + public Employee(String name) { + this.name = name; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Department getDepartment() { + return department; + } + + public void setDepartment(Department department) { + this.department = department; + } +} diff --git a/persistence-modules/hibernate-exceptions/src/main/java/com/baeldung/hibernate/exception/transientobject/entity/User.java b/persistence-modules/hibernate-exceptions/src/main/java/com/baeldung/hibernate/exception/transientobject/entity/User.java new file mode 100644 index 0000000000..eff1a88b51 --- /dev/null +++ b/persistence-modules/hibernate-exceptions/src/main/java/com/baeldung/hibernate/exception/transientobject/entity/User.java @@ -0,0 +1,76 @@ +package com.baeldung.hibernate.exception.transientobject.entity; + +import java.io.Serializable; +import java.util.HashSet; +import java.util.Set; + +import javax.persistence.CascadeType; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.OneToMany; +import javax.persistence.OneToOne; +import javax.persistence.Table; + +@Entity +@Table(name = "user") +public class User { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + private int id; + + @Column(name = "first_name") + private String firstName; + + @Column(name = "last_name") + private String lastName; + + @OneToOne(cascade = CascadeType.ALL) + @JoinColumn(name = "address_id", referencedColumnName = "id") + private Address address; + + public User() { + } + + public User(String firstName, String lastName) { + this.firstName = firstName; + this.lastName = lastName; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + public Address getAddress() { + return address; + } + + public void setAddress(Address address) { + this.address = address; + } +} diff --git a/persistence-modules/hibernate-exceptions/src/test/java/com/baeldung/hibernate/exception/transientobject/HibernateTransientObjectUnitTest.java b/persistence-modules/hibernate-exceptions/src/test/java/com/baeldung/hibernate/exception/transientobject/HibernateTransientObjectUnitTest.java new file mode 100644 index 0000000000..3f6d0effa9 --- /dev/null +++ b/persistence-modules/hibernate-exceptions/src/test/java/com/baeldung/hibernate/exception/transientobject/HibernateTransientObjectUnitTest.java @@ -0,0 +1,84 @@ +package com.baeldung.hibernate.exception.transientobject; + +import com.baeldung.hibernate.exception.transientobject.entity.Address; +import com.baeldung.hibernate.exception.transientobject.entity.Department; +import com.baeldung.hibernate.exception.transientobject.entity.Author; +import com.baeldung.hibernate.exception.transientobject.entity.Book; +import com.baeldung.hibernate.exception.transientobject.entity.Employee; +import com.baeldung.hibernate.exception.transientobject.entity.User; +import org.hibernate.Session; +import org.hibernate.SessionFactory; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +public class HibernateTransientObjectUnitTest { + + private static SessionFactory sessionFactory; + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + @BeforeClass + public static void init() { + sessionFactory = HibernateUtil.getSessionFactory(); + } + + @Test + public void whenSaveEntitiesWithOneToOneAssociation_thenSuccess() { + User user = new User("Bob", "Smith"); + Address address = new Address("London", "221b Baker Street"); + user.setAddress(address); + Session session = sessionFactory.openSession(); + session.beginTransaction(); + session.save(user); + session.getTransaction().commit(); + session.close(); + } + + @Test + public void whenSaveEntitiesWithOneToManyAssociation_thenSuccess() { + Department department = new Department(); + department.setName("IT Support"); + Employee employee = new Employee("John Doe"); + employee.setDepartment(department); + Session session = sessionFactory.openSession(); + session.beginTransaction(); + session.save(employee); + session.getTransaction().commit(); + session.close(); + } + + @Test + public void whenSaveEntitiesWithManyToManyAssociation_thenSuccess_1() { + Book book = new Book("Design Patterns: Elements of Reusable Object-Oriented Software"); + book.addAuthor(new Author("Erich Gamma")); + book.addAuthor(new Author("John Vlissides")); + book.addAuthor(new Author("Richard Helm")); + book.addAuthor(new Author("Ralph Johnson")); + Session session = sessionFactory.openSession(); + session.beginTransaction(); + session.save(book); + session.getTransaction().commit(); + session.close(); + } + + @Test + public void whenSaveEntitiesWithManyToManyAssociation_thenSuccess_2() { + Author author = new Author("Erich Gamma"); + author.addBook(new Book("Design Patterns: Elements of Reusable Object-Oriented Software")); + author.addBook(new Book("Introduction to Object Orient Design in C")); + Session session = sessionFactory.openSession(); + session.beginTransaction(); + session.save(author); + session.getTransaction().commit(); + session.close(); + } + + @AfterClass + public static void cleanUp() { + sessionFactory.close(); + } +} 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 d517c55d7a..202c97a830 100644 --- a/persistence-modules/java-jpa-3/README.md +++ b/persistence-modules/java-jpa-3/README.md @@ -14,3 +14,4 @@ This module contains articles about the Java Persistence API (JPA) in Java. - [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-arangodb/src/live-test/resources/Dockerfile b/persistence-modules/spring-data-arangodb/src/live-test/resources/Dockerfile index 8edb2bbbf6..6380d312a0 100644 --- a/persistence-modules/spring-data-arangodb/src/live-test/resources/Dockerfile +++ b/persistence-modules/spring-data-arangodb/src/live-test/resources/Dockerfile @@ -2,6 +2,10 @@ FROM arangodb:3.8.0 COPY init-session.js /docker-entrypoint-initdb.d/ +COPY arangodb-setup.js /setup/ + EXPOSE 8529 ENV ARANGO_ROOT_PASSWORD=password + +RUN chmod a+x /setup/arangodb-setup.js \ No newline at end of file diff --git a/persistence-modules/spring-data-arangodb/src/live-test/resources/arangodb-setup.js b/persistence-modules/spring-data-arangodb/src/live-test/resources/arangodb-setup.js new file mode 100644 index 0000000000..0c306ee5d5 --- /dev/null +++ b/persistence-modules/spring-data-arangodb/src/live-test/resources/arangodb-setup.js @@ -0,0 +1,4 @@ +#!/usr/bin/arangosh --javascript.execute + +print('creating database: baeldung-database & user: baeldung'); +db._createDatabase("baeldung-database", {}, [{ username: "baeldung", passwd: "password", active: true}]); \ No newline at end of file diff --git a/persistence-modules/spring-data-arangodb/src/live-test/resources/live-test-setup.sh b/persistence-modules/spring-data-arangodb/src/live-test/resources/live-test-setup.sh index b1a4cfb9d0..7f75fbd821 100644 --- a/persistence-modules/spring-data-arangodb/src/live-test/resources/live-test-setup.sh +++ b/persistence-modules/spring-data-arangodb/src/live-test/resources/live-test-setup.sh @@ -3,3 +3,5 @@ docker image build -t spring-data-arangodb:live-test . docker run -p 8529:8529 -e ARANGO_ROOT_PASSWORD=password --name spring-data-arangodb-live-test spring-data-arangodb:live-test + +docker exec spring-data-arangodb-live-test arangosh --server.password password --javascript.execute /setup/arangodb-setup.js \ No newline at end of file diff --git a/persistence-modules/spring-data-arangodb/src/main/java/com/baeldung/arangodb/configuration/ArangoDbConfiguration.java b/persistence-modules/spring-data-arangodb/src/main/java/com/baeldung/arangodb/configuration/ArangoDbConfiguration.java index 3aae10ce60..0042172ad6 100644 --- a/persistence-modules/spring-data-arangodb/src/main/java/com/baeldung/arangodb/configuration/ArangoDbConfiguration.java +++ b/persistence-modules/spring-data-arangodb/src/main/java/com/baeldung/arangodb/configuration/ArangoDbConfiguration.java @@ -13,7 +13,7 @@ public class ArangoDbConfiguration implements ArangoConfiguration { public ArangoDB.Builder arango() { return new ArangoDB.Builder() .host("127.0.0.1", 8529) - .user("root") + .user("baeldung") .password("password"); } diff --git a/persistence-modules/spring-data-arangodb/src/main/resources/arangodb.properties b/persistence-modules/spring-data-arangodb/src/main/resources/arangodb.properties index 7f8ded478c..2a6e667ecc 100644 --- a/persistence-modules/spring-data-arangodb/src/main/resources/arangodb.properties +++ b/persistence-modules/spring-data-arangodb/src/main/resources/arangodb.properties @@ -1,3 +1,3 @@ arangodb.hosts=127.0.0.1:8529 -arangodb.user=root +arangodb.user=baeldung arangodb.password=password \ No newline at end of file diff --git a/persistence-modules/spring-data-arangodb/src/test/java/com/baeldung/arangodb/ArticleRepositoryLiveTest.java b/persistence-modules/spring-data-arangodb/src/test/java/com/baeldung/arangodb/ArticleRepositoryLiveTest.java index 35232766ab..401e3393e8 100644 --- a/persistence-modules/spring-data-arangodb/src/test/java/com/baeldung/arangodb/ArticleRepositoryLiveTest.java +++ b/persistence-modules/spring-data-arangodb/src/test/java/com/baeldung/arangodb/ArticleRepositoryLiveTest.java @@ -2,6 +2,7 @@ package com.baeldung.arangodb; import com.baeldung.arangodb.model.Article; import com.baeldung.arangodb.repository.ArticleRepository; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; @@ -25,6 +26,11 @@ public class ArticleRepositoryLiveTest { @Autowired ArticleRepository articleRepository; + @AfterEach + public void tearDown(){ + articleRepository.deleteAll(); + } + @Test public void givenNewArticle_whenSaveInArangoDb_thenDataIsCorrect() { Article newArticle = new Article( 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 4fbdb87785..0d80fc8b92 100644 --- a/persistence-modules/spring-data-mongodb-reactive/README.md +++ b/persistence-modules/spring-data-mongodb-reactive/README.md @@ -7,4 +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) +- [Spring Data MongoDB Tailable Cursors](https://www.baeldung.com/spring-data-mongodb-tailable-cursors) \ No newline at end of file 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 + 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 + 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 + 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/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/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-basics/pom.xml b/spring-web-modules/spring-mvc-basics/pom.xml index 9fe4494393..a91f4004ff 100644 --- a/spring-web-modules/spring-mvc-basics/pom.xml +++ b/spring-web-modules/spring-mvc-basics/pom.xml @@ -33,7 +33,6 @@ org.apache.tomcat.embed tomcat-embed-jasper - provided javax.servlet diff --git a/spring-web-modules/spring-mvc-basics/src/main/java/com/baeldung/spring/web/config/WebConfig.java b/spring-web-modules/spring-mvc-basics/src/main/java/com/baeldung/spring/web/config/WebConfig.java index ac917018b0..e1987f8345 100644 --- a/spring-web-modules/spring-mvc-basics/src/main/java/com/baeldung/spring/web/config/WebConfig.java +++ b/spring-web-modules/spring-mvc-basics/src/main/java/com/baeldung/spring/web/config/WebConfig.java @@ -1,13 +1,11 @@ package com.baeldung.spring.web.config; -import java.io.IOException; - import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.core.io.ClassPathResource; import org.springframework.http.MediaType; import org.springframework.ui.context.support.ResourceBundleThemeSource; import org.springframework.web.multipart.commons.CommonsMultipartResolver; +import org.springframework.web.servlet.View; import org.springframework.web.servlet.ViewResolver; import org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; @@ -17,10 +15,11 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import org.springframework.web.servlet.resource.PathResourceResolver; import org.springframework.web.servlet.theme.CookieThemeResolver; import org.springframework.web.servlet.theme.ThemeChangeInterceptor; +import org.springframework.web.servlet.view.BeanNameViewResolver; import org.springframework.web.servlet.view.InternalResourceViewResolver; import org.springframework.web.servlet.view.JstlView; -import org.springframework.web.servlet.view.ResourceBundleViewResolver; -import org.springframework.web.servlet.view.XmlViewResolver; + +import java.io.IOException; //@EnableWebMvc //@ComponentScan(basePackages = { "com.baeldung.web.controller" }) @@ -93,19 +92,25 @@ public class WebConfig implements WebMvcConfigurer { /** END theme configuration */ @Bean - public ViewResolver resourceBundleViewResolver() { - final ResourceBundleViewResolver bean = new ResourceBundleViewResolver(); - bean.setBasename("views"); - bean.setOrder(0); - return bean; + public BeanNameViewResolver beanNameViewResolver(){ + BeanNameViewResolver beanNameViewResolver = new BeanNameViewResolver(); + beanNameViewResolver.setOrder(1); + return beanNameViewResolver; } @Bean - public ViewResolver xmlViewResolver() { - final XmlViewResolver bean = new XmlViewResolver(); - bean.setLocation(new ClassPathResource("views.xml")); - bean.setOrder(1); - return bean; + public View sample() { + return new JstlView("/WEB-INF/view/sample.jsp"); + } + + @Bean + public View sample2() { + return new JstlView("/WEB-INF/view2/sample2.jsp"); + } + + @Bean + public View sample3(){ + return new JstlView("/WEB-INF/view3/sample3.jsp"); } /** diff --git a/spring-web-modules/spring-mvc-basics/src/main/resources/views.properties b/spring-web-modules/spring-mvc-basics/src/main/resources/views.properties deleted file mode 100644 index 06d042b446..0000000000 --- a/spring-web-modules/spring-mvc-basics/src/main/resources/views.properties +++ /dev/null @@ -1,3 +0,0 @@ -sample2.(class)=org.springframework.web.servlet.view.JstlView -sample2.url=/WEB-INF/view2/sample2.jsp - diff --git a/spring-web-modules/spring-mvc-basics/src/main/resources/views.xml b/spring-web-modules/spring-mvc-basics/src/main/resources/views.xml deleted file mode 100644 index a44d3deae4..0000000000 --- a/spring-web-modules/spring-mvc-basics/src/main/resources/views.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - \ 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-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/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
This is the tutorial to convert html to pdf.
true