diff --git a/cloud-foundry-uaa/cf-uaa-oauth2-resource-server/src/main/java/com/baeldung/cfuaa/oauth2/resourceserver/CFUAAOAuth2ResourceServerRestController.java b/cloud-foundry-uaa/cf-uaa-oauth2-resource-server/src/main/java/com/baeldung/cfuaa/oauth2/resourceserver/CFUAAOAuth2ResourceServerRestController.java
index c08f17d8d8..75d8507451 100644
--- a/cloud-foundry-uaa/cf-uaa-oauth2-resource-server/src/main/java/com/baeldung/cfuaa/oauth2/resourceserver/CFUAAOAuth2ResourceServerRestController.java
+++ b/cloud-foundry-uaa/cf-uaa-oauth2-resource-server/src/main/java/com/baeldung/cfuaa/oauth2/resourceserver/CFUAAOAuth2ResourceServerRestController.java
@@ -18,7 +18,7 @@ public class CFUAAOAuth2ResourceServerRestController {
@GetMapping("/read")
public String read(JwtAuthenticationToken jwtAuthenticationToken) {
- return "Hello write: " + jwtAuthenticationToken.getTokenAttributes();
+ return "Hello read: " + jwtAuthenticationToken.getTokenAttributes();
}
@GetMapping("/write")
diff --git a/core-java-modules/core-java-lang-2/pom.xml b/core-java-modules/core-java-lang-2/pom.xml
index 22df5f7951..3230498f41 100644
--- a/core-java-modules/core-java-lang-2/pom.xml
+++ b/core-java-modules/core-java-lang-2/pom.xml
@@ -15,10 +15,10 @@
- org.openjdk.jmh
- jmh-core
- ${jmh-core.version}
-
+ commons-beanutils
+ commons-beanutils
+ 1.9.4
+
org.openjdk.jmh
jmh-generator-annprocess
@@ -29,6 +29,11 @@
jmh-generator-bytecode
${jmh-generator.version}
+
+ org.openjdk.jmh
+ jmh-core
+ ${jmh-core.version}
+
diff --git a/core-java-modules/core-java-lang-2/src/main/java/com/baeldung/pojo/EmployeeBean.java b/core-java-modules/core-java-lang-2/src/main/java/com/baeldung/pojo/EmployeeBean.java
new file mode 100644
index 0000000000..faf1c1f261
--- /dev/null
+++ b/core-java-modules/core-java-lang-2/src/main/java/com/baeldung/pojo/EmployeeBean.java
@@ -0,0 +1,53 @@
+package com.baeldung.pojo;
+
+import java.io.Serializable;
+import java.time.LocalDate;
+
+public class EmployeeBean implements Serializable {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = -3760445487636086034L;
+
+ private String firstName;
+
+ private String lastName;
+
+ private LocalDate startDate;
+
+ public EmployeeBean() {
+
+ }
+
+ public EmployeeBean(String firstName, String lastName, LocalDate startDate) {
+ this.firstName = firstName;
+ this.lastName = lastName;
+ this.startDate = startDate;
+ }
+
+ public String getFirstName() {
+ return firstName;
+ }
+
+ public void setFirstName(String firstName) {
+ this.firstName = firstName;
+ }
+
+ public String getLastName() {
+ return lastName;
+ }
+
+ public void setLastName(String lastName) {
+ this.lastName = lastName;
+ }
+
+ public LocalDate getStartDate() {
+ return startDate;
+ }
+
+ public void setStartDate(LocalDate startDate) {
+ this.startDate = startDate;
+ }
+
+}
diff --git a/core-java-modules/core-java-lang-2/src/main/java/com/baeldung/pojo/EmployeePojo.java b/core-java-modules/core-java-lang-2/src/main/java/com/baeldung/pojo/EmployeePojo.java
new file mode 100644
index 0000000000..a48fa94381
--- /dev/null
+++ b/core-java-modules/core-java-lang-2/src/main/java/com/baeldung/pojo/EmployeePojo.java
@@ -0,0 +1,27 @@
+package com.baeldung.pojo;
+
+import java.time.LocalDate;
+
+public class EmployeePojo {
+
+ public String firstName;
+
+ public String lastName;
+
+ private LocalDate startDate;
+
+ public EmployeePojo(String firstName, String lastName, LocalDate startDate) {
+ this.firstName = firstName;
+ this.lastName = lastName;
+ this.startDate = startDate;
+ }
+
+ public String name() {
+ return this.firstName + " " + this.lastName;
+ }
+
+ public LocalDate getStart() {
+ return this.startDate;
+ }
+
+}
diff --git a/core-java-modules/core-java-lang-2/src/main/java/com/baeldung/pojo/ReflectionExample.java b/core-java-modules/core-java-lang-2/src/main/java/com/baeldung/pojo/ReflectionExample.java
new file mode 100644
index 0000000000..ebb4c10d92
--- /dev/null
+++ b/core-java-modules/core-java-lang-2/src/main/java/com/baeldung/pojo/ReflectionExample.java
@@ -0,0 +1,24 @@
+package com.baeldung.pojo;
+
+import java.beans.PropertyDescriptor;
+
+import org.apache.commons.beanutils.PropertyUtils;
+
+
+public class ReflectionExample {
+
+ public static void main(String[] args) {
+
+ System.out.println("Fields for EmployeePojo are:");
+ for (PropertyDescriptor pd : PropertyUtils.getPropertyDescriptors(EmployeePojo.class)) {
+ System.out.println(pd.getDisplayName());
+ }
+
+ System.out.println("Fields for EmployeeBean are:");
+ for (PropertyDescriptor pd : PropertyUtils.getPropertyDescriptors(EmployeeBean.class)) {
+ System.out.println(pd.getDisplayName());
+ }
+
+ }
+
+}
diff --git a/machine-learning/pom.xml b/machine-learning/pom.xml
new file mode 100644
index 0000000000..bb64470c74
--- /dev/null
+++ b/machine-learning/pom.xml
@@ -0,0 +1,150 @@
+
+ 4.0.0
+
+ machine-learning
+ 1.0-SNAPSHOT
+ Supervised Learning
+ jar
+
+
+ com.baeldung
+ parent-modules
+ 1.0.0-SNAPSHOT
+
+
+
+ UTF-8
+ 1.7
+ 1.7
+ 1.3.50
+ 0.9.1
+
+
+
+
+ org.jetbrains.kotlin
+ kotlin-stdlib-jdk8
+ ${kotlin.version}
+
+
+ org.nd4j
+ nd4j-native-platform
+ ${dl4j.version}
+
+
+ org.deeplearning4j
+ deeplearning4j-core
+ ${dl4j.version}
+
+
+ org.jetbrains.kotlin
+ kotlin-stdlib-jdk8
+ ${kotlin.version}
+
+
+ org.jetbrains.kotlin
+ kotlin-test
+ ${kotlin.version}
+ test
+
+
+ org.jetbrains.kotlin
+ kotlin-stdlib-jdk8
+ ${kotlin.version}
+
+
+
+ src/main/kotlin
+ src/test
+
+
+
+
+ maven-clean-plugin
+ 3.1.0
+
+
+
+ maven-resources-plugin
+ 3.0.2
+
+
+ maven-compiler-plugin
+ 3.8.0
+
+
+ maven-surefire-plugin
+ 2.22.1
+
+
+ maven-jar-plugin
+ 3.0.2
+
+
+ maven-install-plugin
+ 2.5.2
+
+
+ maven-deploy-plugin
+ 2.8.2
+
+
+
+ maven-site-plugin
+ 3.7.1
+
+
+ maven-project-info-reports-plugin
+ 3.0.0
+
+
+
+
+
+ org.jetbrains.kotlin
+ kotlin-maven-plugin
+ ${kotlin.version}
+
+
+ compile
+ compile
+
+ compile
+
+
+
+ test-compile
+ test-compile
+
+ test-compile
+
+
+
+
+ 1.8
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+
+ compile
+ compile
+
+ compile
+
+
+
+ testCompile
+ test-compile
+
+ testCompile
+
+
+
+
+
+
+
diff --git a/machine-learning/src/main/kotlin/com/baeldung/cnn/ConvolutionalNeuralNetwork.kt b/machine-learning/src/main/kotlin/com/baeldung/cnn/ConvolutionalNeuralNetwork.kt
new file mode 100644
index 0000000000..b77fe273ae
--- /dev/null
+++ b/machine-learning/src/main/kotlin/com/baeldung/cnn/ConvolutionalNeuralNetwork.kt
@@ -0,0 +1,117 @@
+package com.baeldung.cnn
+
+import org.datavec.api.records.reader.impl.collection.ListStringRecordReader
+import org.datavec.api.split.ListStringSplit
+import org.deeplearning4j.datasets.datavec.RecordReaderDataSetIterator
+import org.deeplearning4j.eval.Evaluation
+import org.deeplearning4j.nn.conf.NeuralNetConfiguration
+import org.deeplearning4j.nn.conf.inputs.InputType
+import org.deeplearning4j.nn.conf.layers.*
+import org.deeplearning4j.nn.multilayer.MultiLayerNetwork
+import org.deeplearning4j.nn.weights.WeightInit
+import org.nd4j.linalg.activations.Activation
+import org.nd4j.linalg.learning.config.Adam
+import org.nd4j.linalg.lossfunctions.LossFunctions
+
+object ConvolutionalNeuralNetwork {
+
+ @JvmStatic
+ fun main(args: Array) {
+ val dataset = ZalandoMNISTDataSet().load()
+ dataset.shuffle()
+ val trainDatasetIterator = createDatasetIterator(dataset.subList(0, 50_000))
+ val testDatasetIterator = createDatasetIterator(dataset.subList(50_000, 60_000))
+
+ val cnn = buildCNN()
+ learning(cnn, trainDatasetIterator)
+ testing(cnn, testDatasetIterator)
+ }
+
+ private fun createDatasetIterator(dataset: MutableList>): RecordReaderDataSetIterator {
+ val listStringRecordReader = ListStringRecordReader()
+ listStringRecordReader.initialize(ListStringSplit(dataset))
+ return RecordReaderDataSetIterator(listStringRecordReader, 128, 28 * 28, 10)
+ }
+
+ private fun buildCNN(): MultiLayerNetwork {
+ val multiLayerNetwork = MultiLayerNetwork(NeuralNetConfiguration.Builder()
+ .seed(123)
+ .l2(0.0005)
+ .updater(Adam())
+ .weightInit(WeightInit.XAVIER)
+ .list()
+ .layer(0, buildInitialConvolutionLayer())
+ .layer(1, buildBatchNormalizationLayer())
+ .layer(2, buildPoolingLayer())
+ .layer(3, buildConvolutionLayer())
+ .layer(4, buildBatchNormalizationLayer())
+ .layer(5, buildPoolingLayer())
+ .layer(6, buildDenseLayer())
+ .layer(7, buildBatchNormalizationLayer())
+ .layer(8, buildDenseLayer())
+ .layer(9, buildOutputLayer())
+ .setInputType(InputType.convolutionalFlat(28, 28, 1))
+ .backprop(true)
+ .build())
+ multiLayerNetwork.init()
+ return multiLayerNetwork
+ }
+
+ private fun buildOutputLayer(): OutputLayer? {
+ return OutputLayer.Builder(LossFunctions.LossFunction.NEGATIVELOGLIKELIHOOD)
+ .nOut(10)
+ .activation(Activation.SOFTMAX)
+ .build()
+ }
+
+ private fun buildDenseLayer(): DenseLayer? {
+ return DenseLayer.Builder().activation(Activation.RELU)
+ .nOut(500)
+ .dropOut(0.5)
+ .build()
+ }
+
+ private fun buildPoolingLayer(): SubsamplingLayer? {
+ return SubsamplingLayer.Builder(SubsamplingLayer.PoolingType.MAX)
+ .kernelSize(2, 2)
+ .stride(2, 2)
+ .build()
+ }
+
+ private fun buildBatchNormalizationLayer() = BatchNormalization.Builder().build()
+
+ private fun buildConvolutionLayer(): ConvolutionLayer? {
+ return ConvolutionLayer.Builder(5, 5)
+ .stride(1, 1) // nIn need not specified in later layers
+ .nOut(50)
+ .activation(Activation.IDENTITY)
+ .build()
+ }
+
+ private fun buildInitialConvolutionLayer(): ConvolutionLayer? {
+ return ConvolutionLayer.Builder(5, 5)
+ .nIn(1)
+ .stride(1, 1)
+ .nOut(20)
+ .activation(Activation.IDENTITY)
+ .build()
+ }
+
+ private fun learning(cnn: MultiLayerNetwork, trainSet: RecordReaderDataSetIterator) {
+ for (i in 0 until 10) {
+ cnn.fit(trainSet)
+ }
+ }
+
+ private fun testing(cnn: MultiLayerNetwork, testSet: RecordReaderDataSetIterator) {
+ val evaluation = Evaluation(10)
+ while (testSet.hasNext()) {
+ val next = testSet.next()
+ val output = cnn.output(next.features)
+ evaluation.eval(next.labels, output)
+ }
+
+ println(evaluation.stats())
+ println(evaluation.confusionToString())
+ }
+}
\ No newline at end of file
diff --git a/machine-learning/src/main/kotlin/com/baeldung/cnn/ZalandoMNISTDataSet.kt b/machine-learning/src/main/kotlin/com/baeldung/cnn/ZalandoMNISTDataSet.kt
new file mode 100644
index 0000000000..f29c8f2d0b
--- /dev/null
+++ b/machine-learning/src/main/kotlin/com/baeldung/cnn/ZalandoMNISTDataSet.kt
@@ -0,0 +1,45 @@
+package com.baeldung.cnn
+
+import java.io.File
+import java.nio.ByteBuffer
+import java.util.*
+import java.util.stream.Collectors
+import kotlin.streams.asStream
+
+class ZalandoMNISTDataSet {
+ private val OFFSET_SIZE = 4 //in bytes
+ private val NUM_ITEMS_OFFSET = 4
+ private val ITEMS_SIZE = 4
+ private val ROWS = 28
+ private val COLUMNS = 28
+ private val IMAGE_OFFSET = 16
+ private val IMAGE_SIZE = ROWS * COLUMNS
+
+ fun load(): MutableList> {
+ val labelsFile = File("machine-learning/src/main/resources/train-labels-idx1-ubyte")
+ val imagesFile = File("machine-learning/src/main/resources/train-images-idx3-ubyte")
+
+ val labelBytes = labelsFile.readBytes()
+ val imageBytes = imagesFile.readBytes()
+
+ val byteLabelCount = Arrays.copyOfRange(labelBytes, NUM_ITEMS_OFFSET, NUM_ITEMS_OFFSET + ITEMS_SIZE)
+ val numberOfLabels = ByteBuffer.wrap(byteLabelCount).int
+
+ val list = mutableListOf>()
+
+ for (i in 0 until numberOfLabels) {
+ val label = labelBytes[OFFSET_SIZE + ITEMS_SIZE + i]
+ val startBoundary = i * IMAGE_SIZE + IMAGE_OFFSET
+ val endBoundary = i * IMAGE_SIZE + IMAGE_OFFSET + IMAGE_SIZE
+ val imageData = Arrays.copyOfRange(imageBytes, startBoundary, endBoundary)
+
+ val imageDataList = imageData.iterator()
+ .asSequence()
+ .asStream().map { b -> b.toString() }
+ .collect(Collectors.toList())
+ imageDataList.add(label.toString())
+ list.add(imageDataList)
+ }
+ return list
+ }
+}
\ No newline at end of file
diff --git a/machine-learning/src/main/kotlin/com/baeldung/simplelinearregression/SimpleLinearRegression.kt b/machine-learning/src/main/kotlin/com/baeldung/simplelinearregression/SimpleLinearRegression.kt
new file mode 100644
index 0000000000..5ab520924e
--- /dev/null
+++ b/machine-learning/src/main/kotlin/com/baeldung/simplelinearregression/SimpleLinearRegression.kt
@@ -0,0 +1,31 @@
+package com.baeldung.simplelinearregression
+
+import kotlin.math.pow
+
+class SimpleLinearRegression(private val xs: List, private val ys: List) {
+ var slope: Double = 0.0
+ var yIntercept: Double = 0.0
+
+ init {
+ val covariance = calculateCovariance(xs, ys)
+ val variance = calculateVariance(xs)
+ slope = calculateSlope(covariance, variance)
+ yIntercept = calculateYIntercept(ys, slope, xs)
+ }
+
+ fun predict(independentVariable: Double) = slope * independentVariable + yIntercept
+
+ fun calculateRSquared(): Double {
+ val sst = ys.sumByDouble { y -> (y - ys.average()).pow(2) }
+ val ssr = xs.zip(ys) { x, y -> (y - predict(x.toDouble())).pow(2) }.sum()
+ return (sst - ssr) / sst
+ }
+
+ private fun calculateYIntercept(ys: List, slope: Double, xs: List) = ys.average() - slope * xs.average()
+
+ private fun calculateSlope(covariance: Double, variance: Double) = covariance / variance
+
+ private fun calculateCovariance(xs: List, ys: List) = xs.zip(ys) { x, y -> (x - xs.average()) * (y - ys.average()) }.sum()
+
+ private fun calculateVariance(xs: List) = xs.sumByDouble { x -> (x - xs.average()).pow(2) }
+}
\ No newline at end of file
diff --git a/machine-learning/src/main/resources/train-images-idx3-ubyte b/machine-learning/src/main/resources/train-images-idx3-ubyte
new file mode 100644
index 0000000000..ff2f5a9636
Binary files /dev/null and b/machine-learning/src/main/resources/train-images-idx3-ubyte differ
diff --git a/machine-learning/src/main/resources/train-labels-idx1-ubyte b/machine-learning/src/main/resources/train-labels-idx1-ubyte
new file mode 100644
index 0000000000..30424ca2ea
Binary files /dev/null and b/machine-learning/src/main/resources/train-labels-idx1-ubyte differ
diff --git a/machine-learning/src/test/com/baeldung/simplelinearregression/SimpleLinearRegressionUnitTest.kt b/machine-learning/src/test/com/baeldung/simplelinearregression/SimpleLinearRegressionUnitTest.kt
new file mode 100644
index 0000000000..a741639d50
--- /dev/null
+++ b/machine-learning/src/test/com/baeldung/simplelinearregression/SimpleLinearRegressionUnitTest.kt
@@ -0,0 +1,40 @@
+package com.baeldung.simplelinearregression
+
+import org.junit.Assert.assertEquals
+import org.junit.jupiter.api.Test
+
+class SimpleLinearRegressionUnitTest {
+ @Test
+ fun givenAProperDataSetWhenFedToASimpleLinearRegressionModelThenItPredictsCorrectly() {
+ val xs = arrayListOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
+ val ys = arrayListOf(25, 35, 49, 60, 75, 90, 115, 130, 150, 200)
+
+ val model = SimpleLinearRegression(xs, ys)
+
+ val predictionOne = model.predict(2.5)
+ assertEquals(38.99, predictionOne, 0.01)
+
+ val predictionTwo = model.predict(7.5)
+ assertEquals(128.84, predictionTwo, 0.01)
+ }
+
+ @Test
+ fun givenAPredictableDataSetWhenCalculatingTheLossFunctionThenTheModelIsConsideredReliable() {
+ val xs = arrayListOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
+ val ys = arrayListOf(25, 35, 49, 60, 75, 90, 115, 130, 150, 200)
+
+ val model = SimpleLinearRegression(xs, ys)
+
+ assertEquals(0.95, model.calculateRSquared(), 0.01)
+ }
+
+ @Test
+ fun givenAnUnpredictableDataSetWhenCalculatingTheLossFunctionThenTheModelIsConsideredUnreliable() {
+ val xs = arrayListOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
+ val ys = arrayListOf(200, 0, 200, 0, 0, 0, -115, 1000, 0, 1)
+
+ val model = SimpleLinearRegression(xs, ys)
+
+ assertEquals(0.01, model.calculateRSquared(), 0.01)
+ }
+}
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 650827081e..bc4c38f386 100644
--- a/pom.xml
+++ b/pom.xml
@@ -625,6 +625,7 @@
spring-boot-nashorn
java-blockchain
+ machine-learning
wildfly
diff --git a/spring-mvc-basics-2/src/main/java/com/baeldung/controller/optionalpathvars/ArticleViewerController.java b/spring-mvc-basics-2/src/main/java/com/baeldung/controller/optionalpathvars/ArticleViewerController.java
new file mode 100644
index 0000000000..62c2502242
--- /dev/null
+++ b/spring-mvc-basics-2/src/main/java/com/baeldung/controller/optionalpathvars/ArticleViewerController.java
@@ -0,0 +1,25 @@
+package com.baeldung.controller.optionalpathvars;
+
+import static com.baeldung.model.Article.DEFAULT_ARTICLE;
+
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.baeldung.model.Article;
+
+@RestController
+public class ArticleViewerController {
+
+ @RequestMapping(value = {"/article", "/article/{id}"})
+ public Article getArticle(@PathVariable(name = "id") Integer articleId) {
+
+ if (articleId != null) {
+ return new Article(articleId);
+ } else {
+ return DEFAULT_ARTICLE;
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/spring-mvc-basics-2/src/main/java/com/baeldung/controller/optionalpathvars/ArticleViewerWithMapParamController.java b/spring-mvc-basics-2/src/main/java/com/baeldung/controller/optionalpathvars/ArticleViewerWithMapParamController.java
new file mode 100644
index 0000000000..d16cf4115c
--- /dev/null
+++ b/spring-mvc-basics-2/src/main/java/com/baeldung/controller/optionalpathvars/ArticleViewerWithMapParamController.java
@@ -0,0 +1,29 @@
+package com.baeldung.controller.optionalpathvars;
+
+import static com.baeldung.model.Article.DEFAULT_ARTICLE;
+
+import java.util.Map;
+
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.baeldung.model.Article;
+
+@RestController
+@RequestMapping(value = "/mapParam")
+public class ArticleViewerWithMapParamController {
+
+ @RequestMapping(value = {"/article", "/article/{id}"})
+ public Article getArticle(@PathVariable Map pathVarsMap) {
+
+ String articleId = pathVarsMap.get("id");
+
+ if (articleId != null) {
+ return new Article(Integer.valueOf(articleId));
+ } else {
+ return DEFAULT_ARTICLE;
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/spring-mvc-basics-2/src/main/java/com/baeldung/controller/optionalpathvars/ArticleViewerWithOptionalParamController.java b/spring-mvc-basics-2/src/main/java/com/baeldung/controller/optionalpathvars/ArticleViewerWithOptionalParamController.java
new file mode 100644
index 0000000000..fd7b900535
--- /dev/null
+++ b/spring-mvc-basics-2/src/main/java/com/baeldung/controller/optionalpathvars/ArticleViewerWithOptionalParamController.java
@@ -0,0 +1,28 @@
+package com.baeldung.controller.optionalpathvars;
+
+import static com.baeldung.model.Article.DEFAULT_ARTICLE;
+
+import java.util.Optional;
+
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.baeldung.model.Article;;
+
+@RestController
+@RequestMapping("/optionalParam")
+public class ArticleViewerWithOptionalParamController {
+
+ @RequestMapping(value = {"/article", "/article/{id}"})
+ public Article getArticle(@PathVariable(name = "id") Optional optionalArticleId) {
+
+ if(optionalArticleId.isPresent()) {
+ Integer articleId = optionalArticleId.get();
+ return new Article(articleId);
+ }else {
+ return DEFAULT_ARTICLE;
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/spring-mvc-basics-2/src/main/java/com/baeldung/controller/optionalpathvars/ArticleViewerWithRequiredAttributeController.java b/spring-mvc-basics-2/src/main/java/com/baeldung/controller/optionalpathvars/ArticleViewerWithRequiredAttributeController.java
new file mode 100644
index 0000000000..d9b36f93e8
--- /dev/null
+++ b/spring-mvc-basics-2/src/main/java/com/baeldung/controller/optionalpathvars/ArticleViewerWithRequiredAttributeController.java
@@ -0,0 +1,26 @@
+package com.baeldung.controller.optionalpathvars;
+
+import static com.baeldung.model.Article.DEFAULT_ARTICLE;
+
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.baeldung.model.Article;;
+
+@RestController
+@RequestMapping(value = "/requiredAttribute")
+public class ArticleViewerWithRequiredAttributeController {
+
+ @RequestMapping(value = {"/article", "/article/{id}"})
+ public Article getArticle(@PathVariable(name = "id", required = false) Integer articleId) {
+
+ if (articleId != null) {
+ return new Article(articleId);
+ } else {
+ return DEFAULT_ARTICLE;
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/spring-mvc-basics-2/src/main/java/com/baeldung/controller/optionalpathvars/ArticleViewerWithTwoSeparateMethodsController.java b/spring-mvc-basics-2/src/main/java/com/baeldung/controller/optionalpathvars/ArticleViewerWithTwoSeparateMethodsController.java
new file mode 100644
index 0000000000..0b66b6cf43
--- /dev/null
+++ b/spring-mvc-basics-2/src/main/java/com/baeldung/controller/optionalpathvars/ArticleViewerWithTwoSeparateMethodsController.java
@@ -0,0 +1,27 @@
+package com.baeldung.controller.optionalpathvars;
+
+import static com.baeldung.model.Article.DEFAULT_ARTICLE;
+
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.baeldung.model.Article;
+
+@RestController
+@RequestMapping(value = "/seperateMethods")
+public class ArticleViewerWithTwoSeparateMethodsController {
+
+ @RequestMapping(value = "/article/{id}")
+ public Article getArticle(@PathVariable(name = "id") Integer articleId) {
+
+ return new Article(articleId);
+ }
+
+ @RequestMapping(value = "/article")
+ public Article getDefaultArticle() {
+
+ return DEFAULT_ARTICLE;
+ }
+
+}
\ No newline at end of file
diff --git a/spring-mvc-basics-2/src/main/java/com/baeldung/model/Article.java b/spring-mvc-basics-2/src/main/java/com/baeldung/model/Article.java
new file mode 100644
index 0000000000..141bd17db7
--- /dev/null
+++ b/spring-mvc-basics-2/src/main/java/com/baeldung/model/Article.java
@@ -0,0 +1,22 @@
+package com.baeldung.model;
+
+public class Article {
+
+ public static final Article DEFAULT_ARTICLE = new Article(12);
+
+ private Integer id;
+
+ public Article(Integer articleId) {
+ this.id = articleId;
+ }
+
+ public Integer getId() {
+ return id;
+ }
+
+ @Override
+ public String toString() {
+ return "Article [id=" + id + "]";
+ }
+
+}
diff --git a/spring-mvc-basics-2/src/main/java/org/baeldung/controller/config/WebConfig.java b/spring-mvc-basics-2/src/main/java/org/baeldung/controller/config/WebConfig.java
index 485c1d9032..018c530f18 100644
--- a/spring-mvc-basics-2/src/main/java/org/baeldung/controller/config/WebConfig.java
+++ b/spring-mvc-basics-2/src/main/java/org/baeldung/controller/config/WebConfig.java
@@ -11,7 +11,7 @@ import org.springframework.web.servlet.view.InternalResourceViewResolver;
@Configuration
@EnableWebMvc
-@ComponentScan(basePackages = { "org.baeldung.controller.controller", "org.baeldung.controller.config" })
+@ComponentScan(basePackages = { "org.baeldung.controller.controller", "com.baeldung.controller", "org.baeldung.controller.config" })
public class WebConfig implements WebMvcConfigurer {
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
diff --git a/spring-mvc-basics-2/src/test/java/com/baeldung/controller/optionalpathvars/ArticleViewerControllerIntegrationTest.java b/spring-mvc-basics-2/src/test/java/com/baeldung/controller/optionalpathvars/ArticleViewerControllerIntegrationTest.java
new file mode 100644
index 0000000000..2fb3569fc1
--- /dev/null
+++ b/spring-mvc-basics-2/src/test/java/com/baeldung/controller/optionalpathvars/ArticleViewerControllerIntegrationTest.java
@@ -0,0 +1,54 @@
+package com.baeldung.controller.optionalpathvars;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.test.context.web.WebAppConfiguration;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
+import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+import org.springframework.web.context.WebApplicationContext;
+import org.baeldung.controller.config.WebConfig;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@WebAppConfiguration
+@ContextConfiguration(classes = { WebConfig.class })
+public class ArticleViewerControllerIntegrationTest {
+
+ @Autowired
+ private WebApplicationContext wac;
+
+ private MockMvc mockMvc;
+
+ @Before
+ public void setup() throws Exception {
+ this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
+ }
+
+ @Test
+ public void whenIdPathVariableIsPassed_thenResponseOK() throws Exception {
+
+ int articleId = 5;
+
+ this.mockMvc
+ .perform(MockMvcRequestBuilders.get("/article/{id}", articleId))
+ .andExpect(MockMvcResultMatchers.status().isOk())
+ .andExpect(MockMvcResultMatchers.jsonPath("$.id").value(articleId));
+
+ }
+
+ @Test
+ public void whenIdPathVariableIsNotPassed_thenResponse500() throws Exception {
+
+ this.mockMvc
+ .perform(MockMvcRequestBuilders.get("/article"))
+ .andExpect(MockMvcResultMatchers.status().isInternalServerError());
+
+ }
+
+
+}
\ No newline at end of file
diff --git a/spring-mvc-basics-2/src/test/java/com/baeldung/controller/optionalpathvars/ArticleViewerControllerWithOptionalParamIntegrationTest.java b/spring-mvc-basics-2/src/test/java/com/baeldung/controller/optionalpathvars/ArticleViewerControllerWithOptionalParamIntegrationTest.java
new file mode 100644
index 0000000000..629e37f963
--- /dev/null
+++ b/spring-mvc-basics-2/src/test/java/com/baeldung/controller/optionalpathvars/ArticleViewerControllerWithOptionalParamIntegrationTest.java
@@ -0,0 +1,55 @@
+package com.baeldung.controller.optionalpathvars;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.test.context.web.WebAppConfiguration;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
+import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+import org.springframework.web.context.WebApplicationContext;
+
+import com.baeldung.model.Article;
+import org.baeldung.controller.config.WebConfig;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@WebAppConfiguration
+@ContextConfiguration(classes = { WebConfig.class })
+public class ArticleViewerControllerWithOptionalParamIntegrationTest {
+
+ @Autowired
+ private WebApplicationContext wac;
+
+ private MockMvc mockMvc;
+
+ @Before
+ public void setup() throws Exception {
+ this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
+ }
+
+ @Test
+ public void givenOPtionalParam_whenIdPathVariableIsPassed_thenResponseOK() throws Exception {
+
+ int articleId = 154;
+
+ this.mockMvc
+ .perform(MockMvcRequestBuilders.get("/optionalParam/article/{id}", articleId))
+ .andExpect(MockMvcResultMatchers.status().isOk())
+ .andExpect(MockMvcResultMatchers.jsonPath("$.id").value(articleId));
+
+ }
+
+ @Test
+ public void givenOPtionalParam_whenIdPathVariableIsNotPassed_thenResponseOK() throws Exception {
+
+ this.mockMvc
+ .perform(MockMvcRequestBuilders.get("/optionalParam/article"))
+ .andExpect(MockMvcResultMatchers.status().isOk())
+ .andExpect(MockMvcResultMatchers.jsonPath("$.id").value(Article.DEFAULT_ARTICLE.getId()));
+
+ }
+}
\ No newline at end of file
diff --git a/spring-mvc-basics-2/src/test/java/com/baeldung/controller/optionalpathvars/ArticleViewerControllerWithRequiredAttributeIntegrationTest.java b/spring-mvc-basics-2/src/test/java/com/baeldung/controller/optionalpathvars/ArticleViewerControllerWithRequiredAttributeIntegrationTest.java
new file mode 100644
index 0000000000..00494171c0
--- /dev/null
+++ b/spring-mvc-basics-2/src/test/java/com/baeldung/controller/optionalpathvars/ArticleViewerControllerWithRequiredAttributeIntegrationTest.java
@@ -0,0 +1,55 @@
+package com.baeldung.controller.optionalpathvars;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.test.context.web.WebAppConfiguration;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
+import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+import org.springframework.web.context.WebApplicationContext;
+
+import com.baeldung.model.Article;
+import org.baeldung.controller.config.WebConfig;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@WebAppConfiguration
+@ContextConfiguration(classes = { WebConfig.class })
+public class ArticleViewerControllerWithRequiredAttributeIntegrationTest {
+
+ @Autowired
+ private WebApplicationContext wac;
+
+ private MockMvc mockMvc;
+
+ @Before
+ public void setup() throws Exception {
+ this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
+ }
+
+ @Test
+ public void givenRequiredAttributeIsFalse_whenIdPathVariableIsPassed_thenResponseOK() throws Exception {
+
+ int articleId = 154;
+
+ this.mockMvc
+ .perform(MockMvcRequestBuilders.get("/requiredAttribute/article/{id}", articleId))
+ .andExpect(MockMvcResultMatchers.status().isOk())
+ .andExpect(MockMvcResultMatchers.jsonPath("$.id").value(articleId));
+
+ }
+
+ @Test
+ public void givenRequiredAttributeIsFalse_whenIdPathVariableIsNotPassed_thenResponseOK() throws Exception {
+
+ this.mockMvc
+ .perform(MockMvcRequestBuilders.get("/requiredAttribute/article"))
+ .andExpect(MockMvcResultMatchers.status().isOk())
+ .andExpect(MockMvcResultMatchers.jsonPath("$.id").value(Article.DEFAULT_ARTICLE.getId()));
+
+ }
+}
\ No newline at end of file
diff --git a/spring-mvc-basics-2/src/test/java/com/baeldung/controller/optionalpathvars/ArticleViewerWithMapParamIntegrationTest.java b/spring-mvc-basics-2/src/test/java/com/baeldung/controller/optionalpathvars/ArticleViewerWithMapParamIntegrationTest.java
new file mode 100644
index 0000000000..3c82b11578
--- /dev/null
+++ b/spring-mvc-basics-2/src/test/java/com/baeldung/controller/optionalpathvars/ArticleViewerWithMapParamIntegrationTest.java
@@ -0,0 +1,57 @@
+package com.baeldung.controller.optionalpathvars;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.test.context.web.WebAppConfiguration;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
+import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+import org.springframework.web.context.WebApplicationContext;
+
+import com.baeldung.model.Article;
+import org.baeldung.controller.config.WebConfig;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@WebAppConfiguration
+@ContextConfiguration(classes = { WebConfig.class })
+public class ArticleViewerWithMapParamIntegrationTest {
+
+ @Autowired
+ private WebApplicationContext wac;
+
+ private MockMvc mockMvc;
+
+ @Before
+ public void setup() throws Exception {
+ this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
+ }
+
+ @Test
+ public void givenPathVarsMapParam_whenIdPathVariableIsPassed_thenResponseOK() throws Exception {
+
+ int articleId = 5;
+
+ this.mockMvc
+ .perform(MockMvcRequestBuilders.get("/mapParam/article/{id}", articleId))
+ .andExpect(MockMvcResultMatchers.status().isOk())
+ .andExpect(MockMvcResultMatchers.jsonPath("$.id").value(articleId));
+
+ }
+
+ @Test
+ public void givenPathVarsMapParam_whenIdPathVariableIsNotPassed_thenResponseOK() throws Exception {
+
+ this.mockMvc
+ .perform(MockMvcRequestBuilders.get("/mapParam/article"))
+ .andExpect(MockMvcResultMatchers.status().isOk())
+ .andExpect(MockMvcResultMatchers.jsonPath("$.id").value(Article.DEFAULT_ARTICLE.getId()));
+
+ }
+
+
+}
\ No newline at end of file
diff --git a/spring-mvc-basics-2/src/test/java/com/baeldung/controller/optionalpathvars/ArticleViewerWithTwoSeparateMethodsIntegrationTest.java b/spring-mvc-basics-2/src/test/java/com/baeldung/controller/optionalpathvars/ArticleViewerWithTwoSeparateMethodsIntegrationTest.java
new file mode 100644
index 0000000000..9532270c43
--- /dev/null
+++ b/spring-mvc-basics-2/src/test/java/com/baeldung/controller/optionalpathvars/ArticleViewerWithTwoSeparateMethodsIntegrationTest.java
@@ -0,0 +1,56 @@
+package com.baeldung.controller.optionalpathvars;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.test.context.web.WebAppConfiguration;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
+import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+import org.springframework.web.context.WebApplicationContext;
+
+import com.baeldung.model.Article;
+import org.baeldung.controller.config.WebConfig;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@WebAppConfiguration
+@ContextConfiguration(classes = { WebConfig.class })
+public class ArticleViewerWithTwoSeparateMethodsIntegrationTest {
+
+ @Autowired
+ private WebApplicationContext wac;
+
+ private MockMvc mockMvc;
+
+ @Before
+ public void setup() throws Exception {
+ this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
+ }
+
+ @Test
+ public void givenTwoSeparateMethods_whenIdPathVariableIsPassed_thenResponseOK() throws Exception {
+
+ int articleId = 5;
+
+ this.mockMvc
+ .perform(MockMvcRequestBuilders.get("/seperateMethods/article/{id}", articleId))
+ .andExpect(MockMvcResultMatchers.status().isOk())
+ .andExpect(MockMvcResultMatchers.jsonPath("$.id").value(articleId));
+
+ }
+
+ @Test
+ public void givenTwoSeparateMethods_whenIdPathVariableIsNotPassed_thenResponseOK() throws Exception {
+
+ this.mockMvc
+ .perform(MockMvcRequestBuilders.get("/seperateMethods/article"))
+ .andExpect(MockMvcResultMatchers.status().isOk())
+ .andExpect(MockMvcResultMatchers.jsonPath("$.id").value(Article.DEFAULT_ARTICLE.getId()));
+
+ }
+
+}
\ No newline at end of file
diff --git a/spring-mvc-java/src/main/java/com/baeldung/model/Article.java b/spring-mvc-java/src/main/java/com/baeldung/model/Article.java
new file mode 100644
index 0000000000..141bd17db7
--- /dev/null
+++ b/spring-mvc-java/src/main/java/com/baeldung/model/Article.java
@@ -0,0 +1,22 @@
+package com.baeldung.model;
+
+public class Article {
+
+ public static final Article DEFAULT_ARTICLE = new Article(12);
+
+ private Integer id;
+
+ public Article(Integer articleId) {
+ this.id = articleId;
+ }
+
+ public Integer getId() {
+ return id;
+ }
+
+ @Override
+ public String toString() {
+ return "Article [id=" + id + "]";
+ }
+
+}
diff --git a/spring-mvc-java/src/main/java/com/baeldung/web/controller/optionalpathvars/ArticleViewerController.java b/spring-mvc-java/src/main/java/com/baeldung/web/controller/optionalpathvars/ArticleViewerController.java
new file mode 100644
index 0000000000..2a4f638407
--- /dev/null
+++ b/spring-mvc-java/src/main/java/com/baeldung/web/controller/optionalpathvars/ArticleViewerController.java
@@ -0,0 +1,25 @@
+package com.baeldung.web.controller.optionalpathvars;
+
+import static com.baeldung.model.Article.DEFAULT_ARTICLE;
+
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.baeldung.model.Article;
+
+@RestController
+public class ArticleViewerController {
+
+ @RequestMapping(value = {"/article", "/article/{id}"})
+ public Article getArticle(@PathVariable(name = "id") Integer articleId) {
+
+ if (articleId != null) {
+ return new Article(articleId);
+ } else {
+ return DEFAULT_ARTICLE;
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/spring-mvc-java/src/main/java/com/baeldung/web/controller/optionalpathvars/ArticleViewerWithMapParamController.java b/spring-mvc-java/src/main/java/com/baeldung/web/controller/optionalpathvars/ArticleViewerWithMapParamController.java
new file mode 100644
index 0000000000..2e79290c02
--- /dev/null
+++ b/spring-mvc-java/src/main/java/com/baeldung/web/controller/optionalpathvars/ArticleViewerWithMapParamController.java
@@ -0,0 +1,29 @@
+package com.baeldung.web.controller.optionalpathvars;
+
+import static com.baeldung.model.Article.DEFAULT_ARTICLE;
+
+import java.util.Map;
+
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.baeldung.model.Article;
+
+@RestController
+@RequestMapping(value = "/mapParam")
+public class ArticleViewerWithMapParamController {
+
+ @RequestMapping(value = {"/article", "/article/{id}"})
+ public Article getArticle(@PathVariable Map pathVarsMap) {
+
+ String articleId = pathVarsMap.get("id");
+
+ if (articleId != null) {
+ return new Article(Integer.valueOf(articleId));
+ } else {
+ return DEFAULT_ARTICLE;
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/spring-mvc-java/src/main/java/com/baeldung/web/controller/optionalpathvars/ArticleViewerWithOptionalParamController.java b/spring-mvc-java/src/main/java/com/baeldung/web/controller/optionalpathvars/ArticleViewerWithOptionalParamController.java
new file mode 100644
index 0000000000..4c077b97c0
--- /dev/null
+++ b/spring-mvc-java/src/main/java/com/baeldung/web/controller/optionalpathvars/ArticleViewerWithOptionalParamController.java
@@ -0,0 +1,28 @@
+package com.baeldung.web.controller.optionalpathvars;
+
+import static com.baeldung.model.Article.DEFAULT_ARTICLE;
+
+import java.util.Optional;
+
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.baeldung.model.Article;;
+
+@RestController
+@RequestMapping("/optionalParam")
+public class ArticleViewerWithOptionalParamController {
+
+ @RequestMapping(value = {"/article", "/article/{id}"})
+ public Article getArticle(@PathVariable(name = "id") Optional optionalArticleId) {
+
+ if(optionalArticleId.isPresent()) {
+ Integer articleId = optionalArticleId.get();
+ return new Article(articleId);
+ }else {
+ return DEFAULT_ARTICLE;
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/spring-mvc-java/src/main/java/com/baeldung/web/controller/optionalpathvars/ArticleViewerWithRequiredAttributeController.java b/spring-mvc-java/src/main/java/com/baeldung/web/controller/optionalpathvars/ArticleViewerWithRequiredAttributeController.java
new file mode 100644
index 0000000000..ab3f37c50a
--- /dev/null
+++ b/spring-mvc-java/src/main/java/com/baeldung/web/controller/optionalpathvars/ArticleViewerWithRequiredAttributeController.java
@@ -0,0 +1,26 @@
+package com.baeldung.web.controller.optionalpathvars;
+
+import static com.baeldung.model.Article.DEFAULT_ARTICLE;
+
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.baeldung.model.Article;;
+
+@RestController
+@RequestMapping(value = "/requiredAttribute")
+public class ArticleViewerWithRequiredAttributeController {
+
+ @RequestMapping(value = {"/article", "/article/{id}"})
+ public Article getArticle(@PathVariable(name = "id", required = false) Integer articleId) {
+
+ if (articleId != null) {
+ return new Article(articleId);
+ } else {
+ return DEFAULT_ARTICLE;
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/spring-mvc-java/src/main/java/com/baeldung/web/controller/optionalpathvars/ArticleViewerWithTwoSeparateMethodsController.java b/spring-mvc-java/src/main/java/com/baeldung/web/controller/optionalpathvars/ArticleViewerWithTwoSeparateMethodsController.java
new file mode 100644
index 0000000000..b4832793ad
--- /dev/null
+++ b/spring-mvc-java/src/main/java/com/baeldung/web/controller/optionalpathvars/ArticleViewerWithTwoSeparateMethodsController.java
@@ -0,0 +1,27 @@
+package com.baeldung.web.controller.optionalpathvars;
+
+import static com.baeldung.model.Article.DEFAULT_ARTICLE;
+
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.baeldung.model.Article;
+
+@RestController
+@RequestMapping(value = "/seperateMethods")
+public class ArticleViewerWithTwoSeparateMethodsController {
+
+ @RequestMapping(value = "/article/{id}")
+ public Article getArticle(@PathVariable(name = "id") Integer articleId) {
+
+ return new Article(articleId);
+ }
+
+ @RequestMapping(value = "/article")
+ public Article getDefaultArticle() {
+
+ return DEFAULT_ARTICLE;
+ }
+
+}
\ No newline at end of file
diff --git a/spring-mvc-java/src/test/java/com/baeldung/web/controller/optionalpathvars/ArticleViewerControllerIntegrationTest.java b/spring-mvc-java/src/test/java/com/baeldung/web/controller/optionalpathvars/ArticleViewerControllerIntegrationTest.java
new file mode 100644
index 0000000000..3e07cd7487
--- /dev/null
+++ b/spring-mvc-java/src/test/java/com/baeldung/web/controller/optionalpathvars/ArticleViewerControllerIntegrationTest.java
@@ -0,0 +1,55 @@
+package com.baeldung.web.controller.optionalpathvars;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.test.context.web.WebAppConfiguration;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
+import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+import org.springframework.web.context.WebApplicationContext;
+
+import com.baeldung.spring.web.config.WebConfig;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@WebAppConfiguration
+@ContextConfiguration(classes = { WebConfig.class })
+public class ArticleViewerControllerIntegrationTest {
+
+ @Autowired
+ private WebApplicationContext wac;
+
+ private MockMvc mockMvc;
+
+ @Before
+ public void setup() throws Exception {
+ this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
+ }
+
+ @Test
+ public void whenIdPathVariableIsPassed_thenResponseOK() throws Exception {
+
+ int articleId = 5;
+
+ this.mockMvc
+ .perform(MockMvcRequestBuilders.get("/article/{id}", articleId))
+ .andExpect(MockMvcResultMatchers.status().isOk())
+ .andExpect(MockMvcResultMatchers.jsonPath("$.id").value(articleId));
+
+ }
+
+ @Test
+ public void whenIdPathVariableIsNotPassed_thenResponse500() throws Exception {
+
+ this.mockMvc
+ .perform(MockMvcRequestBuilders.get("/article"))
+ .andExpect(MockMvcResultMatchers.status().isInternalServerError());
+
+ }
+
+
+}
\ No newline at end of file
diff --git a/spring-mvc-java/src/test/java/com/baeldung/web/controller/optionalpathvars/ArticleViewerControllerWithOptionalParamIntegrationTest.java b/spring-mvc-java/src/test/java/com/baeldung/web/controller/optionalpathvars/ArticleViewerControllerWithOptionalParamIntegrationTest.java
new file mode 100644
index 0000000000..c13e5bab4b
--- /dev/null
+++ b/spring-mvc-java/src/test/java/com/baeldung/web/controller/optionalpathvars/ArticleViewerControllerWithOptionalParamIntegrationTest.java
@@ -0,0 +1,55 @@
+package com.baeldung.web.controller.optionalpathvars;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.test.context.web.WebAppConfiguration;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
+import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+import org.springframework.web.context.WebApplicationContext;
+
+import com.baeldung.model.Article;
+import com.baeldung.spring.web.config.WebConfig;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@WebAppConfiguration
+@ContextConfiguration(classes = { WebConfig.class })
+public class ArticleViewerControllerWithOptionalParamIntegrationTest {
+
+ @Autowired
+ private WebApplicationContext wac;
+
+ private MockMvc mockMvc;
+
+ @Before
+ public void setup() throws Exception {
+ this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
+ }
+
+ @Test
+ public void givenOPtionalParam_whenIdPathVariableIsPassed_thenResponseOK() throws Exception {
+
+ int articleId = 154;
+
+ this.mockMvc
+ .perform(MockMvcRequestBuilders.get("/optionalParam/article/{id}", articleId))
+ .andExpect(MockMvcResultMatchers.status().isOk())
+ .andExpect(MockMvcResultMatchers.jsonPath("$.id").value(articleId));
+
+ }
+
+ @Test
+ public void givenOPtionalParam_whenIdPathVariableIsNotPassed_thenResponseOK() throws Exception {
+
+ this.mockMvc
+ .perform(MockMvcRequestBuilders.get("/optionalParam/article"))
+ .andExpect(MockMvcResultMatchers.status().isOk())
+ .andExpect(MockMvcResultMatchers.jsonPath("$.id").value(Article.DEFAULT_ARTICLE.getId()));
+
+ }
+}
\ No newline at end of file
diff --git a/spring-mvc-java/src/test/java/com/baeldung/web/controller/optionalpathvars/ArticleViewerControllerWithRequiredAttributeIntegrationTest.java b/spring-mvc-java/src/test/java/com/baeldung/web/controller/optionalpathvars/ArticleViewerControllerWithRequiredAttributeIntegrationTest.java
new file mode 100644
index 0000000000..de65e216be
--- /dev/null
+++ b/spring-mvc-java/src/test/java/com/baeldung/web/controller/optionalpathvars/ArticleViewerControllerWithRequiredAttributeIntegrationTest.java
@@ -0,0 +1,55 @@
+package com.baeldung.web.controller.optionalpathvars;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.test.context.web.WebAppConfiguration;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
+import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+import org.springframework.web.context.WebApplicationContext;
+
+import com.baeldung.model.Article;
+import com.baeldung.spring.web.config.WebConfig;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@WebAppConfiguration
+@ContextConfiguration(classes = { WebConfig.class })
+public class ArticleViewerControllerWithRequiredAttributeIntegrationTest {
+
+ @Autowired
+ private WebApplicationContext wac;
+
+ private MockMvc mockMvc;
+
+ @Before
+ public void setup() throws Exception {
+ this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
+ }
+
+ @Test
+ public void givenRequiredAttributeIsFalse_whenIdPathVariableIsPassed_thenResponseOK() throws Exception {
+
+ int articleId = 154;
+
+ this.mockMvc
+ .perform(MockMvcRequestBuilders.get("/requiredAttribute/article/{id}", articleId))
+ .andExpect(MockMvcResultMatchers.status().isOk())
+ .andExpect(MockMvcResultMatchers.jsonPath("$.id").value(articleId));
+
+ }
+
+ @Test
+ public void givenRequiredAttributeIsFalse_whenIdPathVariableIsNotPassed_thenResponseOK() throws Exception {
+
+ this.mockMvc
+ .perform(MockMvcRequestBuilders.get("/requiredAttribute/article"))
+ .andExpect(MockMvcResultMatchers.status().isOk())
+ .andExpect(MockMvcResultMatchers.jsonPath("$.id").value(Article.DEFAULT_ARTICLE.getId()));
+
+ }
+}
\ No newline at end of file
diff --git a/spring-mvc-java/src/test/java/com/baeldung/web/controller/optionalpathvars/ArticleViewerWithMapParamIntegrationTest.java b/spring-mvc-java/src/test/java/com/baeldung/web/controller/optionalpathvars/ArticleViewerWithMapParamIntegrationTest.java
new file mode 100644
index 0000000000..2fb330f03f
--- /dev/null
+++ b/spring-mvc-java/src/test/java/com/baeldung/web/controller/optionalpathvars/ArticleViewerWithMapParamIntegrationTest.java
@@ -0,0 +1,57 @@
+package com.baeldung.web.controller.optionalpathvars;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.test.context.web.WebAppConfiguration;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
+import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+import org.springframework.web.context.WebApplicationContext;
+
+import com.baeldung.model.Article;
+import com.baeldung.spring.web.config.WebConfig;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@WebAppConfiguration
+@ContextConfiguration(classes = { WebConfig.class })
+public class ArticleViewerWithMapParamIntegrationTest {
+
+ @Autowired
+ private WebApplicationContext wac;
+
+ private MockMvc mockMvc;
+
+ @Before
+ public void setup() throws Exception {
+ this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
+ }
+
+ @Test
+ public void givenPathVarsMapParam_whenIdPathVariableIsPassed_thenResponseOK() throws Exception {
+
+ int articleId = 5;
+
+ this.mockMvc
+ .perform(MockMvcRequestBuilders.get("/mapParam/article/{id}", articleId))
+ .andExpect(MockMvcResultMatchers.status().isOk())
+ .andExpect(MockMvcResultMatchers.jsonPath("$.id").value(articleId));
+
+ }
+
+ @Test
+ public void givenPathVarsMapParam_whenIdPathVariableIsNotPassed_thenResponseOK() throws Exception {
+
+ this.mockMvc
+ .perform(MockMvcRequestBuilders.get("/mapParam/article"))
+ .andExpect(MockMvcResultMatchers.status().isOk())
+ .andExpect(MockMvcResultMatchers.jsonPath("$.id").value(Article.DEFAULT_ARTICLE.getId()));
+
+ }
+
+
+}
\ No newline at end of file
diff --git a/spring-mvc-java/src/test/java/com/baeldung/web/controller/optionalpathvars/ArticleViewerWithTwoSeparateMethodsIntegrationTest.java b/spring-mvc-java/src/test/java/com/baeldung/web/controller/optionalpathvars/ArticleViewerWithTwoSeparateMethodsIntegrationTest.java
new file mode 100644
index 0000000000..d417b4d397
--- /dev/null
+++ b/spring-mvc-java/src/test/java/com/baeldung/web/controller/optionalpathvars/ArticleViewerWithTwoSeparateMethodsIntegrationTest.java
@@ -0,0 +1,56 @@
+package com.baeldung.web.controller.optionalpathvars;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.test.context.web.WebAppConfiguration;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
+import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+import org.springframework.web.context.WebApplicationContext;
+
+import com.baeldung.model.Article;
+import com.baeldung.spring.web.config.WebConfig;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@WebAppConfiguration
+@ContextConfiguration(classes = { WebConfig.class })
+public class ArticleViewerWithTwoSeparateMethodsIntegrationTest {
+
+ @Autowired
+ private WebApplicationContext wac;
+
+ private MockMvc mockMvc;
+
+ @Before
+ public void setup() throws Exception {
+ this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
+ }
+
+ @Test
+ public void givenTwoSeparateMethods_whenIdPathVariableIsPassed_thenResponseOK() throws Exception {
+
+ int articleId = 5;
+
+ this.mockMvc
+ .perform(MockMvcRequestBuilders.get("/seperateMethods/article/{id}", articleId))
+ .andExpect(MockMvcResultMatchers.status().isOk())
+ .andExpect(MockMvcResultMatchers.jsonPath("$.id").value(articleId));
+
+ }
+
+ @Test
+ public void givenTwoSeparateMethods_whenIdPathVariableIsNotPassed_thenResponseOK() throws Exception {
+
+ this.mockMvc
+ .perform(MockMvcRequestBuilders.get("/seperateMethods/article"))
+ .andExpect(MockMvcResultMatchers.status().isOk())
+ .andExpect(MockMvcResultMatchers.jsonPath("$.id").value(Article.DEFAULT_ARTICLE.getId()));
+
+ }
+
+}
\ No newline at end of file
diff --git a/spring-mvc-simple-2/README.md b/spring-mvc-simple-2/README.md
index cff8891a1a..3d240531ae 100644
--- a/spring-mvc-simple-2/README.md
+++ b/spring-mvc-simple-2/README.md
@@ -10,4 +10,5 @@ This module contains articles about Spring MVC
- [Using a Slash Character in Spring URLs](https://www.baeldung.com/spring-slash-character-in-url)
- [Using Enums as Request Parameters in Spring](https://www.baeldung.com/spring-enum-request-param)
- [Excluding URLs for a Filter in a Spring Web Application](https://www.baeldung.com/spring-exclude-filter)
+- [Guide to Flash Attributes in a Spring Web Application](https://www.baeldung.com/spring-web-flash-attributes)
- More articles: [[<-- prev]](/spring-mvc-simple)
diff --git a/testing-modules/junit-5/pom.xml b/testing-modules/junit-5/pom.xml
index 96944b4dc6..a27e4da61b 100644
--- a/testing-modules/junit-5/pom.xml
+++ b/testing-modules/junit-5/pom.xml
@@ -124,9 +124,13 @@
com.baeldung.TestLauncher
+
+ org.apache.maven.plugins
+ maven-surefire-report-plugin
+ ${surefire.report.plugin}
+
-
5.4.2
2.23.0
@@ -137,6 +141,7 @@
2.22.0
1.6.0
5.0.1.RELEASE
+ 3.0.0-M3
diff --git a/testing-modules/junit-5/src/test/java/com/baeldung/execution/time/SampleExecutionTimeUnitTest.java b/testing-modules/junit-5/src/test/java/com/baeldung/execution/time/SampleExecutionTimeUnitTest.java
new file mode 100644
index 0000000000..7d43d1a560
--- /dev/null
+++ b/testing-modules/junit-5/src/test/java/com/baeldung/execution/time/SampleExecutionTimeUnitTest.java
@@ -0,0 +1,38 @@
+package com.baeldung.execution.time;
+
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+class SampleExecutionTimeUnitTest {
+
+ @Test
+ void someUnitTest() {
+
+ assertTrue(doSomething());
+ }
+
+// @Test
+// void someIntegrationTest() throws Exception {
+//
+// //simulate an operation that may take 5 seconds
+// Thread.sleep(5000);
+//
+// assertTrue(doSomething());
+// }
+//
+// @Test
+// void someEndToEndTest() throws Exception {
+//
+// //simulate an operation that may take 10 seconds
+// Thread.sleep(10000);
+//
+// assertTrue(doSomething());
+//
+// }
+
+ private boolean doSomething() {
+ return true;
+ }
+}
diff --git a/twitter4j/src/test/java/com/baeldung/ApplicationIntegrationTest.java b/twitter4j/src/test/java/com/baeldung/ApplicationManualTest.java
similarity index 95%
rename from twitter4j/src/test/java/com/baeldung/ApplicationIntegrationTest.java
rename to twitter4j/src/test/java/com/baeldung/ApplicationManualTest.java
index 4696283faa..1605e61acf 100644
--- a/twitter4j/src/test/java/com/baeldung/ApplicationIntegrationTest.java
+++ b/twitter4j/src/test/java/com/baeldung/ApplicationManualTest.java
@@ -9,7 +9,7 @@ import org.junit.Test;
import twitter4j.TwitterException;
-public class ApplicationIntegrationTest {
+public class ApplicationManualTest {
/**
* In order run this jUnit test you need to configure your API details in the twitter4j.properties