This commit is contained in:
Philippe 2020-10-06 10:16:28 -03:00
commit 2bd89b92b2
56 changed files with 3319 additions and 123 deletions

View File

@ -9,4 +9,5 @@
- [The Caesar Cipher in Java](https://www.baeldung.com/java-caesar-cipher) - [The Caesar Cipher in Java](https://www.baeldung.com/java-caesar-cipher)
- [Implementing a 2048 Solver in Java](https://www.baeldung.com/2048-java-solver) - [Implementing a 2048 Solver in Java](https://www.baeldung.com/2048-java-solver)
- [Finding Top K Elements in an Array](https://www.baeldung.com/java-array-top-elements) - [Finding Top K Elements in an Array](https://www.baeldung.com/java-array-top-elements)
- [Reversing a Linked List in Java](https://www.baeldung.com/java-reverse-linked-list)
- More articles: [[<-- prev]](/../algorithms-miscellaneous-5) - More articles: [[<-- prev]](/../algorithms-miscellaneous-5)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,75 @@
package com.baeldung.differences.dataframe.dataset.rdd;
public class TouristData {
private String region;
private String country;
private String year;
private String series;
private Double value;
private String footnotes;
private String source;
public String getRegion() {
return region;
}
public void setRegion(String region) {
this.region = region;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
public String getYear() {
return year;
}
public void setYear(String year) {
this.year = year;
}
public String getSeries() {
return series;
}
public void setSeries(String series) {
this.series = series;
}
public Double getValue() {
return value;
}
public void setValue(Double value) {
this.value = value;
}
public String getFootnotes() {
return footnotes;
}
public void setFootnotes(String footnotes) {
this.footnotes = footnotes;
}
public String getSource() {
return source;
}
public void setSource(String source) {
this.source = source;
}
@Override
public String toString() {
return "TouristData [region=" + region + ", country=" + country + ", year=" + year + ", series=" + series + ", value=" + value + ", footnotes=" + footnotes + ", source=" + source + "]";
}
}

View File

@ -0,0 +1,67 @@
package com.baeldung.differences.rdd;
import static org.junit.Assert.assertEquals;
import java.util.List;
import org.apache.spark.SparkConf;
import org.apache.spark.api.java.JavaPairRDD;
import org.apache.spark.api.java.JavaRDD;
import org.apache.spark.api.java.JavaSparkContext;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import scala.Tuple2;
public class ActionsUnitTest {
private static JavaRDD<String> tourists;
private static JavaSparkContext sc;
public static final String COMMA_DELIMITER = ",(?=([^\"]*\"[^\"]*\")*[^\"]*$)";
@BeforeClass
public static void init() {
SparkConf conf = new SparkConf().setAppName("reduce")
.setMaster("local[*]");
sc = new JavaSparkContext(conf);
tourists = sc.textFile("data/Tourist.csv").filter(line -> !line.startsWith("Region"));
}
@AfterClass
public static void cleanup() {
sc.close();
}
@Test
public void whenDistinctCount_thenReturnDistinctNumRecords() {
JavaRDD<String> countries = tourists.map(line -> {
String[] columns = line.split(COMMA_DELIMITER);
return columns[1];
})
.distinct();
Long numberOfCountries = countries.count();
System.out.println("Count: " + numberOfCountries);
assertEquals(Long.valueOf(220), numberOfCountries);
}
@Test
public void whenReduceByKeySum_thenTotalValuePerKey() {
JavaRDD<String> touristsExpenditure = tourists.filter(line -> line.split(COMMA_DELIMITER)[3].contains("expenditure"));
JavaPairRDD<String, Double> expenditurePairRdd = touristsExpenditure.mapToPair(line -> {
String[] columns = line.split(COMMA_DELIMITER);
return new Tuple2<>(columns[1], Double.valueOf(columns[6]));
});
List<Tuple2<String, Double>> totalByCountry = expenditurePairRdd.reduceByKey((x, y) -> x + y)
.collect();
System.out.println("Total per Country: " + totalByCountry);
for(Tuple2<String, Double> tuple : totalByCountry) {
if (tuple._1.equals("Mexico")) {
assertEquals(Double.valueOf(99164), tuple._2);
}
}
}
}

View File

@ -0,0 +1,74 @@
package com.baeldung.differences.rdd;
import static org.apache.spark.sql.functions.col;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.util.Arrays;
import java.util.List;
import org.apache.spark.sql.DataFrameReader;
import org.apache.spark.sql.Dataset;
import org.apache.spark.sql.Row;
import org.apache.spark.sql.SparkSession;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
public class DataFrameUnitTest {
private static SparkSession session;
private static Dataset<Row> data;
@BeforeClass
public static void init() {
session = SparkSession.builder()
.appName("TouristDataFrameExample")
.master("local[*]")
.getOrCreate();
DataFrameReader dataFrameReader = session.read();
data = dataFrameReader.option("header", "true")
.csv("data/Tourist.csv");
}
@AfterClass
public static void cleanup() {
session.stop();
}
@Test
public void whenSelectSpecificColumns_thenColumnsFiltered() {
Dataset<Row> selectedData = data.select(col("country"), col("year"), col("value"));
selectedData.show();
List<String> resultList = Arrays.asList(selectedData.columns());
assertTrue(resultList.contains("country"));
assertTrue(resultList.contains("year"));
assertTrue(resultList.contains("value"));
assertFalse(resultList.contains("Series"));
}
@Test
public void whenFilteringByCountry_thenCountryRecordsSelected() {
Dataset<Row> filteredData = data.filter(col("country").equalTo("Mexico"));
filteredData.show();
filteredData.foreach(record -> {
assertEquals("Mexico", record.get(1));
});
}
@Test
public void whenGroupCountByCountry_thenContryTotalRecords() {
Dataset<Row> recordsPerCountry = data.groupBy(col("country"))
.count();
recordsPerCountry.show();
Dataset<Row> filteredData = recordsPerCountry.filter(col("country").equalTo("Sweden"));
assertEquals(new Long(12), filteredData.first()
.get(1));
}
}

View File

@ -0,0 +1,83 @@
package com.baeldung.differences.rdd;
import static org.apache.spark.sql.functions.col;
import static org.apache.spark.sql.functions.sum;
import static org.junit.Assert.assertEquals;
import org.apache.spark.api.java.function.FilterFunction;
import org.apache.spark.sql.DataFrameReader;
import org.apache.spark.sql.Dataset;
import org.apache.spark.sql.Encoders;
import org.apache.spark.sql.Row;
import org.apache.spark.sql.SparkSession;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import com.baeldung.differences.dataframe.dataset.rdd.TouristData;
public class DatasetUnitTest {
private static SparkSession session;
private static Dataset<TouristData> typedDataset;
@BeforeClass
public static void init() {
session = SparkSession.builder()
.appName("TouristDatasetExample")
.master("local[*]")
.getOrCreate();
DataFrameReader dataFrameReader = session.read();
Dataset<Row> data = dataFrameReader.option("header", "true")
.csv("data/Tourist.csv");
Dataset<Row> responseWithSelectedColumns = data.select(col("region"),
col("country"), col("year"), col("series"), col("value").cast("double"),
col("footnotes"), col("source"));
typedDataset = responseWithSelectedColumns.as(Encoders.bean(TouristData.class));
}
@AfterClass
public static void cleanup() {
session.stop();
}
@Test
public void whenFilteringByCountry_thenCountryRecordsSelected() {
Dataset<TouristData> selectedData = typedDataset
.filter((FilterFunction<TouristData>) record -> record.getCountry()
.equals("Norway"));
selectedData.show();
selectedData.foreach(record -> {
assertEquals("Norway", record.getCountry());
});
}
@Test
public void whenGroupCountByCountry_thenContryTotalRecords() {
Dataset<Row> countriesCount = typedDataset.groupBy(typedDataset.col("country"))
.count();
countriesCount.show();
assertEquals(Long.valueOf(220), Long.valueOf(countriesCount.count()));
}
@Test
public void whenFilteredByPropertyRange_thenRetreiveValidRecords() {
// Filter records with existing data for years between 2010 and 2017
typedDataset.filter((FilterFunction<TouristData>) record -> record.getYear() != null
&& (Long.valueOf(record.getYear()) > 2010 && Long.valueOf(record.getYear()) < 2017))
.show();
}
@Test
public void whenSumValue_thenRetreiveTotalValue() {
// Total tourist expenditure by country
typedDataset.filter((FilterFunction<TouristData>) record -> record.getValue() != null
&& record.getSeries()
.contains("expenditure"))
.groupBy("country")
.agg(sum("value"))
.show();
}
}

View File

@ -0,0 +1,63 @@
package com.baeldung.differences.rdd;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import org.apache.commons.lang3.StringUtils;
import org.apache.spark.SparkConf;
import org.apache.spark.api.java.JavaRDD;
import org.apache.spark.api.java.JavaSparkContext;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
public class TransformationsUnitTest {
public static final String COMMA_DELIMITER = ",(?=([^\"]*\"[^\"]*\")*[^\"]*$)";
private static JavaSparkContext sc;
private static JavaRDD<String> tourists;
@BeforeClass
public static void init() {
SparkConf conf = new SparkConf().setAppName("uppercaseCountries")
.setMaster("local[*]");
sc = new JavaSparkContext(conf);
tourists = sc.textFile("data/Tourist.csv")
.filter(line -> !line.startsWith("Region")); //filter header row
}
@AfterClass
public static void cleanup() {
sc.close();
}
@Test
public void whenMapUpperCase_thenCountryNameUppercased() {
JavaRDD<String> upperCaseCountries = tourists.map(line -> {
String[] columns = line.split(COMMA_DELIMITER);
return columns[1].toUpperCase();
})
.distinct();
upperCaseCountries.saveAsTextFile("data/output/uppercase.txt");
upperCaseCountries.foreach(country -> {
//replace non alphanumerical characters
country = country.replaceAll("[^a-zA-Z]", "");
assertTrue(StringUtils.isAllUpperCase(country));
});
}
@Test
public void whenFilterByCountry_thenShowRequestedCountryRecords() {
JavaRDD<String> touristsInMexico = tourists.filter(line -> line.split(COMMA_DELIMITER)[1].equals("Mexico"));
touristsInMexico.saveAsTextFile("data/output/touristInMexico.txt");
touristsInMexico.foreach(record -> {
assertEquals("Mexico", record.split(COMMA_DELIMITER)[1]);
});
}
}

View File

@ -13,3 +13,4 @@
- [Quick Guide to the Java Stack](https://www.baeldung.com/java-stack) - [Quick Guide to the Java Stack](https://www.baeldung.com/java-stack)
- [Convert an Array of Primitives to a List](https://www.baeldung.com/java-primitive-array-to-list) - [Convert an Array of Primitives to a List](https://www.baeldung.com/java-primitive-array-to-list)
- [A Guide to BitSet in Java](https://www.baeldung.com/java-bitset) - [A Guide to BitSet in Java](https://www.baeldung.com/java-bitset)
- [Get the First Key and Value From a HashMap](https://www.baeldung.com/java-hashmap-get-first-entry)

View File

@ -11,4 +11,5 @@ This module contains articles about core Java input and output (IO)
- [Java Files Open Options](https://www.baeldung.com/java-file-options) - [Java Files Open Options](https://www.baeldung.com/java-file-options)
- [Creating Temporary Directories in Java](https://www.baeldung.com/java-temp-directories) - [Creating Temporary Directories in Java](https://www.baeldung.com/java-temp-directories)
- [Reading a Line at a Given Line Number From a File in Java](https://www.baeldung.com/java-read-line-at-number) - [Reading a Line at a Given Line Number From a File in Java](https://www.baeldung.com/java-read-line-at-number)
- [Find the Last Modified File in a Directory with Java](https://www.baeldung.com/java-last-modified-file)
- [[<-- Prev]](/core-java-modules/core-java-io-2) - [[<-- Prev]](/core-java-modules/core-java-io-2)

View File

@ -6,6 +6,7 @@ import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import java.io.File; import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
@ -37,6 +38,12 @@ public class CreateFileUnitTest {
assertTrue(success); assertTrue(success);
} }
@Test
void givenUsingFileOutputStream_whenCreatingFile_thenCorrect() throws IOException {
try(FileOutputStream fileOutputStream = new FileOutputStream(FILE_NAME)){
}
}
@Test @Test
public void givenUsingGuava_whenCreatingFile_thenCorrect() throws IOException { public void givenUsingGuava_whenCreatingFile_thenCorrect() throws IOException {
com.google.common.io.Files.touch(new File(FILE_NAME)); com.google.common.io.Files.touch(new File(FILE_NAME));

View File

@ -6,4 +6,5 @@ This module contains articles about core features in the Java language
- [Converting a Java String Into a Boolean](https://www.baeldung.com/java-string-to-boolean) - [Converting a Java String Into a Boolean](https://www.baeldung.com/java-string-to-boolean)
- [When are Static Variables Initialized in Java?](https://www.baeldung.com/java-static-variables-initialization) - [When are Static Variables Initialized in Java?](https://www.baeldung.com/java-static-variables-initialization)
- [Checking if a Class Exists in Java](https://www.baeldung.com/java-check-class-exists) - [Checking if a Class Exists in Java](https://www.baeldung.com/java-check-class-exists)
- [The Difference Between a.getClass() and A.class in Java](https://www.baeldung.com/java-getclass-vs-class)
- [[<-- Prev]](/core-java-modules/core-java-lang-2) - [[<-- Prev]](/core-java-modules/core-java-lang-2)

View File

@ -0,0 +1,15 @@
package com.baeldung.reflection.check.abstractclass;
import java.time.LocalDate;
import java.time.LocalTime;
public abstract class AbstractExample {
public static String getAuthorName() {
return "Umang Budhwar";
}
public abstract LocalDate getLocalDate();
public abstract LocalTime getLocalTime();
}

View File

@ -0,0 +1,16 @@
package com.baeldung.reflection.check.abstractclass;
import java.lang.reflect.Modifier;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
class AbstractExampleUnitTest {
@Test
void givenAbstractClass_whenCheckModifierIsAbstract_thenTrue() throws Exception {
Class<AbstractExample> clazz = AbstractExample.class;
Assertions.assertTrue(Modifier.isAbstract(clazz.getModifiers()));
}
}

View File

@ -10,4 +10,6 @@ This module contains articles about core Java Security
- [SHA-256 and SHA3-256 Hashing in Java](https://www.baeldung.com/sha-256-hashing-java) - [SHA-256 and SHA3-256 Hashing in Java](https://www.baeldung.com/sha-256-hashing-java)
- [Checksums in Java](https://www.baeldung.com/java-checksums) - [Checksums in Java](https://www.baeldung.com/java-checksums)
- [How to Read PEM File to Get Public and Private Keys](https://www.baeldung.com/java-read-pem-file-keys) - [How to Read PEM File to Get Public and Private Keys](https://www.baeldung.com/java-read-pem-file-keys)
- [Listing the Available Cipher Algorithms](https://www.baeldung.com/java-list-cipher-algorithms)
- [Get a List of Trusted Certificates in Java](https://www.baeldung.com/java-list-trusted-certificates)
- More articles: [[<-- prev]](/core-java-modules/core-java-security) - More articles: [[<-- prev]](/core-java-modules/core-java-security)

View File

@ -0,0 +1,37 @@
package com.baeldung.arguments
fun main() {
// Skip both the connectTimeout and enableRetry arguments
connect("http://www.baeldung.com")
// Skip only the enableRetry argument:
connect("http://www.baeldung.com", 5000)
// Skip only the middle argument connectTimeout
// connect("http://www.baeldung.com", false) // This results in a compiler error
// Because we skipped the connectTimeout argument, we must pass the enableRetry as a named argument
connect("http://www.baeldung.com", enableRetry = false)
// Overriding Functions and Default Arguments
val realConnector = RealConnector()
realConnector.connect("www.baeldung.com")
realConnector.connect()
}
fun connect(url: String, connectTimeout: Int = 1000, enableRetry: Boolean = true) {
println("The parameters are url = $url, connectTimeout = $connectTimeout, enableRetry = $enableRetry")
}
open class AbstractConnector {
open fun connect(url: String = "localhost") {
// function implementation
}
}
class RealConnector : AbstractConnector() {
override fun connect(url: String) {
println("The parameter is url = $url")
}
}

View File

@ -0,0 +1,28 @@
package com.baeldung.arguments
fun main() {
resizePane(newSize = 10, forceResize = true, noAnimation = false)
// Swap the order of last two named arguments
resizePane(newSize = 11, noAnimation = false, forceResize = true)
// Named arguments can be passed in any order
resizePane(forceResize = true, newSize = 12, noAnimation = false)
// Mixing Named and Positional Arguments
// Kotlin 1.3 would allow us to name only the arguments after the positional ones
resizePane(20, true, noAnimation = false)
// Using a positional argument in the middle of named arguments (supported from Kotlin 1.4.0)
// resizePane(newSize = 20, true, noAnimation = false)
// Only the last argument as a positional argument (supported from Kotlin 1.4.0)
// resizePane(newSize = 30, forceResize = true, false)
// Use a named argument in the middle of positional arguments (supported from Kotlin 1.4.0)
// resizePane(40, forceResize = true, false)
}
fun resizePane(newSize: Int, forceResize: Boolean, noAnimation: Boolean) {
println("The parameters are newSize = $newSize, forceResize = $forceResize, noAnimation = $noAnimation")
}

View File

@ -0,0 +1,3 @@
### Relevant Articles:
- [Guide to the Gradle Wrapper](https://www.baeldung.com/gradle-wrapper)

View File

@ -8,5 +8,7 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring
### Relevant Articles: ### Relevant Articles:
- [How to Set TLS Version in Apache HttpClient](https://www.baeldung.com/TODO) - [How to Set TLS Version in Apache HttpClient](https://www.baeldung.com/apache-httpclient-tls)
- [Reading an HTTP Response Body as a String in Java](https://www.baeldung.com/java-http-response-body-as-string)
- [How To Get Cookies From the Apache HttpClient Response](https://www.baeldung.com/java-apache-httpclient-cookies)
- More articles: [[<-- prev]](../httpclient) - More articles: [[<-- prev]](../httpclient)

View File

@ -0,0 +1,3 @@
### Relevant Articles:
- [Getting Started with jOOQ](https://www.baeldung.com/jooq-intro)

View File

@ -0,0 +1,10 @@
#spring.datasource.url=jdbc:h2:file:C:/data/demodb
#spring.datasource.url=jdbc:h2:file:~/demodb
spring.datasource.url=jdbc:h2:file:./src/main/resources/db/demodb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=
spring.h2.console.enabled=true
spring.jpa.hibernate.ddl-auto=create-drop
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.h2.console.path=/h2-console

View File

@ -0,0 +1,52 @@
package com.baeldung.persistent;
import static org.junit.Assert.assertTrue;
import java.io.File;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.annotation.DirtiesContext.ClassMode;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit4.SpringRunner;
import com.baeldung.h2db.auto.configuration.AutoConfigurationDemo;
@ActiveProfiles("persistent-on")
@RunWith(SpringRunner.class)
@DirtiesContext(classMode = ClassMode.BEFORE_EACH_TEST_METHOD)
@SpringBootTest(classes = AutoConfigurationDemo.class)
public class FilesLocationUnitTest {
@BeforeClass
public static void beforeClass() {
}
@Test(expected = Test.None.class)
public void whenApplicationStarted_thenEmbeddedDbSubfolderCreated() {
File subdirectory = new File("src/main/resources/db");
System.out.println(subdirectory.getAbsolutePath());
assertTrue(subdirectory.exists());
assertTrue(subdirectory.isDirectory());
}
@Test(expected = Test.None.class)
public void whenApplicationStarted_thenEmbeddedDbFilesCreated() {
File dbFile = new File("src/main/resources/db/demodb.mv.db");
System.out.println(dbFile.getAbsolutePath());
assertTrue(dbFile.exists());
assertTrue(dbFile.isFile());
}
@AfterClass
public static void cleanUp() {
File dbFile = new File("src/main/resources/db/demodb.mv.db");
dbFile.deleteOnExit();
}
}

View File

@ -5,3 +5,4 @@ This module contains articles about configuring the Spring Boot `Environment`
### Relevant Articles: ### Relevant Articles:
- [EnvironmentPostProcessor in Spring Boot](https://www.baeldung.com/spring-boot-environmentpostprocessor) - [EnvironmentPostProcessor in Spring Boot](https://www.baeldung.com/spring-boot-environmentpostprocessor)
- [Spring Properties File Outside jar](https://www.baeldung.com/spring-properties-file-outside-jar) - [Spring Properties File Outside jar](https://www.baeldung.com/spring-properties-file-outside-jar)
- [Get the Running Port in Spring Boot](https://www.baeldung.com/spring-boot-running-port)

View File

@ -76,7 +76,7 @@
</build> </build>
<properties> <properties>
<keycloak-adapter-bom.version>10.0.2</keycloak-adapter-bom.version> <keycloak-adapter-bom.version>11.0.2</keycloak-adapter-bom.version>
</properties> </properties>
</project> </project>

View File

@ -8,4 +8,5 @@ This module contains articles about Spring Web MVC in Spring Boot projects.
- [Download an Image or a File with Spring MVC](https://www.baeldung.com/spring-controller-return-image-file) - [Download an Image or a File with Spring MVC](https://www.baeldung.com/spring-controller-return-image-file)
- [Spring MVC Async vs Spring WebFlux](https://www.baeldung.com/spring-mvc-async-vs-webflux) - [Spring MVC Async vs Spring WebFlux](https://www.baeldung.com/spring-mvc-async-vs-webflux)
- [Differences in @Valid and @Validated Annotations in Spring](https://www.baeldung.com/spring-valid-vs-validated) - [Differences in @Valid and @Validated Annotations in Spring](https://www.baeldung.com/spring-valid-vs-validated)
- [CharacterEncodingFilter In SpringBoot](https://www.baeldung.com/spring-boot-characterencodingfilter)
- More articles: [[prev -->]](/spring-boot-modules/spring-boot-mvc-2) - More articles: [[prev -->]](/spring-boot-modules/spring-boot-mvc-2)

View File

@ -0,0 +1,71 @@
<?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.cloud</groupId>
<artifactId>spring-cloud-netlix-feign</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-cloud-netflix-feign</name>
<description>Netflix Feign project for Spring Boot</description>
<parent>
<groupId>com.baeldung</groupId>
<artifactId>parent-boot-1</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../../parent-boot-1</relativePath>
</parent>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
<dependency>
<groupId>com.netflix.feign</groupId>
<artifactId>feign-okhttp</artifactId>
<version>${feign-ok.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpcore</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<properties>
<spring-cloud.version>Camden.SR7</spring-cloud.version>
<feign-ok.version>8.18.0</feign-ok.version>
<!--
<spring-cloud.version>Hoxton.SR8</spring-cloud.version>
-->
<!--
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
-->
</properties>
</project>

View File

@ -0,0 +1,16 @@
package com.baeldung.cloud.netflix.feign;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.feign.EnableFeignClients;
@SpringBootApplication
@EnableFeignClients
public class ExampleApplication {
public static void main(String[] args) {
SpringApplication.run(ExampleApplication.class, args);
}
}

View File

@ -0,0 +1,25 @@
package com.baeldung.cloud.netflix.feign.client;
import com.baeldung.cloud.netflix.feign.config.ClientConfiguration;
import com.baeldung.cloud.netflix.feign.hystrix.JSONPlaceHolderFallback;
import com.baeldung.cloud.netflix.feign.model.Post;
import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import java.util.List;
@FeignClient(value = "jplaceholder",
url = "https://jsonplaceholder.typicode.com/",
configuration = ClientConfiguration.class,
fallback = JSONPlaceHolderFallback.class)
public interface JSONPlaceHolderClient {
@RequestMapping(method = RequestMethod.GET, value = "/posts")
List<Post> getPosts();
@RequestMapping(method = RequestMethod.GET, value = "/posts/{postId}", produces = "application/json")
Post getPostById(@PathVariable("postId") Long postId);
}

View File

@ -0,0 +1,38 @@
package com.baeldung.cloud.netflix.feign.config;
import feign.Logger;
import feign.RequestInterceptor;
import feign.codec.ErrorDecoder;
import feign.okhttp.OkHttpClient;
import org.apache.http.entity.ContentType;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ClientConfiguration {
@Bean
public Logger.Level feignLoggerLevel() {
return Logger.Level.FULL;
}
@Bean
public ErrorDecoder errorDecoder() {
return new ErrorDecoder.Default();
}
@Bean
public OkHttpClient client() {
return new OkHttpClient();
}
@Bean
public RequestInterceptor requestInterceptor() {
return requestTemplate -> {
requestTemplate.header("user", "ajeje");
requestTemplate.header("password", "brazof");
requestTemplate.header("Accept", ContentType.APPLICATION_JSON.getMimeType());
};
}
}

View File

@ -0,0 +1,21 @@
package com.baeldung.cloud.netflix.feign.config;
import com.baeldung.cloud.netflix.feign.exception.BadRequestException;
import com.baeldung.cloud.netflix.feign.exception.NotFoundException;
import feign.Response;
import feign.codec.ErrorDecoder;
public class CustomErrorDecoder implements ErrorDecoder {
@Override
public Exception decode(String methodKey, Response response) {
switch (response.status()){
case 400:
return new BadRequestException();
case 404:
return new NotFoundException();
default:
return new Exception("Generic error");
}
}
}

View File

@ -0,0 +1,21 @@
package com.baeldung.cloud.netflix.feign.exception;
public class BadRequestException extends Exception {
public BadRequestException() {
}
public BadRequestException(String message) {
super(message);
}
public BadRequestException(Throwable cause) {
super(cause);
}
@Override
public String toString() {
return "BadRequestException: "+getMessage();
}
}

View File

@ -0,0 +1,21 @@
package com.baeldung.cloud.netflix.feign.exception;
public class NotFoundException extends Exception {
public NotFoundException() {
}
public NotFoundException(String message) {
super(message);
}
public NotFoundException(Throwable cause) {
super(cause);
}
@Override
public String toString() {
return "NotFoundException: "+getMessage();
}
}

View File

@ -0,0 +1,22 @@
package com.baeldung.cloud.netflix.feign.hystrix;
import com.baeldung.cloud.netflix.feign.client.JSONPlaceHolderClient;
import com.baeldung.cloud.netflix.feign.model.Post;
import org.springframework.stereotype.Component;
import java.util.Collections;
import java.util.List;
@Component
public class JSONPlaceHolderFallback implements JSONPlaceHolderClient {
@Override
public List<Post> getPosts() {
return Collections.emptyList();
}
@Override
public Post getPostById(Long postId) {
return null;
}
}

View File

@ -0,0 +1,41 @@
package com.baeldung.cloud.netflix.feign.model;
public class Post {
private String userId;
private Long id;
private String title;
private String body;
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getBody() {
return body;
}
public void setBody(String body) {
this.body = body;
}
}

View File

@ -0,0 +1,12 @@
package com.baeldung.cloud.netflix.feign.service;
import com.baeldung.cloud.netflix.feign.model.Post;
import java.util.List;
public interface JSONPlaceHolderService {
List<Post> getPosts();
Post getPostById(Long id);
}

View File

@ -0,0 +1,26 @@
package com.baeldung.cloud.netflix.feign.service.impl;
import com.baeldung.cloud.netflix.feign.client.JSONPlaceHolderClient;
import com.baeldung.cloud.netflix.feign.model.Post;
import com.baeldung.cloud.netflix.feign.service.JSONPlaceHolderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class JSONPlaceHolderServiceImpl implements JSONPlaceHolderService {
@Autowired
private JSONPlaceHolderClient jsonPlaceHolderClient;
@Override
public List<Post> getPosts() {
return jsonPlaceHolderClient.getPosts();
}
@Override
public Post getPostById(Long id) {
return jsonPlaceHolderClient.getPostById(id);
}
}

View File

@ -0,0 +1,3 @@
spring.application.name=netflix-feign
logging.level.com.baeldung.cloud.netflix.feign.client=DEBUG
feign.hystrix.enabled=true

View File

@ -0,0 +1,21 @@
package com.baeldung.cloud.netflix.feign;
import com.baeldung.cloud.netflix.feign.config.ClientConfiguration;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest
@EnableAutoConfiguration
@ContextConfiguration(classes = { ClientConfiguration.class })
public class ExampleTestApplication {
@Test
public void whenSpringContextIsBootstrapped_thenNoExceptions() {
}
}

View File

@ -0,0 +1,43 @@
package com.baeldung.cloud.netflix.feign;
import com.baeldung.cloud.netflix.feign.model.Post;
import com.baeldung.cloud.netflix.feign.service.JSONPlaceHolderService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.List;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
@RunWith(SpringRunner.class)
@SpringBootTest
public class NetflixFeignUnitTest {
@Autowired
private JSONPlaceHolderService jsonPlaceHolderService;
@Test
public void whenSpringContextIsBootstrapped_thenNoExceptions() {
}
@Test
public void whenGetPosts_thenListPostSizeGreaterThanZero() {
List<Post> posts = jsonPlaceHolderService.getPosts();
assertFalse(posts.isEmpty());
}
@Test
public void whenGetPostWithId_thenPostExist() {
Post post = jsonPlaceHolderService.getPostById(1L);
assertNotNull(post);
}
}

View File

@ -21,27 +21,27 @@
<artifactId>spring-boot-starter-web</artifactId> <artifactId>spring-boot-starter-web</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>info.cukes</groupId> <groupId>io.cucumber</groupId>
<artifactId>cucumber-core</artifactId> <artifactId>cucumber-core</artifactId>
<version>${cucumber.java.version}</version> <version>${cucumber.version}</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>info.cukes</groupId> <groupId>io.cucumber</groupId>
<artifactId>cucumber-java</artifactId> <artifactId>cucumber-java</artifactId>
<version>${cucumber.java.version}</version> <version>${cucumber.version}</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>info.cukes</groupId> <groupId>io.cucumber</groupId>
<artifactId>cucumber-junit</artifactId> <artifactId>cucumber-junit</artifactId>
<version>${cucumber.java.version}</version> <version>${cucumber.version}</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>info.cukes</groupId> <groupId>io.cucumber</groupId>
<artifactId>cucumber-spring</artifactId> <artifactId>cucumber-spring</artifactId>
<version>${cucumber.java.version}</version> <version>${cucumber.version}</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-io --> <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-io -->
@ -53,7 +53,7 @@
</dependencies> </dependencies>
<properties> <properties>
<cucumber.java.version>1.2.5</cucumber.java.version> <cucumber.version>6.8.0</cucumber.version>
<commons-io.version>1.3.2</commons-io.version> <commons-io.version>1.3.2</commons-io.version>
</properties> </properties>

View File

@ -4,18 +4,16 @@ import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletResponse;
@RestController @RestController
public class BaeldungController { public class BaeldungController {
@GetMapping("/hello") @GetMapping("/hello")
public String sayHello(HttpServletResponse response) { public String sayHello() {
return "hello"; return "hello";
} }
@PostMapping("/baeldung") @PostMapping("/baeldung")
public String sayHelloPost(HttpServletResponse response) { public String sayHelloPost() {
return "hello"; return "hello";
} }
} }

View File

@ -1,13 +1,12 @@
package com.baeldung; package com.baeldung;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
@RestController @RestController
public class VersionController { public class VersionController {
@RequestMapping(method = { RequestMethod.GET }, value = { "/version" }) @GetMapping("/version")
public String getVersion() { public String getVersion() {
return "1.0"; return "1.0";
} }

View File

@ -1,11 +1,11 @@
package com.baeldung; package com.baeldung;
import io.cucumber.junit.Cucumber;
import io.cucumber.junit.CucumberOptions;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import cucumber.api.CucumberOptions;
import cucumber.api.junit.Cucumber;
@RunWith(Cucumber.class) @RunWith(Cucumber.class)
@CucumberOptions(features = "src/test/resources") @CucumberOptions(features = "src/test/resources")
public class CucumberIntegrationTest extends SpringIntegrationTest{ public class CucumberIntegrationTest extends SpringIntegrationTest {
} }

View File

@ -4,6 +4,7 @@ import java.io.IOException;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import io.cucumber.spring.CucumberContextConfiguration;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
@ -13,9 +14,8 @@ import org.springframework.test.context.ContextConfiguration;
import org.springframework.web.client.ResponseErrorHandler; import org.springframework.web.client.ResponseErrorHandler;
import org.springframework.web.client.RestTemplate; import org.springframework.web.client.RestTemplate;
//@RunWith(SpringJUnit4ClassRunner.class) @CucumberContextConfiguration
@SpringBootTest(classes = SpringDemoApplication.class, webEnvironment = WebEnvironment.DEFINED_PORT) @SpringBootTest(classes = SpringDemoApplication.class, webEnvironment = WebEnvironment.DEFINED_PORT)
@ContextConfiguration
public class SpringIntegrationTest { public class SpringIntegrationTest {
static ResponseResults latestResponse = null; static ResponseResults latestResponse = null;

View File

@ -1,14 +1,14 @@
package com.baeldung; package com.baeldung;
import io.cucumber.java.en.And;
import io.cucumber.java.en.Given;
import io.cucumber.java.en.Then;
import io.cucumber.java.en.When;
import org.springframework.http.HttpStatus;
import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.is;
import cucumber.api.java.en.Given;
import org.springframework.http.HttpStatus;
import cucumber.api.java.en.And;
import cucumber.api.java.en.Then;
import cucumber.api.java.en.When;
public class StepDefsIntegrationTest extends SpringIntegrationTest { public class StepDefsIntegrationTest extends SpringIntegrationTest {

View File

@ -1,37 +1,61 @@
package com.baeldung.spring.configuration; package com.baeldung.spring.configuration;
import freemarker.cache.ClassTemplateLoader;
import freemarker.cache.TemplateLoader;
import freemarker.template.Configuration;
import java.util.Properties; import java.util.Properties;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource;
import org.springframework.context.support.ResourceBundleMessageSource; import org.springframework.context.support.ResourceBundleMessageSource;
import org.springframework.mail.SimpleMailMessage; import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender; import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.JavaMailSenderImpl; import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer; import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;
import org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver;
import org.thymeleaf.spring5.SpringTemplateEngine; import org.thymeleaf.spring5.SpringTemplateEngine;
import org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver; import org.thymeleaf.templateresolver.ClassLoaderTemplateResolver;
import org.thymeleaf.templateresolver.ITemplateResolver;
@Configuration
@ComponentScan(basePackages = { "com.baeldung.spring.mail" }) @ComponentScan(basePackages = { "com.baeldung.spring.mail" })
@PropertySource(value={"classpath:application.properties"})
public class EmailConfiguration { public class EmailConfiguration {
@Value("${spring.mail.host}")
private String mailServerHost;
@Value("${spring.mail.port}")
private Integer mailServerPort;
@Value("${spring.mail.username}")
private String mailServerUsername;
@Value("${spring.mail.password}")
private String mailServerPassword;
@Value("${spring.mail.properties.mail.smtp.auth}")
private String mailServerAuth;
@Value("${spring.mail.properties.mail.smtp.starttls.enable}")
private String mailServerStartTls;
@Value("${spring.mail.templates.path}")
private String mailTemplatesPath;
@Bean @Bean
public JavaMailSender getJavaMailSender() { public JavaMailSender getJavaMailSender() {
JavaMailSenderImpl mailSender = new JavaMailSenderImpl(); JavaMailSenderImpl mailSender = new JavaMailSenderImpl();
mailSender.setHost("smtp.gmail.com"); mailSender.setHost(mailServerHost);
mailSender.setPort(587); mailSender.setPort(mailServerPort);
mailSender.setUsername("my.gmail@gmail.com"); mailSender.setUsername(mailServerUsername);
mailSender.setPassword("password"); mailSender.setPassword(mailServerPassword);
Properties props = mailSender.getJavaMailProperties(); Properties props = mailSender.getJavaMailProperties();
props.put("mail.transport.protocol", "smtp"); props.put("mail.transport.protocol", "smtp");
props.put("mail.smtp.auth", "true"); props.put("mail.smtp.auth", mailServerAuth);
props.put("mail.smtp.starttls.enable", "false"); props.put("mail.smtp.starttls.enable", mailServerStartTls);
props.put("mail.debug", "true"); props.put("mail.debug", "true");
return mailSender; return mailSender;
@ -45,39 +69,52 @@ public class EmailConfiguration {
} }
@Bean @Bean
public SpringTemplateEngine thymeleafTemplateEngine() { public SpringTemplateEngine thymeleafTemplateEngine(ITemplateResolver templateResolver) {
SpringTemplateEngine templateEngine = new SpringTemplateEngine(); SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.setTemplateResolver(thymeleafTemplateResolver()); templateEngine.setTemplateResolver(templateResolver);
templateEngine.setTemplateEngineMessageSource(emailMessageSource()); templateEngine.setTemplateEngineMessageSource(emailMessageSource());
return templateEngine; return templateEngine;
} }
@Bean @Bean
public SpringResourceTemplateResolver thymeleafTemplateResolver() { public ITemplateResolver thymeleafClassLoaderTemplateResolver() {
SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver(); ClassLoaderTemplateResolver templateResolver = new ClassLoaderTemplateResolver();
templateResolver.setPrefix("/WEB-INF/views/mail/"); templateResolver.setPrefix(mailTemplatesPath + "/");
templateResolver.setSuffix(".html"); templateResolver.setSuffix(".html");
templateResolver.setTemplateMode("HTML"); templateResolver.setTemplateMode("HTML");
templateResolver.setCharacterEncoding("UTF-8"); templateResolver.setCharacterEncoding("UTF-8");
return templateResolver; return templateResolver;
} }
// @Bean
// public ITemplateResolver thymeleafFilesystemTemplateResolver() {
// FileTemplateResolver templateResolver = new FileTemplateResolver();
// templateResolver.setPrefix(mailTemplatesPath + "/");
// templateResolver.setSuffix(".html");
// templateResolver.setTemplateMode("HTML");
// templateResolver.setCharacterEncoding("UTF-8");
// return templateResolver;
// }
@Bean @Bean
public FreeMarkerConfigurer freemarkerConfig() { public FreeMarkerConfigurer freemarkerClassLoaderConfig() {
Configuration configuration = new Configuration(Configuration.VERSION_2_3_27);
TemplateLoader templateLoader = new ClassTemplateLoader(this.getClass(), "/" + mailTemplatesPath);
configuration.setTemplateLoader(templateLoader);
FreeMarkerConfigurer freeMarkerConfigurer = new FreeMarkerConfigurer(); FreeMarkerConfigurer freeMarkerConfigurer = new FreeMarkerConfigurer();
freeMarkerConfigurer.setTemplateLoaderPath("/WEB-INF/views/mail"); freeMarkerConfigurer.setConfiguration(configuration);
return freeMarkerConfigurer; return freeMarkerConfigurer;
} }
@Bean // @Bean
public FreeMarkerViewResolver freemarkerViewResolver() { // public FreeMarkerConfigurer freemarkerFilesystemConfig() throws IOException {
FreeMarkerViewResolver resolver = new FreeMarkerViewResolver(); // Configuration configuration = new Configuration(Configuration.VERSION_2_3_27);
resolver.setCache(true); // TemplateLoader templateLoader = new FileTemplateLoader(new File(mailTemplatesPath));
resolver.setPrefix(""); // configuration.setTemplateLoader(templateLoader);
resolver.setSuffix(".ftl"); // FreeMarkerConfigurer freeMarkerConfigurer = new FreeMarkerConfigurer();
return resolver; // freeMarkerConfigurer.setConfiguration(configuration);
} // return freeMarkerConfigurer;
// }
@Bean @Bean
public ResourceBundleMessageSource emailMessageSource() { public ResourceBundleMessageSource emailMessageSource() {

View File

@ -112,7 +112,7 @@ public class EmailServiceImpl implements EmailService {
String to, String subject, Map<String, Object> templateModel) String to, String subject, Map<String, Object> templateModel)
throws IOException, TemplateException, MessagingException { throws IOException, TemplateException, MessagingException {
Template freemarkerTemplate = freemarkerConfigurer.createConfiguration().getTemplate("template-freemarker.ftl"); Template freemarkerTemplate = freemarkerConfigurer.getConfiguration().getTemplate("template-freemarker.ftl");
String htmlBody = FreeMarkerTemplateUtils.processTemplateIntoString(freemarkerTemplate, templateModel); String htmlBody = FreeMarkerTemplateUtils.processTemplateIntoString(freemarkerTemplate, templateModel);
sendHtmlMessage(to, subject, htmlBody); sendHtmlMessage(to, subject, htmlBody);

View File

@ -6,7 +6,7 @@ spring.mail.port=587
spring.mail.username=username spring.mail.username=username
spring.mail.password=password spring.mail.password=password
spring.mail.properties.mail.smtp.auth=true spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true spring.mail.properties.mail.smtp.starttls.enable=false
# Amazon SES SMTP # Amazon SES SMTP
#spring.mail.host=email-smtp.us-west-2.amazonaws.com #spring.mail.host=email-smtp.us-west-2.amazonaws.com
@ -20,3 +20,13 @@ spring.mail.properties.mail.smtp.starttls.enable=true
# path to attachment file # path to attachment file
attachment.invoice=path_to_file attachment.invoice=path_to_file
#
# Mail templates
#
# Templates directory inside main/resources or absolute filesystem path
spring.mail.templates.path=mail-templates
#spring.mail.templates.path=/path/to/templates

View File

@ -5,3 +5,4 @@
- [Introduction to JUnitParams](http://www.baeldung.com/junit-params) - [Introduction to JUnitParams](http://www.baeldung.com/junit-params)
- [Running JUnit Tests Programmatically, from a Java Application](https://www.baeldung.com/junit-tests-run-programmatically-from-java) - [Running JUnit Tests Programmatically, from a Java Application](https://www.baeldung.com/junit-tests-run-programmatically-from-java)
- [Introduction to Lambda Behave](https://www.baeldung.com/lambda-behave) - [Introduction to Lambda Behave](https://www.baeldung.com/lambda-behave)
- [Conditionally Run or Ignore Tests in JUnit 4](https://www.baeldung.com/junit-conditional-assume)

View File

@ -7,3 +7,4 @@
- [Testing an Abstract Class With JUnit](https://www.baeldung.com/junit-test-abstract-class) - [Testing an Abstract Class With JUnit](https://www.baeldung.com/junit-test-abstract-class)
- [Guide to Dynamic Tests in JUnit 5](https://www.baeldung.com/junit5-dynamic-tests) - [Guide to Dynamic Tests in JUnit 5](https://www.baeldung.com/junit5-dynamic-tests)
- [Determine the Execution Time of JUnit Tests](https://www.baeldung.com/junit-test-execution-time) - [Determine the Execution Time of JUnit Tests](https://www.baeldung.com/junit-test-execution-time)
- [@BeforeAll and @AfterAll in Non-Static Methods](https://www.baeldung.com/java-beforeall-afterall-non-static)

View File

@ -65,13 +65,13 @@
</dependency> </dependency>
<dependency> <dependency>
<groupId>info.cukes</groupId> <groupId>io.cucumber</groupId>
<artifactId>cucumber-java</artifactId> <artifactId>cucumber-java</artifactId>
<version>${cucumber.version}</version> <version>${cucumber.version}</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>info.cukes</groupId> <groupId>io.cucumber</groupId>
<artifactId>cucumber-junit</artifactId> <artifactId>cucumber-junit</artifactId>
<version>${cucumber.version}</version> <version>${cucumber.version}</version>
</dependency> </dependency>
@ -105,14 +105,22 @@
<filtering>true</filtering> <filtering>true</filtering>
</resource> </resource>
</resources> </resources>
</build>
<profiles>
<profile>
<id>parallel</id>
<build>
<plugins> <plugins>
<plugin> <plugin>
<artifactId>maven-failsafe-plugin</artifactId> <artifactId>maven-failsafe-plugin</artifactId>
<version>${maven-failsafe-plugin.version}</version> <version>${maven-failsafe-plugin.version}</version>
<configuration> <configuration>
<parallel>classes</parallel> <includes>
<threadCount>4</threadCount> <include>CucumberIntegrationTest.java</include>
</includes>
<parallel>methods</parallel>
<threadCount>2</threadCount>
</configuration> </configuration>
<executions> <executions>
<execution> <execution>
@ -123,30 +131,10 @@
</execution> </execution>
</executions> </executions>
</plugin> </plugin>
<plugin>
<groupId>com.github.temyers</groupId>
<artifactId>cucumber-jvm-parallel-plugin</artifactId>
<version>5.0.0</version>
<executions>
<execution>
<id>generateRunners</id>
<phase>generate-test-sources</phase>
<goals>
<goal>generateRunners</goal>
</goals>
<configuration>
<glue>
<package>com.baeldung.rest.cucumber</package>
</glue>
<featuresDirectory>src/test/resources/Feature/</featuresDirectory>
<parallelScheme>SCENARIO</parallelScheme>
</configuration>
</execution>
</executions>
</plugin>
</plugins> </plugins>
</build> </build>
</profile>
</profiles>
<properties> <properties>
<!-- util --> <!-- util -->
@ -154,7 +142,7 @@
<!-- testing --> <!-- testing -->
<rest-assured.version>2.9.0</rest-assured.version> <rest-assured.version>2.9.0</rest-assured.version>
<cucumber.version>1.2.5</cucumber.version> <cucumber.version>6.8.0</cucumber.version>
<wiremock.version>2.21.0</wiremock.version> <wiremock.version>2.21.0</wiremock.version>
<karate.version>0.6.1</karate.version> <karate.version>0.6.1</karate.version>

View File

@ -1,10 +0,0 @@
Feature: Testing a REST API
Users should be able to submit GET and POST requests to a web service, represented by WireMock
Scenario: Data Upload to a web service
When users upload data on a project
Then the server should handle it and return a success status
Scenario: Data retrieval from a web service
When users want to get information on the Cucumber project
Then the requested data is returned

View File

@ -1,8 +1,8 @@
package com.baeldung.rest.cucumber; package com.baeldung.rest.cucumber;
import io.cucumber.junit.Cucumber;
import io.cucumber.junit.CucumberOptions;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import cucumber.api.CucumberOptions;
import cucumber.api.junit.Cucumber;
@RunWith(Cucumber.class) @RunWith(Cucumber.class)
@CucumberOptions(features = "classpath:Feature") @CucumberOptions(features = "classpath:Feature")

View File

@ -20,6 +20,8 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.Scanner; import java.util.Scanner;
import io.cucumber.java.en.Then;
import io.cucumber.java.en.When;
import org.apache.http.HttpResponse; import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpPost;
@ -29,8 +31,6 @@ import org.apache.http.impl.client.HttpClients;
import com.github.tomakehurst.wiremock.WireMockServer; import com.github.tomakehurst.wiremock.WireMockServer;
import cucumber.api.java.en.Then;
import cucumber.api.java.en.When;
public class StepDefinition { public class StepDefinition {
@ -66,7 +66,8 @@ public class StepDefinition {
wireMockServer.stop(); wireMockServer.stop();
} }
@When("^users want to get information on the (.+) project$") // @When("^users want to get information on the '(.+)' project$")
@When("users want to get information on the {string} project")
public void usersGetInformationOnAProject(String projectName) throws IOException { public void usersGetInformationOnAProject(String projectName) throws IOException {
wireMockServer.start(); wireMockServer.start();
@ -86,11 +87,11 @@ public class StepDefinition {
wireMockServer.stop(); wireMockServer.stop();
} }
@Then("^the server should handle it and return a success status$") @Then("the server should handle it and return a success status")
public void theServerShouldReturnASuccessStatus() { public void theServerShouldReturnASuccessStatus() {
} }
@Then("^the requested data is returned$") @Then("the requested data is returned")
public void theRequestedDataIsReturned() { public void theRequestedDataIsReturned() {
} }

View File

@ -6,5 +6,5 @@ Feature: Testing a REST API
Then the server should handle it and return a success status Then the server should handle it and return a success status
Scenario: Data retrieval from a web service Scenario: Data retrieval from a web service
When users want to get information on the Cucumber project When users want to get information on the 'Cucumber' project
Then the requested data is returned Then the requested data is returned