diff --git a/apache-kafka/pom.xml b/apache-kafka/pom.xml index 7bde041f32..915583fed8 100644 --- a/apache-kafka/pom.xml +++ b/apache-kafka/pom.xml @@ -35,12 +35,12 @@ org.apache.flink - flink-connector-kafka-0.11_2.11 + flink-connector-kafka ${flink.version} org.apache.flink - flink-streaming-java_2.11 + flink-streaming-java ${flink.version} @@ -67,7 +67,7 @@ org.apache.flink - flink-test-utils_2.11 + flink-test-utils ${flink.version} test @@ -163,11 +163,29 @@ + + + + org.apache.maven.plugins + maven-surefire-plugin + + + --add-opens java.base/java.time=ALL-UNNAMED + --add-opens java.base/java.nio=ALL-UNNAMED + --add-opens java.base/java.util=ALL-UNNAMED + + + + + + + + - 2.8.0 + 3.4.0 1.15.3 1.15.3 - 1.5.0 + 1.16.1 3.0.0 2.4.8 0.8.1-spark3.0-s_2.12 diff --git a/apache-kafka/src/main/java/com/baeldung/flink/FlinkDataPipeline.java b/apache-kafka/src/main/java/com/baeldung/flink/FlinkDataPipeline.java index 4502b628b2..8d15b79a63 100644 --- a/apache-kafka/src/main/java/com/baeldung/flink/FlinkDataPipeline.java +++ b/apache-kafka/src/main/java/com/baeldung/flink/FlinkDataPipeline.java @@ -9,8 +9,8 @@ import org.apache.flink.streaming.api.TimeCharacteristic; import org.apache.flink.streaming.api.datastream.DataStream; import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment; import org.apache.flink.streaming.api.windowing.time.Time; -import org.apache.flink.streaming.connectors.kafka.FlinkKafkaConsumer011; -import org.apache.flink.streaming.connectors.kafka.FlinkKafkaProducer011; +import org.apache.flink.streaming.connectors.kafka.FlinkKafkaConsumer; +import org.apache.flink.streaming.connectors.kafka.FlinkKafkaProducer; import static com.baeldung.flink.connector.Consumers.*; import static com.baeldung.flink.connector.Producers.*; @@ -25,12 +25,12 @@ public class FlinkDataPipeline { StreamExecutionEnvironment environment = StreamExecutionEnvironment.getExecutionEnvironment(); - FlinkKafkaConsumer011 flinkKafkaConsumer = createStringConsumerForTopic(inputTopic, address, consumerGroup); + FlinkKafkaConsumer flinkKafkaConsumer = createStringConsumerForTopic(inputTopic, address, consumerGroup); flinkKafkaConsumer.setStartFromEarliest(); DataStream stringInputStream = environment.addSource(flinkKafkaConsumer); - FlinkKafkaProducer011 flinkKafkaProducer = createStringProducer(outputTopic, address); + FlinkKafkaProducer flinkKafkaProducer = createStringProducer(outputTopic, address); stringInputStream.map(new WordsCapitalizer()) .addSink(flinkKafkaProducer); @@ -48,11 +48,11 @@ public class FlinkDataPipeline { environment.setStreamTimeCharacteristic(TimeCharacteristic.EventTime); - FlinkKafkaConsumer011 flinkKafkaConsumer = createInputMessageConsumer(inputTopic, kafkaAddress, consumerGroup); + FlinkKafkaConsumer flinkKafkaConsumer = createInputMessageConsumer(inputTopic, kafkaAddress, consumerGroup); flinkKafkaConsumer.setStartFromEarliest(); flinkKafkaConsumer.assignTimestampsAndWatermarks(new InputMessageTimestampAssigner()); - FlinkKafkaProducer011 flinkKafkaProducer = createBackupProducer(outputTopic, kafkaAddress); + FlinkKafkaProducer flinkKafkaProducer = createBackupProducer(outputTopic, kafkaAddress); DataStream inputMessagesStream = environment.addSource(flinkKafkaConsumer); diff --git a/apache-kafka/src/main/java/com/baeldung/flink/connector/Consumers.java b/apache-kafka/src/main/java/com/baeldung/flink/connector/Consumers.java index c72cb8a2d6..358c9627f7 100644 --- a/apache-kafka/src/main/java/com/baeldung/flink/connector/Consumers.java +++ b/apache-kafka/src/main/java/com/baeldung/flink/connector/Consumers.java @@ -3,26 +3,26 @@ package com.baeldung.flink.connector; import com.baeldung.flink.model.InputMessage; import com.baeldung.flink.schema.InputMessageDeserializationSchema; import org.apache.flink.api.common.serialization.SimpleStringSchema; -import org.apache.flink.streaming.connectors.kafka.FlinkKafkaConsumer011; +import org.apache.flink.streaming.connectors.kafka.FlinkKafkaConsumer; import java.util.Properties; public class Consumers { - public static FlinkKafkaConsumer011 createStringConsumerForTopic(String topic, String kafkaAddress, String kafkaGroup) { + public static FlinkKafkaConsumer createStringConsumerForTopic(String topic, String kafkaAddress, String kafkaGroup) { Properties props = new Properties(); props.setProperty("bootstrap.servers", kafkaAddress); props.setProperty("group.id", kafkaGroup); - FlinkKafkaConsumer011 consumer = new FlinkKafkaConsumer011<>(topic, new SimpleStringSchema(), props); + FlinkKafkaConsumer consumer = new FlinkKafkaConsumer<>(topic, new SimpleStringSchema(), props); return consumer; } - public static FlinkKafkaConsumer011 createInputMessageConsumer(String topic, String kafkaAddress, String kafkaGroup) { + public static FlinkKafkaConsumer createInputMessageConsumer(String topic, String kafkaAddress, String kafkaGroup) { Properties properties = new Properties(); properties.setProperty("bootstrap.servers", kafkaAddress); properties.setProperty("group.id", kafkaGroup); - FlinkKafkaConsumer011 consumer = new FlinkKafkaConsumer011(topic, new InputMessageDeserializationSchema(), properties); + FlinkKafkaConsumer consumer = new FlinkKafkaConsumer(topic, new InputMessageDeserializationSchema(), properties); return consumer; } diff --git a/apache-kafka/src/main/java/com/baeldung/flink/connector/Producers.java b/apache-kafka/src/main/java/com/baeldung/flink/connector/Producers.java index 8e6f3f8f37..a4cb2d70c2 100644 --- a/apache-kafka/src/main/java/com/baeldung/flink/connector/Producers.java +++ b/apache-kafka/src/main/java/com/baeldung/flink/connector/Producers.java @@ -3,15 +3,15 @@ package com.baeldung.flink.connector; import com.baeldung.flink.model.Backup; import com.baeldung.flink.schema.BackupSerializationSchema; import org.apache.flink.api.common.serialization.SimpleStringSchema; -import org.apache.flink.streaming.connectors.kafka.FlinkKafkaProducer011; +import org.apache.flink.streaming.connectors.kafka.FlinkKafkaProducer; public class Producers { - public static FlinkKafkaProducer011 createStringProducer(String topic, String kafkaAddress) { - return new FlinkKafkaProducer011<>(kafkaAddress, topic, new SimpleStringSchema()); + public static FlinkKafkaProducer createStringProducer(String topic, String kafkaAddress) { + return new FlinkKafkaProducer<>(kafkaAddress, topic, new SimpleStringSchema()); } - public static FlinkKafkaProducer011 createBackupProducer(String topic, String kafkaAddress) { - return new FlinkKafkaProducer011(kafkaAddress, topic, new BackupSerializationSchema()); + public static FlinkKafkaProducer createBackupProducer(String topic, String kafkaAddress) { + return new FlinkKafkaProducer(kafkaAddress, topic, new BackupSerializationSchema()); } } diff --git a/azure/pom.xml b/azure/pom.xml index 6a06282a71..aae84db0c6 100644 --- a/azure/pom.xml +++ b/azure/pom.xml @@ -122,6 +122,7 @@ ${azure.containerRegistry}.azurecr.io 1.1.0 1.1.0 + 3.3.2 \ No newline at end of file diff --git a/core-java-modules/core-java-numbers-conversions/README.md b/core-java-modules/core-java-numbers-conversions/README.md new file mode 100644 index 0000000000..e320af31b4 --- /dev/null +++ b/core-java-modules/core-java-numbers-conversions/README.md @@ -0,0 +1 @@ +### Relevant Articles: \ No newline at end of file diff --git a/core-java-modules/core-java-numbers-conversions/pom.xml b/core-java-modules/core-java-numbers-conversions/pom.xml new file mode 100644 index 0000000000..55df86d5c7 --- /dev/null +++ b/core-java-modules/core-java-numbers-conversions/pom.xml @@ -0,0 +1,25 @@ + + 4.0.0 + core-java-numbers-conversions + core-java-numbers-conversions + jar + + + com.baeldung.core-java-modules + core-java-modules + 0.0.1-SNAPSHOT + + + + core-java-numbers-conversions + + + src/main/resources + true + + + + + diff --git a/core-java-modules/core-java-numbers-conversions/src/test/java/com/baeldung/numtoletter/ConvertNumberToLetterUnitTest.java b/core-java-modules/core-java-numbers-conversions/src/test/java/com/baeldung/numtoletter/ConvertNumberToLetterUnitTest.java new file mode 100644 index 0000000000..5652969761 --- /dev/null +++ b/core-java-modules/core-java-numbers-conversions/src/test/java/com/baeldung/numtoletter/ConvertNumberToLetterUnitTest.java @@ -0,0 +1,52 @@ +package com.baeldung.numtoletter; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + + +public class ConvertNumberToLetterUnitTest { + + static char numToLetterBySubstr(int i) { + String LETTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + if (i > 0 && i <= 25) { + return LETTERS.substring(i, i + 1).charAt(0); + } else { + return '?'; + } + } + + static char numToLetterByAsciiCode(int i) { + if (i > 0 && i <= 25) { + return (char) ('A' + i); + } else { + return '?'; + } + } + + @Test + void givenANumber_whenConvertToLetterUsingSubstring_shouldGetExpectedResult() { + char negativeInputResult = numToLetterBySubstr(-7); + assertEquals('?', negativeInputResult); + + char tooLargeInputResult = numToLetterBySubstr(42); + assertEquals('?', tooLargeInputResult); + + char result = numToLetterBySubstr(10); + assertEquals('K', result); + } + + @Test + void givenANumber_whenConvertToLetterUsingAscii_shouldGetExpectedResult() { + char negativeInputResult = numToLetterByAsciiCode(-7); + assertEquals('?', negativeInputResult); + + char tooLargeInputResult = numToLetterByAsciiCode(42); + assertEquals('?', tooLargeInputResult); + + char charResult = numToLetterByAsciiCode(10); + assertEquals('K', charResult); + + assertEquals("K", String.valueOf(charResult)); + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-string-operations-2/src/main/java/com/baeldung/encoding/CharacterEncodingExamples.java b/core-java-modules/core-java-string-operations-2/src/main/java/com/baeldung/encoding/CharacterEncodingExamples.java index 1ed5f9e62a..11cda28ffe 100644 --- a/core-java-modules/core-java-string-operations-2/src/main/java/com/baeldung/encoding/CharacterEncodingExamples.java +++ b/core-java-modules/core-java-string-operations-2/src/main/java/com/baeldung/encoding/CharacterEncodingExamples.java @@ -40,6 +40,6 @@ public class CharacterEncodingExamples { charsetDecoder.onMalformedInput(codingErrorAction); return new BufferedReader( new InputStreamReader( - new ByteArrayInputStream(input.getBytes()), charsetDecoder)).readLine(); + new ByteArrayInputStream(input.getBytes(charset)), charsetDecoder)).readLine(); } } diff --git a/core-java-modules/core-java-string-operations-2/src/test/java/com/baeldung/encoding/CharacterEncodingExamplesUnitTest.java b/core-java-modules/core-java-string-operations-2/src/test/java/com/baeldung/encoding/CharacterEncodingExamplesUnitTest.java index 273839de1f..752f2e1e19 100644 --- a/core-java-modules/core-java-string-operations-2/src/test/java/com/baeldung/encoding/CharacterEncodingExamplesUnitTest.java +++ b/core-java-modules/core-java-string-operations-2/src/test/java/com/baeldung/encoding/CharacterEncodingExamplesUnitTest.java @@ -75,7 +75,7 @@ public class CharacterEncodingExamplesUnitTest { @Test public void givenUTF8String_whenDecodeByUS_ASCII_thenIgnoreMalformedInputSequence() throws IOException { - Assertions.assertEquals("The faade pattern is a software design pattern.", CharacterEncodingExamples.decodeText("The façade pattern is a software design pattern.", StandardCharsets.US_ASCII, CodingErrorAction.IGNORE)); + Assertions.assertEquals("The fa?ade pattern is a software design pattern.", CharacterEncodingExamples.decodeText("The façade pattern is a software design pattern.", StandardCharsets.US_ASCII, CodingErrorAction.IGNORE)); } //@Test @@ -89,7 +89,8 @@ public class CharacterEncodingExamplesUnitTest { CodingErrorAction.REPLACE)); } - @Test + //@Test + // run this manually as it's dependent on platform encoding public void givenUTF8String_whenDecodeByUS_ASCII_thenReportMalformedInputSequence() { Assertions.assertThrows( MalformedInputException.class, diff --git a/core-java-modules/pom.xml b/core-java-modules/pom.xml index ac8b3115b5..f2db98dbfb 100644 --- a/core-java-modules/pom.xml +++ b/core-java-modules/pom.xml @@ -108,6 +108,7 @@ core-java-numbers-3 core-java-numbers-4 core-java-numbers-5 + core-java-numbers-conversions core-java-optional core-java-perf core-java-reflection diff --git a/feign/pom.xml b/feign/pom.xml index 7338cf7508..f39adec607 100644 --- a/feign/pom.xml +++ b/feign/pom.xml @@ -103,7 +103,7 @@ com.baeldung.feign.soap - src/main/resources/users.xsd + ${project.basedir}/src/main/resources/users.xsd diff --git a/java-websocket/pom.xml b/java-websocket/pom.xml index ffc2b0631e..41c1b251c0 100644 --- a/java-websocket/pom.xml +++ b/java-websocket/pom.xml @@ -31,6 +31,7 @@ 1.1 2.8.0 + 3.3.2 \ No newline at end of file diff --git a/jetbrains/README.md b/jetbrains/README.md new file mode 100644 index 0000000000..a63d4dffba --- /dev/null +++ b/jetbrains/README.md @@ -0,0 +1,5 @@ +## Jetbrains + +This module contains articles about Jetbrains' libraries. + +### Relevant articles: diff --git a/jetbrains/pom.xml b/jetbrains/pom.xml new file mode 100644 index 0000000000..a10fd3b913 --- /dev/null +++ b/jetbrains/pom.xml @@ -0,0 +1,37 @@ + + + 4.0.0 + jetbrains + 1.0-SNAPSHOT + jetbrains + jar + http://maven.apache.org + + + com.baeldung + parent-java + 0.0.1-SNAPSHOT + ../parent-java + + + + + org.apache.commons + commons-lang3 + ${apache.commons.version} + + + org.jetbrains + annotations + ${jetbrains.annotations.version} + + + + + 3.12.0 + 24.0.1 + + + \ No newline at end of file diff --git a/jetbrains/src/main/java/com/baeldung/annotations/Demo.java b/jetbrains/src/main/java/com/baeldung/annotations/Demo.java new file mode 100644 index 0000000000..3638d13581 --- /dev/null +++ b/jetbrains/src/main/java/com/baeldung/annotations/Demo.java @@ -0,0 +1,112 @@ +package com.baeldung.annotations; + +import java.util.List; + +import org.apache.commons.lang3.StringUtils; +import org.jetbrains.annotations.Contract; + +public class Demo { + + @Contract("_ -> new") + Person fromName(String name) { + return new Person().withName(name); + } + + @Contract(" -> fail") + void alwaysFail() { + throw new RuntimeException(); + } + + @Contract(" -> fail") + void doNothingWithWrongContract() { + + } + + @Contract("_, null -> null; null, _ -> param2; _, !null -> !null") + String concatenateOnlyIfSecondArgumentIsNotNull(String head, String tail) { + if (tail == null) { + return null; + } + if (head == null) { + return tail; + } + return head + tail; + } + + void uselessNullCheck() { + String head = "1234"; + String tail = "5678"; + String concatenation = concatenateOnlyIfSecondArgumentIsNotNull(head, tail); + if (concatenation != null) { + System.out.println(concatenation); + } + } + + void uselessNullCheckOnInferredAnnotation() { + if (StringUtils.isEmpty(null)) { + System.out.println("baeldung"); + } + } + + @Contract(pure = true) + String replace(String string, char oldChar, char newChar) { + return string.replace(oldChar, newChar); + } + + @Contract(value = "true -> false; false -> true", pure = true) + boolean not(boolean input) { + return !input; + } + + @Contract("true -> new") + void contractExpectsWrongParameterType(List integers) { + + } + + @Contract("_, _ -> new") + void contractExpectsMoreParametersThanMethodHas(String s) { + + } + + @Contract("_ -> _; null -> !null") + String secondContractClauseNotReachable(String s) { + return ""; + } + + @Contract("_ -> true") + void contractExpectsWrongReturnType(String s) { + + } + + // NB: the following examples demonstrate how to use the mutates attribute of the annotation + // This attribute is currently experimental and could be changed or removed in the future + @Contract(mutates = "param") + void incrementArrayFirstElement(Integer[] integers) { + if (integers.length > 0) { + integers[0] = integers[0] + 1; + } + } + + @Contract(pure = true, mutates = "param") + void impossibleToMutateParamInPureFunction(List strings) { + if (strings != null) { + strings.forEach(System.out::println); + } + } + + @Contract(mutates = "param3") + void impossibleToMutateThirdParamWhenMethodHasOnlyTwoParams(int a, int b) { + + } + + @Contract(mutates = "param") + void impossibleToMutableImmutableType(String s) { + + } + + @Contract(mutates = "this") + static void impossibleToMutateThisInStaticMethod() { + + } + +} diff --git a/jetbrains/src/main/java/com/baeldung/annotations/Person.java b/jetbrains/src/main/java/com/baeldung/annotations/Person.java new file mode 100644 index 0000000000..086b73b47f --- /dev/null +++ b/jetbrains/src/main/java/com/baeldung/annotations/Person.java @@ -0,0 +1,15 @@ +package com.baeldung.annotations; + +import org.jetbrains.annotations.Contract; + +public class Person { + + String name; + + @Contract("_ -> this") + Person withName(String name) { + this.name = name; + return this; + } + +} diff --git a/jmeter/pom.xml b/jmeter/pom.xml index acd823b74f..d349fc526b 100644 --- a/jmeter/pom.xml +++ b/jmeter/pom.xml @@ -48,8 +48,15 @@ com.lazerycode.jmeter jmeter-maven-plugin - ${jmeter.version} + 3.7.0 + + + configuration + + configure + + jmeter-tests @@ -66,7 +73,6 @@ - 2.6.0 diff --git a/jmeter/src/main/resources/FileExtractionExample.jmx b/jmeter/src/main/resources/FileExtractionExample.jmx index 961b6f143f..a86300ea01 100644 --- a/jmeter/src/main/resources/FileExtractionExample.jmx +++ b/jmeter/src/main/resources/FileExtractionExample.jmx @@ -57,7 +57,7 @@ false - FileWriter fWriter = new FileWriter("/result.txt", true); + FileWriter fWriter = new FileWriter("<path>/result.txt", true); BufferedWriter buff = new BufferedWriter(fWriter); buff.write("Response Code : " + ctx.getPreviousResult().getResponseCode()); diff --git a/jsoup/src/test/java/com/baeldung/jsoup/JsoupParserIntegrationTest.java b/jsoup/src/test/java/com/baeldung/jsoup/JsoupParserIntegrationTest.java index ee39f2550f..006427ae47 100644 --- a/jsoup/src/test/java/com/baeldung/jsoup/JsoupParserIntegrationTest.java +++ b/jsoup/src/test/java/com/baeldung/jsoup/JsoupParserIntegrationTest.java @@ -47,7 +47,7 @@ public class JsoupParserIntegrationTest { } @Test - public void examplesSelectors() { + public void examplesSelectors() throws IOException { Elements links = doc.select("a"); Elements logo = doc.select(".spring-logo--container"); Elements pagination = doc.select("#pagination_control"); @@ -57,52 +57,46 @@ public class JsoupParserIntegrationTest { Element pag = doc.getElementById("pagination_control"); Elements desktopOnly = doc.getElementsByClass("desktopOnly"); - Elements sections = doc.select("section"); - Element firstSection = sections.first(); - Elements sectionParagraphs = firstSection.select(".paragraph"); + Elements articles = doc.select("article"); + Element firstArticle = articles.first(); + Elements sectionParagraphs = firstArticle.select(".paragraph"); } @Test - public void examplesTraversing() { - Elements sections = doc.select("section"); + public void examplesTraversing() throws IOException { + Elements articles = doc.select("article"); - Element firstSection = sections.first(); - Element lastSection = sections.last(); - Element secondSection = sections.get(2); - Elements allParents = firstSection.parents(); - Element parent = firstSection.parent(); - Elements children = firstSection.children(); - Elements siblings = firstSection.siblingElements(); + Element firstArticle = articles.first(); + Element lastSection = articles.last(); + Element secondSection = articles.get(2); + Elements allParents = firstArticle.parents(); + Element parent = firstArticle.parent(); + Elements children = firstArticle.children(); + Elements siblings = firstArticle.siblingElements(); - sections.forEach(el -> System.out.println("section: " + el)); + articles.forEach(el -> System.out.println("article: " + el)); } @Test - public void examplesExtracting() { + public void examplesExtracting() throws IOException { Element firstArticle = doc.select("article") .first(); - Element timeElement = firstArticle.select("time") + Element titleElement = firstArticle.select("h1 a") .first(); - String dateTimeOfFirstArticle = timeElement.attr("datetime"); - Element sectionDiv = firstArticle.select("section div") - .first(); - String sectionDivText = sectionDiv.text(); + + String titleText = titleElement.text(); String articleHtml = firstArticle.html(); String outerHtml = firstArticle.outerHtml(); } @Test - public void examplesModifying() { + public void examplesModifying() throws IOException { Element firstArticle = doc.select("article") .first(); - Element timeElement = firstArticle.select("time") - .first(); - Element sectionDiv = firstArticle.select("section div") + Element h1Element = firstArticle.select("h1") .first(); - String dateTimeOfFirstArticle = timeElement.attr("datetime"); - timeElement.attr("datetime", "2016-12-16 15:19:54.3"); - sectionDiv.text("foo bar"); + h1Element.text("foo bar"); firstArticle.select("h2") .html("
"); diff --git a/kubernetes-modules/pom.xml b/kubernetes-modules/pom.xml index 3ed79d0f09..5b6510e58b 100644 --- a/kubernetes-modules/pom.xml +++ b/kubernetes-modules/pom.xml @@ -15,8 +15,7 @@ k8s-intro k8s-admission-controller - - k8s-java-heap-dump + kubernetes-spring \ No newline at end of file diff --git a/libraries-2/pom.xml b/libraries-2/pom.xml index 1d5cde75a2..d9b0545d54 100644 --- a/libraries-2/pom.xml +++ b/libraries-2/pom.xml @@ -132,7 +132,7 @@ 3.0.8 4.8.153 - 7.1.0.Final + 7.20.0.Final 4.7.0 3.24ea1 4.4.0 diff --git a/libraries-2/src/main/resources/com/baeldung/process/helloworld.bpmn b/libraries-2/src/main/resources/com/baeldung/process/helloworld.bpmn index 30813b2057..66f402f942 100644 --- a/libraries-2/src/main/resources/com/baeldung/process/helloworld.bpmn +++ b/libraries-2/src/main/resources/com/baeldung/process/helloworld.bpmn @@ -15,7 +15,7 @@ - + diff --git a/libraries-2/src/test/java/com/baeldung/jbpm/WorkflowEngineIntegrationTest.java b/libraries-2/src/test/java/com/baeldung/jbpm/WorkflowEngineIntegrationTest.java index ded46d7639..65195e55d6 100644 --- a/libraries-2/src/test/java/com/baeldung/jbpm/WorkflowEngineIntegrationTest.java +++ b/libraries-2/src/test/java/com/baeldung/jbpm/WorkflowEngineIntegrationTest.java @@ -1,5 +1,8 @@ package com.baeldung.jbpm; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + import org.jbpm.test.JbpmJUnitBaseTestCase; import org.junit.After; import org.junit.Before; @@ -47,6 +50,6 @@ public class WorkflowEngineIntegrationTest extends JbpmJUnitBaseTestCase { @Test public void givenProcessInstance_whenExecutionCompleted_thenVerifyProcessInstanceStatus() { assertProcessInstanceCompleted(processInstance.getId(), ksession); - assertTrue("ProcessInstance completed with status 2", processInstance.getState() == 2); + assertEquals("ProcessInstance completed with status 2", 2, processInstance.getState()); } } diff --git a/messaging-modules/pom.xml b/messaging-modules/pom.xml index 8bda46f5cd..f843b0fe11 100644 --- a/messaging-modules/pom.xml +++ b/messaging-modules/pom.xml @@ -18,6 +18,7 @@ jgroups rabbitmq spring-amqp + spring-apache-camel spring-jms diff --git a/messaging-modules/spring-jms/pom.xml b/messaging-modules/spring-jms/pom.xml index b94a31c0c5..2dee95136d 100644 --- a/messaging-modules/spring-jms/pom.xml +++ b/messaging-modules/spring-jms/pom.xml @@ -67,7 +67,6 @@ org.apache.maven.plugins maven-war-plugin - ${maven-war-plugin.version} src/main/webapp spring-jms @@ -83,6 +82,7 @@ 4.3.4.RELEASE 5.14.1 1.5.10.RELEASE + 3.3.2 \ No newline at end of file diff --git a/patterns-modules/design-patterns-behavioral-2/src/main/java/com/baeldung/fluentinterface/HtmlDocument.java b/patterns-modules/design-patterns-behavioral-2/src/main/java/com/baeldung/fluentinterface/HtmlDocument.java new file mode 100644 index 0000000000..db0f988908 --- /dev/null +++ b/patterns-modules/design-patterns-behavioral-2/src/main/java/com/baeldung/fluentinterface/HtmlDocument.java @@ -0,0 +1,46 @@ +package com.baeldung.fluentinterface; + +import static java.util.Arrays.stream; +import static java.util.stream.Collectors.joining; + +public class HtmlDocument { + private final String content; + + private HtmlDocument(String html) { + this.content = html; + } + + public HtmlDocument() { + this(""); + } + + public String html() { + return String.format("%s", content); + } + + public HtmlDocument header(String header) { + return new HtmlDocument(String.format("%s

%s

", content, header)); + } + + public HtmlDocument secondaryHeader(String header) { + return new HtmlDocument(String.format("%s

%s

", content, header)); + } + + public HtmlDocument paragraph(String paragraph) { + return new HtmlDocument(String.format("%s

%s

", content, paragraph)); + } + + public HtmlDocument horizontalLine() { + return new HtmlDocument(String.format("%s
", content)); + } + + public HtmlDocument orderedList(String... items) { + String listItems = stream(items).map(el -> String.format("
  • %s
  • ", el)).collect(joining()); + return new HtmlDocument(String.format("%s
      %s
    ", content, listItems)); + } + + public HtmlDocument unorderedList(String... items) { + String listItems = stream(items).map(el -> String.format("
  • %s
  • ", el)).collect(joining()); + return new HtmlDocument(String.format("%s
      %s
    ", content, listItems)); + } +} \ No newline at end of file diff --git a/patterns-modules/design-patterns-behavioral-2/src/main/java/com/baeldung/fluentinterface/LargeHtmlDocument.java b/patterns-modules/design-patterns-behavioral-2/src/main/java/com/baeldung/fluentinterface/LargeHtmlDocument.java new file mode 100644 index 0000000000..fff8c97b5b --- /dev/null +++ b/patterns-modules/design-patterns-behavioral-2/src/main/java/com/baeldung/fluentinterface/LargeHtmlDocument.java @@ -0,0 +1,40 @@ +package com.baeldung.fluentinterface; + +import com.baeldung.fluentinterface.components.HtmlElement; +import com.baeldung.fluentinterface.components.HtmlHeader; +import com.baeldung.fluentinterface.components.HtmlList; + +import static java.lang.String.format; +import static java.util.Arrays.stream; +import static java.util.stream.Collectors.joining; + +public class LargeHtmlDocument { + private final String content; + + private LargeHtmlDocument(String html) { + this.content = html; + } + + public LargeHtmlDocument() { + this(""); + } + + public String html() { + return format("%s", content); + } + + public LargeHtmlDocument head(HtmlElement head) { + return new LargeHtmlDocument(format("%s %s", content, head.html())); + } + public LargeHtmlDocument body(HtmlElement body) { + return new LargeHtmlDocument(format("%s %s", content, body.html())); + } + public LargeHtmlDocument footer(HtmlElement footer) { + return new LargeHtmlDocument(format("%s
    %s
    ", content, footer.html())); + } + + private LargeHtmlDocument append(String html) { + return new LargeHtmlDocument(format("%s %s", content, html)); + } + +} \ No newline at end of file diff --git a/patterns-modules/design-patterns-behavioral-2/src/main/java/com/baeldung/fluentinterface/User.java b/patterns-modules/design-patterns-behavioral-2/src/main/java/com/baeldung/fluentinterface/User.java new file mode 100644 index 0000000000..1606369c26 --- /dev/null +++ b/patterns-modules/design-patterns-behavioral-2/src/main/java/com/baeldung/fluentinterface/User.java @@ -0,0 +1,65 @@ +package com.baeldung.fluentinterface; + +public class User { + private String firstName; + private String lastName; + private String email; + private String username; + private Long id; + + public String name() { + return firstName + " " + lastName; + } + + public User(String firstName, String lastName, String email, String username, Long id) { + this.firstName = firstName; + this.lastName = lastName; + this.email = email; + this.username = username; + this.id = id; + } + + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + private String firstName; + private String lastName; + private String email; + private String username; + private Long id; + + private Builder() { + } + + public Builder firstName(String firstName) { + this.firstName = firstName; + return this; + } + + public Builder lastName(String lastName) { + this.lastName = lastName; + return this; + } + + public Builder email(String email) { + this.email = email; + return this; + } + + public Builder username(String username) { + this.username = username; + return this; + } + + public Builder id(Long id) { + this.id = id; + return this; + } + + public User build() { + return new User(firstName, lastName, email, username, id); + } + } +} diff --git a/patterns-modules/design-patterns-behavioral-2/src/main/java/com/baeldung/fluentinterface/components/HorizontalLine.java b/patterns-modules/design-patterns-behavioral-2/src/main/java/com/baeldung/fluentinterface/components/HorizontalLine.java new file mode 100644 index 0000000000..66979b98f9 --- /dev/null +++ b/patterns-modules/design-patterns-behavioral-2/src/main/java/com/baeldung/fluentinterface/components/HorizontalLine.java @@ -0,0 +1,8 @@ +package com.baeldung.fluentinterface.components; + +public class HorizontalLine implements HtmlElement { + @Override + public String html() { + return "
    "; + } +} diff --git a/patterns-modules/design-patterns-behavioral-2/src/main/java/com/baeldung/fluentinterface/components/HtmlDiv.java b/patterns-modules/design-patterns-behavioral-2/src/main/java/com/baeldung/fluentinterface/components/HtmlDiv.java new file mode 100644 index 0000000000..7625401444 --- /dev/null +++ b/patterns-modules/design-patterns-behavioral-2/src/main/java/com/baeldung/fluentinterface/components/HtmlDiv.java @@ -0,0 +1,29 @@ +package com.baeldung.fluentinterface.components; + +public class HtmlDiv implements HtmlElement { + + private final String content; + + public HtmlDiv(String content) { + this.content = content; + } + + public HtmlDiv() { + this.content = ""; + } + + public HtmlDiv append(HtmlElement element) { + return new HtmlDiv(content + element.html()); + } + public HtmlDiv text(String text) { + return new HtmlDiv(content + text); + } + public HtmlDiv paragraph(String text) { + return new HtmlDiv(content + text); + } + + @Override + public String html() { + return String.format("
    %s
    ", content); + } +} diff --git a/patterns-modules/design-patterns-behavioral-2/src/main/java/com/baeldung/fluentinterface/components/HtmlElement.java b/patterns-modules/design-patterns-behavioral-2/src/main/java/com/baeldung/fluentinterface/components/HtmlElement.java new file mode 100644 index 0000000000..ff46dc0029 --- /dev/null +++ b/patterns-modules/design-patterns-behavioral-2/src/main/java/com/baeldung/fluentinterface/components/HtmlElement.java @@ -0,0 +1,5 @@ +package com.baeldung.fluentinterface.components; + +public interface HtmlElement { + String html(); +} diff --git a/patterns-modules/design-patterns-behavioral-2/src/main/java/com/baeldung/fluentinterface/components/HtmlHeader.java b/patterns-modules/design-patterns-behavioral-2/src/main/java/com/baeldung/fluentinterface/components/HtmlHeader.java new file mode 100644 index 0000000000..12c400014d --- /dev/null +++ b/patterns-modules/design-patterns-behavioral-2/src/main/java/com/baeldung/fluentinterface/components/HtmlHeader.java @@ -0,0 +1,34 @@ +package com.baeldung.fluentinterface.components; + +public class HtmlHeader implements HtmlElement { + + private final Type type; + private final String value; + + public HtmlHeader(Type type, String value) { + this.type = type; + this.value = value; + } + + @Override + public String html() { + return String.format("<%s>%s", type.tag(), value, type.tag()); + } + + public enum Type { + PRIMARY("h1"), + SECONDARY("h2"), + THIRD("h3"), + FOURTH("h4"); + + private final String tag; + + Type(String tag) { + this.tag = tag; + } + + public String tag() { + return tag; + } + } +} diff --git a/patterns-modules/design-patterns-behavioral-2/src/main/java/com/baeldung/fluentinterface/components/HtmlList.java b/patterns-modules/design-patterns-behavioral-2/src/main/java/com/baeldung/fluentinterface/components/HtmlList.java new file mode 100644 index 0000000000..030c9aaa5c --- /dev/null +++ b/patterns-modules/design-patterns-behavioral-2/src/main/java/com/baeldung/fluentinterface/components/HtmlList.java @@ -0,0 +1,39 @@ +package com.baeldung.fluentinterface.components; + +import java.util.Arrays; +import java.util.List; + +import static java.lang.String.format; +import static java.util.stream.Collectors.joining; + +public class HtmlList implements HtmlElement { + + private final Type type; + private final List items; + + public HtmlList(Type type, String... items) { + this.type = type; + this.items = Arrays.asList(items); + } + + @Override + public String html() { + String listItems = items.stream().map(el -> format("
  • %s
  • ", el)).collect(joining()); + return String.format("<%s>%s", type.tag(), listItems, type.tag()); + } + + public enum Type { + ORDERED("ol"), + UNORDERED("ul"); + + private final String tag; + + Type(String tag) { + this.tag = tag; + } + + public String tag() { + return tag; + } + } +} diff --git a/patterns-modules/design-patterns-behavioral-2/src/main/java/com/baeldung/fluentinterface/components/HtmlSpan.java b/patterns-modules/design-patterns-behavioral-2/src/main/java/com/baeldung/fluentinterface/components/HtmlSpan.java new file mode 100644 index 0000000000..2bdf55eb72 --- /dev/null +++ b/patterns-modules/design-patterns-behavioral-2/src/main/java/com/baeldung/fluentinterface/components/HtmlSpan.java @@ -0,0 +1,27 @@ +package com.baeldung.fluentinterface.components; + +public class HtmlSpan implements HtmlElement { + + private final String content; + + public HtmlSpan(String content) { + this.content = content; + } + + public HtmlSpan() { + this.content = ""; + } + + public HtmlSpan append(HtmlElement element) { + return new HtmlSpan(content + element.html()); + } + + public HtmlSpan paragraph(String text) { + return new HtmlSpan(content + text); + } + + @Override + public String html() { + return String.format("%s", content); + } +} diff --git a/patterns-modules/design-patterns-behavioral-2/src/test/java/com/baeldung/fluentinterface/FluentInterfaceUnitTest.java b/patterns-modules/design-patterns-behavioral-2/src/test/java/com/baeldung/fluentinterface/FluentInterfaceUnitTest.java new file mode 100644 index 0000000000..bf5aadcf13 --- /dev/null +++ b/patterns-modules/design-patterns-behavioral-2/src/test/java/com/baeldung/fluentinterface/FluentInterfaceUnitTest.java @@ -0,0 +1,101 @@ +package com.baeldung.fluentinterface; + +import com.baeldung.fluentinterface.components.*; +import com.baeldung.fluentinterface.components.HtmlHeader.Type; +import org.junit.jupiter.api.Test; + +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static com.baeldung.fluentinterface.components.HtmlList.Type.ORDERED; +import static org.assertj.core.api.Assertions.assertThat; + +class FluentInterfaceUnitTest { + + @Test + void givenTenNumbers_thenStreamIsProcessedCorrectly() { + Stream numbers = Stream.of(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + Stream processedNumbers = numbers.distinct() + .filter(nr -> nr % 2 == 0) + .skip(1) + .limit(4) + .map(nr -> "#" + nr) + .peek(nr -> System.out.println(nr)); + String result = processedNumbers.collect(Collectors.joining(", ")); + + assertThat(result).isEqualTo("#2, #4, #6, #8"); + } + + @Test + void givenUserBuilder_thenCreateUserCorrectly() { + User.Builder userBuilder = User.builder(); + userBuilder = userBuilder + .firstName("John") + .lastName("Doe") + .email("jd@gmail.com") + .username("jd_2000") + .id(1234L); + + User user = userBuilder.build(); + + assertThat(user.name()).isEqualTo("John Doe"); + } + + @Test + void givenHtmlDocument_thenGenerateHtmlCorrectly() { + HtmlDocument document = new HtmlDocument() + .header("Principles of O.O.P.") + .paragraph("OOP in Java.") + .horizontalLine() + .paragraph("The main pillars of OOP are:") + .orderedList("Encapsulation", "Inheritance", "Abstraction", "Polymorphism"); + String html = document.html(); + + assertThat(html).isEqualToIgnoringWhitespace( + "" + + "

    Principles of O.O.P.

    " + + "

    OOP in Java.

    " + + "
    " + + "

    The main pillars of OOP are:

    " + + "
      " + + "
    1. Encapsulation
    2. " + + "
    3. Inheritance
    4. " + + "
    5. Abstraction
    6. " + + "
    7. Polymorphism
    8. " + + "
    " + + "" + ); + } + + @Test + void givenHtmlDocument_thenInstanceIsImmutable() { + HtmlDocument document = new HtmlDocument() + .header("Principles of O.O.P."); + HtmlDocument updatedDocument = document + .paragraph("OOP in Java."); + + assertThat(document).isNotEqualTo(updatedDocument); + } + + + @Test + void givenLargeHtmlDocument_thenGenerateHtmlCorrectly() { + String html = new LargeHtmlDocument() + .head(new HtmlHeader(Type.PRIMARY, "title")) + .body(new HtmlDiv() + .append(new HtmlSpan() + .paragraph("learning OOP from John Doe") + .append(new HorizontalLine()) + .paragraph("The pillars of OOP:") + ) + .append(new HtmlList(ORDERED, "Encapsulation", "Inheritance", "Abstraction", "Polymorphism")) + ) + .footer(new HtmlDiv() + .paragraph("trademark John Doe") + ) + .html(); + + String expectedHtml = "

    title

    learning OOP from John Doe
    The pillars of OOP:
    1. Encapsulation
    2. Inheritance
    3. Abstraction
    4. Polymorphism
    trademark John Doe
    "; + assertThat(html).isEqualToIgnoringWhitespace(expectedHtml); + } +} \ No newline at end of file diff --git a/patterns-modules/idd/pom.xml b/patterns-modules/idd/pom.xml index 02795089e0..e08e058b92 100644 --- a/patterns-modules/idd/pom.xml +++ b/patterns-modules/idd/pom.xml @@ -7,16 +7,7 @@ 1.0 idd - - - org.apache.maven.plugins - maven-compiler-plugin - - 9 - 9 - - - + jar diff --git a/patterns-modules/idd/src/test/java/com/baeldung/idd/HelpRequestServiceUnitTest.java b/patterns-modules/idd/src/test/java/com/baeldung/idd/HelpRequestServiceUnitTest.java index 7bfacf8a48..52cbcaba57 100644 --- a/patterns-modules/idd/src/test/java/com/baeldung/idd/HelpRequestServiceUnitTest.java +++ b/patterns-modules/idd/src/test/java/com/baeldung/idd/HelpRequestServiceUnitTest.java @@ -1,7 +1,7 @@ package com.baeldung.idd; import org.assertj.core.api.Assertions; -import org.junit.Test; +import org.junit.jupiter.api.Test; import java.util.List; diff --git a/persistence-modules/pom.xml b/persistence-modules/pom.xml index 9606da4594..d7ff51b487 100644 --- a/persistence-modules/pom.xml +++ b/persistence-modules/pom.xml @@ -98,7 +98,8 @@ spring-data-mongodb-reactive spring-data-neo4j spring-data-redis - spring-data-rest + + spring-data-rest-2 spring-data-rest-querydsl spring-data-solr diff --git a/persistence-modules/questdb/README.md b/persistence-modules/questdb/README.md new file mode 100644 index 0000000000..cf4c7cbbbc --- /dev/null +++ b/persistence-modules/questdb/README.md @@ -0,0 +1,2 @@ +### Relevant Articles: +- [Introduction to QuestDB](#) diff --git a/persistence-modules/questdb/pom.xml b/persistence-modules/questdb/pom.xml new file mode 100644 index 0000000000..ee3db461cb --- /dev/null +++ b/persistence-modules/questdb/pom.xml @@ -0,0 +1,29 @@ + + 4.0.0 + + org.baeldung + questdb + questdb + 0.0.1-SNAPSHOT + + + com.baeldung + parent-java + 0.0.1-SNAPSHOT + ../../parent-java + + + + UTF-8 + 7.0.0 + + + + + org.questdb + questdb + ${questdb.version} + + + diff --git a/persistence-modules/questdb/src/main/java/com/baeldung/InsertData.java b/persistence-modules/questdb/src/main/java/com/baeldung/InsertData.java new file mode 100644 index 0000000000..9699b7c2d0 --- /dev/null +++ b/persistence-modules/questdb/src/main/java/com/baeldung/InsertData.java @@ -0,0 +1,29 @@ +package com.baeldung; + +import io.questdb.client.Sender; + + +public class InsertData { + static final String SENSORS_TABLE_NAME = "sensors"; + + public static void main(String[] args) { + try (Sender sender = Sender.builder().address("localhost:9009").build()) { + sender.table(SENSORS_TABLE_NAME) + .stringColumn("id", "KTC") + .stringColumn("name", "Kitchen temperature (Celsius)") + .doubleColumn("currentValue", 20) + .atNow(); + sender.table(SENSORS_TABLE_NAME) + .stringColumn("id", "SMT") + .stringColumn("name", "Smart Garden temperature (Celsius)") + .doubleColumn("currentValue", 28.5) + .atNow(); + sender.table(SENSORS_TABLE_NAME) + .stringColumn("id", "RM1") + .stringColumn("name", "Room 1") + .doubleColumn("currentValue", 19.5) + .doubleColumn("idealValue", 18.5) + .atNow(); + } + } +} \ No newline at end of file diff --git a/persistence-modules/spring-data-rest/pom.xml b/persistence-modules/spring-data-rest/pom.xml index f5601cb7ce..fa2cd033f5 100644 --- a/persistence-modules/spring-data-rest/pom.xml +++ b/persistence-modules/spring-data-rest/pom.xml @@ -11,9 +11,9 @@ com.baeldung - parent-boot-2 + parent-boot-3 0.0.1-SNAPSHOT - ../../parent-boot-2 + ../../parent-boot-3 @@ -42,6 +42,17 @@ spring-boot-starter-test test + + org.hibernate.orm + hibernate-community-dialects + ${hibernate-community-dialects.version} + + + io.rest-assured + rest-assured + 3.3.0 + test + com.h2database h2 @@ -64,23 +75,6 @@ ${project.artifactId} - - com.mysema.maven - maven-apt-plugin - ${maven.version} - - - generate-sources - - process - - - target/generated-sources - com.querydsl.apt.jpa.JPAAnnotationProcessor - - - - org.springframework.boot spring-boot-maven-plugin @@ -91,6 +85,7 @@ com.baeldung.books.SpringDataRestApplication 1.0 + 6.1.7.Final \ No newline at end of file diff --git a/persistence-modules/spring-data-rest/src/main/java/com/baeldung/books/dialect/SQLiteDialect.java b/persistence-modules/spring-data-rest/src/main/java/com/baeldung/books/dialect/SQLiteDialect.java deleted file mode 100644 index 6e840eec43..0000000000 --- a/persistence-modules/spring-data-rest/src/main/java/com/baeldung/books/dialect/SQLiteDialect.java +++ /dev/null @@ -1,78 +0,0 @@ -package com.baeldung.books.dialect; - -import org.hibernate.dialect.Dialect; -import org.hibernate.dialect.identity.IdentityColumnSupport; - -import java.sql.Types; - -public class SQLiteDialect extends Dialect { - - public SQLiteDialect() { - registerColumnType(Types.BIT, "integer"); - registerColumnType(Types.TINYINT, "tinyint"); - registerColumnType(Types.SMALLINT, "smallint"); - registerColumnType(Types.INTEGER, "integer"); - registerColumnType(Types.BIGINT, "bigint"); - registerColumnType(Types.FLOAT, "float"); - registerColumnType(Types.REAL, "real"); - registerColumnType(Types.DOUBLE, "double"); - registerColumnType(Types.NUMERIC, "numeric"); - registerColumnType(Types.DECIMAL, "decimal"); - registerColumnType(Types.CHAR, "char"); - registerColumnType(Types.VARCHAR, "varchar"); - registerColumnType(Types.LONGVARCHAR, "longvarchar"); - registerColumnType(Types.DATE, "date"); - registerColumnType(Types.TIME, "time"); - registerColumnType(Types.TIMESTAMP, "timestamp"); - registerColumnType(Types.BINARY, "blob"); - registerColumnType(Types.VARBINARY, "blob"); - registerColumnType(Types.LONGVARBINARY, "blob"); - registerColumnType(Types.BLOB, "blob"); - registerColumnType(Types.CLOB, "clob"); - registerColumnType(Types.BOOLEAN, "integer"); - } - - public IdentityColumnSupport getIdentityColumnSupport() { - return new SQLiteIdentityColumnSupport(); - } - - public boolean hasAlterTable() { - return false; - } - - public boolean dropConstraints() { - return false; - } - - public String getDropForeignKeyString() { - return ""; - } - - public String getAddForeignKeyConstraintString(String constraintName, String[] foreignKey, String referencedTable, String[] primaryKey, boolean referencesPrimaryKey) { - return ""; - } - - public String getAddPrimaryKeyConstraintString(String constraintName) { - return ""; - } - - public String getForUpdateString() { - return ""; - } - - public String getAddColumnString() { - return "add column"; - } - - public boolean supportsOuterJoinForUpdate() { - return false; - } - - public boolean supportsIfExistsBeforeTableName() { - return true; - } - - public boolean supportsCascadeDelete() { - return false; - } -} diff --git a/persistence-modules/spring-data-rest/src/main/java/com/baeldung/books/dialect/SQLiteIdentityColumnSupport.java b/persistence-modules/spring-data-rest/src/main/java/com/baeldung/books/dialect/SQLiteIdentityColumnSupport.java deleted file mode 100644 index 682d82c6f1..0000000000 --- a/persistence-modules/spring-data-rest/src/main/java/com/baeldung/books/dialect/SQLiteIdentityColumnSupport.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.baeldung.books.dialect; - -import org.hibernate.MappingException; -import org.hibernate.dialect.identity.IdentityColumnSupportImpl; - -public class SQLiteIdentityColumnSupport extends IdentityColumnSupportImpl { - - @Override - public boolean supportsIdentityColumns() { - return true; - } - - @Override - public String getIdentitySelectString(String table, String column, int type) throws MappingException { - return "select last_insert_rowid()"; - } - - @Override - public String getIdentityColumnString(int type) throws MappingException { - return "integer"; - } -} diff --git a/persistence-modules/spring-data-rest/src/main/java/com/baeldung/books/models/Address.java b/persistence-modules/spring-data-rest/src/main/java/com/baeldung/books/models/Address.java index 3c36db0f3c..2627c21615 100644 --- a/persistence-modules/spring-data-rest/src/main/java/com/baeldung/books/models/Address.java +++ b/persistence-modules/spring-data-rest/src/main/java/com/baeldung/books/models/Address.java @@ -1,11 +1,11 @@ package com.baeldung.books.models; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.OneToOne; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.OneToOne; @Entity public class Address { diff --git a/persistence-modules/spring-data-rest/src/main/java/com/baeldung/books/models/Author.java b/persistence-modules/spring-data-rest/src/main/java/com/baeldung/books/models/Author.java index aec2e62ebf..385113d800 100644 --- a/persistence-modules/spring-data-rest/src/main/java/com/baeldung/books/models/Author.java +++ b/persistence-modules/spring-data-rest/src/main/java/com/baeldung/books/models/Author.java @@ -2,15 +2,15 @@ package com.baeldung.books.models; import java.util.List; -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.JoinTable; -import javax.persistence.ManyToMany; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.JoinTable; +import jakarta.persistence.ManyToMany; @Entity public class Author { diff --git a/persistence-modules/spring-data-rest/src/main/java/com/baeldung/books/models/Book.java b/persistence-modules/spring-data-rest/src/main/java/com/baeldung/books/models/Book.java index 7451b04b3b..ea3fb325c1 100644 --- a/persistence-modules/spring-data-rest/src/main/java/com/baeldung/books/models/Book.java +++ b/persistence-modules/spring-data-rest/src/main/java/com/baeldung/books/models/Book.java @@ -2,15 +2,15 @@ package com.baeldung.books.models; import java.util.List; -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.ManyToMany; -import javax.persistence.ManyToOne; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToMany; +import jakarta.persistence.ManyToOne; @Entity public class Book { diff --git a/persistence-modules/spring-data-rest/src/main/java/com/baeldung/books/models/Library.java b/persistence-modules/spring-data-rest/src/main/java/com/baeldung/books/models/Library.java index 5f95169a9b..28a54dbd33 100644 --- a/persistence-modules/spring-data-rest/src/main/java/com/baeldung/books/models/Library.java +++ b/persistence-modules/spring-data-rest/src/main/java/com/baeldung/books/models/Library.java @@ -2,14 +2,14 @@ package com.baeldung.books.models; import java.util.List; -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 jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.OneToMany; +import jakarta.persistence.OneToOne; import org.springframework.data.rest.core.annotation.RestResource; diff --git a/persistence-modules/spring-data-rest/src/main/java/com/baeldung/books/models/Subject.java b/persistence-modules/spring-data-rest/src/main/java/com/baeldung/books/models/Subject.java index 11a4425fdd..28d16f5054 100644 --- a/persistence-modules/spring-data-rest/src/main/java/com/baeldung/books/models/Subject.java +++ b/persistence-modules/spring-data-rest/src/main/java/com/baeldung/books/models/Subject.java @@ -1,10 +1,10 @@ package com.baeldung.books.models; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; @Entity public class Subject { diff --git a/persistence-modules/spring-data-rest/src/main/resources/persistence-sqlite.properties b/persistence-modules/spring-data-rest/src/main/resources/persistence-sqlite.properties index b6b5f4e4d6..e570322a82 100644 --- a/persistence-modules/spring-data-rest/src/main/resources/persistence-sqlite.properties +++ b/persistence-modules/spring-data-rest/src/main/resources/persistence-sqlite.properties @@ -2,6 +2,6 @@ driverClassName=org.sqlite.JDBC url=jdbc:sqlite:memory:myDb?cache=shared username=sa password=sa -hibernate.dialect=com.baeldung.dialect.SQLiteDialect +spring.jpa.database-platform=org.hibernate.community.dialect.SQLiteDialect hibernate.hbm2ddl.auto=create-drop hibernate.show_sql=true diff --git a/pom.xml b/pom.xml index 6f159ac8a7..8e23a6e94f 100644 --- a/pom.xml +++ b/pom.xml @@ -330,59 +330,35 @@ parent-spring-5 parent-java - - azure checker-plugin - core-java-modules - couchbase - gradle-modules/gradle/maven-to-gradle - - apache-httpclient apache-httpclient4 - java-jdi - java-websocket + jetbrains jhipster-5 - jmh - - kubernetes-modules - language-interop libraries-3 - libraries-data-db - logging-modules lombok-modules - maven-modules - messaging-modules - microservices-modules muleesb - - netflix-modules - osgi - - persistence-modules - - vavr-modules web-modules @@ -428,7 +404,6 @@ parent-spring-5 parent-java - spf4j spring-4 spring-aop @@ -436,14 +411,11 @@ spring-boot-modules spring-cloud-modules - spring-di - spring-di-2 - spring-ejb-modules + spring-exceptions spring-integration spring-jenkins-pipeline - spring-jinq spring-katharsis spring-mobile spring-remoting-modules @@ -520,10 +492,9 @@ libraries-5 libraries-6 spring-boot-modules/spring-boot-react - spring-ejb-modules/ejb-beans vaadin - vavr-modules + @@ -559,8 +530,6 @@ parent-spring-5 parent-java - - azure checker-plugin @@ -571,43 +540,24 @@ gradle-modules/gradle/maven-to-gradle - apache-httpclient apache-httpclient4 - java-jdi - java-websocket jhipster-5 jmh - - kubernetes-modules - language-interop libraries-3 - libraries-data-db - logging-modules lombok-modules - maven-modules - - messaging-modules - microservices-modules muleesb - netflix-modules - osgi - - - persistence-modules - - vavr-modules web-modules @@ -645,21 +595,17 @@ parent-spring-5 parent-java - - spf4j spring-4 spring-bom spring-boot-modules spring-cloud-modules - spring-di - spring-di-2 - spring-ejb-modules + spring-exceptions spring-integration spring-jenkins-pipeline - spring-jinq + spring-katharsis spring-mobile spring-remoting-modules @@ -728,9 +674,7 @@ libraries-5 libraries-6 spring-boot-modules/spring-boot-react - spring-ejb-modules/ejb-beans vaadin - vavr-modules @@ -796,9 +740,20 @@ + spring-ejb-modules + spring-di + spring-di-2 + spring-jinq + vavr-modules + java-websocket + azure + netflix-modules + spf4j + spring-jersey jersey jaxb + javafx spring-batch spring-boot-rest @@ -884,7 +839,7 @@ drools guava-modules apache-httpclient-2 - kubernetes-modules/kubernetes-spring + kubernetes-modules libraries-concurrency libraries-testing maven-modules/compiler-plugin-java-9 @@ -904,6 +859,7 @@ spring-swagger-codegen/custom-validations-opeanpi-codegen testing-modules/testing-assertions persistence-modules/fauna + persistence-modules/spring-data-rest rule-engines-modules @@ -933,7 +889,7 @@ asm atomikos atomix - + bazel code-generation @@ -942,7 +898,7 @@ disruptor dozer dubbo - feign + google-cloud graphql-modules grpc @@ -1021,9 +977,10 @@ xstream webrtc persistence-modules/java-mongodb - messaging-modules/spring-apache-camel + messaging-modules spring-boot-modules/spring-boot-redis spring-security-modules/spring-security-saml2 + persistence-modules/questdb @@ -1057,9 +1014,20 @@ + spring-ejb-modules + spring-di + spring-di-2 + spring-jinq + vavr-modules + java-websocket + azure + netflix-modules + spf4j + spring-jersey jersey jaxb + javafx spring-batch spring-boot-rest @@ -1143,7 +1111,7 @@ drools guava-modules apache-httpclient-2 - kubernetes-modules/kubernetes-spring + kubernetes-modules libraries-concurrency libraries-testing maven-modules/compiler-plugin-java-9 @@ -1163,6 +1131,7 @@ spring-swagger-codegen/custom-validations-opeanpi-codegen testing-modules/testing-assertions persistence-modules/fauna + persistence-modules/spring-data-rest rule-engines-modules @@ -1191,7 +1160,7 @@ asm atomikos atomix - + bazel code-generation @@ -1201,7 +1170,7 @@ dozer dubbo - feign + google-cloud graphql-modules grpc @@ -1282,9 +1251,10 @@ webrtc persistence-modules/java-mongodb libraries-2 - messaging-modules/spring-apache-camel + messaging-modules spring-boot-modules/spring-boot-redis spring-security-modules/spring-security-saml2 + persistence-modules/questdb diff --git a/spf4j/spf4j-aspects-app/pom.xml b/spf4j/spf4j-aspects-app/pom.xml index 09ca41ea47..3eccdd879a 100644 --- a/spf4j/spf4j-aspects-app/pom.xml +++ b/spf4j/spf4j-aspects-app/pom.xml @@ -55,11 +55,6 @@ org.apache.maven.plugins maven-compiler-plugin - ${compiler.plugin.version} - - ${java.version} - ${java.version} - org.apache.maven.plugins @@ -98,7 +93,6 @@ 8.9.0 - 3.8.0 3.1.1 diff --git a/spf4j/spf4j-core-app/pom.xml b/spf4j/spf4j-core-app/pom.xml index 2f7f3745f1..20251860aa 100644 --- a/spf4j/spf4j-core-app/pom.xml +++ b/spf4j/spf4j-core-app/pom.xml @@ -61,11 +61,6 @@ org.apache.maven.plugins maven-compiler-plugin - ${compiler.plugin.version} - - ${java.version} - ${java.version} - org.apache.maven.plugins @@ -104,7 +99,6 @@ 8.9.0 - 3.8.0 3.1.1 diff --git a/spring-batch/pom.xml b/spring-batch/pom.xml index 32126fec9b..e9d3afa376 100644 --- a/spring-batch/pom.xml +++ b/spring-batch/pom.xml @@ -28,13 +28,13 @@ javax.xml.bind jaxb-api ${jaxb.version} - runtime + org.glassfish.jaxb jaxb-runtime ${jaxb.version} - runtime + diff --git a/spring-boot-modules/spring-boot-3/pom.xml b/spring-boot-modules/spring-boot-3/pom.xml index cc8e7e1426..685df233ba 100644 --- a/spring-boot-modules/spring-boot-3/pom.xml +++ b/spring-boot-modules/spring-boot-3/pom.xml @@ -124,6 +124,8 @@ 1.5.2.Final 2.0.0 3.0.0-M7 + com.baeldung.sample.TodoApplication + \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/recordswithjpa/QueryService.java b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/recordswithjpa/QueryService.java new file mode 100644 index 0000000000..4c1e73e530 --- /dev/null +++ b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/recordswithjpa/QueryService.java @@ -0,0 +1,42 @@ +package com.baeldung.recordswithjpa; + +import com.baeldung.recordswithjpa.entity.Book; +import com.baeldung.recordswithjpa.records.BookRecord; +import jakarta.persistence.EntityManager; +import jakarta.persistence.PersistenceContext; +import jakarta.persistence.Query; +import jakarta.persistence.TypedQuery; +import jakarta.persistence.criteria.CriteriaBuilder; +import jakarta.persistence.criteria.CriteriaQuery; +import jakarta.persistence.criteria.Root; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public class QueryService { + @PersistenceContext + private EntityManager entityManager; + + public List findAllBooks() { + CriteriaBuilder cb = entityManager.getCriteriaBuilder(); + CriteriaQuery query = cb.createQuery(BookRecord.class); + Root root = query.from(Book.class); + query.select(cb + .construct(BookRecord.class, root.get("id"), root.get("title"), root.get("author"), root.get("isbn"))); + return entityManager.createQuery(query).getResultList(); + } + + public BookRecord findBookById(Long id) { + TypedQuery query = entityManager + .createQuery("SELECT new com.baeldung.recordswithjpa.records.BookRecord(b.id, b.title, b.author, b.isbn) " + + "FROM Book b WHERE b.id = :id", BookRecord.class); + query.setParameter("id", id); + return query.getSingleResult(); + } + + public List findAllBooksUsingMapping() { + Query query = entityManager.createNativeQuery("SELECT * FROM book", "BookRecordMapping"); + return query.getResultList(); + } +} \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/recordswithjpa/RecordsAsJpaApplication.java b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/recordswithjpa/RecordsAsJpaApplication.java new file mode 100644 index 0000000000..d6eb1edec1 --- /dev/null +++ b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/recordswithjpa/RecordsAsJpaApplication.java @@ -0,0 +1,13 @@ +package com.baeldung.recordswithjpa; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class RecordsAsJpaApplication { + + public static void main(String[] args) { + SpringApplication.run(RecordsAsJpaApplication.class, args); + } + +} diff --git a/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/recordswithjpa/entity/Book.java b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/recordswithjpa/entity/Book.java new file mode 100644 index 0000000000..9ea982e323 --- /dev/null +++ b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/recordswithjpa/entity/Book.java @@ -0,0 +1,70 @@ +package com.baeldung.recordswithjpa.entity; + +import com.baeldung.recordswithjpa.records.BookRecord; +import jakarta.persistence.*; + +@SqlResultSetMapping( + name = "BookRecordMapping", + classes = @ConstructorResult( + targetClass = BookRecord.class, + columns = { + @ColumnResult(name = "id", type = Long.class), + @ColumnResult(name = "title", type = String.class), + @ColumnResult(name = "author", type = String.class), + @ColumnResult(name = "isbn", type = String.class) + } + ) +) +@Entity +@Table(name = "book") +public class Book { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + private String title; + private String author; + private String isbn; + + public Book() { + } + + public Book(Long id, String title, String author, String isbn) { + this.id = id; + this.title = title; + this.author = author; + this.isbn = isbn; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getAuthor() { + return author; + } + + public void setAuthor(String author) { + this.author = author; + } + + public String getIsbn() { + return isbn; + } + + public void setIsbn(String isbn) { + this.isbn = isbn; + } + +} \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/recordswithjpa/records/BookRecord.java b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/recordswithjpa/records/BookRecord.java new file mode 100644 index 0000000000..96968575d9 --- /dev/null +++ b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/recordswithjpa/records/BookRecord.java @@ -0,0 +1,4 @@ +package com.baeldung.recordswithjpa.records; + +public record BookRecord(Long id, String title, String author, String isbn) { +} \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/recordswithjpa/records/CustomBookRecord.java b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/recordswithjpa/records/CustomBookRecord.java new file mode 100644 index 0000000000..35e9be9513 --- /dev/null +++ b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/recordswithjpa/records/CustomBookRecord.java @@ -0,0 +1,4 @@ +package com.baeldung.recordswithjpa.records; + +public record CustomBookRecord(Long id, String title) { +} \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/recordswithjpa/repository/BookRepository.java b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/recordswithjpa/repository/BookRepository.java new file mode 100644 index 0000000000..4ef5f17296 --- /dev/null +++ b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/recordswithjpa/repository/BookRepository.java @@ -0,0 +1,17 @@ +package com.baeldung.recordswithjpa.repository; + +import com.baeldung.recordswithjpa.entity.Book; +import com.baeldung.recordswithjpa.records.BookRecord; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.CrudRepository; +import org.springframework.data.repository.query.Param; + +import java.util.List; + +public interface BookRepository extends CrudRepository { + List findBookByAuthor(String author); + + @Query("SELECT new com.baeldung.recordswithjpa.records.BookRecord(b.id, b.title, b.author, b.isbn) " + + "FROM Book b WHERE b.id = :id") + BookRecord findBookById(@Param("id") Long id); +} \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/recordswithjpa/repository/CustomBookRepository.java b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/recordswithjpa/repository/CustomBookRepository.java new file mode 100644 index 0000000000..bb8002d70d --- /dev/null +++ b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/recordswithjpa/repository/CustomBookRepository.java @@ -0,0 +1,9 @@ +package com.baeldung.recordswithjpa.repository; + +import com.baeldung.recordswithjpa.records.CustomBookRecord; + +import java.util.List; + +public interface CustomBookRepository { + List findAllBooks(); +} diff --git a/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/recordswithjpa/repository/CustomBookRepositoryImpl.java b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/recordswithjpa/repository/CustomBookRepositoryImpl.java new file mode 100644 index 0000000000..8d420a9874 --- /dev/null +++ b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/recordswithjpa/repository/CustomBookRepositoryImpl.java @@ -0,0 +1,20 @@ +package com.baeldung.recordswithjpa.repository; + +import com.baeldung.recordswithjpa.records.CustomBookRecord; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public class CustomBookRepositoryImpl implements CustomBookRepository { + private final JdbcTemplate jdbcTemplate; + + public CustomBookRepositoryImpl(JdbcTemplate jdbcTemplate) { + this.jdbcTemplate = jdbcTemplate; + } + + public List findAllBooks() { + return jdbcTemplate.query("SELECT id, title FROM book", (rs, rowNum) -> new CustomBookRecord(rs.getLong("id"), rs.getString("title"))); + } +} diff --git a/spring-boot-modules/spring-boot-3/src/test/java/com/baeldung/recordswithjpa/QueryServiceIntegrationTest.java b/spring-boot-modules/spring-boot-3/src/test/java/com/baeldung/recordswithjpa/QueryServiceIntegrationTest.java new file mode 100644 index 0000000000..011895e7fa --- /dev/null +++ b/spring-boot-modules/spring-boot-3/src/test/java/com/baeldung/recordswithjpa/QueryServiceIntegrationTest.java @@ -0,0 +1,39 @@ +package com.baeldung.recordswithjpa; + +import com.baeldung.recordswithjpa.entity.Book; +import com.baeldung.recordswithjpa.records.BookRecord; +import com.baeldung.recordswithjpa.repository.BookRepository; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; + +public class QueryServiceIntegrationTest extends RecordsAsJpaIntegrationTest { + + @Autowired + private QueryService queryService; + + + @Test + void findAllBooks() { + List allBooks = queryService.findAllBooks(); + assertEquals(3, allBooks.size()); + } + + @Test + void findBookById() { + BookRecord bookById = queryService.findBookById(1L); + assertEquals("The Lord of the Rings", bookById.title()); + } + + @Test + void findAllBooksUsingMapping() { + List allBooksUsingMapping = queryService.findAllBooksUsingMapping(); + assertEquals(3, allBooksUsingMapping.size()); + } +} \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-3/src/test/java/com/baeldung/recordswithjpa/RecordsAsJpaIntegrationTest.java b/spring-boot-modules/spring-boot-3/src/test/java/com/baeldung/recordswithjpa/RecordsAsJpaIntegrationTest.java new file mode 100644 index 0000000000..f0869dad48 --- /dev/null +++ b/spring-boot-modules/spring-boot-3/src/test/java/com/baeldung/recordswithjpa/RecordsAsJpaIntegrationTest.java @@ -0,0 +1,30 @@ +package com.baeldung.recordswithjpa; + +import com.baeldung.recordswithjpa.entity.Book; +import com.baeldung.recordswithjpa.repository.BookRepository; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +public class RecordsAsJpaIntegrationTest { + @Autowired + protected BookRepository bookRepository; + + @BeforeEach + void setUp() { + Book book = new Book(1L,"The Lord of the Rings", "J.R.R. Tolkien", "978-0544003415"); + Book book2 = new Book(2L,"The Hobbit", "J.R.R. Tolkien", "978-0547928227"); + Book book3 = new Book(3L,"Harry Potter and the Philosopher's Stone", "J.K. Rowling", "978-0747532699"); + + bookRepository.save(book); + bookRepository.save(book2); + bookRepository.save(book3); + } + + @AfterEach + void tearDown() { + bookRepository.deleteAll(); + } +} diff --git a/spring-boot-modules/spring-boot-3/src/test/java/com/baeldung/recordswithjpa/repository/BookRepositoryIntegrationTest.java b/spring-boot-modules/spring-boot-3/src/test/java/com/baeldung/recordswithjpa/repository/BookRepositoryIntegrationTest.java new file mode 100644 index 0000000000..9173fea269 --- /dev/null +++ b/spring-boot-modules/spring-boot-3/src/test/java/com/baeldung/recordswithjpa/repository/BookRepositoryIntegrationTest.java @@ -0,0 +1,19 @@ +package com.baeldung.recordswithjpa.repository; + +import com.baeldung.recordswithjpa.RecordsAsJpaIntegrationTest; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class BookRepositoryIntegrationTest extends RecordsAsJpaIntegrationTest { + + @Test + void findBookByAuthor() { + assertEquals(2, bookRepository.findBookByAuthor("J.R.R. Tolkien").size()); + } + + @Test + void findBookById() { + assertEquals("The Lord of the Rings", bookRepository.findBookById(1L).title()); + } +} \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-3/src/test/java/com/baeldung/recordswithjpa/repository/CustomBookRepositoryIntegrationTest.java b/spring-boot-modules/spring-boot-3/src/test/java/com/baeldung/recordswithjpa/repository/CustomBookRepositoryIntegrationTest.java new file mode 100644 index 0000000000..866645429a --- /dev/null +++ b/spring-boot-modules/spring-boot-3/src/test/java/com/baeldung/recordswithjpa/repository/CustomBookRepositoryIntegrationTest.java @@ -0,0 +1,23 @@ +package com.baeldung.recordswithjpa.repository; + +import com.baeldung.recordswithjpa.RecordsAsJpaIntegrationTest; +import com.baeldung.recordswithjpa.records.CustomBookRecord; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; + +class CustomBookRepositoryIntegrationTest extends RecordsAsJpaIntegrationTest { + + @Autowired + private CustomBookRepository customBookRepository; + + @Test + void findAllBooks() { + List allBooks = customBookRepository.findAllBooks(); + assertEquals(3, allBooks.size()); + } +} \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-swagger-2/src/main/java/com/baeldung/springdoc/demo/SpringDocExampleApplication.java b/spring-boot-modules/spring-boot-swagger-2/src/main/java/com/baeldung/springdoc/demo/SpringDocExampleApplication.java new file mode 100644 index 0000000000..3ae057630d --- /dev/null +++ b/spring-boot-modules/spring-boot-swagger-2/src/main/java/com/baeldung/springdoc/demo/SpringDocExampleApplication.java @@ -0,0 +1,17 @@ +package com.baeldung.springdoc.demo; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +import com.baeldung.springdoc.demo.config.SpringDocSwaggerConfig; + +@SpringBootApplication +public class SpringDocExampleApplication { + + public static void main(String[] args) { + SpringApplication application = new SpringApplication(SpringDocExampleApplication.class); + //Note: SpringDocExampleApplication is the name of your main class + application.addListeners(new SpringDocSwaggerConfig()); + application.run(args); + } +} diff --git a/spring-boot-modules/spring-boot-swagger-2/src/main/java/com/baeldung/springdoc/demo/SpringFoxExampleApplication.java b/spring-boot-modules/spring-boot-swagger-2/src/main/java/com/baeldung/springdoc/demo/SpringFoxExampleApplication.java new file mode 100644 index 0000000000..c6106cc95d --- /dev/null +++ b/spring-boot-modules/spring-boot-swagger-2/src/main/java/com/baeldung/springdoc/demo/SpringFoxExampleApplication.java @@ -0,0 +1,13 @@ +package com.baeldung.springdoc.demo; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class SpringFoxExampleApplication { + + public static void main(String[] args) { + SpringApplication.run(SpringFoxExampleApplication.class, args); + } + +} diff --git a/spring-boot-modules/spring-boot-swagger-2/src/main/java/com/baeldung/springdoc/demo/config/SpringDocSwaggerConfig.java b/spring-boot-modules/spring-boot-swagger-2/src/main/java/com/baeldung/springdoc/demo/config/SpringDocSwaggerConfig.java new file mode 100644 index 0000000000..5836235445 --- /dev/null +++ b/spring-boot-modules/spring-boot-swagger-2/src/main/java/com/baeldung/springdoc/demo/config/SpringDocSwaggerConfig.java @@ -0,0 +1,25 @@ +package com.baeldung.springdoc.demo.config; + +import java.util.Properties; + +import org.springframework.boot.context.event.ApplicationPreparedEvent; +import org.springframework.context.ApplicationListener; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.PropertiesPropertySource; +import org.springframework.stereotype.Component; + +@Component +public class SpringDocSwaggerConfig implements ApplicationListener { + + @Override + public void onApplicationEvent(final ApplicationPreparedEvent event) { + ConfigurableEnvironment environment = event.getApplicationContext().getEnvironment(); + Properties props = new Properties(); + props.put("springdoc.swagger-ui.path", swaggerPath()); + environment.getPropertySources().addFirst(new PropertiesPropertySource("programmatically", props)); + } + + private String swaggerPath() { + return "/myproject"; // TODO: implement your logic here. + } +} \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-swagger-2/src/main/java/com/baeldung/springdoc/demo/config/SpringFoxSwaggerConfig.java b/spring-boot-modules/spring-boot-swagger-2/src/main/java/com/baeldung/springdoc/demo/config/SpringFoxSwaggerConfig.java new file mode 100644 index 0000000000..e07ca5c2a1 --- /dev/null +++ b/spring-boot-modules/spring-boot-swagger-2/src/main/java/com/baeldung/springdoc/demo/config/SpringFoxSwaggerConfig.java @@ -0,0 +1,28 @@ +package com.baeldung.springdoc.demo.config; + +import java.util.ArrayList; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import springfox.documentation.builders.PathSelectors; +import springfox.documentation.builders.RequestHandlerSelectors; +import springfox.documentation.service.ApiInfo; +import springfox.documentation.spi.DocumentationType; +import springfox.documentation.spring.web.plugins.Docket; + +@Configuration +public class SpringFoxSwaggerConfig { + + @Bean + public Docket productApi() { + return new Docket(DocumentationType.SWAGGER_2).select().apis(RequestHandlerSelectors.any()) + .paths(PathSelectors.any()).build().apiInfo(metaInfo()); + } + + private ApiInfo metaInfo() { + + return new ApiInfo("Sample API REST", "API REST", "1.0", "Terms of Service", null, "Apache License Version 2.0", + "https://www.apache.org/licesen.html", new ArrayList<>()); + } +} \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-swagger-2/src/main/java/com/baeldung/springdoc/demo/controller/SwaggerController.java b/spring-boot-modules/spring-boot-swagger-2/src/main/java/com/baeldung/springdoc/demo/controller/SwaggerController.java new file mode 100644 index 0000000000..79c35e025e --- /dev/null +++ b/spring-boot-modules/spring-boot-swagger-2/src/main/java/com/baeldung/springdoc/demo/controller/SwaggerController.java @@ -0,0 +1,13 @@ +package com.baeldung.springdoc.demo.controller; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; + +@Controller +public class SwaggerController { + + @RequestMapping("/myproject") + public String getRedirectUrl() { + return "redirect:swagger-ui.html"; + } +} \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-swagger-2/src/main/java/com/baeldung/springdoc/demo/controller/TopicsController.java b/spring-boot-modules/spring-boot-swagger-2/src/main/java/com/baeldung/springdoc/demo/controller/TopicsController.java new file mode 100644 index 0000000000..dee825788d --- /dev/null +++ b/spring-boot-modules/spring-boot-swagger-2/src/main/java/com/baeldung/springdoc/demo/controller/TopicsController.java @@ -0,0 +1,26 @@ +package com.baeldung.springdoc.demo.controller; + +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.baeldung.springdoc.demo.model.Topic; +import com.baeldung.springdoc.demo.service.TopicService; + + +@RestController +public class TopicsController { + + @Autowired + TopicService topicService; + + @GetMapping(value = "/topics") + public ResponseEntity> getAllTopics() { + return new ResponseEntity<>(topicService.getAlllTopics(), HttpStatus.OK); + } +} diff --git a/spring-boot-modules/spring-boot-swagger-2/src/main/java/com/baeldung/springdoc/demo/model/Topic.java b/spring-boot-modules/spring-boot-swagger-2/src/main/java/com/baeldung/springdoc/demo/model/Topic.java new file mode 100644 index 0000000000..0e4417b64f --- /dev/null +++ b/spring-boot-modules/spring-boot-swagger-2/src/main/java/com/baeldung/springdoc/demo/model/Topic.java @@ -0,0 +1,26 @@ +package com.baeldung.springdoc.demo.model; + +public class Topic { + + Integer id; + String name; + + public Topic(Integer id, String name) { + super(); + this.id = id; + this.name = name; + } + + public Integer getId() { + return id; + } + public void setId(Integer id) { + this.id = id; + } + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } +} diff --git a/spring-boot-modules/spring-boot-swagger-2/src/main/java/com/baeldung/springdoc/demo/service/TopicService.java b/spring-boot-modules/spring-boot-swagger-2/src/main/java/com/baeldung/springdoc/demo/service/TopicService.java new file mode 100644 index 0000000000..a468d2915b --- /dev/null +++ b/spring-boot-modules/spring-boot-swagger-2/src/main/java/com/baeldung/springdoc/demo/service/TopicService.java @@ -0,0 +1,26 @@ +package com.baeldung.springdoc.demo.service; + +import java.util.ArrayList; +import java.util.List; + +import org.springframework.stereotype.Service; + +import com.baeldung.springdoc.demo.model.Topic; + +@Service +public class TopicService { + + private List topicsList; + + public TopicService(){ + this.topicsList = new ArrayList() {{ + add(new Topic(1, "Topic1")); + add(new Topic(2, "Topic2")); + add(new Topic(3, "Topic3")); + }}; + } + + public List getAlllTopics(){ + return topicsList; + } +} diff --git a/spring-boot-modules/spring-boot-swagger-2/src/main/resources/application.properties b/spring-boot-modules/spring-boot-swagger-2/src/main/resources/application.properties index 03302ebb1c..901f0a6cc3 100644 --- a/spring-boot-modules/spring-boot-swagger-2/src/main/resources/application.properties +++ b/spring-boot-modules/spring-boot-swagger-2/src/main/resources/application.properties @@ -1,2 +1,7 @@ springdoc.api-docs.enabled=false springdoc.swagger-ui.url=/api_3.yaml + +# Properties for custom Springdoc swagger-ui url + +#springdoc.swagger-ui.disable-swagger-default-url=true +#springdoc.swagger-ui.path=/myproject \ No newline at end of file diff --git a/spring-di-2/pom.xml b/spring-di-2/pom.xml index 1207506d17..69333c74f1 100644 --- a/spring-di-2/pom.xml +++ b/spring-di-2/pom.xml @@ -85,7 +85,7 @@ 2.6.1 - 1.11 + 1.14.0 1 2.17.1 diff --git a/spring-di/pom.xml b/spring-di/pom.xml index af0601deb6..cf3703096c 100644 --- a/spring-di/pom.xml +++ b/spring-di/pom.xml @@ -149,6 +149,7 @@ 1.5.2.RELEASE 1.10.19 1.9.5 + 3.3.2 \ No newline at end of file diff --git a/spring-ejb-modules/wildfly/pom.xml b/spring-ejb-modules/wildfly/pom.xml index c73a1f128d..f122e99001 100644 --- a/spring-ejb-modules/wildfly/pom.xml +++ b/spring-ejb-modules/wildfly/pom.xml @@ -85,8 +85,6 @@ - 1.8 - 1.8 7.0 10.1.0.Final 5.2.3.Final diff --git a/spring-ejb-modules/wildfly/widlfly-web/pom.xml b/spring-ejb-modules/wildfly/widlfly-web/pom.xml index fb8a7678af..46c3f7d0bc 100644 --- a/spring-ejb-modules/wildfly/widlfly-web/pom.xml +++ b/spring-ejb-modules/wildfly/widlfly-web/pom.xml @@ -41,4 +41,7 @@ + + 3.3.2 + \ No newline at end of file diff --git a/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/multiplelisteners/BookConsumer.java b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/multiplelisteners/BookConsumer.java new file mode 100644 index 0000000000..77c7dc2e91 --- /dev/null +++ b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/multiplelisteners/BookConsumer.java @@ -0,0 +1,26 @@ +package com.baeldung.spring.kafka.multiplelisteners; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.kafka.annotation.KafkaListener; +import org.springframework.stereotype.Service; + +@Service +public class BookConsumer { + private static final Logger logger = LoggerFactory.getLogger(BookConsumer.class); + + @KafkaListener(topics = "books", groupId = "books-content-search") + public void bookContentSearchConsumer(BookEvent event) { + logger.info("Books event received for full-text search indexing => {}", event); + } + + @KafkaListener(topics = "books", groupId = "books-price-index") + public void bookPriceIndexerConsumer(BookEvent event) { + logger.info("Books event received for price indexing => {}", event); + } + + @KafkaListener(topics = "books", groupId = "book-notification-consumer", concurrency = "2") + public void bookNotificationConsumer(BookEvent event) { + logger.info("Books event received for notification => {}", event); + } +} diff --git a/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/multiplelisteners/BookEvent.java b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/multiplelisteners/BookEvent.java new file mode 100644 index 0000000000..11b13f120d --- /dev/null +++ b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/multiplelisteners/BookEvent.java @@ -0,0 +1,15 @@ +package com.baeldung.spring.kafka.multiplelisteners; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class BookEvent { + + private String title; + private String description; + private Double price; +} diff --git a/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/multiplelisteners/KafkaConsumerConfig.java b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/multiplelisteners/KafkaConsumerConfig.java new file mode 100644 index 0000000000..a6e0a91425 --- /dev/null +++ b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/multiplelisteners/KafkaConsumerConfig.java @@ -0,0 +1,64 @@ +package com.baeldung.spring.kafka.multiplelisteners; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.kafka.clients.consumer.ConsumerConfig; +import org.apache.kafka.common.serialization.StringDeserializer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.kafka.annotation.EnableKafka; +import org.springframework.kafka.config.ConcurrentKafkaListenerContainerFactory; +import org.springframework.kafka.core.ConsumerFactory; +import org.springframework.kafka.core.DefaultKafkaConsumerFactory; +import org.springframework.kafka.listener.DefaultErrorHandler; +import org.springframework.kafka.support.serializer.JsonDeserializer; +import org.springframework.util.backoff.BackOff; +import org.springframework.util.backoff.FixedBackOff; + +@EnableKafka +@Configuration +public class KafkaConsumerConfig { + + private static final Logger LOGGER = LoggerFactory.getLogger(KafkaConsumerConfig.class); + + @Value(value = "${spring.kafka.bootstrap-servers}") + private String bootstrapAddress; + + @Value(value = "${kafka.backoff.interval}") + private Long interval; + + @Value(value = "${kafka.backoff.max_failure}") + private Long maxAttempts; + + public ConsumerFactory consumerFactory() { + Map props = new HashMap<>(); + props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapAddress); + props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class); + props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, JsonDeserializer.class); + props.put(ConsumerConfig.MAX_PARTITION_FETCH_BYTES_CONFIG, "20971520"); + props.put(ConsumerConfig.FETCH_MAX_BYTES_CONFIG, "20971520"); + props.put(JsonDeserializer.TRUSTED_PACKAGES, "*"); + props.put(JsonDeserializer.TYPE_MAPPINGS, "bookEvent:com.baeldung.spring.kafka.multiplelisteners.BookEvent"); + + return new DefaultKafkaConsumerFactory<>(props); + } + + @Bean + public ConcurrentKafkaListenerContainerFactory kafkaListenerContainerFactory() { + ConcurrentKafkaListenerContainerFactory factory = new ConcurrentKafkaListenerContainerFactory<>(); + factory.setConsumerFactory(consumerFactory()); + factory.setCommonErrorHandler(errorHandler()); + return factory; + } + + @Bean + public DefaultErrorHandler errorHandler() { + BackOff fixedBackOff = new FixedBackOff(interval, maxAttempts); + return new DefaultErrorHandler((consumerRecord, e) -> LOGGER.error(String.format("consumed record %s because this exception was thrown", consumerRecord.toString())), fixedBackOff); + } + +} diff --git a/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/multiplelisteners/KafkaProducerConfig.java b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/multiplelisteners/KafkaProducerConfig.java new file mode 100644 index 0000000000..35204428a0 --- /dev/null +++ b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/multiplelisteners/KafkaProducerConfig.java @@ -0,0 +1,54 @@ +package com.baeldung.spring.kafka.multiplelisteners; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.kafka.clients.producer.ProducerConfig; +import org.apache.kafka.common.serialization.StringSerializer; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.kafka.core.DefaultKafkaProducerFactory; +import org.springframework.kafka.core.KafkaTemplate; +import org.springframework.kafka.core.ProducerFactory; +import org.springframework.kafka.support.serializer.JsonSerializer; + +@Configuration +public class KafkaProducerConfig { + + @Value(value = "${spring.kafka.bootstrap-servers}") + private String bootstrapAddress; + + @Bean + public ProducerFactory producerFactory() { + Map configProps = new HashMap<>(); + configProps.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapAddress); + configProps.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class); + configProps.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class); + configProps.put(ProducerConfig.MAX_REQUEST_SIZE_CONFIG, "20971520"); + + return new DefaultKafkaProducerFactory<>(configProps); + } + + @Bean + public KafkaTemplate kafkaTemplate() { + return new KafkaTemplate<>(producerFactory()); + } + + @Bean + public ProducerFactory bookProducerFactory() { + Map configProps = new HashMap<>(); + configProps.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapAddress); + configProps.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class); + configProps.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, JsonSerializer.class); + configProps.put(JsonSerializer.TYPE_MAPPINGS, "bookEvent:com.baeldung.spring.kafka.multiplelisteners.BookEvent"); + + return new DefaultKafkaProducerFactory<>(configProps); + } + + @Bean + public KafkaTemplate bookKafkaTemplate() { + return new KafkaTemplate<>(bookProducerFactory()); + } + +} diff --git a/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/multiplelisteners/KafkaTopicConfig.java b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/multiplelisteners/KafkaTopicConfig.java new file mode 100644 index 0000000000..5bc0a966b5 --- /dev/null +++ b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/multiplelisteners/KafkaTopicConfig.java @@ -0,0 +1,33 @@ +package com.baeldung.spring.kafka.multiplelisteners; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.kafka.clients.admin.AdminClientConfig; +import org.apache.kafka.clients.admin.NewTopic; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.kafka.core.KafkaAdmin; + +@Configuration +public class KafkaTopicConfig { + + @Value(value = "${spring.kafka.bootstrap-servers}") + private String bootstrapAddress; + + @Value(value = "${multiple-listeners.books.topic.name}") + private String booksTopicName; + + @Bean + public KafkaAdmin kafkaAdmin() { + Map configs = new HashMap<>(); + configs.put(AdminClientConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapAddress); + return new KafkaAdmin(configs); + } + + @Bean + public NewTopic booksTopic() { + return new NewTopic(booksTopicName, 1, (short) 1); + } +} diff --git a/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/multiplelisteners/MultipleListenersApplicationKafkaApp.java b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/multiplelisteners/MultipleListenersApplicationKafkaApp.java new file mode 100644 index 0000000000..c8a2f6e689 --- /dev/null +++ b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/multiplelisteners/MultipleListenersApplicationKafkaApp.java @@ -0,0 +1,14 @@ +package com.baeldung.spring.kafka.multiplelisteners; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Import; + +@SpringBootApplication +@Import(value = { KafkaTopicConfig.class, KafkaConsumerConfig.class, KafkaProducerConfig.class }) +public class MultipleListenersApplicationKafkaApp { + + public static void main(String[] args) { + SpringApplication.run(MultipleListenersApplicationKafkaApp.class, args); + } +} diff --git a/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/Farewell.java b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/retryable/Farewell.java similarity index 94% rename from spring-kafka-2/src/main/java/com/baeldung/spring/kafka/Farewell.java rename to spring-kafka-2/src/main/java/com/baeldung/spring/kafka/retryable/Farewell.java index bbff315ad2..519d847aab 100644 --- a/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/Farewell.java +++ b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/retryable/Farewell.java @@ -1,4 +1,4 @@ -package com.baeldung.spring.kafka; +package com.baeldung.spring.kafka.retryable; public class Farewell { diff --git a/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/Greeting.java b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/retryable/Greeting.java similarity index 92% rename from spring-kafka-2/src/main/java/com/baeldung/spring/kafka/Greeting.java rename to spring-kafka-2/src/main/java/com/baeldung/spring/kafka/retryable/Greeting.java index b4633e802a..79abeda34e 100644 --- a/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/Greeting.java +++ b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/retryable/Greeting.java @@ -1,4 +1,4 @@ -package com.baeldung.spring.kafka; +package com.baeldung.spring.kafka.retryable; public class Greeting { diff --git a/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/KafkaConsumerConfig.java b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/retryable/KafkaConsumerConfig.java similarity index 98% rename from spring-kafka-2/src/main/java/com/baeldung/spring/kafka/KafkaConsumerConfig.java rename to spring-kafka-2/src/main/java/com/baeldung/spring/kafka/retryable/KafkaConsumerConfig.java index 463d3209ea..cf4b29137e 100644 --- a/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/KafkaConsumerConfig.java +++ b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/retryable/KafkaConsumerConfig.java @@ -1,6 +1,5 @@ -package com.baeldung.spring.kafka; +package com.baeldung.spring.kafka.retryable; -import java.net.SocketTimeoutException; import java.util.HashMap; import java.util.Map; diff --git a/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/KafkaProducerConfig.java b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/retryable/KafkaProducerConfig.java similarity index 94% rename from spring-kafka-2/src/main/java/com/baeldung/spring/kafka/KafkaProducerConfig.java rename to spring-kafka-2/src/main/java/com/baeldung/spring/kafka/retryable/KafkaProducerConfig.java index da8b2bd1a6..90dcb2ccf9 100644 --- a/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/KafkaProducerConfig.java +++ b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/retryable/KafkaProducerConfig.java @@ -1,4 +1,4 @@ -package com.baeldung.spring.kafka; +package com.baeldung.spring.kafka.retryable; import java.util.HashMap; import java.util.Map; @@ -55,7 +55,7 @@ public class KafkaProducerConfig { configProps.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapAddress); configProps.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class); configProps.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, JsonSerializer.class); - configProps.put(JsonSerializer.TYPE_MAPPINGS, "greeting:com.baeldung.spring.kafka.Greeting, farewell:com.baeldung.spring.kafka.Farewell"); + configProps.put(JsonSerializer.TYPE_MAPPINGS, "greeting:com.baeldung.spring.kafka.retrayable.Greeting, farewell:com.baeldung.spring.kafka.retrayable.Farewell"); return new DefaultKafkaProducerFactory<>(configProps); } diff --git a/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/KafkaTopicConfig.java b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/retryable/KafkaTopicConfig.java similarity index 97% rename from spring-kafka-2/src/main/java/com/baeldung/spring/kafka/KafkaTopicConfig.java rename to spring-kafka-2/src/main/java/com/baeldung/spring/kafka/retryable/KafkaTopicConfig.java index 6a20915699..3b4c2d9928 100644 --- a/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/KafkaTopicConfig.java +++ b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/retryable/KafkaTopicConfig.java @@ -1,4 +1,4 @@ -package com.baeldung.spring.kafka; +package com.baeldung.spring.kafka.retryable; import java.util.HashMap; import java.util.Map; diff --git a/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/MultiTypeKafkaListener.java b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/retryable/MultiTypeKafkaListener.java similarity index 95% rename from spring-kafka-2/src/main/java/com/baeldung/spring/kafka/MultiTypeKafkaListener.java rename to spring-kafka-2/src/main/java/com/baeldung/spring/kafka/retryable/MultiTypeKafkaListener.java index 6c4d78171b..441e564176 100644 --- a/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/MultiTypeKafkaListener.java +++ b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/retryable/MultiTypeKafkaListener.java @@ -1,4 +1,4 @@ -package com.baeldung.spring.kafka; +package com.baeldung.spring.kafka.retryable; import org.springframework.kafka.annotation.KafkaHandler; import org.springframework.kafka.annotation.KafkaListener; diff --git a/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/RetryableApplicationKafkaApp.java b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/retryable/RetryableApplicationKafkaApp.java similarity index 91% rename from spring-kafka-2/src/main/java/com/baeldung/spring/kafka/RetryableApplicationKafkaApp.java rename to spring-kafka-2/src/main/java/com/baeldung/spring/kafka/retryable/RetryableApplicationKafkaApp.java index e43207829a..458ebac124 100644 --- a/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/RetryableApplicationKafkaApp.java +++ b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/retryable/RetryableApplicationKafkaApp.java @@ -1,4 +1,4 @@ -package com.baeldung.spring.kafka; +package com.baeldung.spring.kafka.retryable; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; diff --git a/spring-kafka-2/src/main/resources/application.properties b/spring-kafka-2/src/main/resources/application.properties index 691b6f55b7..4725ace2d9 100644 --- a/spring-kafka-2/src/main/resources/application.properties +++ b/spring-kafka-2/src/main/resources/application.properties @@ -16,5 +16,7 @@ monitor.kafka.consumer.groupid.simulate=baeldungGrpSimulate test.topic=testtopic1 kafka.backoff.interval=9000 kafka.backoff.max_failure=5 +# multiple listeners properties +multiple-listeners.books.topic.name=books diff --git a/spring-kafka-2/src/test/java/com/baeldung/spring/kafka/multiplelisteners/KafkaMultipleListenersIntegrationTest.java b/spring-kafka-2/src/test/java/com/baeldung/spring/kafka/multiplelisteners/KafkaMultipleListenersIntegrationTest.java new file mode 100644 index 0000000000..b6634ec7ed --- /dev/null +++ b/spring-kafka-2/src/test/java/com/baeldung/spring/kafka/multiplelisteners/KafkaMultipleListenersIntegrationTest.java @@ -0,0 +1,75 @@ +package com.baeldung.spring.kafka.multiplelisteners; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +import java.util.Arrays; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.kafka.config.KafkaListenerEndpointRegistry; +import org.springframework.kafka.core.KafkaTemplate; +import org.springframework.kafka.listener.AcknowledgingConsumerAwareMessageListener; +import org.springframework.kafka.listener.ConcurrentMessageListenerContainer; +import org.springframework.kafka.test.context.EmbeddedKafka; + +@SpringBootTest(classes = MultipleListenersApplicationKafkaApp.class) +@EmbeddedKafka(partitions = 1, brokerProperties = { "listeners=PLAINTEXT://localhost:9092", "port=9092" }) +class KafkaMultipleListenersIntegrationTest { + + @Autowired + private KafkaListenerEndpointRegistry registry; + @Autowired + private KafkaTemplate bookEventKafkaTemplate; + + private static final String TOPIC = "books"; + + @Test + void givenEmbeddedKafkaBroker_whenSendingAMessage_thenMessageIsConsumedByAll3Listeners() throws Exception { + BookEvent bookEvent = new BookEvent("test-book-title-1", "test-book-desc-1", 2.0); + CountDownLatch latch = new CountDownLatch(3); + + List> bookListeners = registry.getAllListenerContainers() + .stream() + .map(c -> (ConcurrentMessageListenerContainer) c) + .collect(Collectors.toList()); + + bookListeners.forEach(listener -> { + listener.stop(); + listener.getContainerProperties() + .setMessageListener((AcknowledgingConsumerAwareMessageListener) (data, acknowledgment, consumer) -> { + assertThat(data.value()).isEqualTo(bookEvent); + latch.countDown(); + }); + listener.start(); + }); + + bookEventKafkaTemplate.send(TOPIC, UUID.randomUUID() + .toString(), bookEvent); + + assertThat(bookListeners.size()).isEqualTo(3); + assertThat(latch.await(10, TimeUnit.SECONDS)).isTrue(); + } + + @Test + void givenEmbeddedKafkaBroker_whenSendingThreeMessage_thenListenerPrintLogs() throws Exception { + CountDownLatch latch = new CountDownLatch(3); + Arrays.stream(new int[] { 1, 2, 3 }) + .mapToObj(i -> new BookEvent(String.format("book %s", i), String.format("description %s", i), (double) i)) + .forEach(bookEvent -> { + bookEventKafkaTemplate.send(TOPIC, UUID.randomUUID() + .toString(), bookEvent); + latch.countDown(); + }); + + // wait for messages to be printed + Thread.sleep(1000); + + assertThat(latch.await(10, TimeUnit.SECONDS)).isTrue(); + } +} diff --git a/spring-kafka-2/src/test/java/com/baeldung/spring/kafka/KafkaRetryableIntegrationTest.java b/spring-kafka-2/src/test/java/com/baeldung/spring/kafka/retryable/KafkaRetryableIntegrationTest.java similarity index 95% rename from spring-kafka-2/src/test/java/com/baeldung/spring/kafka/KafkaRetryableIntegrationTest.java rename to spring-kafka-2/src/test/java/com/baeldung/spring/kafka/retryable/KafkaRetryableIntegrationTest.java index 5417fee1ac..52cda85f90 100644 --- a/spring-kafka-2/src/test/java/com/baeldung/spring/kafka/KafkaRetryableIntegrationTest.java +++ b/spring-kafka-2/src/test/java/com/baeldung/spring/kafka/retryable/KafkaRetryableIntegrationTest.java @@ -1,4 +1,4 @@ -package com.baeldung.spring.kafka; +package com.baeldung.spring.kafka.retryable; import static org.assertj.core.api.AssertionsForClassTypes.assertThat; @@ -17,6 +17,8 @@ import org.springframework.kafka.listener.ConcurrentMessageListenerContainer; import org.springframework.kafka.test.EmbeddedKafkaBroker; import org.springframework.kafka.test.context.EmbeddedKafka; +import com.baeldung.spring.kafka.retryable.Greeting; +import com.baeldung.spring.kafka.retryable.RetryableApplicationKafkaApp; import com.fasterxml.jackson.databind.ObjectMapper; @SpringBootTest(classes = RetryableApplicationKafkaApp.class) diff --git a/spring-reactive-modules/spring-5-data-reactive/pom.xml b/spring-reactive-modules/spring-5-data-reactive/pom.xml index bf5170c621..0ed997b3f4 100644 --- a/spring-reactive-modules/spring-5-data-reactive/pom.xml +++ b/spring-reactive-modules/spring-5-data-reactive/pom.xml @@ -42,6 +42,7 @@ org.projectlombok lombok + 1.18.22 io.projectreactor diff --git a/spring-vault/src/main/java/com/baeldung/springvault/CredentialsService.java b/spring-vault/src/main/java/com/baeldung/springvault/CredentialsService.java index 75bdd382cb..d9718252cb 100644 --- a/spring-vault/src/main/java/com/baeldung/springvault/CredentialsService.java +++ b/spring-vault/src/main/java/com/baeldung/springvault/CredentialsService.java @@ -5,54 +5,54 @@ import java.util.Optional; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import org.springframework.vault.core.VaultKeyValueOperations; +import org.springframework.vault.core.VaultKeyValueOperationsSupport; import org.springframework.vault.core.VaultTemplate; import org.springframework.vault.support.VaultResponseSupport; /** * Sample service to demonstrate storing and retrieval of secrets. - * + * * NOTE: We need to configure Vault and provide the Vault uri in the properties file. * */ @Service public class CredentialsService { + private final VaultTemplate vaultTemplate; + private final VaultKeyValueOperations vaultKeyValueOperations; + private final CredentialsRepository credentialsRepository; @Autowired - private VaultTemplate vaultTemplate; - - @Autowired - private CredentialsRepository credentialsRepository; + public CredentialsService(VaultTemplate vaultTemplate, CredentialsRepository credentialsRepository) { + this.vaultTemplate = vaultTemplate; + this.credentialsRepository = credentialsRepository; + this.vaultKeyValueOperations = vaultTemplate.opsForKeyValue("credentials/myapp", VaultKeyValueOperationsSupport.KeyValueBackend.KV_2); + } /** - * To Secure Credentials - * @param credentials - * @return VaultResponse - * @throws URISyntaxException - */ - public void secureCredentials(Credentials credentials) throws URISyntaxException { - - vaultTemplate.write("credentials/myapp", credentials); + * To Secure Credentials + * @param credentials + * @return VaultResponse + * @throws URISyntaxException + */ + public void secureCredentials(Credentials credentials) { + vaultKeyValueOperations.put(credentials.getUsername(), credentials); } /** * To Retrieve Credentials * @return Credentials - * @throws URISyntaxException */ - public Credentials accessCredentials() throws URISyntaxException { - - VaultResponseSupport response = vaultTemplate.read("credentials/myapp", Credentials.class); + public Credentials accessCredentials(String username) { + VaultResponseSupport response = vaultKeyValueOperations.get(username, Credentials.class); return response.getData(); } public Credentials saveCredentials(Credentials credentials) { - return credentialsRepository.save(credentials); } public Optional findById(String username) { - return credentialsRepository.findById(username); } - } diff --git a/spring-vault/src/test/java/com/baeldung/springvault/SpringContextLiveTest.java b/spring-vault/src/test/java/com/baeldung/springvault/SpringContextLiveTest.java index 8139522745..6e2a61ca40 100644 --- a/spring-vault/src/test/java/com/baeldung/springvault/SpringContextLiveTest.java +++ b/spring-vault/src/test/java/com/baeldung/springvault/SpringContextLiveTest.java @@ -5,6 +5,7 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.vault.repository.configuration.EnableVaultRepositories; /** * This live test requires: @@ -17,6 +18,7 @@ import org.springframework.test.context.junit4.SpringRunner; */ @RunWith(SpringRunner.class) @SpringBootTest(classes = SpringVaultApplication.class) +@EnableVaultRepositories public class SpringContextLiveTest { @Test diff --git a/spring-vault/src/test/java/com/baeldung/springvault/VaultInitializer.java b/spring-vault/src/test/java/com/baeldung/springvault/VaultInitializer.java index a823a4cd27..cf6b425581 100644 --- a/spring-vault/src/test/java/com/baeldung/springvault/VaultInitializer.java +++ b/spring-vault/src/test/java/com/baeldung/springvault/VaultInitializer.java @@ -7,11 +7,12 @@ import java.io.InputStreamReader; import java.util.Map; /** - * + * * This is a test class to initialize Vault. */ public class VaultInitializer implements Closeable { + public static final String API_VERSION = "v1"; private static final String UNSEAL_KEY = "Unseal Key:"; private static final String ROOT_TOKEN = "Root Token:"; @@ -27,7 +28,7 @@ public class VaultInitializer implements Closeable { return unSealKey; } - public static final VaultInitializer initializeValut() { + public static final VaultInitializer initializeVault() { VaultInitializer vaultProcess = new VaultInitializer(); vaultProcess.start(); // Secrets is by default enabled. @@ -37,8 +38,9 @@ public class VaultInitializer implements Closeable { @SuppressWarnings("unused") private void enableSecrets() { - System.out.println("Enabling Secrets at path credentials/myapp..."); - ProcessBuilder pb = new ProcessBuilder("vault", "secrets", "enable", "-path=credentials/myapp", "kv"); + System.out.println("Enabling Secrets at path secret/..."); + ProcessBuilder pb = new ProcessBuilder("vault", "secrets", "enable", "-path=credentials/myapp/", String.format("kv-%s", API_VERSION)); ; + Map map = pb.environment(); map.put("VAULT_ADDR", "http://127.0.0.1:8200"); try { @@ -106,8 +108,7 @@ public class VaultInitializer implements Closeable { @Override public void close() throws IOException { - - System.out.println("stoping vault"); + System.out.println("stopping vault"); vaultProcess.destroy(); } } diff --git a/spring-vault/src/test/java/com/baeldung/springvault/VaultIntegrationManualTest.java b/spring-vault/src/test/java/com/baeldung/springvault/VaultIntegrationManualTest.java new file mode 100644 index 0000000000..9913a7dc5c --- /dev/null +++ b/spring-vault/src/test/java/com/baeldung/springvault/VaultIntegrationManualTest.java @@ -0,0 +1,103 @@ +package com.baeldung.springvault; + +import static com.baeldung.springvault.VaultInitializer.API_VERSION; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import java.net.URISyntaxException; +import java.util.Optional; + +import org.junit.Before; +import org.junit.Assume; +import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.annotation.DirtiesContext.ClassMode; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.context.support.AnnotationConfigContextLoader; +import org.springframework.vault.core.VaultTemplate; +import org.springframework.vault.repository.configuration.EnableVaultRepositories; + +/** + * These tests are requiring the {@code vault} command to be installed and available in the executing + * platform. So, if you intend to run them in your environment, the please install the vault and then + * run the ignored tests. + */ +@RunWith(SpringJUnit4ClassRunner.class) +@SpringBootTest(classes = CredentialsService.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +@ContextConfiguration(classes = VaultTestConfiguration.class, loader = AnnotationConfigContextLoader.class) +@DirtiesContext(classMode = ClassMode.AFTER_CLASS) +@EnableVaultRepositories +public class VaultIntegrationManualTest { + @Autowired + private CredentialsRepository credentialsRepository; + + @Autowired + private VaultTemplate vaultTemplate; + + private CredentialsService credentialsService; + + @Before + public void setup() { + this.credentialsService = new CredentialsService(vaultTemplate, credentialsRepository); + } + + /** + * Test to secure credentials. + * + * @throws URISyntaxException + */ + @Test + public void givenCredentials_whenSecureCredentials_thenCredentialsSecuredSuccessfully() throws URISyntaxException { + // Given + Credentials credentials = new Credentials("username", "password"); + // When + credentialsService.secureCredentials(credentials); + // Then + Credentials storedCredentials = credentialsService.accessCredentials(credentials.getUsername()); + Assertions.assertNotNull(storedCredentials); + Assertions.assertEquals(credentials.getUsername(), storedCredentials.getUsername()); + Assertions.assertEquals(credentials.getPassword(), storedCredentials.getPassword()); + } + + @Test + public void givenCredentials_whenSave_thenReturnCredentials() throws InterruptedException { + Assume.assumeTrue("v1".equals(API_VERSION)); + + credentialsService = new CredentialsService(vaultTemplate, credentialsRepository); + // Given + Credentials credentials = new Credentials("login", "password"); + + // When + Credentials savedCredentials = credentialsService.saveCredentials(credentials); + + // Then + assertNotNull(savedCredentials); + assertEquals(credentials.getUsername(), savedCredentials.getUsername()); + assertEquals(credentials.getPassword(), savedCredentials.getPassword()); + } + + @Test + public void givenId_whenFindById_thenReturnCredentials() { + // Given + Assume.assumeTrue("v1".equals(API_VERSION)); + Credentials expectedCredentials = new Credentials("login", "p@ssw@rd"); + credentialsService.saveCredentials(expectedCredentials); + + // When + Optional retrievedCredentials = credentialsService.findById(expectedCredentials.getUsername()); + + // Then + assertNotNull(retrievedCredentials); + assertNotNull(retrievedCredentials.get()); + assertEquals(expectedCredentials.getUsername(), retrievedCredentials.get() + .getUsername()); + assertEquals(expectedCredentials.getPassword(), retrievedCredentials.get() + .getPassword()); + } + +} diff --git a/spring-vault/src/test/java/com/baeldung/springvault/VaultIntegrationTest.java b/spring-vault/src/test/java/com/baeldung/springvault/VaultIntegrationTest.java deleted file mode 100644 index 7987ae9904..0000000000 --- a/spring-vault/src/test/java/com/baeldung/springvault/VaultIntegrationTest.java +++ /dev/null @@ -1,118 +0,0 @@ -package com.baeldung.springvault; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; - -import java.net.URISyntaxException; -import java.util.Optional; - -import org.junit.FixMethodOrder; -import org.junit.Ignore; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.MethodSorters; -import org.mockito.Mockito; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.mock.mockito.MockBean; -import org.springframework.test.annotation.DirtiesContext; -import org.springframework.test.annotation.DirtiesContext.ClassMode; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringRunner; -import org.springframework.test.context.support.AnnotationConfigContextLoader; - -/** - * These tests are requiring the {@code vault} command to be installed and available in the executing - * platform. So, if you intend to run them in your environment, the please install the vault and then - * run the ignored tests. - */ -@RunWith(SpringRunner.class) -@SpringBootTest(classes = CredentialsService.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) -@ContextConfiguration(classes = VaultTestConfiguration.class, loader = AnnotationConfigContextLoader.class) -@FixMethodOrder(MethodSorters.NAME_ASCENDING) -@DirtiesContext(classMode = ClassMode.AFTER_CLASS) -public class VaultIntegrationTest { - - @Autowired - private CredentialsService credentialsService; - - @MockBean - private CredentialsRepository credentialsRepository; - - /** - * Test to secure credentials. - * - * @throws URISyntaxException - */ - @Test - @Ignore - public void givenCredentials_whenSecureCredentials_thenCredentialsSecured() throws URISyntaxException { - try { - // Given - Credentials credentials = new Credentials("username", "password"); - - // When - credentialsService.secureCredentials(credentials); - - } catch (Exception e) { - e.printStackTrace(); - } - - } - - /** - * Test to access credentials - * - * @throws URISyntaxException - */ - @Test - @Ignore - public void whenAccessCredentials_thenCredentialsRetrieved() throws URISyntaxException { - - // Given - Credentials credentials = credentialsService.accessCredentials(); - - // Then - assertNotNull(credentials); - assertEquals("username", credentials.getUsername()); - assertEquals("password", credentials.getPassword()); - } - - @Test - @Ignore - public void givenCredentials_whenSave_thenReturnCredentials() { - // Given - Credentials credentials = new Credentials("login", "password"); - Mockito.when(credentialsRepository.save(credentials)) - .thenReturn(credentials); - - // When - Credentials savedCredentials = credentialsService.saveCredentials(credentials); - - // Then - assertNotNull(savedCredentials); - assertEquals(savedCredentials.getUsername(), credentials.getUsername()); - assertEquals(savedCredentials.getPassword(), credentials.getPassword()); - } - - @Test - @Ignore - public void givenId_whenFindById_thenReturnCredentials() { - // Given - Credentials credentials = new Credentials("login", "p@ssw@rd"); - Mockito.when(credentialsRepository.findById("login")) - .thenReturn(Optional.of(credentials)); - - // When - Optional returnedCredentials = credentialsService.findById("login"); - - // Then - assertNotNull(returnedCredentials); - assertNotNull(returnedCredentials.get()); - assertEquals(returnedCredentials.get() - .getUsername(), credentials.getUsername()); - assertEquals(returnedCredentials.get() - .getPassword(), credentials.getPassword()); - } - -} diff --git a/spring-vault/src/test/java/com/baeldung/springvault/VaultTestConfiguration.java b/spring-vault/src/test/java/com/baeldung/springvault/VaultTestConfiguration.java index 42f0bfbce9..2e3651d646 100644 --- a/spring-vault/src/test/java/com/baeldung/springvault/VaultTestConfiguration.java +++ b/spring-vault/src/test/java/com/baeldung/springvault/VaultTestConfiguration.java @@ -5,6 +5,7 @@ import java.net.URISyntaxException; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.vault.annotation.VaultPropertySource; import org.springframework.vault.authentication.TokenAuthentication; import org.springframework.vault.client.VaultEndpoint; import org.springframework.vault.core.VaultTemplate; @@ -14,7 +15,7 @@ public class VaultTestConfiguration { @Bean public VaultInitializer vaultInitializer() { - VaultInitializer vaultInitializer = VaultInitializer.initializeValut(); + VaultInitializer vaultInitializer = VaultInitializer.initializeVault(); return vaultInitializer; } @@ -24,6 +25,5 @@ public class VaultTestConfiguration { VaultInitializer vaultInitializer = vaultInitializer(); VaultTemplate vaultTemplate = new VaultTemplate(VaultEndpoint.from(new URI("http://localhost:8200")), new TokenAuthentication(vaultInitializer.getRootToken())); return vaultTemplate; - } } diff --git a/testing-modules/gatling-java/Jenkinsfile b/testing-modules/gatling-java/Jenkinsfile new file mode 100644 index 0000000000..0786788406 --- /dev/null +++ b/testing-modules/gatling-java/Jenkinsfile @@ -0,0 +1,20 @@ +pipeline { + agent any + stages { + stage("Build Maven") { + steps { + sh 'mvn -B clean package' + } + } + stage("Run Gatling") { + steps { + sh 'mvn gatling:test' + } + post { + always { + gatlingArchive() + } + } + } + } +} \ No newline at end of file diff --git a/testing-modules/gatling-java/README.md b/testing-modules/gatling-java/README.md new file mode 100644 index 0000000000..71848ecfdc --- /dev/null +++ b/testing-modules/gatling-java/README.md @@ -0,0 +1,7 @@ +### Relevant Articles: +Load testing Rest End point using Gatling + + + +### Running a simualtion + To run the simulation from command prompt use mvn gatling:test \ No newline at end of file diff --git a/testing-modules/gatling-java/pom.xml b/testing-modules/gatling-java/pom.xml new file mode 100644 index 0000000000..c759928cc5 --- /dev/null +++ b/testing-modules/gatling-java/pom.xml @@ -0,0 +1,79 @@ + + + 4.0.0 + org.baeldung + gatling-java + 1.0-SNAPSHOT + gatling-java + + + com.baeldung + testing-modules + 1.0.0-SNAPSHOT + + + + io.gatling + gatling-app + ${gatling.version} + + + io.gatling.highcharts + gatling-charts-highcharts + ${gatling.version} + + + + org.springframework.boot + spring-boot-starter-web + ${spring.version} + + + org.projectlombok + lombok + 1.18.24 + provided + + + com.github.javafaker + javafaker + ${faker.version} + + + + + + + + + net.alchim31.maven + scala-maven-plugin + ${scala-maven-plugin.version} + + + + + + io.gatling + gatling-maven-plugin + ${gatling-maven-plugin.version} + + org.baeldung.EmployeeRegistrationSimulation + + + + + + + 1.8 + 1.8 + UTF-8 + 3.9.0 + 4.2.9 + 1.0.2 + 2.7.5 + + + \ No newline at end of file diff --git a/testing-modules/gatling-java/src/main/java/org/baeldung/Address.java b/testing-modules/gatling-java/src/main/java/org/baeldung/Address.java new file mode 100644 index 0000000000..2a8e6c60dc --- /dev/null +++ b/testing-modules/gatling-java/src/main/java/org/baeldung/Address.java @@ -0,0 +1,13 @@ +package org.baeldung; + +import lombok.Builder; +import lombok.Data; + +@Builder +@Data +public class Address { + private String postCode; + private String Street; + private String houseNo; + private String city; +} diff --git a/testing-modules/gatling-java/src/main/java/org/baeldung/Application.java b/testing-modules/gatling-java/src/main/java/org/baeldung/Application.java new file mode 100644 index 0000000000..fce18fe70c --- /dev/null +++ b/testing-modules/gatling-java/src/main/java/org/baeldung/Application.java @@ -0,0 +1,12 @@ +package org.baeldung; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class Application { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } +} \ No newline at end of file diff --git a/testing-modules/gatling-java/src/main/java/org/baeldung/Employee.java b/testing-modules/gatling-java/src/main/java/org/baeldung/Employee.java new file mode 100644 index 0000000000..c52130b175 --- /dev/null +++ b/testing-modules/gatling-java/src/main/java/org/baeldung/Employee.java @@ -0,0 +1,16 @@ +package org.baeldung; + +import java.util.Set; + +import lombok.Builder; +import lombok.Data; + +@Data +@Builder +public class Employee { + private String empName; + private Address address; + private String id; + private Set projects; + +} diff --git a/testing-modules/gatling-java/src/main/java/org/baeldung/EmployeeController.java b/testing-modules/gatling-java/src/main/java/org/baeldung/EmployeeController.java new file mode 100644 index 0000000000..ce5d558d8e --- /dev/null +++ b/testing-modules/gatling-java/src/main/java/org/baeldung/EmployeeController.java @@ -0,0 +1,99 @@ +package org.baeldung; + +import java.net.URI; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.ThreadLocalRandom; + +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +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.util.UriComponentsBuilder; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@RestController +@RequestMapping("/api/employees") +public class EmployeeController { + + @GetMapping(produces = { MediaType.APPLICATION_JSON_VALUE }) + public List getAllEmployees() { + return createEmployees(); + } + + @GetMapping("/{id}") + public Employee getEmployeeWithId(@PathVariable("id") Long id) { + log.info("Getting employee with ID '{}'", id); + + List allEmployees = createEmployees(); + return allEmployees.get(ThreadLocalRandom.current() + .nextInt(0, allEmployees.size())); + } + + @PostMapping(consumes = { MediaType.APPLICATION_JSON_VALUE }) + public ResponseEntity addEmployee(@RequestBody EmployeeCreationRequest request, UriComponentsBuilder uriComponentsBuilder) { + + log.info("Creating new employee with employeeName: {}", request.getEmpName()); + + URI location = uriComponentsBuilder.path("/api/employees/{id}") + .buildAndExpand("99") + .toUri(); + return ResponseEntity.created(location) + .build(); + } + + private List createEmployees() { + + Set projects = new HashSet(); + projects.add("proj1"); + projects.add("proj2"); + + Employee employee1 = Employee.builder() + .id(UUID.randomUUID() + .toString()) + .address(Address.builder() + .houseNo("1") + .city("London") + .postCode("HP17") + .build()) + .projects(projects) + .empName("Andy") + .build(); + + Employee employee2 = Employee.builder() + .id(UUID.randomUUID() + .toString()) + .address(Address.builder() + .houseNo("2") + .city("Cardiff") + .postCode("CF12") + .build()) + .projects(projects) + .empName("Bob") + .build(); + + Employee employee3 = Employee.builder() + .id(UUID.randomUUID() + .toString()) + .address(Address.builder() + .houseNo("4") + .city("Burmingham") + .postCode("BA4") + .build()) + .projects(projects) + .empName("Clive") + .build(); + + return Arrays.asList(employee1, employee2, employee3); + + } +} \ No newline at end of file diff --git a/testing-modules/gatling-java/src/main/java/org/baeldung/EmployeeCreationRequest.java b/testing-modules/gatling-java/src/main/java/org/baeldung/EmployeeCreationRequest.java new file mode 100644 index 0000000000..72c5e1ec27 --- /dev/null +++ b/testing-modules/gatling-java/src/main/java/org/baeldung/EmployeeCreationRequest.java @@ -0,0 +1,29 @@ +package org.baeldung; + +public class EmployeeCreationRequest { + + private String empName; + + private String empNumber; + + public String getEmpName() { + return empName; + } + + public void setEmpName(String empName) { + this.empName = empName; + } + + @Override + public String toString() { + return "org.baeldung.EmployeeCreationRequest{" + "employeename='" + empName + '\'' + '}'; + } + + public String getEmpNumber() { + return empNumber; + } + + public void setEmpNumber(String empNumber) { + this.empNumber = empNumber; + } +} \ No newline at end of file diff --git a/testing-modules/gatling-java/src/test/java/org/baeldung/EmployeeRegistrationSimulation.java b/testing-modules/gatling-java/src/test/java/org/baeldung/EmployeeRegistrationSimulation.java new file mode 100644 index 0000000000..de59273bbd --- /dev/null +++ b/testing-modules/gatling-java/src/test/java/org/baeldung/EmployeeRegistrationSimulation.java @@ -0,0 +1,87 @@ +package org.baeldung; + +import static io.gatling.javaapi.core.CoreDsl.StringBody; +import static io.gatling.javaapi.core.CoreDsl.global; +import static io.gatling.javaapi.core.CoreDsl.rampUsersPerSec; +import static io.gatling.javaapi.http.HttpDsl.header; +import static io.gatling.javaapi.http.HttpDsl.http; +import static io.gatling.javaapi.http.HttpDsl.status; + +import java.time.Duration; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.stream.Stream; + +import com.github.javafaker.Faker; + +import io.gatling.javaapi.core.CoreDsl; +import io.gatling.javaapi.core.OpenInjectionStep.RampRate.RampRateOpenInjectionStep; +import io.gatling.javaapi.core.ScenarioBuilder; +import io.gatling.javaapi.core.Simulation; +import io.gatling.javaapi.http.HttpDsl; +import io.gatling.javaapi.http.HttpProtocolBuilder; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class EmployeeRegistrationSimulation extends Simulation { + + private static final HttpProtocolBuilder HTTP_PROTOCOL_BUILDER = setupProtocolForSimulation(); + + private static final Iterator> FEED_DATA = setupTestFeedData(); + + private static final ScenarioBuilder POST_SCENARIO_BUILDER = buildPostScenario(); + + public EmployeeRegistrationSimulation() { + + setUp(POST_SCENARIO_BUILDER.injectOpen(postEndpointInjectionProfile()) + .protocols(HTTP_PROTOCOL_BUILDER)).assertions(global().responseTime() + .max() + .lte(10000), global().successfulRequests() + .percent() + .gt(90d)); + } + + private RampRateOpenInjectionStep postEndpointInjectionProfile() { + int totalDesiredUserCount = 200; + double userRampUpPerInterval = 50; + double rampUpIntervalSeconds = 30; + + int totalRampUptimeSeconds = 120; + int steadyStateDurationSeconds = 300; + return rampUsersPerSec(userRampUpPerInterval / (rampUpIntervalSeconds / 60)).to(totalDesiredUserCount) + .during(Duration.ofSeconds(totalRampUptimeSeconds + steadyStateDurationSeconds)); + } + + private static HttpProtocolBuilder setupProtocolForSimulation() { + return HttpDsl.http.baseUrl("http://localhost:8080") + .acceptHeader("application/json") + .maxConnectionsPerHost(10) + .userAgentHeader("Gatling/Performance Test"); + } + + private static Iterator> setupTestFeedData() { + Faker faker = new Faker(); + Iterator> iterator; + iterator = Stream.generate(() -> { + Map stringObjectMap = new HashMap<>(); + stringObjectMap.put("empName", faker.name() + .fullName()); + return stringObjectMap; + }) + .iterator(); + return iterator; + } + + private static ScenarioBuilder buildPostScenario() { + return CoreDsl.scenario("Load Test Creating User") + .feed(FEED_DATA) + .exec(http("create-employee-request").post("/api/employees") + .header("Content-Type", "application/json") + .body(StringBody("{ \"empName\": \"${empName}\" }")) + .check(status().is(201)) + .check(header("Location").saveAs("location"))) + .exec(http("get-employee-request").get(session -> session.getString("location")) + .check(status().is(200))); + } +} diff --git a/testing-modules/gatling-java/src/test/resources/gatling.conf b/testing-modules/gatling-java/src/test/resources/gatling.conf new file mode 100644 index 0000000000..6ebfd6e820 --- /dev/null +++ b/testing-modules/gatling-java/src/test/resources/gatling.conf @@ -0,0 +1,127 @@ + ######################### +# Gatling Configuration # +######################### + +# This file contains all the settings configurable for Gatling with their default values + +gatling { + core { + #outputDirectoryBaseName = "" # The prefix for each simulation result folder (then suffixed by the report generation timestamp) + #runDescription = "" # The description for this simulation run, displayed in each report + #encoding = "utf-8" # Encoding to use throughout Gatling for file and string manipulation + #simulationClass = "" # The FQCN of the simulation to run (when used in conjunction with noReports, the simulation for which assertions will be validated) + #mute = false # When set to true, don't ask for simulation name nor run description (currently only used by Gatling SBT plugin) + #elFileBodiesCacheMaxCapacity = 200 # Cache size for request body EL templates, set to 0 to disable + #rawFileBodiesCacheMaxCapacity = 200 # Cache size for request body Raw templates, set to 0 to disable + #rawFileBodiesInMemoryMaxSize = 1000 # Below this limit, raw file bodies will be cached in memory + + extract { + regex { + #cacheMaxCapacity = 200 # Cache size for the compiled regexes, set to 0 to disable caching + } + xpath { + #cacheMaxCapacity = 200 # Cache size for the compiled XPath queries, set to 0 to disable caching + } + jsonPath { + #cacheMaxCapacity = 200 # Cache size for the compiled jsonPath queries, set to 0 to disable caching + #preferJackson = false # When set to true, prefer Jackson over Boon for JSON-related operations + } + css { + #cacheMaxCapacity = 200 # Cache size for the compiled CSS selectors queries, set to 0 to disable caching + } + } + + directory { + #data = user-files/data # Folder where user's data (e.g. files used by Feeders) is located + #bodies = user-files/bodies # Folder where bodies are located + #simulations = user-files/simulations # Folder where the bundle's simulations are located + #reportsOnly = "" # If set, name of report folder to look for in order to generate its report + #binaries = "" # If set, name of the folder where compiles classes are located: Defaults to GATLING_HOME/target. + #results = results # Name of the folder where all reports folder are located + } + } + charting { + #noReports = false # When set to true, don't generate HTML reports + #maxPlotPerSeries = 1000 # Number of points per graph in Gatling reports + #useGroupDurationMetric = false # Switch group timings from cumulated response time to group duration. + indicators { + #lowerBound = 800 # Lower bound for the requests' response time to track in the reports and the console summary + #higherBound = 1200 # Higher bound for the requests' response time to track in the reports and the console summary + #percentile1 = 50 # Value for the 1st percentile to track in the reports, the console summary and Graphite + #percentile2 = 75 # Value for the 2nd percentile to track in the reports, the console summary and Graphite + #percentile3 = 95 # Value for the 3rd percentile to track in the reports, the console summary and Graphite + #percentile4 = 99 # Value for the 4th percentile to track in the reports, the console summary and Graphite + } + } + http { + #fetchedCssCacheMaxCapacity = 200 # Cache size for CSS parsed content, set to 0 to disable + #fetchedHtmlCacheMaxCapacity = 200 # Cache size for HTML parsed content, set to 0 to disable + #perUserCacheMaxCapacity = 200 # Per virtual user cache size, set to 0 to disable + #warmUpUrl = "http://gatling.io" # The URL to use to warm-up the HTTP stack (blank means disabled) + #enableGA = true # Very light Google Analytics, please support + ssl { + keyStore { + #type = "" # Type of SSLContext's KeyManagers store + #file = "" # Location of SSLContext's KeyManagers store + #password = "" # Password for SSLContext's KeyManagers store + #algorithm = "" # Algorithm used SSLContext's KeyManagers store + } + trustStore { + #type = "" # Type of SSLContext's TrustManagers store + #file = "" # Location of SSLContext's TrustManagers store + #password = "" # Password for SSLContext's TrustManagers store + #algorithm = "" # Algorithm used by SSLContext's TrustManagers store + } + } + ahc { + #keepAlive = true # Allow pooling HTTP connections (keep-alive header automatically added) + #connectTimeout = 60000 # Timeout when establishing a connection + #pooledConnectionIdleTimeout = 60000 # Timeout when a connection stays unused in the pool + #readTimeout = 60000 # Timeout when a used connection stays idle + #maxRetry = 2 # Number of times that a request should be tried again + #requestTimeout = 60000 # Timeout of the requests + #acceptAnyCertificate = true # When set to true, doesn't validate SSL certificates + #httpClientCodecMaxInitialLineLength = 4096 # Maximum length of the initial line of the response (e.g. "HTTP/1.0 200 OK") + #httpClientCodecMaxHeaderSize = 8192 # Maximum size, in bytes, of each request's headers + #httpClientCodecMaxChunkSize = 8192 # Maximum length of the content or each chunk + #webSocketMaxFrameSize = 10240000 # Maximum frame payload size + #sslEnabledProtocols = [TLSv1.2, TLSv1.1, TLSv1] # Array of enabled protocols for HTTPS, if empty use the JDK defaults + #sslEnabledCipherSuites = [] # Array of enabled cipher suites for HTTPS, if empty use the JDK defaults + #sslSessionCacheSize = 0 # SSLSession cache size, set to 0 to use JDK's default + #sslSessionTimeout = 0 # SSLSession timeout in seconds, set to 0 to use JDK's default (24h) + #useOpenSsl = false # if OpenSSL should be used instead of JSSE (requires tcnative jar) + #useNativeTransport = false # if native transport should be used instead of Java NIO (requires netty-transport-native-epoll, currently Linux only) + #usePooledMemory = true # if Gatling should use pooled memory + #tcpNoDelay = true + #soReuseAddress = false + #soLinger = -1 + #soSndBuf = -1 + #soRcvBuf = -1 + } + dns { + #queryTimeout = 5000 # Timeout of each DNS query in millis + #maxQueriesPerResolve = 3 # Maximum allowed number of DNS queries for a given name resolution + } + } + data { + #writers = [console, file] # The list of DataWriters to which Gatling write simulation data (currently supported : console, file, graphite, jdbc) + console { + #light = false # When set to true, displays a light version without detailed request stats + } + file { + #bufferSize = 8192 # FileDataWriter's internal data buffer size, in bytes + } + leak { + #noActivityTimeout = 30 # Period, in seconds, for which Gatling may have no activity before considering a leak may be happening + } + graphite { + #light = false # only send the all* stats + #host = "localhost" # The host where the Carbon server is located + #port = 2003 # The port to which the Carbon server listens to (2003 is default for plaintext, 2004 is default for pickle) + #protocol = "tcp" # The protocol used to send data to Carbon (currently supported : "tcp", "udp") + #rootPathPrefix = "gatling" # The common prefix of all metrics sent to Graphite + #bufferSize = 8192 # GraphiteDataWriter's internal data buffer size, in bytes + #writeInterval = 1 # GraphiteDataWriter's write interval, in seconds + } + } +} diff --git a/testing-modules/gatling-java/src/test/resources/logback.xml b/testing-modules/gatling-java/src/test/resources/logback.xml new file mode 100644 index 0000000000..b9ba6255a0 --- /dev/null +++ b/testing-modules/gatling-java/src/test/resources/logback.xml @@ -0,0 +1,22 @@ + + + + + + %d{HH:mm:ss.SSS} [%-5level] %logger{15} - %msg%n%rEx + false + + + + + + + + + + + + + + + diff --git a/testing-modules/pom.xml b/testing-modules/pom.xml index 64546b5064..80e0c3bc29 100644 --- a/testing-modules/pom.xml +++ b/testing-modules/pom.xml @@ -51,6 +51,7 @@ xmlunit-2 zerocode mockito-2 + gatling-java \ No newline at end of file diff --git a/vavr-modules/vavr/src/test/java/com/baeldung/vavr/future/FutureUnitTest.java b/vavr-modules/vavr/src/test/java/com/baeldung/vavr/future/FutureUnitTest.java index c398cc4095..5c6959e950 100644 --- a/vavr-modules/vavr/src/test/java/com/baeldung/vavr/future/FutureUnitTest.java +++ b/vavr-modules/vavr/src/test/java/com/baeldung/vavr/future/FutureUnitTest.java @@ -184,6 +184,6 @@ public class FutureUnitTest { assertThat( errorMessage.get().getMessage()) - .isEqualTo("String index out of range: -1"); + .isEqualTo("begin -1, end 5, length 5"); } }