Merge branch 'eugenp:master' into master

This commit is contained in:
rvsathe 2021-09-03 08:30:15 +05:30 committed by GitHub
commit 935f5d24e7
104 changed files with 5140 additions and 13214 deletions

View File

@ -12,7 +12,8 @@ This module contains articles about Apache Kafka.
- [Kafka Connect Example with MQTT and MongoDB](https://www.baeldung.com/kafka-connect-mqtt-mongodb)
- [Building a Data Pipeline with Flink and Kafka](https://www.baeldung.com/kafka-flink-data-pipeline)
- [Exactly Once Processing in Kafka with Java](https://www.baeldung.com/kafka-exactly-once)
- [Custom Serializers in Apache Kafka](https://www.baeldung.com/kafka-custom-serializer)
##### Building the project
You can build the project from the command line using: *mvn clean install*, or in an IDE.
You can build the project from the command line using: *mvn clean install*, or in an IDE.

File diff suppressed because it is too large Load Diff

View File

@ -2,3 +2,4 @@
- [String API Updates in Java 12](https://www.baeldung.com/java12-string-api)
- [New Features in Java 12](https://www.baeldung.com/java-12-new-features)
- [Compare the Content of Two Files in Java](https://www.baeldung.com/java-compare-files)

View File

@ -0,0 +1,49 @@
package com.baeldung.java_16_features.mapmulti;
import java.util.List;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
public class Album {
private String albumName;
private int albumCost;
private List<Artist> artists;
Album(String name, int albumCost, List<Artist> artists) {
this.albumName = name;
this.artists = artists;
this.albumCost = albumCost;
}
public void artistAlbumPairsToMajorLabels(Consumer<Pair<String, String>> consumer) {
for (Artist artist : artists) {
if (artist.isAssociatedMajorLabels()) {
String concatLabels = artist.getMajorLabels()
.stream()
.collect(Collectors.joining(","));
consumer.accept(new ImmutablePair<>(artist.getName() + ":" + albumName, concatLabels));
}
}
}
public String getAlbumName() {
return albumName;
}
public int getAlbumCost() {
return albumCost;
}
List<Artist> getArtists() {
return artists;
}
public String toString() {
return albumName;
}
}

View File

@ -0,0 +1,50 @@
package com.baeldung.java_16_features.mapmulti;
import java.util.List;
import java.util.Objects;
public class Artist {
private final String name;
private boolean associatedMajorLabels;
private List<String> majorLabels;
Artist(String name, boolean associatedMajorLabels, List<String> majorLabels) {
this.name = name;
this.associatedMajorLabels = associatedMajorLabels;
this.majorLabels = majorLabels;
}
public String getName() {
return name;
}
public boolean isAssociatedMajorLabels() {
return associatedMajorLabels;
}
public List<String> getMajorLabels() {
return majorLabels;
}
@Override
public int hashCode() {
return Objects.hash(name);
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Artist other = (Artist) obj;
return Objects.equals(name, other.name);
}
public String toString() {
return name;
}
}

View File

@ -0,0 +1,134 @@
package com.baeldung.java_16_features.mapmulti;
import static java.util.stream.Collectors.toList;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.offset;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.Arrays;
import java.util.List;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
import org.junit.jupiter.api.Test;
public class JavaStreamMapMultiUnitTest {
private static final List<Album> albums = Arrays.asList(new Album("album1", 10, Arrays.asList(new Artist("bob", true, Arrays.asList("label1", "label3")), new Artist("tom", true, Arrays.asList("label2", "label3")))),
new Album("album2", 20, Arrays.asList(new Artist("bill", true, Arrays.asList("label2", "label3")), new Artist("tom", true, Arrays.asList("label2", "label4")))));
@Test
public void givenAListOfintegers_whenMapMulti_thenGetListOfOfEvenDoublesPlusPercentage() {
List<Integer> integers = Arrays.asList(1, 2, 3, 4, 5);
double percentage = .01;
List<Double> evenDoubles = integers.stream()
.<Double> mapMulti((integer, consumer) -> {
if (integer % 2 == 0) {
consumer.accept((double) integer * (1 + percentage));
}
})
.collect(toList());
assertThat(evenDoubles).containsAll(Arrays.asList(2.02D, 4.04D));
}
@Test
public void givenAListOfintegers_whenFilterMap_thenGetListOfOfEvenDoublesPlusPercentage() {
List<Integer> integers = Arrays.asList(1, 2, 3, 4, 5);
double percentage = .01;
List<Double> evenDoubles = integers.stream()
.filter(integer -> integer % 2 == 0)
.<Double> map(integer -> ((double) integer * (1 + percentage)))
.collect(toList());
assertThat(evenDoubles).containsAll(Arrays.asList(2.02D, 4.04D));
}
@Test
public void givenAListOfintegers_whenMapMultiToDouble_thenGetSumOfEvenNumbersAfterApplyPercentage() {
List<Integer> integers = Arrays.asList(1, 2, 3, 4, 5, 6, 7);
double percentage = .01;
double sum = integers.stream()
.mapMultiToDouble((integer, consumer) -> {
if (integer % 2 == 0) {
consumer.accept(integer * (1 + percentage));
}
})
.sum();
assertThat(sum).isEqualTo(12.12, offset(0.001d));
}
@Test
public void givenAListOfAlbums_whenFlatMap_thenGetListOfArtistAlbumPairs() {
List<Pair<String, String>> artistAlbum = albums.stream()
.flatMap(album -> album.getArtists()
.stream()
.map(artist -> new ImmutablePair<String, String>(artist.getName(), album.getAlbumName())))
.collect(toList());
assertThat(artistAlbum).contains(new ImmutablePair<String, String>("bob", "album1"), new ImmutablePair<String,
String>("tom", "album1"), new ImmutablePair<String, String>("bill", "album2"), new ImmutablePair<String, String>("tom", "album2"));
}
@Test
public void givenAListOfAlbums_whenMapMulti_thenGetListOfPairsOfArtistAlbum() {
List<Pair<String, String>> artistAlbum = albums.stream()
.<Pair<String, String>> mapMulti((album, consumer) -> {
for (Artist artist : album.getArtists()) {
consumer.accept(new ImmutablePair<String, String>(artist.getName(), album.getAlbumName()));
}
})
.collect(toList());
assertThat(artistAlbum).contains(new ImmutablePair<String, String>("bob", "album1"), new ImmutablePair<String, String>("tom", "album1"),
new ImmutablePair<String, String>("bill", "album2"), new ImmutablePair<String, String>("tom", "album2"));
}
@Test
public void givenAListOfAlbums_whenFlatMap_thenGetListOfArtistAlbumjPairsBelowGivenCost() {
int upperCost = 9;
List<Pair<String, String>> artistAlbum = albums.stream()
.flatMap(album -> album.getArtists()
.stream()
.filter(artist -> upperCost > album.getAlbumCost())
.map(artist -> new ImmutablePair<String, String>(artist.getName(), album.getAlbumName())))
.collect(toList());
assertTrue(artistAlbum.isEmpty());
}
@Test
public void givenAListOfAlbums_whenMapMulti_thenGetListOfArtistAlbumPairsBelowGivenCost() {
int upperCost = 9;
List<Pair<String, String>> artistAlbum = albums.stream()
.<Pair<String, String>> mapMulti((album, consumer) -> {
if (album.getAlbumCost() < upperCost) {
for (Artist artist : album.getArtists()) {
consumer.accept(new ImmutablePair<String, String>(artist.getName(), album.getAlbumName()));
}
}
})
.collect(toList());
assertTrue(artistAlbum.isEmpty());
}
@Test
public void givenAListOfAlbums_whenMapMulti_thenGetPairsOfArtistMajorLabelsUsingMethodReference() {
List<Pair<String, String>> artistLabels = albums.stream()
.mapMulti(Album::artistAlbumPairsToMajorLabels)
.collect(toList());
assertThat(artistLabels).contains(new ImmutablePair<String, String>("bob:album1", "label1,label3"), new ImmutablePair<String, String>("tom:album1", "label2,label3"),
new ImmutablePair<String, String>("bill:album2", "label2,label3"), new ImmutablePair<String, String>("tom:album2", "label2,label4"));
}
}

View File

@ -11,3 +11,4 @@ This module contains articles about parsing and formatting Java date and time ob
- [Display All Time Zones With GMT And UTC in Java](http://www.baeldung.com/java-time-zones)
- [Convert between String and Timestamp](https://www.baeldung.com/java-string-to-timestamp)
- [Convert String to Date in Java](http://www.baeldung.com/java-string-to-date)
- [Format a Milliseconds Duration to HH:MM:SS](https://www.baeldung.com/java-ms-to-hhmmss)

View File

@ -75,7 +75,7 @@
<properties>
<commons-validator.version>1.6</commons-validator.version>
<joda-time.version>2.10</joda-time.version>
<joda-time.version>2.10.10</joda-time.version>
<!-- testing -->
<assertj.version>3.6.1</assertj.version>
<maven.compiler.source>1.9</maven.compiler.source>

View File

@ -0,0 +1,54 @@
package com.baeldung.formatduration;
import org.apache.commons.lang3.time.DurationFormatUtils;
import org.joda.time.Period;
import org.junit.Test;
import java.time.Duration;
import java.util.concurrent.TimeUnit;
import static org.assertj.core.api.Assertions.assertThat;
public class FormatDurationUnitTest {
@Test
public void givenInterval_WhenFormatInterval_formatDuration() {
long HH = TimeUnit.MILLISECONDS.toHours(38114000);
long MM = TimeUnit.MILLISECONDS.toMinutes(38114000) % 60;
long SS = TimeUnit.MILLISECONDS.toSeconds(38114000) % 60;
String timeInHHMMSS = String.format("%02d:%02d:%02d", HH, MM, SS);
assertThat(timeInHHMMSS).isEqualTo("10:35:14");
}
@Test
public void givenInterval_WhenFormatUsingDuration_formatDuration() {
Duration duration = Duration.ofMillis(38114000);
long seconds = duration.getSeconds();
long HH = seconds / 3600;
long MM = (seconds % 3600) / 60;
long SS = seconds % 60;
String timeInHHMMSS = String.format("%02d:%02d:%02d", HH, MM, SS);
assertThat(timeInHHMMSS).isEqualTo("10:35:14");
}
@Test
public void givenInterval_WhenFormatDurationUsingApacheCommons_formatDuration() {
assertThat(DurationFormatUtils.formatDuration(38114000, "HH:mm:ss"))
.isEqualTo("10:35:14");
}
@Test
public void givenInterval_WhenFormatDurationUsingJodaTime_formatDuration() {
org.joda.time.Duration duration = new org.joda.time.Duration(38114000);
Period period = duration.toPeriod();
long HH = period.getHours();
long MM = period.getMinutes();
long SS = period.getSeconds();
String timeInHHMMSS = String.format("%02d:%02d:%02d", HH, MM, SS);
assertThat(timeInHHMMSS).isEqualTo("10:35:14");
}
}

View File

@ -3,5 +3,6 @@
This module contains articles about JavaFX.
### Relevant Articles:
-[Introduction to JavaFX](https://www.baeldung.com/javafx)
- [Introduction to JavaFX](https://www.baeldung.com/javafx)
- [Display Custom Items in JavaFX ListView](https://www.baeldung.com/javafx-listview-display-custom-items)

View File

@ -17,7 +17,6 @@
</prerequisites>
<properties>
<lifecycle.mapping.version>1.0.0</lifecycle.mapping.version>
<argLine>-Djava.security.egd=file:/dev/./urandom -Xmx256m</argLine>
<assertj.version>3.6.2</assertj.version>
<awaitility.version>2.0.0</awaitility.version>
@ -31,6 +30,7 @@
<jcache.version>1.0.0</jcache.version>
<jhipster.server.version>1.1.0</jhipster.server.version>
<jjwt.version>0.7.0</jjwt.version>
<lifecycle.mapping.version>1.0.0</lifecycle.mapping.version>
<liquibase-hibernate5.version>3.6</liquibase-hibernate5.version>
<liquibase-slf4j.version>2.0.0</liquibase-slf4j.version>
<liquibase.version>3.6.2</liquibase.version>
@ -59,14 +59,14 @@
<sonar.issue.ignore.multicriteria>S3437,UndocumentedApi,BoldAndItalicTagsCheck</sonar.issue.ignore.multicriteria>
<!-- Rule https://sonarqube.com/coding_rules#rule_key=Web%3ABoldAndItalicTagsCheck is ignored. Even if we agree that using the "i" tag is an awful practice, this is what is
<!-- Rule https://sonarqube.com/coding_rules#rule_key=Web%3ABoldAndItalicTagsCheck is ignored. Even if we agree that using the "i" tag is an awful practice, this is what is
recommended by http://fontawesome.io/examples/ -->
<sonar.issue.ignore.multicriteria.BoldAndItalicTagsCheck.resourceKey>src/main/webapp/app/**/*.*</sonar.issue.ignore.multicriteria.BoldAndItalicTagsCheck.resourceKey>
<sonar.issue.ignore.multicriteria.BoldAndItalicTagsCheck.ruleKey>Web:BoldAndItalicTagsCheck</sonar.issue.ignore.multicriteria.BoldAndItalicTagsCheck.ruleKey>
<!-- Rule https://sonarqube.com/coding_rules#rule_key=squid%3AS3437 is ignored, as a JPA-managed field cannot be transient -->
<sonar.issue.ignore.multicriteria.S3437.resourceKey>src/main/java/**/*</sonar.issue.ignore.multicriteria.S3437.resourceKey>
<sonar.issue.ignore.multicriteria.S3437.ruleKey>squid:S3437</sonar.issue.ignore.multicriteria.S3437.ruleKey>
<!-- Rule http://sonarqube.com/coding_rules#rule_key=squid%3AUndocumentedApi is ignored, as we want to follow "clean code" guidelines and classes, methods and arguments names
<!-- Rule http://sonarqube.com/coding_rules#rule_key=squid%3AUndocumentedApi is ignored, as we want to follow "clean code" guidelines and classes, methods and arguments names
should be self-explanatory -->
<sonar.issue.ignore.multicriteria.UndocumentedApi.resourceKey>src/main/java/**/*</sonar.issue.ignore.multicriteria.UndocumentedApi.resourceKey>
<sonar.issue.ignore.multicriteria.UndocumentedApi.ruleKey>squid:UndocumentedApi</sonar.issue.ignore.multicriteria.UndocumentedApi.ruleKey>
@ -349,7 +349,6 @@
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
@ -365,11 +364,6 @@
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test</artifactId>
<scope>test</scope>
</dependency>
<!-- Spring Cloud -->
<dependency>
<groupId>org.springframework.cloud</groupId>
@ -427,7 +421,7 @@
<defaultGoal>spring-boot:run</defaultGoal>
<pluginManagement>
<plugins>
<!-- This plugin's configuration is used to store Eclipse m2e settings only. It has no influence on the Maven build itself. Remove when the m2e plugin can correctly
<!-- This plugin's configuration is used to store Eclipse m2e settings only. It has no influence on the Maven build itself. Remove when the m2e plugin can correctly
bind to Maven lifecycle -->
<plugin>
<groupId>org.eclipse.m2e</groupId>
@ -580,14 +574,6 @@
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<!-- Force alphabetical order to have a reproducible build -->
<runOrder>alphabetical</runOrder>
</configuration>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
@ -768,8 +754,8 @@
</dependencies>
</profile>
<profile>
<!-- Profile for doing "continuous compilation" with the Scala Maven plugin. It allows automatic compilation of Java classes as soon as they are saved. To use it, run in
3 terminals: - './mvnw -Pcc scala:cc' for continous compilation of your classes - './mvnw -Pcc' for hot reload of Spring boot - 'gulp' for hot reload of the HTML/JavaScript assets Everything
<!-- Profile for doing "continuous compilation" with the Scala Maven plugin. It allows automatic compilation of Java classes as soon as they are saved. To use it, run in
3 terminals: - './mvnw -Pcc scala:cc' for continous compilation of your classes - './mvnw -Pcc' for hot reload of Spring boot - 'gulp' for hot reload of the HTML/JavaScript assets Everything
should hot reload automatically! -->
<id>cc</id>
<build>

View File

@ -21,6 +21,8 @@ eureka:
instanceId: carapp:${spring.application.instance_id:${random.value}}
spring:
main:
banner-mode: "off"
application:
name: carapp
jackson:
@ -37,7 +39,7 @@ spring:
database-platform: io.github.jhipster.domain.util.FixedH2Dialect
database: H2
open-in-view: false
show-sql: true
show-sql: false
hibernate:
ddl-auto: none
naming:

View File

@ -3,7 +3,7 @@
<configuration scan="true">
<include resource="org/springframework/boot/logging/logback/base.xml"/>
<logger name="com.car.app" level="DEBUG"/>
<logger name="com.car.app" level="INFO"/>
<logger name="org.hibernate" level="WARN"/>
<logger name="org.hibernate.ejb.HibernatePersistence" level="OFF"/>
<logger name="org.apache.catalina.startup.DigesterFactory" level="OFF"/>

View File

@ -29,6 +29,7 @@
<jcache.version>1.0.0</jcache.version>
<jhipster.server.version>1.1.0</jhipster.server.version>
<jjwt.version>0.7.0</jjwt.version>
<lifecycle.mapping.version>1.0.0</lifecycle.mapping.version>
<liquibase-hibernate5.version>3.6</liquibase-hibernate5.version>
<liquibase-slf4j.version>2.0.0</liquibase-slf4j.version>
<liquibase.version>3.6.2</liquibase.version>
@ -57,14 +58,14 @@
<sonar.issue.ignore.multicriteria>S3437,UndocumentedApi,BoldAndItalicTagsCheck</sonar.issue.ignore.multicriteria>
<!-- Rule https://sonarqube.com/coding_rules#rule_key=Web%3ABoldAndItalicTagsCheck is ignored. Even if we agree that using the "i" tag is an awful practice, this is what is
<!-- Rule https://sonarqube.com/coding_rules#rule_key=Web%3ABoldAndItalicTagsCheck is ignored. Even if we agree that using the "i" tag is an awful practice, this is what is
recommended by http://fontawesome.io/examples/ -->
<sonar.issue.ignore.multicriteria.BoldAndItalicTagsCheck.resourceKey>src/main/webapp/app/**/*.*</sonar.issue.ignore.multicriteria.BoldAndItalicTagsCheck.resourceKey>
<sonar.issue.ignore.multicriteria.BoldAndItalicTagsCheck.ruleKey>Web:BoldAndItalicTagsCheck</sonar.issue.ignore.multicriteria.BoldAndItalicTagsCheck.ruleKey>
<!-- Rule https://sonarqube.com/coding_rules#rule_key=squid%3AS3437 is ignored, as a JPA-managed field cannot be transient -->
<sonar.issue.ignore.multicriteria.S3437.resourceKey>src/main/java/**/*</sonar.issue.ignore.multicriteria.S3437.resourceKey>
<sonar.issue.ignore.multicriteria.S3437.ruleKey>squid:S3437</sonar.issue.ignore.multicriteria.S3437.ruleKey>
<!-- Rule http://sonarqube.com/coding_rules#rule_key=squid%3AUndocumentedApi is ignored, as we want to follow "clean code" guidelines and classes, methods and arguments names
<!-- Rule http://sonarqube.com/coding_rules#rule_key=squid%3AUndocumentedApi is ignored, as we want to follow "clean code" guidelines and classes, methods and arguments names
should be self-explanatory -->
<sonar.issue.ignore.multicriteria.UndocumentedApi.resourceKey>src/main/java/**/*</sonar.issue.ignore.multicriteria.UndocumentedApi.resourceKey>
<sonar.issue.ignore.multicriteria.UndocumentedApi.ruleKey>squid:UndocumentedApi</sonar.issue.ignore.multicriteria.UndocumentedApi.ruleKey>
@ -90,7 +91,6 @@
<undertow.version>1.4.10.Final</undertow.version>
<validation-api.version>1.1.0.Final</validation-api.version>
<yarn.version>v0.21.3</yarn.version>
<lifecycle.mapping.version>1.0.0</lifecycle.mapping.version>
</properties>
<dependencyManagement>
@ -345,6 +345,10 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
@ -359,11 +363,6 @@
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test</artifactId>
<scope>test</scope>
</dependency>
<!-- Spring Cloud -->
<dependency>
<groupId>org.springframework.cloud</groupId>
@ -421,7 +420,7 @@
<defaultGoal>spring-boot:run</defaultGoal>
<pluginManagement>
<plugins>
<!-- This plugin's configuration is used to store Eclipse m2e settings only. It has no influence on the Maven build itself. Remove when the m2e plugin can correctly
<!-- This plugin's configuration is used to store Eclipse m2e settings only. It has no influence on the Maven build itself. Remove when the m2e plugin can correctly
bind to Maven lifecycle -->
<plugin>
<groupId>org.eclipse.m2e</groupId>
@ -574,14 +573,6 @@
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<!-- Force alphabetical order to have a reproducible build -->
<runOrder>alphabetical</runOrder>
</configuration>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
@ -762,8 +753,8 @@
</dependencies>
</profile>
<profile>
<!-- Profile for doing "continuous compilation" with the Scala Maven plugin. It allows automatic compilation of Java classes as soon as they are saved. To use it, run in
3 terminals: - './mvnw -Pcc scala:cc' for continous compilation of your classes - './mvnw -Pcc' for hot reload of Spring boot - 'gulp' for hot reload of the HTML/JavaScript assets Everything
<!-- Profile for doing "continuous compilation" with the Scala Maven plugin. It allows automatic compilation of Java classes as soon as they are saved. To use it, run in
3 terminals: - './mvnw -Pcc scala:cc' for continous compilation of your classes - './mvnw -Pcc' for hot reload of Spring boot - 'gulp' for hot reload of the HTML/JavaScript assets Everything
should hot reload automatically! -->
<id>cc</id>
<build>

View File

@ -21,6 +21,8 @@ eureka:
instanceId: dealerapp:${spring.application.instance_id:${random.value}}
spring:
main:
banner-mode: "off"
application:
name: dealerapp
jackson:
@ -37,7 +39,7 @@ spring:
database-platform: io.github.jhipster.domain.util.FixedH2Dialect
database: H2
open-in-view: false
show-sql: true
show-sql: false
hibernate:
ddl-auto: none
naming:

View File

@ -3,7 +3,7 @@
<configuration scan="true">
<include resource="org/springframework/boot/logging/logback/base.xml"/>
<logger name="com.dealer.app" level="DEBUG"/>
<logger name="com.dealer.app" level="INFO"/>
<logger name="org.hibernate" level="WARN"/>
<logger name="org.hibernate.ejb.HibernatePersistence" level="OFF"/>
<logger name="org.apache.catalina.startup.DigesterFactory" level="OFF"/>

View File

@ -32,6 +32,7 @@
<jcache.version>1.0.0</jcache.version>
<jhipster.server.version>1.1.0</jhipster.server.version>
<jjwt.version>0.7.0</jjwt.version>
<lifecycle.mapping.version>1.0.0</lifecycle.mapping.version>
<liquibase-hibernate5.version>3.6</liquibase-hibernate5.version>
<liquibase-slf4j.version>2.0.0</liquibase-slf4j.version>
<liquibase.version>3.6.2</liquibase.version>
@ -61,14 +62,14 @@
<sonar.issue.ignore.multicriteria>S3437,UndocumentedApi,BoldAndItalicTagsCheck</sonar.issue.ignore.multicriteria>
<!-- Rule https://sonarqube.com/coding_rules#rule_key=Web%3ABoldAndItalicTagsCheck is ignored. Even if we agree that using the "i" tag is an awful practice, this is what is
<!-- Rule https://sonarqube.com/coding_rules#rule_key=Web%3ABoldAndItalicTagsCheck is ignored. Even if we agree that using the "i" tag is an awful practice, this is what is
recommended by http://fontawesome.io/examples/ -->
<sonar.issue.ignore.multicriteria.BoldAndItalicTagsCheck.resourceKey>src/main/webapp/app/**/*.*</sonar.issue.ignore.multicriteria.BoldAndItalicTagsCheck.resourceKey>
<sonar.issue.ignore.multicriteria.BoldAndItalicTagsCheck.ruleKey>Web:BoldAndItalicTagsCheck</sonar.issue.ignore.multicriteria.BoldAndItalicTagsCheck.ruleKey>
<!-- Rule https://sonarqube.com/coding_rules#rule_key=squid%3AS3437 is ignored, as a JPA-managed field cannot be transient -->
<sonar.issue.ignore.multicriteria.S3437.resourceKey>src/main/java/**/*</sonar.issue.ignore.multicriteria.S3437.resourceKey>
<sonar.issue.ignore.multicriteria.S3437.ruleKey>squid:S3437</sonar.issue.ignore.multicriteria.S3437.ruleKey>
<!-- Rule http://sonarqube.com/coding_rules#rule_key=squid%3AUndocumentedApi is ignored, as we want to follow "clean code" guidelines and classes, methods and arguments names
<!-- Rule http://sonarqube.com/coding_rules#rule_key=squid%3AUndocumentedApi is ignored, as we want to follow "clean code" guidelines and classes, methods and arguments names
should be self-explanatory -->
<sonar.issue.ignore.multicriteria.UndocumentedApi.resourceKey>src/main/java/**/*</sonar.issue.ignore.multicriteria.UndocumentedApi.resourceKey>
<sonar.issue.ignore.multicriteria.UndocumentedApi.ruleKey>squid:UndocumentedApi</sonar.issue.ignore.multicriteria.UndocumentedApi.ruleKey>
@ -94,7 +95,6 @@
<undertow.version>1.4.10.Final</undertow.version>
<validation-api.version>1.1.0.Final</validation-api.version>
<yarn.version>v0.21.3</yarn.version>
<lifecycle.mapping.version>1.0.0</lifecycle.mapping.version>
</properties>
<dependencyManagement>
@ -383,6 +383,10 @@
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
@ -397,11 +401,6 @@
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter</artifactId>
@ -463,7 +462,7 @@
<defaultGoal>spring-boot:run</defaultGoal>
<pluginManagement>
<plugins>
<!-- This plugin's configuration is used to store Eclipse m2e settings only. It has no influence on the Maven build itself. Remove when the m2e plugin can correctly
<!-- This plugin's configuration is used to store Eclipse m2e settings only. It has no influence on the Maven build itself. Remove when the m2e plugin can correctly
bind to Maven lifecycle -->
<plugin>
<groupId>org.eclipse.m2e</groupId>
@ -632,14 +631,6 @@
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<!-- Force alphabetical order to have a reproducible build -->
<runOrder>alphabetical</runOrder>
</configuration>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
@ -878,8 +869,8 @@
</dependencies>
</profile>
<profile>
<!-- Profile for doing "continuous compilation" with the Scala Maven plugin. It allows automatic compilation of Java classes as soon as they are saved. To use it, run in
3 terminals: - './mvnw -Pcc scala:cc' for continous compilation of your classes - './mvnw -Pcc' for hot reload of Spring boot - 'gulp' for hot reload of the HTML/JavaScript assets Everything
<!-- Profile for doing "continuous compilation" with the Scala Maven plugin. It allows automatic compilation of Java classes as soon as they are saved. To use it, run in
3 terminals: - './mvnw -Pcc scala:cc' for continous compilation of your classes - './mvnw -Pcc' for hot reload of Spring boot - 'gulp' for hot reload of the HTML/JavaScript assets Everything
should hot reload automatically! -->
<id>cc</id>
<build>

View File

@ -49,7 +49,7 @@ public class LogsResourceIntegrationTest {
public void changeLogs()throws Exception {
LoggerVM logger = new LoggerVM();
logger.setLevel("INFO");
logger.setName("ROOT");
logger.setName("some.test.logger");
restLogsMockMvc.perform(put("/management/logs")
.contentType(TestUtil.APPLICATION_JSON_UTF8)

View File

@ -21,6 +21,8 @@ eureka:
instanceId: gateway:${spring.application.instance_id:${random.value}}
spring:
main:
banner-mode: "off"
application:
name: gateway
autoconfigure:
@ -39,7 +41,7 @@ spring:
database-platform: io.github.jhipster.domain.util.FixedH2Dialect
database: H2
open-in-view: false
show-sql: true
show-sql: false
hibernate:
ddl-auto: none
naming:

View File

@ -3,7 +3,7 @@
<configuration scan="true">
<include resource="org/springframework/boot/logging/logback/base.xml"/>
<logger name="com.gateway" level="DEBUG"/>
<logger name="com.gateway" level="INFO"/>
<logger name="org.hibernate" level="WARN"/>
<logger name="org.hibernate.ejb.HibernatePersistence" level="OFF"/>
<logger name="org.apache.catalina.startup.DigesterFactory" level="OFF"/>

View File

@ -11,7 +11,7 @@
<groupId>com.baeldung.jhipster</groupId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<modules>
<module>car-app</module>
<module>dealer-app</module>

View File

@ -277,8 +277,7 @@
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test</artifactId>
<scope>test</scope>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<!-- security -->
<dependency>
@ -297,7 +296,7 @@
<defaultGoal>spring-boot:run</defaultGoal>
<pluginManagement>
<plugins>
<!-- This plugin's configuration is used to store Eclipse m2e settings only. It has no influence on the Maven build itself. Remove when the m2e plugin can correctly
<!-- This plugin's configuration is used to store Eclipse m2e settings only. It has no influence on the Maven build itself. Remove when the m2e plugin can correctly
bind to Maven lifecycle -->
<plugin>
<groupId>org.eclipse.m2e</groupId>
@ -751,8 +750,8 @@
</dependencies>
</profile>
<profile>
<!-- Profile for doing "continuous compilation" with the Scala Maven plugin. It allows automatic compilation of Java classes as soon as they are saved. To use it, run in
3 terminals: - './mvnw -Pcc scala:cc' for continous compilation of your classes - './mvnw -Pcc' for hot reload of Spring boot - 'gulp' for hot reload of the HTML/JavaScript assets Everything
<!-- Profile for doing "continuous compilation" with the Scala Maven plugin. It allows automatic compilation of Java classes as soon as they are saved. To use it, run in
3 terminals: - './mvnw -Pcc scala:cc' for continous compilation of your classes - './mvnw -Pcc' for hot reload of Spring boot - 'gulp' for hot reload of the HTML/JavaScript assets Everything
should hot reload automatically! -->
<id>cc</id>
<build>
@ -931,14 +930,14 @@
<sonar.issue.ignore.multicriteria>S3437,UndocumentedApi,BoldAndItalicTagsCheck</sonar.issue.ignore.multicriteria>
<!-- Rule https://sonarqube.com/coding_rules#rule_key=Web%3ABoldAndItalicTagsCheck is ignored. Even if we agree that using the "i" tag is an awful practice, this is what is
<!-- Rule https://sonarqube.com/coding_rules#rule_key=Web%3ABoldAndItalicTagsCheck is ignored. Even if we agree that using the "i" tag is an awful practice, this is what is
recommended by http://fontawesome.io/examples/ -->
<sonar.issue.ignore.multicriteria.BoldAndItalicTagsCheck.resourceKey>src/main/webapp/app/**/*.*</sonar.issue.ignore.multicriteria.BoldAndItalicTagsCheck.resourceKey>
<sonar.issue.ignore.multicriteria.BoldAndItalicTagsCheck.ruleKey>Web:BoldAndItalicTagsCheck</sonar.issue.ignore.multicriteria.BoldAndItalicTagsCheck.ruleKey>
<!-- Rule https://sonarqube.com/coding_rules#rule_key=squid%3AS3437 is ignored, as a JPA-managed field cannot be transient -->
<sonar.issue.ignore.multicriteria.S3437.resourceKey>src/main/java/**/*</sonar.issue.ignore.multicriteria.S3437.resourceKey>
<sonar.issue.ignore.multicriteria.S3437.ruleKey>squid:S3437</sonar.issue.ignore.multicriteria.S3437.ruleKey>
<!-- Rule http://sonarqube.com/coding_rules#rule_key=squid%3AUndocumentedApi is ignored, as we want to follow "clean code" guidelines and classes, methods and arguments names
<!-- Rule http://sonarqube.com/coding_rules#rule_key=squid%3AUndocumentedApi is ignored, as we want to follow "clean code" guidelines and classes, methods and arguments names
should be self-explanatory -->
<sonar.issue.ignore.multicriteria.UndocumentedApi.resourceKey>src/main/java/**/*</sonar.issue.ignore.multicriteria.UndocumentedApi.resourceKey>
<sonar.issue.ignore.multicriteria.UndocumentedApi.ruleKey>squid:UndocumentedApi</sonar.issue.ignore.multicriteria.UndocumentedApi.ruleKey>

View File

@ -49,7 +49,7 @@ public class LogsResourceIntegrationTest {
public void changeLogs()throws Exception {
LoggerVM logger = new LoggerVM();
logger.setLevel("INFO");
logger.setName("ROOT");
logger.setName("some.test.logger");
restLogsMockMvc.perform(put("/management/logs")
.contentType(TestUtil.APPLICATION_JSON_UTF8)

View File

@ -15,6 +15,8 @@
spring:
main:
banner-mode: "off"
application:
name: baeldung
jackson:
@ -31,7 +33,7 @@ spring:
database-platform: io.github.jhipster.domain.util.FixedH2Dialect
database: H2
open-in-view: false
show-sql: true
show-sql: false
hibernate:
ddl-auto: none
naming:

View File

@ -3,7 +3,7 @@
<configuration scan="true">
<include resource="org/springframework/boot/logging/logback/base.xml"/>
<logger name="com.baeldung" level="DEBUG"/>
<logger name="com.baeldung" level="INFO"/>
<logger name="org.hibernate" level="WARN"/>
<logger name="org.hibernate.ejb.HibernatePersistence" level="OFF"/>
<logger name="org.apache.catalina.startup.DigesterFactory" level="OFF"/>

View File

@ -1,6 +1,13 @@
<?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>
<parent>
<artifactId>jhipster-uaa</artifactId>
<groupId>com.baeldung.jhipster</groupId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<groupId>com.baeldung.jhipster.gateway</groupId>
<artifactId>gateway</artifactId>
<version>0.0.1-SNAPSHOT</version>
@ -415,15 +422,6 @@
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${maven-surefire-plugin.version}</version>
<configuration>
<!-- Force alphabetical order to have a reproducible build -->
<runOrder>alphabetical</runOrder>
</configuration>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
@ -1010,7 +1008,7 @@
</profile>
<!-- jhipster-needle-maven-add-profile -->
</profiles>
<properties>
<lifecycle.mapping.version>1.0.0</lifecycle.mapping.version>
<spring.web.version>0.24.0</spring.web.version>
@ -1090,5 +1088,5 @@
<sonar.tests>${project.basedir}/src/test/</sonar.tests>
<!-- jhipster-needle-maven-property -->
</properties>
</properties>
</project>

View File

@ -40,7 +40,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
*
* @see WebConfigurer
*/
public class WebConfigurerTest {
public class WebConfigurerUnitTest {
private WebConfigurer webConfigurer;

View File

@ -18,7 +18,7 @@ import static springfox.documentation.swagger2.web.Swagger2Controller.DEFAULT_UR
/**
* Tests SwaggerBasePathRewritingFilter class.
*/
public class SwaggerBasePathRewritingFilterTest {
public class SwaggerBasePathRewritingFilterUnitTest {
private SwaggerBasePathRewritingFilter filter = new SwaggerBasePathRewritingFilter();

View File

@ -16,7 +16,7 @@ import java.util.List;
*
* @see CookieCollection
*/
public class CookieCollectionTest {
public class CookieCollectionUnitTest {
public static final String COOKIE_NAME = "chocolate";
public static final String COOKIE_VALUE = "yummy";
public static final String BROWNIE_NAME = "brownie";

View File

@ -12,7 +12,7 @@ import org.springframework.security.oauth2.common.OAuth2AccessToken;
* Test whether the CookieTokenExtractor can properly extract access tokens from
* Cookies and Headers.
*/
public class CookieTokenExtractorTest {
public class CookieTokenExtractorUnitTest {
private CookieTokenExtractor cookieTokenExtractor;
@Before
@ -22,24 +22,24 @@ public class CookieTokenExtractorTest {
@Test
public void testExtractTokenCookie() {
MockHttpServletRequest request = OAuth2AuthenticationServiceTest.createMockHttpServletRequest();
MockHttpServletRequest request = OAuth2AuthenticationServiceUnitTest.createMockHttpServletRequest();
Authentication authentication = cookieTokenExtractor.extract(request);
Assert.assertEquals(OAuth2AuthenticationServiceTest.ACCESS_TOKEN_VALUE, authentication.getPrincipal().toString());
Assert.assertEquals(OAuth2AuthenticationServiceUnitTest.ACCESS_TOKEN_VALUE, authentication.getPrincipal().toString());
}
@Test
public void testExtractTokenHeader() {
MockHttpServletRequest request = new MockHttpServletRequest(HttpMethod.GET.name(), "http://www.test.com");
request.addHeader("Authorization", OAuth2AccessToken.BEARER_TYPE + " " + OAuth2AuthenticationServiceTest.ACCESS_TOKEN_VALUE);
request.addHeader("Authorization", OAuth2AccessToken.BEARER_TYPE + " " + OAuth2AuthenticationServiceUnitTest.ACCESS_TOKEN_VALUE);
Authentication authentication = cookieTokenExtractor.extract(request);
Assert.assertEquals(OAuth2AuthenticationServiceTest.ACCESS_TOKEN_VALUE, authentication.getPrincipal().toString());
Assert.assertEquals(OAuth2AuthenticationServiceUnitTest.ACCESS_TOKEN_VALUE, authentication.getPrincipal().toString());
}
@Test
public void testExtractTokenParam() {
MockHttpServletRequest request = new MockHttpServletRequest(HttpMethod.GET.name(), "http://www.test.com");
request.addParameter(OAuth2AccessToken.ACCESS_TOKEN, OAuth2AuthenticationServiceTest.ACCESS_TOKEN_VALUE);
request.addParameter(OAuth2AccessToken.ACCESS_TOKEN, OAuth2AuthenticationServiceUnitTest.ACCESS_TOKEN_VALUE);
Authentication authentication = cookieTokenExtractor.extract(request);
Assert.assertEquals(OAuth2AuthenticationServiceTest.ACCESS_TOKEN_VALUE, authentication.getPrincipal().toString());
Assert.assertEquals(OAuth2AuthenticationServiceUnitTest.ACCESS_TOKEN_VALUE, authentication.getPrincipal().toString());
}
}

View File

@ -39,7 +39,7 @@ import static org.mockito.Mockito.when;
* @see OAuth2AuthenticationService
*/
@RunWith(MockitoJUnitRunner.class)
public class OAuth2AuthenticationServiceTest {
public class OAuth2AuthenticationServiceUnitTest {
public static final String CLIENT_AUTHORIZATION = "Basic d2ViX2FwcDpjaGFuZ2VpdA==";
public static final String ACCESS_TOKEN_VALUE = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE0OTQyNzI4NDQsInVzZXJfbmFtZSI6InVzZXIiLCJhdXRob3JpdGllcyI6WyJST0xFX1VTRVIiXSwianRpIjoiNzc1ZTJkYWUtYWYzZi00YTdhLWExOTktNzNiZTU1MmIxZDVkIiwiY2xpZW50X2lkIjoid2ViX2FwcCIsInNjb3BlIjpbIm9wZW5pZCJdfQ.gEK0YcX2IpkpxnkxXXHQ4I0xzTjcy7edqb89ukYE0LPe7xUcZVwkkCJF_nBxsGJh2jtA6NzNLfY5zuL6nP7uoAq3fmvsyrcyR2qPk8JuuNzGtSkICx3kPDRjAT4ST8SZdeh7XCbPVbySJ7ZmPlRWHyedzLA1wXN0NUf8yZYS4ELdUwVBYIXSjkNoKqfWm88cwuNr0g0teypjPtjDqCnXFt1pibwdfIXn479Y1neNAdvSpHcI4Ost-c7APCNxW2gqX-0BItZQearxRgKDdBQ7CGPAIky7dA0gPuKUpp_VCoqowKCXqkE9yKtRQGIISewtj2UkDRZePmzmYrUBXRzfYw";
public static final String REFRESH_TOKEN_VALUE = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJ1c2VyIiwic2NvcGUiOlsib3BlbmlkIl0sImF0aSI6Ijc3NWUyZGFlLWFmM2YtNGE3YS1hMTk5LTczYmU1NTJiMWQ1ZCIsImV4cCI6MTQ5Njg2NDc0MywiYXV0aG9yaXRpZXMiOlsiUk9MRV9VU0VSIl0sImp0aSI6IjhmYjI2YTllLTdjYzQtNDFlMi1hNzBjLTk4MDc0N2U2YWFiOSIsImNsaWVudF9pZCI6IndlYl9hcHAifQ.q1-Df9_AFO6TJNiLKV2YwTjRbnd7qcXv52skXYnog5siHYRoR6cPtm6TNQ04iDAoIHljTSTNnD6DS3bHk41mV55gsSVxGReL8VCb_R8ZmhVL4-5yr90sfms0wFp6lgD2bPmZ-TXiS2Oe9wcbNWagy5RsEplZ-sbXu3tjmDao4FN35ojPsXmUs84XnNQH3Y_-PY9GjZG0JEfLQIvE0J5BkXS18Z015GKyA6GBIoLhAGBQQYyG9m10ld_a9fD5SmCyCF72Jad_pfP1u8Z_WyvO-wrlBvm2x-zBthreVrXU5mOb9795wJEP-xaw3dXYGjht_grcW4vKUFtj61JgZk98CQ";

View File

@ -12,7 +12,7 @@ import org.springframework.test.util.ReflectionTestUtils;
*
* @see OAuth2CookieHelper
*/
public class OAuth2CookieHelperTest {
public class OAuth2CookieHelperUnitTest {
public static final String GET_COOKIE_DOMAIN_METHOD = "getCookieDomain";
private OAuth2Properties oAuth2Properties;
private OAuth2CookieHelper cookieHelper;

View File

@ -51,7 +51,7 @@ public class LogsResourceIntTest {
public void changeLogs() throws Exception {
LoggerVM logger = new LoggerVM();
logger.setLevel("INFO");
logger.setName("ROOT");
logger.setName("some.test.logger");
restLogsMockMvc.perform(put("/management/logs")
.contentType(TestUtil.APPLICATION_JSON_UTF8)

View File

@ -21,6 +21,8 @@ eureka:
instanceId: gateway:${spring.application.instance-id:${random.value}}
spring:
main:
banner-mode: "off"
application:
name: gateway
cache:
@ -93,7 +95,7 @@ jhipster:
authentication:
jwt:
# This token must be encoded using Base64 (you can type `echo 'secret-key'|base64` on your command line)
base64-secret:
base64-secret:
# Token is valid 24 hours
token-validity-in-seconds: 86400
metrics: # DropWizard Metrics configuration, used by MetricsConfiguration

View File

@ -1,6 +1,13 @@
<?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>
<parent>
<artifactId>jhipster-uaa</artifactId>
<groupId>com.baeldung.jhipster</groupId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<groupId>com.baeldung.jhipster.quotes</groupId>
<artifactId>quotes</artifactId>
<version>0.0.1-SNAPSHOT</version>
@ -399,15 +406,6 @@
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${maven-surefire-plugin.version}</version>
<configuration>
<!-- Force alphabetical order to have a reproducible build -->
<runOrder>alphabetical</runOrder>
</configuration>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
@ -832,7 +830,7 @@
</profile>
<!-- jhipster-needle-maven-add-profile -->
</profiles>
<properties>
<!-- Build properties -->
<maven.version>3.0.0</maven.version>
@ -909,5 +907,5 @@
<!-- jhipster-needle-maven-property -->
<zalando.version>0.24.0</zalando.version>
</properties>
</properties>
</project>

View File

@ -38,7 +38,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
*
* @see WebConfigurer
*/
public class WebConfigurerTest {
public class WebConfigurerUnitTest {
private WebConfigurer webConfigurer;

View File

@ -51,7 +51,7 @@ public class LogsResourceIntTest {
public void changeLogs() throws Exception {
LoggerVM logger = new LoggerVM();
logger.setLevel("INFO");
logger.setName("ROOT");
logger.setName("some.test.logger");
restLogsMockMvc.perform(put("/management/logs")
.contentType(TestUtil.APPLICATION_JSON_UTF8)

View File

@ -21,6 +21,8 @@ eureka:
instanceId: quotes:${spring.application.instance-id:${random.value}}
spring:
main:
banner-mode: "off"
application:
name: quotes
cache:

View File

@ -1,6 +1,12 @@
<?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>
<parent>
<artifactId>jhipster-uaa</artifactId>
<groupId>com.baeldung.jhipster</groupId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<groupId>com.baeldung.jhipster.uaa</groupId>
<artifactId>uaa</artifactId>
<version>0.0.1-SNAPSHOT</version>
@ -399,15 +405,6 @@
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${maven-surefire-plugin.version}</version>
<configuration>
<!-- Force alphabetical order to have a reproducible build -->
<runOrder>alphabetical</runOrder>
</configuration>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
@ -832,7 +829,7 @@
</profile>
<!-- jhipster-needle-maven-add-profile -->
</profiles>
<properties>
<lifecycle.mapping.version>1.0.0</lifecycle.mapping.version>
<spring.web.version>0.24.0</spring.web.version>
@ -911,5 +908,5 @@
<!-- jhipster-needle-maven-property -->
</properties>
</project>

View File

@ -38,7 +38,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
*
* @see WebConfigurer
*/
public class WebConfigurerTest {
public class WebConfigurerUnitTest {
private WebConfigurer webConfigurer;

View File

@ -51,7 +51,7 @@ public class LogsResourceIntTest {
public void changeLogs() throws Exception {
LoggerVM logger = new LoggerVM();
logger.setLevel("INFO");
logger.setName("ROOT");
logger.setName("some.test.logger");
restLogsMockMvc.perform(put("/management/logs")
.contentType(TestUtil.APPLICATION_JSON_UTF8)

View File

@ -21,6 +21,8 @@ eureka:
instanceId: uaa:${spring.application.instance-id:${random.value}}
spring:
main:
banner-mode: "off"
application:
name: uaa
cache:

View File

@ -9,7 +9,7 @@
<packaging>pom</packaging>
<parent>
<!-- Jhipster project is autogenerated and upgrading it will need a newly generated project.
<!-- Jhipster project is autogenerated and upgrading it will need a newly generated project.
Also, we already have jhipster-5 which has new version of boot-2. So, this project should be left as a legacy version. -->
<artifactId>parent-boot-1</artifactId>
<groupId>com.baeldung</groupId>
@ -17,11 +17,39 @@
<relativePath>../parent-boot-1</relativePath>
</parent>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>${spring-boot.version}</version>
<exclusions>
<exclusion>
<groupId>com.vaadin.external.google</groupId>
<artifactId>android-json</artifactId>
</exclusion>
<exclusion>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
</exclusion>
</exclusions>
<scope>test</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-java8</artifactId>
</dependency>
<dependency>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy</artifactId>
<version>${byte-buddy.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<modules>
@ -29,5 +57,5 @@
<module>jhipster-microservice</module>
<module>jhipster-uaa</module>
</modules>
</project>

3
ksqldb/README.md Normal file
View File

@ -0,0 +1,3 @@
### Relevant Articles:
- [Introduction to ksqlDB](https://www.baeldung.com/ksqldb)

View File

@ -78,6 +78,29 @@
<artifactId>sshd-core</artifactId>
<version>${apache-mina.version}</version>
</dependency>
<dependency>
<groupId>org.xacml4j</groupId>
<artifactId>xacml-core</artifactId>
<version>${xacml4j.version}</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.xacml4j</groupId>
<artifactId>xacml-test</artifactId>
<version>${xacml4j.version}</version>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<properties>
@ -90,6 +113,7 @@
<jsch.version>0.1.55</jsch.version>
<apache-mina.version>2.5.1</apache-mina.version>
<spring-security-oauth2.version>2.4.0.RELEASE</spring-security-oauth2.version>
<xacml4j.version>1.4.0</xacml4j.version>
</properties>
</project>

View File

@ -2,9 +2,11 @@ package com.baeldung.scribejava;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
@SpringBootApplication
@ServletComponentScan
public class ScribejavaApplication {
public static void main(String[] args) {

View File

@ -0,0 +1,27 @@
package com.baeldung.scribejava.controller;
import java.io.IOException;
import javax.annotation.security.DeclareRoles;
import javax.annotation.security.RolesAllowed;
import javax.servlet.ServletException;
import javax.servlet.annotation.HttpConstraint;
import javax.servlet.annotation.ServletSecurity;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet(name="rbac", urlPatterns = {"/protected"})
@DeclareRoles("USER")
@ServletSecurity(
@HttpConstraint(rolesAllowed = "USER")
)
public class RBACController extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().println("Hello, USER");
}
}

View File

@ -0,0 +1,233 @@
package com.baeldung.xacml4j;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.util.ArrayList;
import java.util.List;
import org.junit.Test;
import org.xacml4j.v20.Xacml20TestUtility;
import org.xacml4j.v30.Attribute;
import org.xacml4j.v30.Categories;
import org.xacml4j.v30.Category;
import org.xacml4j.v30.CompositeDecisionRule;
import org.xacml4j.v30.Decision;
import org.xacml4j.v30.Entity;
import org.xacml4j.v30.RequestContext;
import org.xacml4j.v30.ResponseContext;
import org.xacml4j.v30.Result;
import org.xacml4j.v30.XacmlPolicyTestSupport;
import org.xacml4j.v30.pdp.PolicyDecisionPoint;
import org.xacml4j.v30.pdp.PolicyDecisionPointBuilder;
import org.xacml4j.v30.spi.combine.DecisionCombiningAlgorithmProviderBuilder;
import org.xacml4j.v30.spi.function.FunctionProviderBuilder;
import org.xacml4j.v30.spi.pip.PolicyInformationPointBuilder;
import org.xacml4j.v30.spi.repository.InMemoryPolicyRepository;
import org.xacml4j.v30.spi.repository.PolicyRepository;
import org.xacml4j.v30.types.DoubleExp;
import org.xacml4j.v30.types.StringExp;
import org.xacml4j.v30.types.TimeExp;
public class NightlyWithdrawalPolicyUnitTest extends XacmlPolicyTestSupport {
private static final String POLICY_SET = "xacml4j/NightlyWithdrawalsPolicy.xml";
@Test
public void testWhenNightlyWithdrawalOver500_thenFail() throws Exception {
PolicyDecisionPoint pdp = buildPDP(POLICY_SET);
// Action category
Attribute actionAttribute = Attribute.builder("urn:oasis:names:tc:xacml:1.0:action:action-id")
.value(StringExp.of("withdrawal"))
.build();
Entity actionEntity = Entity.builder()
.attribute(actionAttribute)
.build();
Category actionCategory = Category.builder(Categories.ACTION)
.entity(actionEntity)
.build();
// Environment Category
Attribute timeAttribute = Attribute.builder("urn:oasis:names:tc:xacml:1.0:environment:current-time")
.includeInResult(false)
.value(TimeExp.of("21:00:00"))
.build();
Entity timeEntity = Entity.builder()
.attribute(timeAttribute)
.build();
Category environmentCategory = Category.builder(Categories.ENVIRONMENT)
.entity(timeEntity)
.build();
// ATM category
Attribute amountAttribute = Attribute.builder("urn:baeldung:atm:withdrawal:amount")
.value(DoubleExp.of("1200.00"))
.build();
Entity atmEntity = Entity.builder()
.attribute(amountAttribute)
.build();
Category atmCategory = Category.builder(Categories.parse("urn:baeldung:atm:withdrawal"))
.entity(atmEntity)
.build();
RequestContext request = RequestContext.builder()
.attributes(actionCategory, environmentCategory, atmCategory)
.build();
ResponseContext response = pdp.decide(request);
assertNotNull(response);
assertTrue("Shoud have at least one result", response.getResults() != null && !response.getResults()
.isEmpty());
Result result = response.getResults()
.iterator()
.next();
assertTrue("Evaluation should succeed", result.getStatus()
.isSuccess());
assertEquals("Should DENY withdrawal", Decision.DENY, result.getDecision());
}
@Test
public void testWhenNightlyWithdrawalUnder500_thenSuccess() throws Exception {
PolicyDecisionPoint pdp = buildPDP(POLICY_SET);
// Action category
Attribute actionAttribute = Attribute.builder("urn:oasis:names:tc:xacml:1.0:action:action-id")
.includeInResult(false)
.value(StringExp.of("withdrawal"))
.build();
Entity actionEntity = Entity.builder()
.attribute(actionAttribute)
.build();
Category actionCategory = Category.builder(Categories.ACTION)
.entity(actionEntity)
.build();
// Environment Category
Attribute timeAttribute = Attribute.builder("urn:oasis:names:tc:xacml:1.0:environment:current-time")
.includeInResult(false)
.value(TimeExp.of("21:00:00"))
.build();
Entity timeEntity = Entity.builder()
.attribute(timeAttribute)
.build();
Category environmentCategory = Category.builder(Categories.ENVIRONMENT)
.entity(timeEntity)
.build();
// ATM category
Attribute amountAttribute = Attribute.builder("urn:baeldung:atm:withdrawal:amount")
.value(DoubleExp.of("499.00"))
.build();
Entity atmEntity = Entity.builder()
.attribute(amountAttribute)
.build();
Category atmCategory = Category.builder(Categories.parse("urn:baeldung:atm:withdrawal"))
.entity(atmEntity)
.build();
RequestContext request = RequestContext.builder()
.attributes(actionCategory, environmentCategory, atmCategory)
.build();
ResponseContext response = pdp.decide(request);
assertNotNull(response);
assertTrue("Shoud have at least one result",
response.getResults() != null && !response.getResults().isEmpty());
Result result = response.getResults().iterator().next();
assertTrue("Evaluation should succeed", result.getStatus().isSuccess());
assertEquals("Should PERMIT withdrawal", Decision.PERMIT, result.getDecision());
}
@Test
public void testWhenBusinessHoursWithdrawalOver500_thenSuccess() throws Exception {
PolicyDecisionPoint pdp = buildPDP(POLICY_SET);
// Action category
Attribute actionAttribute = Attribute.builder("urn:oasis:names:tc:xacml:1.0:action:action-id")
.includeInResult(false)
.value(StringExp.of("withdrawal"))
.build();
Entity actionEntity = Entity.builder()
.attribute(actionAttribute)
.build();
Category actionCategory = Category.builder(Categories.ACTION)
.entity(actionEntity)
.build();
// Environment Category
Attribute timeAttribute = Attribute.builder("urn:oasis:names:tc:xacml:1.0:environment:current-time")
.includeInResult(false)
.value(TimeExp.of("12:00:00"))
.build();
Entity timeEntity = Entity.builder()
.attribute(timeAttribute)
.build();
Category environmentCategory = Category.builder(Categories.ENVIRONMENT)
.entity(timeEntity)
.build();
// ATM category
Attribute amountAttribute = Attribute.builder("urn:baeldung:atm:withdrawal:amount")
.value(DoubleExp.of("2000.00"))
.build();
Entity atmEntity = Entity.builder()
.attribute(amountAttribute)
.build();
Category atmCategory = Category.builder(Categories.parse("urn:baeldung:atm:withdrawal"))
.entity(atmEntity)
.build();
RequestContext request = RequestContext.builder()
.attributes(actionCategory, environmentCategory, atmCategory)
.build();
ResponseContext response = pdp.decide(request);
assertNotNull(response);
assertTrue("Shoud have at least one result", response.getResults() != null && !response.getResults()
.isEmpty());
Result result = response.getResults()
.iterator()
.next();
assertTrue("Evaluation should succeed", result.getStatus().isSuccess());
assertEquals("Should PERMIT withdrawal", Decision.PERMIT, result.getDecision());
}
private PolicyDecisionPoint buildPDP(String... policyResources) throws Exception {
PolicyRepository repository = new InMemoryPolicyRepository("tes-repository", FunctionProviderBuilder.builder()
.defaultFunctions()
.build(),
DecisionCombiningAlgorithmProviderBuilder.builder()
.withDefaultAlgorithms()
.create());
List<CompositeDecisionRule> policies = new ArrayList<CompositeDecisionRule>(policyResources.length);
for (String policyResource : policyResources) {
CompositeDecisionRule policy = repository.importPolicy(Xacml20TestUtility.getClasspathResource(policyResource));
log.info("Policy: {}", policy);
policies.add(policy);
}
return PolicyDecisionPointBuilder.builder("testPdp")
.policyRepository(repository)
.pip(PolicyInformationPointBuilder.builder("testPip")
.defaultResolvers()
.build())
.rootPolicy(policies.get(0))
.build();
}
}

View File

@ -0,0 +1,137 @@
<?xml version="1.0" encoding="UTF-8"?>
<Policy xmlns="urn:oasis:names:tc:xacml:3.0:core:schema:wd-17"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="urn:oasis:names:tc:xacml:3.0:core:schema:wd-17 http://docs.oasis-open.org/xacml/3.0/xacml-core-v3-schema-wd-17.xsd"
PolicyId="urn:baeldung:atm:WithdrawalPolicy"
Version="1.0"
RuleCombiningAlgId="urn:oasis:names:tc:xacml:1.0:rule-combining-algorithm:deny-overrides">
<Description>
Withdrawal policy example
</Description>
<Target/>
<Rule RuleId="urn:oasis:names:tc:baeldung:WithDrawalPolicy:Rule1" Effect="Deny">
<Description>
Deny withdrawals over $500 between 20:00 and 08:00
</Description>
<Target>
<AnyOf>
<AllOf>
<Match MatchId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
<AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">withdrawal</AttributeValue>
<AttributeDesignator
DataType="http://www.w3.org/2001/XMLSchema#string"
MustBePresent="true"
Category="urn:oasis:names:tc:xacml:3.0:attribute-category:action"
AttributeId="urn:oasis:names:tc:xacml:1.0:action:action-id"/>
</Match>
</AllOf>
</AnyOf>
</Target>
<Condition>
<Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:and">
<Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:not">
<Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:time-in-range">
<Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:time-one-and-only">
<AttributeDesignator
DataType="http://www.w3.org/2001/XMLSchema#time"
MustBePresent="true"
Category="urn:oasis:names:tc:xacml:3.0:attribute-category:environment"
AttributeId="urn:oasis:names:tc:xacml:1.0:environment:current-time"/>
</Apply>
<AttributeValue DataType="http://www.w3.org/2001/XMLSchema#time">08:00:00</AttributeValue>
<AttributeValue DataType="http://www.w3.org/2001/XMLSchema#time">20:00:00</AttributeValue>
</Apply>
</Apply>
<Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:double-greater-than">
<Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:double-one-and-only">
<AttributeDesignator
DataType="http://www.w3.org/2001/XMLSchema#double"
MustBePresent="true"
Category="urn:baeldung:atm:withdrawal"
AttributeId="urn:baeldung:atm:withdrawal:amount"/>
</Apply>
<AttributeValue DataType="http://www.w3.org/2001/XMLSchema#double">500.00</AttributeValue>
</Apply>
</Apply>
</Condition>
</Rule>
<Rule RuleId="urn:oasis:names:tc:baeldung:WithDrawalPolicy:Rule2" Effect="Permit">
<Description>
Permit withdrawals under $500 between 20:00 and 08:00
</Description>
<Target>
<AnyOf>
<AllOf>
<Match MatchId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
<AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">withdrawal</AttributeValue>
<AttributeDesignator
DataType="http://www.w3.org/2001/XMLSchema#string"
MustBePresent="true"
Category="urn:oasis:names:tc:xacml:3.0:attribute-category:action"
AttributeId="urn:oasis:names:tc:xacml:1.0:action:action-id"/>
</Match>
</AllOf>
</AnyOf>
</Target>
<Condition>
<Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:and">
<Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:not">
<Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:time-in-range">
<Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:time-one-and-only">
<AttributeDesignator
DataType="http://www.w3.org/2001/XMLSchema#time"
MustBePresent="true"
Category="urn:oasis:names:tc:xacml:3.0:attribute-category:environment"
AttributeId="urn:oasis:names:tc:xacml:1.0:environment:current-time"/>
</Apply>
<AttributeValue DataType="http://www.w3.org/2001/XMLSchema#time">08:00:00</AttributeValue>
<AttributeValue DataType="http://www.w3.org/2001/XMLSchema#time">20:00:00</AttributeValue>
</Apply>
</Apply>
<Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:double-less-than-or-equal">
<Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:double-one-and-only">
<AttributeDesignator
DataType="http://www.w3.org/2001/XMLSchema#double"
MustBePresent="true"
Category="urn:baeldung:atm:withdrawal"
AttributeId="urn:baeldung:atm:withdrawal:amount"/>
</Apply>
<AttributeValue DataType="http://www.w3.org/2001/XMLSchema#double">500.00</AttributeValue>
</Apply>
</Apply>
</Condition>
</Rule>
<Rule RuleId="urn:oasis:names:tc:baeldung:WithDrawalPolicy:Rule3" Effect="Permit">
<Description>
Permit withdrawals of any value between 08:00 and 20:00
</Description>
<Target>
<AnyOf>
<AllOf>
<Match MatchId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
<AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">withdrawal</AttributeValue>
<AttributeDesignator
DataType="http://www.w3.org/2001/XMLSchema#string"
MustBePresent="true"
Category="urn:oasis:names:tc:xacml:3.0:attribute-category:action"
AttributeId="urn:oasis:names:tc:xacml:1.0:action:action-id"/>
</Match>
</AllOf>
</AnyOf>
</Target>
<Condition>
<Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:time-in-range">
<Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:time-one-and-only">
<AttributeDesignator
DataType="http://www.w3.org/2001/XMLSchema#time"
MustBePresent="true"
Category="urn:oasis:names:tc:xacml:3.0:attribute-category:environment"
AttributeId="urn:oasis:names:tc:xacml:1.0:environment:current-time"/>
</Apply>
<AttributeValue DataType="http://www.w3.org/2001/XMLSchema#time">08:00:00</AttributeValue>
<AttributeValue DataType="http://www.w3.org/2001/XMLSchema#time">20:00:00</AttributeValue>
</Apply>
</Condition>
</Rule>
</Policy>

View File

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<Request
xmlns="urn:oasis:names:tc:xacml:3.0:core:schema:wd-17"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="urn:oasis:names:tc:xacml:3.0:core:schema:wd-17 http://docs.oasis-open.org/xacml/3.0/xacml-core-v3-schema-wd-17.xsd"
CombinedDecision="true"
ReturnPolicyIdList="false">
<Attributes Category="urn:oasis:names:tc:xacml:3.0:attribute-category:action">
<Attribute
IncludeInResult="false"
AttributeId="urn:oasis:names:tc:xacml:3.0:attribute-category:action">
<AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">withdrawal</AttributeValue>
</Attribute>
</Attributes>
<Attributes Category="urn:oasis:names:tc:xacml:3.0:attribute-category:action">
<Attribute
IncludeInResult="false"
AttributeId="urn:oasis:names:tc:xacml:1.0:environment:current-time">
<AttributeValue DataType="http://www.w3.org/2001/XMLSchema#time">21:00:00</AttributeValue>
</Attribute>
</Attributes>
<Attributes Category="urn:baeldung:atm:withdrawal">
<Attribute
IncludeInResult="false"
AttributeId="urn:baeldung:atm:withdrawal:amount">
<AttributeValue DataType="http://www.w3.org/2001/XMLSchema#decimal">1200</AttributeValue>
</Attribute>
</Attributes>
</Request>

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<Response xmlns="urn:oasis:names:tc:xacml:2.0:context:schema:os" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:oasis:names:tc:xacml:2.0:context:schema:os http://docs.oasis-open.org/xacml/access_control-xacml-2.0-context-schema-os.xsd">
<Result>
<Decision>NotApplicable</Decision>
<Status>
<StatusCode Value="urn:oasis:names:tc:xacml:1.0:status:ok"/>
</Status>
</Result>
</Response>

View File

@ -40,6 +40,11 @@
<artifactId>javatuples</artifactId>
<version>${javatuples.version}</version>
</dependency>
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>${javaassist.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.assertj/assertj-core -->
<dependency>
<groupId>org.assertj</groupId>
@ -51,42 +56,6 @@
<artifactId>javers-core</artifactId>
<version>${javers.version}</version>
</dependency>
<dependency>
<groupId>net.serenity-bdd</groupId>
<artifactId>serenity-core</artifactId>
<version>${serenity.version}</version>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.asciidoctor</groupId>
<artifactId>asciidoctorj</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>net.serenity-bdd</groupId>
<artifactId>serenity-junit</artifactId>
<version>${serenity.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>net.serenity-bdd</groupId>
<artifactId>serenity-jbehave</artifactId>
<version>${serenity.jbehave.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>net.serenity-bdd</groupId>
<artifactId>serenity-rest-assured</artifactId>
<version>${serenity.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>net.serenity-bdd</groupId>
<artifactId>serenity-jira-requirements-provider</artifactId>
<version>${serenity.jira.version}</version>
<scope>test</scope>
</dependency>
<!-- JDO -->
<dependency>
<groupId>org.datanucleus</groupId>
@ -139,30 +108,6 @@
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>net.serenity-bdd</groupId>
<artifactId>serenity-spring</artifactId>
<version>${serenity.version}</version>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>net.serenity-bdd</groupId>
<artifactId>serenity-screenplay</artifactId>
<version>${serenity.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>net.serenity-bdd</groupId>
<artifactId>serenity-screenplay-webdriver</artifactId>
<version>${serenity.version}</version>
<scope>test</scope>
</dependency>
<!-- JetS3t -->
<dependency>
<groupId>org.lucee</groupId>
@ -253,29 +198,6 @@
<build>
<plugins>
<plugin>
<artifactId>maven-failsafe-plugin</artifactId>
<version>${maven-failsafe-plugin.version}</version>
<configuration>
<systemProperties>
<webdriver.chrome.driver>chromedriver</webdriver.chrome.driver>
</systemProperties>
</configuration>
</plugin>
<plugin>
<groupId>net.serenity-bdd.maven.plugins</groupId>
<artifactId>serenity-maven-plugin</artifactId>
<version>${serenity.plugin.version}</version>
<executions>
<execution>
<id>serenity-reports</id>
<phase>post-integration-test</phase>
<goals>
<goal>aggregate</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- JDO Plugin -->
<plugin>
<groupId>org.datanucleus</groupId>
@ -380,6 +302,7 @@
<spring.version>4.3.8.RELEASE</spring.version>
<spring-mock-mvc.version>3.0.3</spring-mock-mvc.version>
<quartz.version>2.3.0</quartz.version>
<javaassist.version>3.21.0-GA</javaassist.version>
<jool.version>0.9.12</jool.version>
<maven-jar-plugin.version>3.0.2</maven-jar-plugin.version>
<commons-net.version>3.6</commons-net.version>

View File

@ -1,4 +0,0 @@
jira.url=<jira-url>
jira.project=<jira-project>
jira.username=<jira-username>
jira.password=<jira-password>

View File

@ -0,0 +1,3 @@
### Relevant Articles:
- [Understanding the "relativePath" Tag - Maven Parent POM Resolution At A Glance](https://www.baeldung.com/maven-relativepath)

View File

@ -0,0 +1,28 @@
<?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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.baeldung</groupId>
<artifactId>maven-parent-pom-resolution</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<modules>
<module>project-a</module>
</modules>
<!-- to detect the POM hierarchy, just type "mvn dependency:display-ancestors" -->
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>3.2.0</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>

View File

@ -0,0 +1,20 @@
<?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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>project-a</artifactId>
<parent>
<groupId>com.baeldung</groupId>
<artifactId>maven-parent-pom-resolution</artifactId>
<version>1.0-SNAPSHOT</version>
<!-- The parent pom is resolved to ../pom.xml -->
</parent>
<packaging>pom</packaging>
<modules>
<module>project-b</module>
<module>project-c</module>
</modules>
</project>

View File

@ -0,0 +1,15 @@
<?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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>project-b</artifactId>
<parent>
<groupId>com.baeldung</groupId>
<artifactId>project-a</artifactId>
<version>1.0-SNAPSHOT</version>
<!-- The parent pom is resolved to project a's pom.xml -->
</parent>
<packaging>pom</packaging>
</project>

View File

@ -0,0 +1,20 @@
<?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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>project-c</artifactId>
<parent>
<groupId>com.baeldung</groupId>
<artifactId>project-b</artifactId>
<version>1.0-SNAPSHOT</version>
<relativePath>../project-b/pom.xml</relativePath>
<!-- The parent pom is resolved to project a's pom.xml -->
</parent>
<packaging>pom</packaging>
<modules>
<module>project-d</module>
</modules>
</project>

View File

@ -0,0 +1,17 @@
<?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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>project-d</artifactId>
<parent>
<groupId>com.baeldung</groupId>
<artifactId>project-a</artifactId>
<version>1.0-SNAPSHOT</version>
<!-- removing relativePath won't work even if project-a is the aggregator project -->
<!-- it only works in IntelliJ IDEA when project-a is registered as a Maven Project -->
<relativePath>../../pom.xml</relativePath>
</parent>
<packaging>pom</packaging>
</project>

View File

@ -13,12 +13,12 @@
<version>1.0.0-SNAPSHOT</version>
<relativePath>../..</relativePath>
</parent>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
<version>${junit.version}</version>
</dependency>
</dependencies>
@ -46,6 +46,7 @@
<properties>
<name>${project.name}</name>
<my.awesome.property>property-from-pom</my.awesome.property>
<junit.version>4.13</junit.version>
</properties>
</project>
</project>

View File

@ -0,0 +1,3 @@
## Relevant Articles:
- [Running a Single Test or Method With Maven](https://www.baeldung.com/maven-run-single-test)

View File

@ -36,6 +36,7 @@
<module>host-maven-repo-example</module>
<module>plugin-management</module>
<module>maven-surefire-plugin</module>
<module>maven-parent-pom-resolution</module>
</modules>
</project>

View File

@ -30,7 +30,7 @@
</dependencies>
<properties>
<spring.version>5.3.7</spring.version>
<spring.version>5.3.9</spring.version>
<spring-security.version>5.2.3.RELEASE</spring-security.version>
<spring-boot-starter-test.version>1.5.10.RELEASE</spring-boot-starter-test.version>
</properties>

View File

@ -3,3 +3,4 @@
- [The DAO Pattern in Java](https://www.baeldung.com/java-dao-pattern)
- [DAO vs Repository Patterns](https://www.baeldung.com/java-dao-vs-repository)
- [Difference Between MVC and MVP Patterns](https://www.baeldung.com/mvc-vs-mvp-pattern)
- [The DTO Pattern (Data Transfer Object)](https://www.baeldung.com/java-dto-pattern)

View File

@ -15,6 +15,21 @@
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<version>${rest-assured.version}</version>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
@ -38,6 +53,9 @@
<assertj-core.version>3.9.1</assertj-core.version>
<hibernate-core.version>5.2.16.Final</hibernate-core.version>
<mysql-connector.version>6.0.6</mysql-connector.version>
<spring-boot.version>2.5.3</spring-boot.version>
<rest-assured.version>3.3.0</rest-assured.version>
</properties>
</project>

View File

@ -0,0 +1,12 @@
package com.baeldung.dtopattern;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Main {
public static void main(String[] args) {
SpringApplication.run(Main.class, args);
}
}

View File

@ -0,0 +1,28 @@
package com.baeldung.dtopattern.api;
import com.baeldung.dtopattern.domain.Role;
import com.baeldung.dtopattern.domain.User;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
import static java.util.stream.Collectors.toList;
@Component
class Mapper {
public UserDTO toDto(User user) {
String name = user.getName();
List<String> roles = user
.getRoles()
.stream()
.map(Role::getName)
.collect(toList());
return new UserDTO(name, roles);
}
public User toUser(UserCreationDTO userDTO) {
return new User(userDTO.getName(), userDTO.getPassword(), new ArrayList<>());
}
}

View File

@ -0,0 +1,51 @@
package com.baeldung.dtopattern.api;
import com.baeldung.dtopattern.domain.RoleService;
import com.baeldung.dtopattern.domain.User;
import com.baeldung.dtopattern.domain.UserService;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import static java.util.stream.Collectors.toList;
@RestController
@RequestMapping("/users")
class UserController {
private UserService userService;
private RoleService roleService;
private Mapper mapper;
public UserController(UserService userService, RoleService roleService, Mapper mapper) {
this.userService = userService;
this.roleService = roleService;
this.mapper = mapper;
}
@GetMapping
@ResponseBody
public List<UserDTO> getUsers() {
return userService.getAll()
.stream()
.map(mapper::toDto)
.collect(toList());
}
@PostMapping
@ResponseBody
public UserIdDTO create(@RequestBody UserCreationDTO userDTO) {
User user = mapper.toUser(userDTO);
userDTO.getRoles()
.stream()
.map(role -> roleService.getOrCreate(role))
.forEach(user::addRole);
userService.save(user);
return new UserIdDTO(user.getId());
}
}

View File

@ -0,0 +1,36 @@
package com.baeldung.dtopattern.api;
import java.util.List;
public class UserCreationDTO {
private String name;
private String password;
private List<String> roles;
UserCreationDTO() {}
public String getName() {
return name;
}
public String getPassword() {
return password;
}
public List<String> getRoles() {
return roles;
}
void setName(String name) {
this.name = name;
}
void setPassword(String password) {
this.password = password;
}
void setRoles(List<String> roles) {
this.roles = roles;
}
}

View File

@ -0,0 +1,22 @@
package com.baeldung.dtopattern.api;
import java.util.List;
public class UserDTO {
private String name;
private List<String> roles;
public UserDTO(String name, List<String> roles) {
this.name = name;
this.roles = roles;
}
public String getName() {
return name;
}
public List<String> getRoles() {
return roles;
}
}

View File

@ -0,0 +1,14 @@
package com.baeldung.dtopattern.api;
public class UserIdDTO {
private String id;
public UserIdDTO(String id) {
this.id = id;
}
public String getId() {
return id;
}
}

View File

@ -0,0 +1,49 @@
package com.baeldung.dtopattern.domain;
import org.springframework.stereotype.Service;
import java.util.*;
@Service
class InMemoryRepository implements UserRepository, RoleRepository {
private Map<String, User> users = new LinkedHashMap<>();
private Map<String, Role> roles = new LinkedHashMap<>();
@Override
public List<User> getAll() {
return new ArrayList<>(users.values());
}
@Override
public void save(User user) {
user.setId(UUID.randomUUID().toString());
users.put(user.getId(), user);
}
@Override
public void save(Role role) {
role.setId(UUID.randomUUID().toString());
roles.put(role.getId(), role);
}
@Override
public Role getRoleById(String id) {
return roles.get(id);
}
@Override
public Role getRoleByName(String name) {
return roles.values()
.stream()
.filter(role -> role.getName().equalsIgnoreCase(name))
.findFirst()
.orElse(null);
}
@Override
public void deleteAll() {
users.clear();
roles.clear();
}
}

View File

@ -0,0 +1,28 @@
package com.baeldung.dtopattern.domain;
import java.util.Objects;
public class Role {
private String id;
private String name;
public Role(String name) {
this.name = Objects.requireNonNull(name);
}
public String getId() {
return id;
}
void setId(String id) {
this.id = Objects.requireNonNull(id);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = Objects.requireNonNull(name);
}
}

View File

@ -0,0 +1,7 @@
package com.baeldung.dtopattern.domain;
public interface RoleRepository {
Role getRoleById(String id);
Role getRoleByName(String name);
void save(Role role);
}

View File

@ -0,0 +1,32 @@
package com.baeldung.dtopattern.domain;
import org.springframework.stereotype.Service;
import java.util.Objects;
@Service
public class RoleService {
private RoleRepository repository;
public RoleService(RoleRepository repository) {
this.repository = repository;
}
public Role getOrCreate(String name) {
Role role = repository.getRoleByName(name);
if (role == null) {
role = new Role(name);
repository.save(role);
}
return role;
}
public void save(Role role) {
Objects.requireNonNull(role);
repository.save(role);
}
}

View File

@ -0,0 +1,80 @@
package com.baeldung.dtopattern.domain;
import javax.crypto.*;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
public class User {
private static SecretKeySpec KEY = initKey();
static SecretKeySpec initKey(){
try {
SecretKey secretKey = KeyGenerator.getInstance("AES").generateKey();
return new SecretKeySpec(secretKey.getEncoded(), "AES");
} catch (NoSuchAlgorithmException ex) {
return null;
}
}
private String id;
private String name;
private String password;
private List<Role> roles;
public User(String name, String password, List<Role> roles) {
this.name = Objects.requireNonNull(name);
this.password = this.encrypt(password);
this.roles = Objects.requireNonNull(roles);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public void addRole(Role role) {
roles.add(role);
}
public List<Role> getRoles() {
return Collections.unmodifiableList(roles);
}
public String getId() {
return id;
}
void setId(String id) {
this.id = id;
}
String encrypt(String password) {
Objects.requireNonNull(password);
try {
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, KEY);
final byte[] encryptedBytes = cipher.doFinal(password.getBytes(StandardCharsets.UTF_8));
return new String(encryptedBytes, StandardCharsets.UTF_8);
} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException e) {
// do nothing
return "";
}
}
}

View File

@ -0,0 +1,9 @@
package com.baeldung.dtopattern.domain;
import java.util.List;
public interface UserRepository {
List<User> getAll();
void save(User user);
void deleteAll();
}

View File

@ -0,0 +1,25 @@
package com.baeldung.dtopattern.domain;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Objects;
@Service
public class UserService {
private UserRepository repository;
public UserService(UserRepository repository) {
this.repository = repository;
}
public List<User> getAll() {
return repository.getAll();
}
public void save(User user) {
Objects.requireNonNull(user);
repository.save(user);
}
}

View File

@ -0,0 +1,56 @@
package com.baeldung.dtopattern.api;
import com.baeldung.dtopattern.domain.Role;
import com.baeldung.dtopattern.domain.User;
import org.junit.jupiter.api.Test;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
class MapperUnitTest {
@Test
void toDto_shouldMapFromDomainToDTO() {
String name = "Test";
String password = "test";
Role admin = new Role("admin");
List<String> expectedRoles = Collections.singletonList("admin");
List<Role> roles = new ArrayList<>();
roles.add(admin);
User user = new User(name, password, roles);
Mapper mapper = new Mapper();
UserDTO dto = mapper.toDto(user);
assertEquals(name, dto.getName());
assertEquals(expectedRoles, dto.getRoles());
}
@Test
void toUser_shouldMapFromDTOToDomain() {
String name = "Test";
String password = "test";
String role = "admin";
UserCreationDTO dto = new UserCreationDTO();
dto.setName(name);
dto.setPassword(password);
dto.setRoles(Collections.singletonList("admin"));
User expectedUser = new User(name, password, new ArrayList<>());
Mapper mapper = new Mapper();
User user = mapper.toUser(dto);
assertEquals(name, user.getName());
assertEquals(expectedUser.getPassword(), user.getPassword());
assertEquals(Collections.emptyList(), user.getRoles());
}
}

View File

@ -0,0 +1,80 @@
package com.baeldung.dtopattern.api;
import com.baeldung.dtopattern.domain.Role;
import com.baeldung.dtopattern.domain.RoleRepository;
import com.baeldung.dtopattern.domain.User;
import com.baeldung.dtopattern.domain.UserRepository;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.restassured.http.ContentType;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.boot.web.server.LocalServerPort;
import java.util.Collections;
import static io.restassured.RestAssured.given;
import static org.hamcrest.CoreMatchers.*;
import static org.springframework.http.HttpStatus.OK;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class UserControllerIntegrationTest {
@Autowired
private TestRestTemplate restTemplate;
@Autowired
private UserRepository userRepository;
@Autowired
private RoleRepository roleRepository;
@LocalServerPort
int port;
@Autowired
private ObjectMapper objectMapper;
@Test
void create_shouldReturnUseId() throws Exception {
UserCreationDTO request = new UserCreationDTO();
request.setName("User 1");
request.setPassword("Test@123456");
request.setRoles(Collections.singletonList("admin"));
given()
.contentType(ContentType.JSON)
.body(objectMapper.writeValueAsString(request))
.when()
.port(port)
.post("/users")
.then()
.statusCode(OK.value())
.body("id", notNullValue());
}
@Test
void getAll_shouldReturnUseDTO() {
userRepository.deleteAll();
String roleName = "admin";
Role admin = new Role(roleName);
roleRepository.save(admin);
String name = "User 1";
User user = new User(name, "Test@123456", Collections.singletonList(admin));
userRepository.save(user);
given()
.port(port)
.when()
.get("/users")
.then()
.statusCode(OK.value())
.body("size()", is(1))
.body("[0].name", equalTo(name))
.body("[0].roles", hasItem(roleName));
}
}

View File

@ -0,0 +1,83 @@
package com.baeldung.dtopattern.domain;
import org.junit.jupiter.api.Test;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
class InMemoryRepositoryUnitTest {
@Test
void getAll_shouldReturnAllUsers() {
String name = "Test";
String password = "test123";
List<Role> roles = new ArrayList<>();
User user = new User(name, password, roles);
List<User> expectedUsers = Collections.singletonList(user);
InMemoryRepository repository = new InMemoryRepository();
repository.save(user);
List<User> users = repository.getAll();
assertEquals(expectedUsers, users);
}
@Test
void save_whenSavingUser_shouldSetId() {
String name = "Test";
String password = "test123";
List<Role> roles = new ArrayList<>();
User user = new User(name, password, roles);
InMemoryRepository repository = new InMemoryRepository();
repository.save(user);
assertNotNull(user.getId());
}
@Test
void save_whenSavingRole_shouldSetId() {
String name = "Test";
Role role = new Role(name);
InMemoryRepository repository = new InMemoryRepository();
repository.save(role);
assertNotNull(role.getId());
}
@Test
void getRoleById_shouldReturnRoleById() {
String name = "Test";
Role expectedRole = new Role(name);
InMemoryRepository repository = new InMemoryRepository();
repository.save(expectedRole);
Role role = repository.getRoleById(expectedRole.getId());
assertEquals(expectedRole, role);
}
@Test
void getRoleByName_shouldReturnRoleByName() {
String name = "Test";
Role expectedRole = new Role(name);
InMemoryRepository repository = new InMemoryRepository();
repository.save(expectedRole);
Role role = repository.getRoleByName(name);
assertEquals(expectedRole, role);
}
}

View File

@ -0,0 +1,38 @@
package com.baeldung.dtopattern.domain;
import org.junit.jupiter.api.Test;
import java.util.ArrayList;
import static org.junit.jupiter.api.Assertions.*;
class UserUnitTest {
@Test
void whenUserIsCreated_shouldEncryptPassword() {
User user = new User("Test", "test", new ArrayList<>());
assertEquals(user.encrypt("test"), user.getPassword());
assertNotEquals(user.encrypt("Test"), user.getPassword());
}
@Test
void whenUserIsCreated_shouldFailIfNameIsNull() {
assertThrows(NullPointerException.class, () ->
new User(null, "test", new ArrayList<>()));
}
@Test
void whenUserIsCreated_shouldFailIfPasswordIsNull() {
assertThrows(NullPointerException.class, () ->
new User("Test", null, new ArrayList<>()));
}
@Test
void whenUserIsCreated_shouldFailIfRolesIsNull() {
assertThrows(NullPointerException.class, () ->
new User("Test", "Test", null));
}
}

View File

@ -13,3 +13,4 @@ This module contains articles about the Java Persistence API (JPA) in Java.
- [Returning an Auto-Generated Id with JPA](https://www.baeldung.com/jpa-get-auto-generated-id)
- [How to Return Multiple Entities In JPA Query](https://www.baeldung.com/jpa-return-multiple-entities)
- [Defining Unique Constraints in JPA](https://www.baeldung.com/jpa-unique-constraints)
- [How to Check Field Existence in MongoDB?](https://www.baeldung.com/mongodb-check-field-exists)

View File

@ -11,3 +11,4 @@ This module contains articles about Reactor Core.
- [How to Convert Mono<List<T\>> Into Flux<T\>](https://www.baeldung.com/java-mono-list-to-flux)
- [Project Reactor: map() vs flatMap()](https://www.baeldung.com/java-reactor-map-flatmap)
- [What Does Mono.defer() Do?](https://www.baeldung.com/java-mono-defer)
- [Handling Exceptions in Project Reactor](https://www.baeldung.com/reactor-exceptions)

View File

@ -41,8 +41,8 @@
</dependencies>
<properties>
<reactor.version>3.3.9.RELEASE</reactor.version>
<reactor.version>3.4.9</reactor.version>
<assertj.version>3.6.1</assertj.version>
</properties>
</project>
</project>

View File

@ -0,0 +1,89 @@
package com.baeldung.reactor.exception;
import org.junit.Test;
import org.reactivestreams.Publisher;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.core.publisher.SynchronousSink;
import reactor.test.StepVerifier;
import java.util.function.BiConsumer;
import java.util.function.Function;
public class ExceptionUnitTest {
@Test
public void givenInvalidElement_whenPipelineThrowsException_thenErrorIsSentDownstream() {
Function<String, Integer> mapper = input -> {
if (input.matches("\\D")) {
throw new NumberFormatException();
} else {
return Integer.parseInt(input);
}
};
Flux<String> inFlux = Flux.just("1", "1.5", "2");
Flux<Integer> outFlux = inFlux.map(mapper);
StepVerifier.create(outFlux)
.expectNext(1)
.expectError(NumberFormatException.class)
.verify();
}
@Test
public void givenInvalidElement_whenHandleCallsSinkErrorMethod_thenErrorIsSentDownstream() {
BiConsumer<String, SynchronousSink<Integer>> handler = (input, sink) -> {
if (input.matches("\\D")) {
sink.error(new NumberFormatException());
} else {
sink.next(Integer.parseInt(input));
}
};
Flux<String> inFlux = Flux.just("1", "1.5", "2");
Flux<Integer> outFlux = inFlux.handle(handler);
StepVerifier.create(outFlux)
.expectNext(1)
.expectError(NumberFormatException.class)
.verify();
}
@Test
public void givenInvalidElement_whenFlatMapCallsMonoErrorMethod_thenErrorIsSentDownstream() {
Function<String, Publisher<Integer>> mapper = input -> {
if (input.matches("\\D")) {
return Mono.error(new NumberFormatException());
} else {
return Mono.just(Integer.parseInt(input));
}
};
Flux<String> inFlux = Flux.just("1", "1.5", "2");
Flux<Integer> outFlux = inFlux.flatMap(mapper);
StepVerifier.create(outFlux)
.expectNext(1)
.expectError(NumberFormatException.class)
.verify();
}
@Test
public void givenNullElement_whenPipelineOperatorExecutes_thenNpeIsSentDownstream() {
Function<String, Integer> mapper = input -> {
if (input == null) {
return 0;
} else {
return Integer.parseInt(input);
}
};
Flux<String> inFlux = Flux.just("1", null, "2");
Flux<Integer> outFlux = inFlux.map(mapper);
StepVerifier.create(outFlux)
.expectNext(1)
.expectError(NullPointerException.class)
.verify();
}
}

View File

@ -8,6 +8,7 @@ This module contains articles about Spring with Kafka
- [Testing Kafka and Spring Boot](https://www.baeldung.com/spring-boot-kafka-testing)
- [Monitor the Consumer Lag in Apache Kafka](https://www.baeldung.com/java-kafka-consumer-lag)
- [Send Large Messages With Kafka](https://www.baeldung.com/java-kafka-send-large-message)
- [Configuring Kafka SSL Using Spring Boot](https://www.baeldung.com/spring-boot-kafka-ssl)
### Intro

View File

@ -28,6 +28,10 @@
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.kafka</groupId>
<artifactId>spring-kafka-test</artifactId>
@ -41,9 +45,15 @@
<scope>test</scope>
</dependency>
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.1</version>
<groupId>org.testcontainers</groupId>
<artifactId>junit-jupiter</artifactId>
<version>${testcontainers-kafka.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.awaitility</groupId>
<artifactId>awaitility</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

View File

@ -0,0 +1,25 @@
package com.baeldung.kafka.ssl;
import lombok.extern.slf4j.Slf4j;
import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
@Component
@Slf4j
public class KafkaConsumer {
public static final String TOPIC = "test-topic";
public final List<String> messages = new ArrayList<>();
@KafkaListener(topics = TOPIC)
public void receive(ConsumerRecord<String, String> consumerRecord) {
log.info("Received payload: '{}'", consumerRecord.toString());
messages.add(consumerRecord.value());
}
}

View File

@ -0,0 +1,23 @@
package com.baeldung.kafka.ssl;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Component;
@Slf4j
@AllArgsConstructor
@Component
public class KafkaProducer {
private final KafkaTemplate<String, String> kafkaTemplate;
public void sendMessage(String message, String topic) {
log.info("Producing message: {}", message);
kafkaTemplate.send(topic, "key", message)
.addCallback(
result -> log.info("Message sent to topic: {}", message),
ex -> log.error("Failed to send message", ex)
);
}
}

View File

@ -0,0 +1,15 @@
package com.baeldung.kafka.ssl;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@EnableAutoConfiguration
public class KafkaSslApplication {
public static void main(String[] args) {
SpringApplication.run(KafkaSslApplication.class, args);
}
}

View File

@ -0,0 +1,18 @@
spring:
kafka:
security:
protocol: "SSL"
bootstrap-servers: localhost:9093
ssl:
trust-store-location: classpath:/client-certs/kafka.client.truststore.jks
trust-store-password: password
key-store-location: classpath:/client-certs/kafka.client.keystore.jks
key-store-password: password
consumer:
group-id: demo-group-id
auto-offset-reset: earliest
key-deserializer: org.apache.kafka.common.serialization.StringDeserializer
value-deserializer: org.apache.kafka.common.serialization.StringDeserializer
producer:
key-deserializer: org.apache.kafka.common.serialization.StringDeserializer
value-deserializer: org.apache.kafka.common.serialization.StringDeserializer

View File

@ -0,0 +1,54 @@
package com.baeldung.kafka.ssl;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;
import org.testcontainers.containers.DockerComposeContainer;
import org.testcontainers.containers.wait.strategy.Wait;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import java.io.File;
import java.time.Duration;
import java.util.UUID;
import static com.baeldung.kafka.ssl.KafkaConsumer.TOPIC;
import static org.assertj.core.api.Assertions.assertThat;
import static org.awaitility.Awaitility.await;
@Slf4j
@ActiveProfiles("ssl")
@Testcontainers
@SpringBootTest(classes = KafkaSslApplication.class)
class KafkaSslApplicationLiveTest {
private static final File KAFKA_COMPOSE_FILE = new File("src/test/resources/docker/docker-compose.yml");
private static final String KAFKA_SERVICE = "kafka";
private static final int SSL_PORT = 9093;
@Container
public DockerComposeContainer<?> container =
new DockerComposeContainer<>(KAFKA_COMPOSE_FILE)
.withExposedService(KAFKA_SERVICE, SSL_PORT, Wait.forListeningPort());
@Autowired
private KafkaProducer kafkaProducer;
@Autowired
private KafkaConsumer kafkaConsumer;
@Test
void givenSslIsConfigured_whenProducerSendsMessageOverSsl_thenConsumerReceivesOverSsl() {
String message = generateSampleMessage();
kafkaProducer.sendMessage(message, TOPIC);
await().atMost(Duration.ofMinutes(2))
.untilAsserted(() -> assertThat(kafkaConsumer.messages).containsExactly(message));
}
private static String generateSampleMessage() {
return UUID.randomUUID().toString();
}
}

View File

@ -0,0 +1 @@
password

View File

@ -0,0 +1 @@
password

View File

@ -0,0 +1 @@
password

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