Merge branch 'master' into master

This commit is contained in:
davidmartinezbarua 2023-03-21 14:46:30 -03:00 committed by GitHub
commit 944f31de8e
117 changed files with 2302 additions and 473 deletions

View File

@ -35,12 +35,12 @@
</dependency>
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-connector-kafka-0.11_2.11</artifactId>
<artifactId>flink-connector-kafka</artifactId>
<version>${flink.version}</version>
</dependency>
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-streaming-java_2.11</artifactId>
<artifactId>flink-streaming-java</artifactId>
<version>${flink.version}</version>
</dependency>
<dependency>
@ -67,7 +67,7 @@
</dependency>
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-test-utils_2.11</artifactId>
<artifactId>flink-test-utils</artifactId>
<version>${flink.version}</version>
<scope>test</scope>
</dependency>
@ -163,11 +163,29 @@
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>
--add-opens java.base/java.time=ALL-UNNAMED
--add-opens java.base/java.nio=ALL-UNNAMED
--add-opens java.base/java.util=ALL-UNNAMED
</argLine>
</configuration>
</plugin>
</plugins>
</build>
<properties>
<kafka.version>2.8.0</kafka.version>
<kafka.version>3.4.0</kafka.version>
<testcontainers-kafka.version>1.15.3</testcontainers-kafka.version>
<testcontainers-jupiter.version>1.15.3</testcontainers-jupiter.version>
<flink.version>1.5.0</flink.version>
<flink.version>1.16.1</flink.version>
<awaitility.version>3.0.0</awaitility.version>
<org.apache.spark.spark-core.version>2.4.8</org.apache.spark.spark-core.version>
<graphframes.version>0.8.1-spark3.0-s_2.12</graphframes.version>

View File

@ -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<String> flinkKafkaConsumer = createStringConsumerForTopic(inputTopic, address, consumerGroup);
FlinkKafkaConsumer<String> flinkKafkaConsumer = createStringConsumerForTopic(inputTopic, address, consumerGroup);
flinkKafkaConsumer.setStartFromEarliest();
DataStream<String> stringInputStream = environment.addSource(flinkKafkaConsumer);
FlinkKafkaProducer011<String> flinkKafkaProducer = createStringProducer(outputTopic, address);
FlinkKafkaProducer<String> flinkKafkaProducer = createStringProducer(outputTopic, address);
stringInputStream.map(new WordsCapitalizer())
.addSink(flinkKafkaProducer);
@ -48,11 +48,11 @@ public class FlinkDataPipeline {
environment.setStreamTimeCharacteristic(TimeCharacteristic.EventTime);
FlinkKafkaConsumer011<InputMessage> flinkKafkaConsumer = createInputMessageConsumer(inputTopic, kafkaAddress, consumerGroup);
FlinkKafkaConsumer<InputMessage> flinkKafkaConsumer = createInputMessageConsumer(inputTopic, kafkaAddress, consumerGroup);
flinkKafkaConsumer.setStartFromEarliest();
flinkKafkaConsumer.assignTimestampsAndWatermarks(new InputMessageTimestampAssigner());
FlinkKafkaProducer011<Backup> flinkKafkaProducer = createBackupProducer(outputTopic, kafkaAddress);
FlinkKafkaProducer<Backup> flinkKafkaProducer = createBackupProducer(outputTopic, kafkaAddress);
DataStream<InputMessage> inputMessagesStream = environment.addSource(flinkKafkaConsumer);

View File

@ -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<String> createStringConsumerForTopic(String topic, String kafkaAddress, String kafkaGroup) {
public static FlinkKafkaConsumer<String> createStringConsumerForTopic(String topic, String kafkaAddress, String kafkaGroup) {
Properties props = new Properties();
props.setProperty("bootstrap.servers", kafkaAddress);
props.setProperty("group.id", kafkaGroup);
FlinkKafkaConsumer011<String> consumer = new FlinkKafkaConsumer011<>(topic, new SimpleStringSchema(), props);
FlinkKafkaConsumer<String> consumer = new FlinkKafkaConsumer<>(topic, new SimpleStringSchema(), props);
return consumer;
}
public static FlinkKafkaConsumer011<InputMessage> createInputMessageConsumer(String topic, String kafkaAddress, String kafkaGroup) {
public static FlinkKafkaConsumer<InputMessage> createInputMessageConsumer(String topic, String kafkaAddress, String kafkaGroup) {
Properties properties = new Properties();
properties.setProperty("bootstrap.servers", kafkaAddress);
properties.setProperty("group.id", kafkaGroup);
FlinkKafkaConsumer011<InputMessage> consumer = new FlinkKafkaConsumer011<InputMessage>(topic, new InputMessageDeserializationSchema(), properties);
FlinkKafkaConsumer<InputMessage> consumer = new FlinkKafkaConsumer<InputMessage>(topic, new InputMessageDeserializationSchema(), properties);
return consumer;
}

View File

@ -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<String> createStringProducer(String topic, String kafkaAddress) {
return new FlinkKafkaProducer011<>(kafkaAddress, topic, new SimpleStringSchema());
public static FlinkKafkaProducer<String> createStringProducer(String topic, String kafkaAddress) {
return new FlinkKafkaProducer<>(kafkaAddress, topic, new SimpleStringSchema());
}
public static FlinkKafkaProducer011<Backup> createBackupProducer(String topic, String kafkaAddress) {
return new FlinkKafkaProducer011<Backup>(kafkaAddress, topic, new BackupSerializationSchema());
public static FlinkKafkaProducer<Backup> createBackupProducer(String topic, String kafkaAddress) {
return new FlinkKafkaProducer<Backup>(kafkaAddress, topic, new BackupSerializationSchema());
}
}

View File

@ -122,6 +122,7 @@
<docker.image.prefix>${azure.containerRegistry}.azurecr.io</docker.image.prefix>
<docker-maven-plugin.version>1.1.0</docker-maven-plugin.version>
<azure-webapp-maven-plugin.version>1.1.0</azure-webapp-maven-plugin.version>
<maven-war-plugin.version>3.3.2</maven-war-plugin.version>
</properties>
</project>

View File

@ -0,0 +1 @@
### Relevant Articles:

View File

@ -0,0 +1,25 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-conversions.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>core-java-numbers-conversions</artifactId>
<name>core-java-numbers-conversions</name>
<packaging>jar</packaging>
<parent>
<groupId>com.baeldung.core-java-modules</groupId>
<artifactId>core-java-modules</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<build>
<finalName>core-java-numbers-conversions</finalName>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
</build>
</project>

View File

@ -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));
}
}

View File

@ -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();
}
}

View File

@ -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,

View File

@ -108,6 +108,7 @@
<module>core-java-numbers-3</module>
<module>core-java-numbers-4</module>
<module>core-java-numbers-5</module>
<module>core-java-numbers-conversions</module>
<module>core-java-optional</module>
<module>core-java-perf</module>
<module>core-java-reflection</module>

View File

@ -103,7 +103,7 @@
<configuration>
<packageName>com.baeldung.feign.soap</packageName>
<sources>
<source>src/main/resources/users.xsd</source>
<source>${project.basedir}/src/main/resources/users.xsd</source>
</sources>
</configuration>
</plugin>

View File

@ -31,6 +31,7 @@
<properties>
<javax.websocket-api.version>1.1</javax.websocket-api.version>
<gson.version>2.8.0</gson.version>
<maven-war-plugin.version>3.3.2</maven-war-plugin.version>
</properties>
</project>

5
jetbrains/README.md Normal file
View File

@ -0,0 +1,5 @@
## Jetbrains
This module contains articles about Jetbrains' libraries.
### Relevant articles:

37
jetbrains/pom.xml Normal file
View File

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>jetbrains</artifactId>
<version>1.0-SNAPSHOT</version>
<name>jetbrains</name>
<packaging>jar</packaging>
<url>http://maven.apache.org</url>
<parent>
<groupId>com.baeldung</groupId>
<artifactId>parent-java</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../parent-java</relativePath>
</parent>
<dependencies>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>${apache.commons.version}</version>
</dependency>
<dependency>
<groupId>org.jetbrains</groupId>
<artifactId>annotations</artifactId>
<version>${jetbrains.annotations.version}</version>
</dependency>
</dependencies>
<properties>
<apache.commons.version>3.12.0</apache.commons.version>
<jetbrains.annotations.version>24.0.1</jetbrains.annotations.version>
</properties>
</project>

View File

@ -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<Integer> 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<String> 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() {
}
}

View File

@ -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;
}
}

View File

@ -48,8 +48,15 @@
<plugin>
<groupId>com.lazerycode.jmeter</groupId>
<artifactId>jmeter-maven-plugin</artifactId>
<version>${jmeter.version}</version>
<version>3.7.0</version>
<executions>
<!-- Generate JMeter configuration -->
<execution>
<id>configuration</id>
<goals>
<goal>configure</goal>
</goals>
</execution>
<execution>
<id>jmeter-tests</id>
<goals>
@ -66,7 +73,6 @@
</build>
<properties>
<jmeter.version>2.6.0</jmeter.version>
</properties>
<profiles>

View File

@ -57,7 +57,7 @@
<stringProp name="filename"></stringProp>
<stringProp name="parameters"></stringProp>
<boolProp name="resetInterpreter">false</boolProp>
<stringProp name="script">FileWriter fWriter = new FileWriter(&quot;<path>/result.txt&quot;, true);
<stringProp name="script">FileWriter fWriter = new FileWriter(&quot;&lt;path&gt;/result.txt&quot;, true);
BufferedWriter buff = new BufferedWriter(fWriter);
buff.write(&quot;Response Code : &quot; + ctx.getPreviousResult().getResponseCode());

View File

@ -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("<div><span></span></div>");

View File

@ -15,8 +15,7 @@
<modules>
<module>k8s-intro</module>
<module>k8s-admission-controller</module>
<!-- <module>kubernetes-spring</module> --> <!-- JDK-11 Module -->
<module>k8s-java-heap-dump</module>
<module>kubernetes-spring</module>
</modules>
</project>

View File

@ -132,7 +132,7 @@
<properties>
<mapdb.version>3.0.8</mapdb.version>
<classgraph.version>4.8.153</classgraph.version>
<jbpm.version>7.1.0.Final</jbpm.version>
<jbpm.version>7.20.0.Final</jbpm.version>
<picocli.version>4.7.0</picocli.version>
<chronicle.map.version>3.24ea1</chronicle.map.version>
<crawler4j.version>4.4.0</crawler4j.version>

View File

@ -15,7 +15,7 @@
<process processType="Private" isExecutable="true" id="com.baeldung.bpmn.helloworld" name="HelloWorld Process" tns:packageName="com.baeldung.bpmn.process" >
<!-- nodes -->
<scriptTask id="_jbpm-unique-1" name="HelloWorld" scriptFormat="http://www.java.com/java" >
<scriptTask id="_jbpm-unique-1" name="HelloWorld">
<script>System.out.println("Hello World");</script>
</scriptTask>
<endEvent id="_jbpm-unique-2" name="End" >

View File

@ -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());
}
}

View File

@ -18,6 +18,7 @@
<module>jgroups</module>
<module>rabbitmq</module>
<module>spring-amqp</module>
<module>spring-apache-camel</module>
<module>spring-jms</module>
</modules>

View File

@ -67,7 +67,6 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>${maven-war-plugin.version}</version>
<configuration>
<warSourceDirectory>src/main/webapp</warSourceDirectory>
<warName>spring-jms</warName>
@ -83,6 +82,7 @@
<springframework.version>4.3.4.RELEASE</springframework.version>
<activemq.version>5.14.1</activemq.version>
<spring-boot-test.version>1.5.10.RELEASE</spring-boot-test.version>
<maven-war-plugin.version>3.3.2</maven-war-plugin.version>
</properties>
</project>

View File

@ -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("<html>%s</html>", content);
}
public HtmlDocument header(String header) {
return new HtmlDocument(String.format("%s <h1>%s</h1>", content, header));
}
public HtmlDocument secondaryHeader(String header) {
return new HtmlDocument(String.format("%s <h2>%s</h2>", content, header));
}
public HtmlDocument paragraph(String paragraph) {
return new HtmlDocument(String.format("%s <p>%s</p>", content, paragraph));
}
public HtmlDocument horizontalLine() {
return new HtmlDocument(String.format("%s <hr>", content));
}
public HtmlDocument orderedList(String... items) {
String listItems = stream(items).map(el -> String.format("<li>%s</li>", el)).collect(joining());
return new HtmlDocument(String.format("%s <ol>%s</ol>", content, listItems));
}
public HtmlDocument unorderedList(String... items) {
String listItems = stream(items).map(el -> String.format("<li>%s</li>", el)).collect(joining());
return new HtmlDocument(String.format("%s <ul>%s</ul>", content, listItems));
}
}

View File

@ -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("<html>%s</html>", content);
}
public LargeHtmlDocument head(HtmlElement head) {
return new LargeHtmlDocument(format("%s <head>%s</head>", content, head.html()));
}
public LargeHtmlDocument body(HtmlElement body) {
return new LargeHtmlDocument(format("%s <body>%s</body>", content, body.html()));
}
public LargeHtmlDocument footer(HtmlElement footer) {
return new LargeHtmlDocument(format("%s <footer>%s</footer>", content, footer.html()));
}
private LargeHtmlDocument append(String html) {
return new LargeHtmlDocument(format("%s %s", content, html));
}
}

View File

@ -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);
}
}
}

View File

@ -0,0 +1,8 @@
package com.baeldung.fluentinterface.components;
public class HorizontalLine implements HtmlElement {
@Override
public String html() {
return "<hr>";
}
}

View File

@ -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("<div>%s</div>", content);
}
}

View File

@ -0,0 +1,5 @@
package com.baeldung.fluentinterface.components;
public interface HtmlElement {
String html();
}

View File

@ -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</%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;
}
}
}

View File

@ -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<String> 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("<li>%s</li>", el)).collect(joining());
return String.format("<%s>%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;
}
}
}

View File

@ -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("<span>%s</span>", content);
}
}

View File

@ -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<Integer> numbers = Stream.of(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
Stream<String> 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(
"<html>"
+ "<h1>Principles of O.O.P.</h1>"
+ "<p>OOP in Java.</p>"
+ "<hr>"
+ "<p>The main pillars of OOP are:</p>"
+ "<ol>"
+ "<li>Encapsulation</li>"
+ "<li>Inheritance</li>"
+ "<li>Abstraction</li>"
+ "<li>Polymorphism</li>"
+ "</ol>"
+ "</html>"
);
}
@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 = "<html> <head><h1>title</h1></head> <body><div><span>learning OOP from John Doe<hr>The pillars of OOP:</span><ol><li>Encapsulation</li><li>Inheritance</li><li>Abstraction</li><li>Polymorphism</li></ol></div></body> <footer><div>trademark John Doe</div></footer></html>";
assertThat(html).isEqualToIgnoringWhitespace(expectedHtml);
}
}

View File

@ -7,16 +7,7 @@
<version>1.0</version>
<name>idd</name>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>9</source>
<target>9</target>
</configuration>
</plugin>
</plugins>
</build>
<packaging>jar</packaging>

View File

@ -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;

View File

@ -98,7 +98,8 @@
<module>spring-data-mongodb-reactive</module>
<module>spring-data-neo4j</module>
<module>spring-data-redis</module>
<module>spring-data-rest</module>
<!-- Moved to JDK9+ profiles-->
<!-- <module>spring-data-rest</module>-->
<module>spring-data-rest-2</module>
<module>spring-data-rest-querydsl</module>
<module>spring-data-solr</module>

View File

@ -0,0 +1,2 @@
### Relevant Articles:
- [Introduction to QuestDB](#)

View File

@ -0,0 +1,29 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.baeldung</groupId>
<artifactId>questdb</artifactId>
<name>questdb</name>
<version>0.0.1-SNAPSHOT</version>
<parent>
<groupId>com.baeldung</groupId>
<artifactId>parent-java</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../../parent-java</relativePath>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<questdb.version>7.0.0</questdb.version>
</properties>
<dependencies>
<dependency>
<groupId>org.questdb</groupId>
<artifactId>questdb</artifactId>
<version>${questdb.version}</version>
</dependency>
</dependencies>
</project>

View File

@ -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();
}
}
}

View File

@ -11,9 +11,9 @@
<parent>
<groupId>com.baeldung</groupId>
<artifactId>parent-boot-2</artifactId>
<artifactId>parent-boot-3</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../../parent-boot-2</relativePath>
<relativePath>../../parent-boot-3</relativePath>
</parent>
<dependencies>
@ -42,6 +42,17 @@
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hibernate.orm</groupId>
<artifactId>hibernate-community-dialects</artifactId>
<version>${hibernate-community-dialects.version}</version>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<version>3.3.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
@ -64,23 +75,6 @@
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<groupId>com.mysema.maven</groupId>
<artifactId>maven-apt-plugin</artifactId>
<version>${maven.version}</version>
<executions>
<execution>
<phase>generate-sources</phase>
<goals>
<goal>process</goal>
</goals>
<configuration>
<outputDirectory>target/generated-sources</outputDirectory>
<processor>com.querydsl.apt.jpa.JPAAnnotationProcessor</processor>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
@ -91,6 +85,7 @@
<properties>
<start-class>com.baeldung.books.SpringDataRestApplication</start-class>
<maven.version>1.0</maven.version>
<hibernate-community-dialects.version>6.1.7.Final</hibernate-community-dialects.version>
</properties>
</project>

View File

@ -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;
}
}

View File

@ -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";
}
}

View File

@ -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 {

View File

@ -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 {

View File

@ -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 {

View File

@ -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;

View File

@ -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 {

View File

@ -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

108
pom.xml
View File

@ -330,59 +330,35 @@
<module>parent-spring-5</module>
<module>parent-java</module>
<module>azure</module>
<module>checker-plugin</module>
<!-- <module>clojure</module> --> <!-- Not a maven project -->
<module>core-java-modules</module>
<module>couchbase</module>
<!-- <module>ethereum</module> --> <!-- JAVA-6001 -->
<!-- <module>gradle-modules</module> --> <!-- Not a maven project -->
<module>gradle-modules/gradle/maven-to-gradle</module>
<!-- <module>grails</module> --> <!-- Not a maven project -->
<!-- <module>guest</module> --> <!-- not to be built as its for guest articles -->
<module>apache-httpclient</module>
<module>apache-httpclient4</module>
<module>java-jdi</module>
<module>java-websocket</module>
<module>jetbrains</module>
<module>jhipster-5</module>
<module>jmh</module>
<module>kubernetes-modules</module>
<!-- <module>lagom</module> --> <!-- Not a maven project -->
<module>language-interop</module>
<module>libraries-3</module>
<module>libraries-data-db</module>
<module>logging-modules</module>
<module>lombok-modules</module>
<module>maven-modules</module>
<module>messaging-modules</module>
<module>microservices-modules</module>
<module>muleesb</module>
<module>netflix-modules</module>
<module>osgi</module>
<module>persistence-modules</module>
<module>vavr-modules</module>
<module>web-modules</module>
</modules>
@ -428,7 +404,6 @@
<module>parent-spring-5</module>
<module>parent-java</module>
<module>spf4j</module>
<module>spring-4</module>
<module>spring-aop</module>
@ -436,14 +411,11 @@
<module>spring-boot-modules</module>
<module>spring-cloud-modules</module>
<!-- <module>spring-cloud-cli</module> --> <!-- Not a maven project -->
<module>spring-di</module>
<module>spring-di-2</module>
<module>spring-ejb-modules</module>
<module>spring-exceptions</module>
<module>spring-integration</module>
<module>spring-jenkins-pipeline</module>
<module>spring-jinq</module>
<module>spring-katharsis</module>
<module>spring-mobile</module>
<module>spring-remoting-modules</module>
@ -520,10 +492,9 @@
<module>libraries-5</module>
<module>libraries-6</module>
<module>spring-boot-modules/spring-boot-react</module>
<module>spring-ejb-modules/ejb-beans</module>
<module>vaadin</module>
<module>vavr-modules</module>
</modules>
</profile>
@ -559,8 +530,6 @@
<module>parent-spring-5</module>
<module>parent-java</module>
<module>azure</module>
<module>checker-plugin</module>
<!-- <module>clojure</module> --> <!-- Not a maven project -->
@ -571,43 +540,24 @@
<module>gradle-modules/gradle/maven-to-gradle</module>
<!-- <module>grails</module> --> <!-- Not a maven project -->
<!-- <module>guest</module> --> <!-- not to be built as its for guest articles -->
<module>apache-httpclient</module>
<module>apache-httpclient4</module>
<module>java-jdi</module>
<module>java-websocket</module>
<module>jhipster-5</module>
<module>jmh</module>
<module>kubernetes-modules</module>
<!-- <module>lagom</module> --> <!-- Not a maven project -->
<module>language-interop</module>
<module>libraries-3</module>
<module>libraries-data-db</module>
<module>logging-modules</module>
<module>lombok-modules</module>
<module>maven-modules</module>
<module>messaging-modules</module>
<module>microservices-modules</module>
<module>muleesb</module>
<module>netflix-modules</module>
<module>osgi</module>
<module>persistence-modules</module>
<module>vavr-modules</module>
<module>web-modules</module>
</modules>
@ -645,21 +595,17 @@
<module>parent-spring-5</module>
<module>parent-java</module>
<module>spf4j</module>
<module>spring-4</module>
<module>spring-bom</module>
<module>spring-boot-modules</module>
<module>spring-cloud-modules</module>
<!-- <module>spring-cloud-cli</module> --> <!-- Not a maven project -->
<module>spring-di</module>
<module>spring-di-2</module>
<module>spring-ejb-modules</module>
<module>spring-exceptions</module>
<module>spring-integration</module>
<module>spring-jenkins-pipeline</module>
<module>spring-jinq</module>
<module>spring-katharsis</module>
<module>spring-mobile</module>
<module>spring-remoting-modules</module>
@ -728,9 +674,7 @@
<module>libraries-5</module>
<module>libraries-6</module>
<module>spring-boot-modules/spring-boot-react</module>
<module>spring-ejb-modules/ejb-beans</module>
<module>vaadin</module>
<module>vavr-modules</module>
</modules>
</profile>
@ -796,9 +740,20 @@
</build>
<modules>
<module>spring-ejb-modules</module>
<module>spring-di</module>
<module>spring-di-2</module>
<module>spring-jinq</module>
<module>vavr-modules</module>
<module>java-websocket</module>
<module>azure</module>
<module>netflix-modules</module>
<module>spf4j</module>
<module>spring-jersey</module>
<module>jersey</module>
<module>jaxb</module>
<module>javafx</module>
<module>spring-batch</module>
<module>spring-boot-rest</module>
@ -884,7 +839,7 @@
<module>drools</module>
<module>guava-modules</module>
<module>apache-httpclient-2</module>
<module>kubernetes-modules/kubernetes-spring</module>
<module>kubernetes-modules</module>
<module>libraries-concurrency</module>
<module>libraries-testing</module>
<module>maven-modules/compiler-plugin-java-9</module>
@ -904,6 +859,7 @@
<module>spring-swagger-codegen/custom-validations-opeanpi-codegen</module>
<module>testing-modules/testing-assertions</module>
<module>persistence-modules/fauna</module>
<module>persistence-modules/spring-data-rest</module>
<module>rule-engines-modules</module>
@ -933,7 +889,7 @@
<module>asm</module>
<module>atomikos</module>
<module>atomix</module>
<!-- <module>axon</module>--><!-- JAVA-18408 -->
<!-- <module>axon</module>--><!-- JAVA-18408 -->
<module>bazel</module>
<module>code-generation</module>
@ -942,7 +898,7 @@
<module>disruptor</module>
<module>dozer</module>
<module>dubbo</module>
<module>feign</module>
<!-- <module>feign</module> --> <!-- JAVA-19475 -->
<module>google-cloud</module>
<module>graphql-modules</module>
<module>grpc</module>
@ -1021,9 +977,10 @@
<module>xstream</module>
<module>webrtc</module>
<module>persistence-modules/java-mongodb</module>
<module>messaging-modules/spring-apache-camel</module>
<module>messaging-modules</module>
<module>spring-boot-modules/spring-boot-redis</module>
<module>spring-security-modules/spring-security-saml2</module>
<module>persistence-modules/questdb</module>
</modules>
<properties>
@ -1057,9 +1014,20 @@
</build>
<modules>
<module>spring-ejb-modules</module>
<module>spring-di</module>
<module>spring-di-2</module>
<module>spring-jinq</module>
<module>vavr-modules</module>
<module>java-websocket</module>
<module>azure</module>
<module>netflix-modules</module>
<module>spf4j</module>
<module>spring-jersey</module>
<module>jersey</module>
<module>jaxb</module>
<module>javafx</module>
<module>spring-batch</module>
<module>spring-boot-rest</module>
@ -1143,7 +1111,7 @@
<module>drools</module>
<module>guava-modules</module>
<module>apache-httpclient-2</module>
<module>kubernetes-modules/kubernetes-spring</module>
<module>kubernetes-modules</module>
<module>libraries-concurrency</module>
<module>libraries-testing</module>
<module>maven-modules/compiler-plugin-java-9</module>
@ -1163,6 +1131,7 @@
<module>spring-swagger-codegen/custom-validations-opeanpi-codegen</module>
<module>testing-modules/testing-assertions</module>
<module>persistence-modules/fauna</module>
<module>persistence-modules/spring-data-rest</module>
<module>rule-engines-modules</module>
@ -1191,7 +1160,7 @@
<module>asm</module>
<module>atomikos</module>
<module>atomix</module>
<!-- <module>axon</module>--><!-- JAVA-18408 -->
<!-- <module>axon</module>--><!-- JAVA-18408 -->
<module>bazel</module>
<module>code-generation</module>
@ -1201,7 +1170,7 @@
<module>dozer</module>
<module>dubbo</module>
<module>feign</module>
<!-- <module>feign</module> -->
<module>google-cloud</module>
<module>graphql-modules</module>
<module>grpc</module>
@ -1282,9 +1251,10 @@
<module>webrtc</module>
<module>persistence-modules/java-mongodb</module>
<module>libraries-2</module>
<module>messaging-modules/spring-apache-camel</module>
<module>messaging-modules</module>
<module>spring-boot-modules/spring-boot-redis</module>
<module>spring-security-modules/spring-security-saml2</module>
<module>persistence-modules/questdb</module>
</modules>
<properties>

View File

@ -55,11 +55,6 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${compiler.plugin.version}</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
@ -98,7 +93,6 @@
<properties>
<spf4j.version>8.9.0</spf4j.version>
<compiler.plugin.version>3.8.0</compiler.plugin.version>
<dependency.plugin.version>3.1.1</dependency.plugin.version>
</properties>

View File

@ -61,11 +61,6 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${compiler.plugin.version}</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
@ -104,7 +99,6 @@
<properties>
<spf4j.version>8.9.0</spf4j.version>
<compiler.plugin.version>3.8.0</compiler.plugin.version>
<dependency.plugin.version>3.1.1</dependency.plugin.version>
</properties>

View File

@ -28,13 +28,13 @@
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>${jaxb.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>${jaxb.version}</version>
<scope>runtime</scope>
</dependency>
<!-- SQLite database driver -->
<dependency>

View File

@ -124,6 +124,8 @@
<mapstruct.version>1.5.2.Final</mapstruct.version>
<springdoc.version>2.0.0</springdoc.version>
<maven-surefire-plugin.version>3.0.0-M7</maven-surefire-plugin.version>
<start-class>com.baeldung.sample.TodoApplication</start-class>
</properties>
</project>

View File

@ -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<BookRecord> findAllBooks() {
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<BookRecord> query = cb.createQuery(BookRecord.class);
Root<Book> 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<BookRecord> 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<BookRecord> findAllBooksUsingMapping() {
Query query = entityManager.createNativeQuery("SELECT * FROM book", "BookRecordMapping");
return query.getResultList();
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -0,0 +1,4 @@
package com.baeldung.recordswithjpa.records;
public record BookRecord(Long id, String title, String author, String isbn) {
}

View File

@ -0,0 +1,4 @@
package com.baeldung.recordswithjpa.records;
public record CustomBookRecord(Long id, String title) {
}

View File

@ -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<Book, Long> {
List<BookRecord> 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);
}

View File

@ -0,0 +1,9 @@
package com.baeldung.recordswithjpa.repository;
import com.baeldung.recordswithjpa.records.CustomBookRecord;
import java.util.List;
public interface CustomBookRepository {
List<CustomBookRecord> findAllBooks();
}

View File

@ -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<CustomBookRecord> findAllBooks() {
return jdbcTemplate.query("SELECT id, title FROM book", (rs, rowNum) -> new CustomBookRecord(rs.getLong("id"), rs.getString("title")));
}
}

View File

@ -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<BookRecord> 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<BookRecord> allBooksUsingMapping = queryService.findAllBooksUsingMapping();
assertEquals(3, allBooksUsingMapping.size());
}
}

View File

@ -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();
}
}

View File

@ -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());
}
}

View File

@ -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<CustomBookRecord> allBooks = customBookRepository.findAllBooks();
assertEquals(3, allBooks.size());
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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<ApplicationPreparedEvent> {
@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.
}
}

View File

@ -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<>());
}
}

View File

@ -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";
}
}

View File

@ -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<List<Topic>> getAllTopics() {
return new ResponseEntity<>(topicService.getAlllTopics(), HttpStatus.OK);
}
}

View File

@ -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;
}
}

View File

@ -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<Topic> topicsList;
public TopicService(){
this.topicsList = new ArrayList<Topic>() {{
add(new Topic(1, "Topic1"));
add(new Topic(2, "Topic2"));
add(new Topic(3, "Topic3"));
}};
}
public List<Topic> getAlllTopics(){
return topicsList;
}
}

View File

@ -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

View File

@ -85,7 +85,7 @@
<properties>
<spring-boot.version>2.6.1</spring-boot.version>
<aspectj-plugin.version>1.11</aspectj-plugin.version>
<aspectj-plugin.version>1.14.0</aspectj-plugin.version>
<javax.inject.version>1</javax.inject.version>
<log4j2.version>2.17.1</log4j2.version>
</properties>

View File

@ -149,6 +149,7 @@
<spring-boot.version>1.5.2.RELEASE</spring-boot.version>
<mockito.version>1.10.19</mockito.version>
<aspectjweaver.version>1.9.5</aspectjweaver.version>
<maven-war-plugin.version>3.3.2</maven-war-plugin.version>
</properties>
</project>

View File

@ -85,8 +85,6 @@
</dependencyManagement>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<javaee-api.version>7.0</javaee-api.version>
<wildfly-javaee7.version>10.1.0.Final</wildfly-javaee7.version>
<hibernate-core.version>5.2.3.Final</hibernate-core.version>

View File

@ -41,4 +41,7 @@
</dependency>
</dependencies>
<properties>
<maven-war-plugin.version>3.3.2</maven-war-plugin.version>
</properties>
</project>

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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<String, BookEvent> consumerFactory() {
Map<String, Object> 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<String, BookEvent> kafkaListenerContainerFactory() {
ConcurrentKafkaListenerContainerFactory<String, BookEvent> 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);
}
}

View File

@ -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<String, String> producerFactory() {
Map<String, Object> 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<String, String> kafkaTemplate() {
return new KafkaTemplate<>(producerFactory());
}
@Bean
public ProducerFactory<String, BookEvent> bookProducerFactory() {
Map<String, Object> 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<String, BookEvent> bookKafkaTemplate() {
return new KafkaTemplate<>(bookProducerFactory());
}
}

View File

@ -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<String, Object> 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);
}
}

View File

@ -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);
}
}

View File

@ -1,4 +1,4 @@
package com.baeldung.spring.kafka;
package com.baeldung.spring.kafka.retryable;
public class Farewell {

View File

@ -1,4 +1,4 @@
package com.baeldung.spring.kafka;
package com.baeldung.spring.kafka.retryable;
public class Greeting {

View File

@ -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;

View File

@ -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);
}

View File

@ -1,4 +1,4 @@
package com.baeldung.spring.kafka;
package com.baeldung.spring.kafka.retryable;
import java.util.HashMap;
import java.util.Map;

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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<String, BookEvent> 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<? extends ConcurrentMessageListenerContainer<?, ?>> bookListeners = registry.getAllListenerContainers()
.stream()
.map(c -> (ConcurrentMessageListenerContainer<?, ?>) c)
.collect(Collectors.toList());
bookListeners.forEach(listener -> {
listener.stop();
listener.getContainerProperties()
.setMessageListener((AcknowledgingConsumerAwareMessageListener<String, BookEvent>) (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();
}
}

View File

@ -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)

View File

@ -42,6 +42,7 @@
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.22</version>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>

View File

@ -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<Credentials> response = vaultTemplate.read("credentials/myapp", Credentials.class);
public Credentials accessCredentials(String username) {
VaultResponseSupport<Credentials> response = vaultKeyValueOperations.get(username, Credentials.class);
return response.getData();
}
public Credentials saveCredentials(Credentials credentials) {
return credentialsRepository.save(credentials);
}
public Optional<Credentials> findById(String username) {
return credentialsRepository.findById(username);
}
}

View File

@ -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

Some files were not shown because too many files have changed in this diff Show More