From e6e0c065d509357f6a04bef853ad0f52c4c9e420 Mon Sep 17 00:00:00 2001 From: Rajesh Bhojwani Date: Thu, 17 Jan 2019 15:17:09 +0530 Subject: [PATCH 01/33] Added test file to demo the deletion of file content --- .../file/FilesClearDataManualTest.java | 98 +++++++++++++++++++ .../src/test/resources/fileexample.txt | 1 + 2 files changed, 99 insertions(+) create mode 100644 core-java-io/src/test/java/com/baeldung/file/FilesClearDataManualTest.java create mode 100644 core-java-io/src/test/resources/fileexample.txt diff --git a/core-java-io/src/test/java/com/baeldung/file/FilesClearDataManualTest.java b/core-java-io/src/test/java/com/baeldung/file/FilesClearDataManualTest.java new file mode 100644 index 0000000000..8a4b3a7380 --- /dev/null +++ b/core-java-io/src/test/java/com/baeldung/file/FilesClearDataManualTest.java @@ -0,0 +1,98 @@ +package com.baeldung.file; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.nio.channels.FileChannel; +import java.nio.charset.Charset; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.nio.file.StandardOpenOption; + +import org.apache.commons.io.FileUtils; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import com.baeldung.util.StreamUtils; + +public class FilesClearDataManualTest { + + public static final String FILE_PATH = "src/test/resources/fileexample.txt"; + + @Before + @After + public void setup() throws IOException { + PrintWriter writer = new PrintWriter(FILE_PATH); + writer.print("This example shows how we can delete the file contents without deleting the file"); + writer.close(); + } + + @Test + public void givenExistingFile_whenDeleteContentUsingPrintWritter_thenEmptyFile() throws IOException { + PrintWriter writer = new PrintWriter(FILE_PATH); + writer.print(""); + writer.close(); + assertEquals(0, StreamUtils.getStringFromInputStream(new FileInputStream(FILE_PATH)).length()); + } + + @Test + public void givenExistingFile_whenDeleteContentUsingPrintWritterWithougObject_thenEmptyFile() throws IOException { + new PrintWriter(FILE_PATH).close(); + assertEquals(0, StreamUtils.getStringFromInputStream(new FileInputStream(FILE_PATH)).length()); + } + + + @Test + public void givenExistingFile_whenDeleteContentUsingFileWriter_thenEmptyFile() throws IOException { + new FileWriter(FILE_PATH, false).close(); + + assertEquals(0, StreamUtils.getStringFromInputStream(new FileInputStream(FILE_PATH)).length()); + } + + @Test + public void givenExistingFile_whenDeleteContentUsingFileOutputStream_thenEmptyFile() throws IOException { + new FileOutputStream(FILE_PATH).close(); + + assertEquals(0, StreamUtils.getStringFromInputStream(new FileInputStream(FILE_PATH)).length()); + } + + @Test + public void givenExistingFile_whenDeleteContentUsingFileUtils_thenEmptyFile() throws IOException { + FileUtils.write(new File(FILE_PATH), "", Charset.defaultCharset()); + + assertEquals(0, StreamUtils.getStringFromInputStream(new FileInputStream(FILE_PATH)).length()); + } + + @Test + public void givenExistingFile_whenDeleteContentUsingNIOFiles_thenEmptyFile() throws IOException { + BufferedWriter writer = Files.newBufferedWriter(Paths.get(FILE_PATH)); + writer.write(""); + writer.flush(); + + assertEquals(0, StreamUtils.getStringFromInputStream(new FileInputStream(FILE_PATH)).length()); + } + + @Test + public void givenExistingFile_whenDeleteContentUsingNIOFileChannel_thenEmptyFile() throws IOException { + FileChannel.open(Paths.get(FILE_PATH), StandardOpenOption.WRITE).truncate(0).close(); + + assertEquals(0, StreamUtils.getStringFromInputStream(new FileInputStream(FILE_PATH)).length()); + } + + @Test + public void givenExistingFile_whenDeleteContentUsingGuava_thenEmptyFile() throws IOException { + File file = new File(FILE_PATH); + byte[] empty = new byte[0]; + com.google.common.io.Files.write(empty, file); + + assertEquals(0, StreamUtils.getStringFromInputStream(new FileInputStream(FILE_PATH)).length()); + } + +} diff --git a/core-java-io/src/test/resources/fileexample.txt b/core-java-io/src/test/resources/fileexample.txt new file mode 100644 index 0000000000..ee48fdfb84 --- /dev/null +++ b/core-java-io/src/test/resources/fileexample.txt @@ -0,0 +1 @@ +This example shows how we can delete the file contents without deleting the file \ No newline at end of file From 273c569b88de74d048a1b7989021c686c9764dbf Mon Sep 17 00:00:00 2001 From: Rajesh Bhojwani Date: Thu, 17 Jan 2019 15:20:25 +0530 Subject: [PATCH 02/33] remove space --- .../test/java/com/baeldung/file/FilesClearDataManualTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/core-java-io/src/test/java/com/baeldung/file/FilesClearDataManualTest.java b/core-java-io/src/test/java/com/baeldung/file/FilesClearDataManualTest.java index 8a4b3a7380..c00290168c 100644 --- a/core-java-io/src/test/java/com/baeldung/file/FilesClearDataManualTest.java +++ b/core-java-io/src/test/java/com/baeldung/file/FilesClearDataManualTest.java @@ -47,7 +47,6 @@ public class FilesClearDataManualTest { new PrintWriter(FILE_PATH).close(); assertEquals(0, StreamUtils.getStringFromInputStream(new FileInputStream(FILE_PATH)).length()); } - @Test public void givenExistingFile_whenDeleteContentUsingFileWriter_thenEmptyFile() throws IOException { From 8510b07a5642e261eceb76711c3739e4379d359b Mon Sep 17 00:00:00 2001 From: Loredana Crusoveanu Date: Thu, 17 Jan 2019 23:27:50 +0200 Subject: [PATCH 03/33] Update FilesClearDataManualTest.java --- .../test/java/com/baeldung/file/FilesClearDataManualTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/core-java-io/src/test/java/com/baeldung/file/FilesClearDataManualTest.java b/core-java-io/src/test/java/com/baeldung/file/FilesClearDataManualTest.java index c00290168c..6abe677acf 100644 --- a/core-java-io/src/test/java/com/baeldung/file/FilesClearDataManualTest.java +++ b/core-java-io/src/test/java/com/baeldung/file/FilesClearDataManualTest.java @@ -93,5 +93,4 @@ public class FilesClearDataManualTest { assertEquals(0, StreamUtils.getStringFromInputStream(new FileInputStream(FILE_PATH)).length()); } - } From 89ff253342752027c17b8088b8940df972a5d17f Mon Sep 17 00:00:00 2001 From: Loredana Crusoveanu Date: Sun, 20 Jan 2019 21:56:30 +0200 Subject: [PATCH 04/33] Update TaskScheduler.java --- .../java/com/baeldung/scheduling/shedlock/TaskScheduler.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spring-boot-libraries/src/main/java/com/baeldung/scheduling/shedlock/TaskScheduler.java b/spring-boot-libraries/src/main/java/com/baeldung/scheduling/shedlock/TaskScheduler.java index b1b1ad921f..060afe660e 100644 --- a/spring-boot-libraries/src/main/java/com/baeldung/scheduling/shedlock/TaskScheduler.java +++ b/spring-boot-libraries/src/main/java/com/baeldung/scheduling/shedlock/TaskScheduler.java @@ -7,9 +7,9 @@ import org.springframework.stereotype.Component; @Component class TaskScheduler { - @Scheduled(cron = "*/15 * * * * *") + @Scheduled(cron = "*/15 * * * *") @SchedulerLock(name = "TaskScheduler_scheduledTask", lockAtLeastForString = "PT5M", lockAtMostForString = "PT14M") public void scheduledTask() { System.out.println("Running ShedLock task"); } -} \ No newline at end of file +} From 08b8c427bd1784f0dc0de4f43f7638a0aabcdfc3 Mon Sep 17 00:00:00 2001 From: Rajesh Bhojwani Date: Mon, 21 Jan 2019 08:15:38 +0530 Subject: [PATCH 05/33] rename file --- ...ilesClearDataManualTest.java => FilesClearDataUnitTest.java} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename core-java-io/src/test/java/com/baeldung/file/{FilesClearDataManualTest.java => FilesClearDataUnitTest.java} (98%) diff --git a/core-java-io/src/test/java/com/baeldung/file/FilesClearDataManualTest.java b/core-java-io/src/test/java/com/baeldung/file/FilesClearDataUnitTest.java similarity index 98% rename from core-java-io/src/test/java/com/baeldung/file/FilesClearDataManualTest.java rename to core-java-io/src/test/java/com/baeldung/file/FilesClearDataUnitTest.java index c00290168c..653c4320c0 100644 --- a/core-java-io/src/test/java/com/baeldung/file/FilesClearDataManualTest.java +++ b/core-java-io/src/test/java/com/baeldung/file/FilesClearDataUnitTest.java @@ -22,7 +22,7 @@ import org.junit.Test; import com.baeldung.util.StreamUtils; -public class FilesClearDataManualTest { +public class FilesClearDataUnitTest { public static final String FILE_PATH = "src/test/resources/fileexample.txt"; From 3aff027b7a7e47a4700604b0b44ae45f48fa3c9b Mon Sep 17 00:00:00 2001 From: Urvy Agrawal Date: Mon, 21 Jan 2019 11:23:24 +0530 Subject: [PATCH 06/33] Adding file for BAEL-2558 --- .../BitwiseOperatorExample.java | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 core-java/src/main/java/com/baeldung/bitwiseoperator/BitwiseOperatorExample.java diff --git a/core-java/src/main/java/com/baeldung/bitwiseoperator/BitwiseOperatorExample.java b/core-java/src/main/java/com/baeldung/bitwiseoperator/BitwiseOperatorExample.java new file mode 100644 index 0000000000..4fef92102a --- /dev/null +++ b/core-java/src/main/java/com/baeldung/bitwiseoperator/BitwiseOperatorExample.java @@ -0,0 +1,56 @@ +package com.baeldung.bitwiseoperator; + +public class BitwiseOperatorExample { + + public static void main(String[] args) { + + int value1 = 6; + int value2 = 5; + + // Bitwise AND Operator + int result = value1 & value2; + System.out.println("result : " + result); + + // Bitwise OR Operator + result = value1 | value2; + System.out.println("result : " + result); + + // Bitwise Exclusive OR Operator + result = value1 ^ value2; + System.out.println("result : " + result); + + // Bitwise NOT operator + result = ~value1; + System.out.println("result : " + result); + + // Right Shift Operator with positive number + int value = 12; + int rightShift = value >> 2; + System.out.println("rightShift result with positive number : " + rightShift); + + // Right Shift Operator with negative number + value = -12; + rightShift = value >> 2; + System.out.println("rightShift result with negative number : " + rightShift); + + // Left Shift Operator with positive number + value = 1; + int leftShift = value << 1; + System.out.println("leftShift result with positive number : " + leftShift); + + // Left Shift Operator with negative number + value = -12; + leftShift = value << 2; + System.out.println("leftShift result with negative number : " + leftShift); + + // Unsigned Right Shift Operator with positive number + value = 12; + int unsignedRightShift = value >>> 2; + System.out.println("unsignedRightShift result with positive number : " + unsignedRightShift); + + // Unsigned Right Shift Operator with negative number + value = -12; + unsignedRightShift = value >>> 2; + System.out.println("unsignedRightShift result with negative number : " + unsignedRightShift); + } +} From a608d7cd1553ae67508054446c30a44b54b9c5c8 Mon Sep 17 00:00:00 2001 From: Michael Pratt Date: Mon, 21 Jan 2019 15:12:25 +0000 Subject: [PATCH 07/33] BAEL-2491: Conditionally enable spring scheduled jobs --- spring-scheduling/.gitignore | 25 ++ .../.mvn/wrapper/maven-wrapper.jar | Bin 0 -> 48337 bytes .../.mvn/wrapper/maven-wrapper.properties | 1 + spring-scheduling/mvnw | 286 ++++++++++++++++++ spring-scheduling/mvnw.cmd | 161 ++++++++++ spring-scheduling/pom.xml | 42 +++ .../scheduling/ScheduleJobsByProfile.java | 20 ++ .../com/baeldung/scheduling/ScheduledJob.java | 21 ++ .../scheduling/ScheduledJobsWithBoolean.java | 28 ++ .../ScheduledJobsWithConditional.java | 20 ++ .../ScheduledJobsWithExpression.java | 23 ++ .../scheduling/SchedulingApplication.java | 16 + .../src/main/resources/application.properties | 0 .../SchedulingApplicationTests.java | 17 ++ 14 files changed, 660 insertions(+) create mode 100644 spring-scheduling/.gitignore create mode 100644 spring-scheduling/.mvn/wrapper/maven-wrapper.jar create mode 100644 spring-scheduling/.mvn/wrapper/maven-wrapper.properties create mode 100755 spring-scheduling/mvnw create mode 100644 spring-scheduling/mvnw.cmd create mode 100644 spring-scheduling/pom.xml create mode 100644 spring-scheduling/src/main/java/com/baeldung/scheduling/ScheduleJobsByProfile.java create mode 100644 spring-scheduling/src/main/java/com/baeldung/scheduling/ScheduledJob.java create mode 100644 spring-scheduling/src/main/java/com/baeldung/scheduling/ScheduledJobsWithBoolean.java create mode 100644 spring-scheduling/src/main/java/com/baeldung/scheduling/ScheduledJobsWithConditional.java create mode 100644 spring-scheduling/src/main/java/com/baeldung/scheduling/ScheduledJobsWithExpression.java create mode 100644 spring-scheduling/src/main/java/com/baeldung/scheduling/SchedulingApplication.java create mode 100644 spring-scheduling/src/main/resources/application.properties create mode 100644 spring-scheduling/src/test/java/com/baeldung/scheduling/SchedulingApplicationTests.java diff --git a/spring-scheduling/.gitignore b/spring-scheduling/.gitignore new file mode 100644 index 0000000000..82eca336e3 --- /dev/null +++ b/spring-scheduling/.gitignore @@ -0,0 +1,25 @@ +/target/ +!.mvn/wrapper/maven-wrapper.jar + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/build/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ \ No newline at end of file diff --git a/spring-scheduling/.mvn/wrapper/maven-wrapper.jar b/spring-scheduling/.mvn/wrapper/maven-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..01e67997377a393fd672c7dcde9dccbedf0cb1e9 GIT binary patch literal 48337 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 \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG="`dirname "$PRG"`/$link" + fi + done + + saveddir=`pwd` + + M2_HOME=`dirname "$PRG"`/.. + + # make it fully qualified + M2_HOME=`cd "$M2_HOME" && pwd` + + cd "$saveddir" + # echo Using m2 at $M2_HOME +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin ; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --unix "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --unix "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --unix "$CLASSPATH"` +fi + +# For Mingw, ensure paths are in UNIX format before anything is touched +if $mingw ; then + [ -n "$M2_HOME" ] && + M2_HOME="`(cd "$M2_HOME"; pwd)`" + [ -n "$JAVA_HOME" ] && + JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" + # TODO classpath? +fi + +if [ -z "$JAVA_HOME" ]; then + javaExecutable="`which javac`" + if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then + # readlink(1) is not available as standard on Solaris 10. + readLink=`which readlink` + if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then + if $darwin ; then + javaHome="`dirname \"$javaExecutable\"`" + javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" + else + javaExecutable="`readlink -f \"$javaExecutable\"`" + fi + javaHome="`dirname \"$javaExecutable\"`" + javaHome=`expr "$javaHome" : '\(.*\)/bin'` + JAVA_HOME="$javaHome" + export JAVA_HOME + fi + fi +fi + +if [ -z "$JAVACMD" ] ; then + if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + else + JAVACMD="`which java`" + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." >&2 + echo " We cannot execute $JAVACMD" >&2 + exit 1 +fi + +if [ -z "$JAVA_HOME" ] ; then + echo "Warning: JAVA_HOME environment variable is not set." +fi + +CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher + +# traverses directory structure from process work directory to filesystem root +# first directory with .mvn subdirectory is considered project base directory +find_maven_basedir() { + + if [ -z "$1" ] + then + echo "Path not specified to find_maven_basedir" + return 1 + fi + + basedir="$1" + wdir="$1" + while [ "$wdir" != '/' ] ; do + if [ -d "$wdir"/.mvn ] ; then + basedir=$wdir + break + fi + # workaround for JBEAP-8937 (on Solaris 10/Sparc) + if [ -d "${wdir}" ]; then + wdir=`cd "$wdir/.."; pwd` + fi + # end of workaround + done + echo "${basedir}" +} + +# concatenates all lines of a file +concat_lines() { + if [ -f "$1" ]; then + echo "$(tr -s '\n' ' ' < "$1")" + fi +} + +BASE_DIR=`find_maven_basedir "$(pwd)"` +if [ -z "$BASE_DIR" ]; then + exit 1; +fi + +########################################################################################## +# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +# This allows using the maven wrapper in projects that prohibit checking in binary data. +########################################################################################## +if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found .mvn/wrapper/maven-wrapper.jar" + fi +else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." + fi + jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar" + while IFS="=" read key value; do + case "$key" in (wrapperUrl) jarUrl="$value"; break ;; + esac + done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" + if [ "$MVNW_VERBOSE" = true ]; then + echo "Downloading from: $jarUrl" + fi + wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" + + if command -v wget > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found wget ... using wget" + fi + wget "$jarUrl" -O "$wrapperJarPath" + elif command -v curl > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found curl ... using curl" + fi + curl -o "$wrapperJarPath" "$jarUrl" + else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Falling back to using Java to download" + fi + javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" + if [ -e "$javaClass" ]; then + if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Compiling MavenWrapperDownloader.java ..." + fi + # Compiling the Java class + ("$JAVA_HOME/bin/javac" "$javaClass") + fi + if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + # Running the downloader + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Running MavenWrapperDownloader.java ..." + fi + ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") + fi + fi + fi +fi +########################################################################################## +# End of extension +########################################################################################## + +export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} +if [ "$MVNW_VERBOSE" = true ]; then + echo $MAVEN_PROJECTBASEDIR +fi +MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --path --windows "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --windows "$CLASSPATH"` + [ -n "$MAVEN_PROJECTBASEDIR" ] && + MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` +fi + +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +exec "$JAVACMD" \ + $MAVEN_OPTS \ + -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ + "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/spring-scheduling/mvnw.cmd b/spring-scheduling/mvnw.cmd new file mode 100644 index 0000000000..e5cfb0ae9e --- /dev/null +++ b/spring-scheduling/mvnw.cmd @@ -0,0 +1,161 @@ +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM http://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Maven2 Start Up Batch script +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM M2_HOME - location of maven2's installed home dir +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM set title of command window +title %0 +@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" +if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar" +FOR /F "tokens=1,2 delims==" %%A IN (%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties) DO ( + IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + echo Found %WRAPPER_JAR% +) else ( + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %DOWNLOAD_URL% + powershell -Command "(New-Object Net.WebClient).DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')" + echo Finished downloading %WRAPPER_JAR% +) +@REM End of extension + +%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" +if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%" == "on" pause + +if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% + +exit /B %ERROR_CODE% diff --git a/spring-scheduling/pom.xml b/spring-scheduling/pom.xml new file mode 100644 index 0000000000..d739985f7c --- /dev/null +++ b/spring-scheduling/pom.xml @@ -0,0 +1,42 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.1.2.RELEASE + + + com.baeldung + scheduling + 0.0.1-SNAPSHOT + scheduling + Example of conditionally enabling spring scheduled jobs + + + 1.8 + + + + + org.springframework.boot + spring-boot-starter + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/spring-scheduling/src/main/java/com/baeldung/scheduling/ScheduleJobsByProfile.java b/spring-scheduling/src/main/java/com/baeldung/scheduling/ScheduleJobsByProfile.java new file mode 100644 index 0000000000..33cd44331f --- /dev/null +++ b/spring-scheduling/src/main/java/com/baeldung/scheduling/ScheduleJobsByProfile.java @@ -0,0 +1,20 @@ +package com.baeldung.scheduling; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; + +@Configuration +public class ScheduleJobsByProfile { + + private final static Logger LOG = LoggerFactory.getLogger(ScheduleJobsByProfile.class); + + @Profile("prod") + @Bean + public ScheduledJob scheduledJob() + { + return new ScheduledJob("@Profile"); + } +} diff --git a/spring-scheduling/src/main/java/com/baeldung/scheduling/ScheduledJob.java b/spring-scheduling/src/main/java/com/baeldung/scheduling/ScheduledJob.java new file mode 100644 index 0000000000..df7cefcd3c --- /dev/null +++ b/spring-scheduling/src/main/java/com/baeldung/scheduling/ScheduledJob.java @@ -0,0 +1,21 @@ +package com.baeldung.scheduling; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.scheduling.annotation.Scheduled; + +public class ScheduledJob { + + private String source; + + public ScheduledJob(String source) { + this.source = source; + } + + private final static Logger LOG = LoggerFactory.getLogger(ScheduledJob.class); + + @Scheduled(fixedDelay = 60000) + public void cleanTempDir() { + LOG.info("Cleaning temp directory via {}", source); + } +} diff --git a/spring-scheduling/src/main/java/com/baeldung/scheduling/ScheduledJobsWithBoolean.java b/spring-scheduling/src/main/java/com/baeldung/scheduling/ScheduledJobsWithBoolean.java new file mode 100644 index 0000000000..b03de61641 --- /dev/null +++ b/spring-scheduling/src/main/java/com/baeldung/scheduling/ScheduledJobsWithBoolean.java @@ -0,0 +1,28 @@ +package com.baeldung.scheduling; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.Scheduled; + +@Configuration +public class ScheduledJobsWithBoolean { + + private final static Logger LOG = LoggerFactory.getLogger(ScheduledJobsWithBoolean.class); + + @Value("${jobs.enabled:true}") + private boolean isEnabled; + + /** + * A scheduled job controlled via application property. The job always + * executes, but the logic inside is protected by a configurable boolean + * flag. + */ + @Scheduled(fixedDelay = 60000) + public void cleanTempDirectory() { + if(isEnabled) { + LOG.info("Cleaning temp directory via boolean flag"); + } + } +} diff --git a/spring-scheduling/src/main/java/com/baeldung/scheduling/ScheduledJobsWithConditional.java b/spring-scheduling/src/main/java/com/baeldung/scheduling/ScheduledJobsWithConditional.java new file mode 100644 index 0000000000..081c8d990a --- /dev/null +++ b/spring-scheduling/src/main/java/com/baeldung/scheduling/ScheduledJobsWithConditional.java @@ -0,0 +1,20 @@ +package com.baeldung.scheduling; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class ScheduledJobsWithConditional +{ + /** + * This uses @ConditionalOnProperty to conditionally create a bean, which itself + * is a scheduled job. + * @return ScheduledJob + */ + @Bean + @ConditionalOnProperty(value = "jobs.enabled", matchIfMissing = true, havingValue = "true") + public ScheduledJob runMyCronTask() { + return new ScheduledJob("@ConditionalOnProperty"); + } +} diff --git a/spring-scheduling/src/main/java/com/baeldung/scheduling/ScheduledJobsWithExpression.java b/spring-scheduling/src/main/java/com/baeldung/scheduling/ScheduledJobsWithExpression.java new file mode 100644 index 0000000000..577a01f241 --- /dev/null +++ b/spring-scheduling/src/main/java/com/baeldung/scheduling/ScheduledJobsWithExpression.java @@ -0,0 +1,23 @@ +package com.baeldung.scheduling; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.Scheduled; + +@Configuration +public class ScheduledJobsWithExpression +{ + private final static Logger LOG = + LoggerFactory.getLogger(ScheduledJobsWithExpression.class); + + /** + * A scheduled job controlled via application property. The job always + * executes, but the logic inside is protected by a configurable boolean + * flag. + */ + @Scheduled(cron = "${jobs.cronSchedule:-}") + public void cleanTempDirectory() { + LOG.info("Cleaning temp directory via placeholder"); + } +} diff --git a/spring-scheduling/src/main/java/com/baeldung/scheduling/SchedulingApplication.java b/spring-scheduling/src/main/java/com/baeldung/scheduling/SchedulingApplication.java new file mode 100644 index 0000000000..913e2137f8 --- /dev/null +++ b/spring-scheduling/src/main/java/com/baeldung/scheduling/SchedulingApplication.java @@ -0,0 +1,16 @@ +package com.baeldung.scheduling; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.scheduling.annotation.EnableScheduling; + +@SpringBootApplication +@EnableScheduling +public class SchedulingApplication { + + public static void main(String[] args) { + SpringApplication.run(SchedulingApplication.class, args); + } + +} + diff --git a/spring-scheduling/src/main/resources/application.properties b/spring-scheduling/src/main/resources/application.properties new file mode 100644 index 0000000000..e69de29bb2 diff --git a/spring-scheduling/src/test/java/com/baeldung/scheduling/SchedulingApplicationTests.java b/spring-scheduling/src/test/java/com/baeldung/scheduling/SchedulingApplicationTests.java new file mode 100644 index 0000000000..60e6d820bb --- /dev/null +++ b/spring-scheduling/src/test/java/com/baeldung/scheduling/SchedulingApplicationTests.java @@ -0,0 +1,17 @@ +package com.baeldung.scheduling; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +@RunWith(SpringRunner.class) +@SpringBootTest +public class SchedulingApplicationTests { + + @Test + public void contextLoads() { + } + +} + From 196c17e612c00e789d2aee0138709ae8c49362fb Mon Sep 17 00:00:00 2001 From: Michael Pratt Date: Mon, 21 Jan 2019 15:14:13 +0000 Subject: [PATCH 08/33] BAEL-2491: Conditionally enable spring scheduled jobs --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 1c0738cafb..1f25dd0691 100644 --- a/pom.xml +++ b/pom.xml @@ -714,7 +714,7 @@ spring-rest-simple spring-resttemplate spring-roo - + spring-scheduling spring-security-acl spring-security-angular/server spring-security-cache-control From 974950923c1069448c873033f27f42463d1c2350 Mon Sep 17 00:00:00 2001 From: Trevor Gowing Date: Mon, 24 Dec 2018 17:15:46 +0200 Subject: [PATCH 09/33] Refactor Passenger Entity Change seat number type to integer wrapper. Enable QuerybyExample (QBE) BAEL-2406 --- .../src/main/java/com/baeldung/passenger/Passenger.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/passenger/Passenger.java b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/passenger/Passenger.java index 24ae47e597..a96b1edb20 100644 --- a/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/passenger/Passenger.java +++ b/persistence-modules/spring-data-jpa/src/main/java/com/baeldung/passenger/Passenger.java @@ -25,15 +25,15 @@ class Passenger { @Basic(optional = false) @Column(nullable = false) - private int seatNumber; + private Integer seatNumber; - private Passenger(String firstName, String lastName, int seatNumber) { + private Passenger(String firstName, String lastName, Integer seatNumber) { this.firstName = firstName; this.lastName = lastName; this.seatNumber = seatNumber; } - static Passenger from(String firstName, String lastName, int seatNumber) { + static Passenger from(String firstName, String lastName, Integer seatNumber) { return new Passenger(firstName, lastName, seatNumber); } @@ -76,7 +76,7 @@ class Passenger { return lastName; } - int getSeatNumber() { + Integer getSeatNumber() { return seatNumber; } } From 14b65b327f571594f1572df4c145a0097cd272e8 Mon Sep 17 00:00:00 2001 From: Ger Roza Date: Sun, 20 Jan 2019 18:19:52 -0200 Subject: [PATCH 10/33] moved Rest Pagination article code from spring-rest-full to spring-boot-rest --- spring-boot-rest/README.md | 1 + spring-boot-rest/pom.xml | 30 ++++- .../{web => }/SpringBootRestApplication.java | 2 +- .../com/baeldung/persistence/IOperations.java | 16 +++ .../com/baeldung/persistence/dao/IFooDao.java | 9 ++ .../com/baeldung/persistence/model/Foo.java | 83 ++++++++++++++ .../persistence/service/IFooService.java | 13 +++ .../service/common/AbstractService.java | 31 ++++++ .../persistence/service/impl/FooService.java | 40 +++++++ .../baeldung/spring/PersistenceConfig.java | 85 +++++++++++++++ .../java/com/baeldung/spring/WebConfig.java | 43 ++++++++ .../web/config/MyErrorController.java | 1 - .../com/baeldung/web/config/WebConfig.java | 8 -- .../web/controller/FooController.java | 89 +++++++++++++++ .../web/controller/RootController.java | 40 +++++++ .../event/PaginatedResultsRetrievedEvent.java | 2 +- .../hateoas/event/ResourceCreatedEvent.java | 28 +++++ ...sultsRetrievedDiscoverabilityListener.java | 6 +- ...esourceCreatedDiscoverabilityListener.java | 36 ++++++ .../java/com/baeldung/web/util/LinkUtil.java | 36 ++++++ .../baeldung/web/util/RestPreconditions.java | 48 ++++++++ .../src/main/resources/application.properties | 3 + .../main/resources/persistence-h2.properties | 22 ++++ .../resources/persistence-mysql.properties | 10 ++ .../resources/springDataPersistenceConfig.xml | 12 ++ .../src/test/java/com/baeldung/Consts.java | 5 + .../SpringContextIntegrationTest.java | 2 +- .../common/web/AbstractBasicLiveTest.java | 103 ++++++++++++++++++ .../baeldung/common/web/AbstractLiveTest.java | 65 +++++++++++ .../spring/ConfigIntegrationTest.java | 17 +++ .../java/com/baeldung/test/IMarshaller.java | 15 +++ .../com/baeldung/test/JacksonMarshaller.java | 81 ++++++++++++++ .../baeldung/test/TestMarshallerFactory.java | 49 +++++++++ .../java/com/baeldung/web/FooLiveTest.java | 36 ++++++ .../baeldung/web/FooPageableLiveTest.java | 22 ++-- .../baeldung/web/LiveTestSuiteLiveTest.java | 14 +++ .../web/error/ErrorHandlingLiveTest.java | 7 +- .../baeldung/web/util/HTTPLinkHeaderUtil.java | 36 ++++++ spring-rest-full/README.md | 1 - .../org/baeldung/persistence/IOperations.java | 4 - .../persistence/service/IFooService.java | 4 - .../service/common/AbstractService.java | 7 -- .../persistence/service/impl/FooService.java | 7 -- .../web/controller/FooController.java | 31 ------ .../baeldung/web/util/RestPreconditions.java | 3 +- .../common/web/AbstractBasicLiveTest.java | 80 +------------- .../web/AbstractDiscoverabilityLiveTest.java | 5 +- .../baeldung/web/LiveTestSuiteLiveTest.java | 1 - 48 files changed, 1125 insertions(+), 164 deletions(-) rename spring-boot-rest/src/main/java/com/baeldung/{web => }/SpringBootRestApplication.java (92%) create mode 100644 spring-boot-rest/src/main/java/com/baeldung/persistence/IOperations.java create mode 100644 spring-boot-rest/src/main/java/com/baeldung/persistence/dao/IFooDao.java create mode 100644 spring-boot-rest/src/main/java/com/baeldung/persistence/model/Foo.java create mode 100644 spring-boot-rest/src/main/java/com/baeldung/persistence/service/IFooService.java create mode 100644 spring-boot-rest/src/main/java/com/baeldung/persistence/service/common/AbstractService.java create mode 100644 spring-boot-rest/src/main/java/com/baeldung/persistence/service/impl/FooService.java create mode 100644 spring-boot-rest/src/main/java/com/baeldung/spring/PersistenceConfig.java create mode 100644 spring-boot-rest/src/main/java/com/baeldung/spring/WebConfig.java delete mode 100644 spring-boot-rest/src/main/java/com/baeldung/web/config/WebConfig.java create mode 100644 spring-boot-rest/src/main/java/com/baeldung/web/controller/FooController.java create mode 100644 spring-boot-rest/src/main/java/com/baeldung/web/controller/RootController.java rename {spring-rest-full/src/main/java/org => spring-boot-rest/src/main/java/com}/baeldung/web/hateoas/event/PaginatedResultsRetrievedEvent.java (97%) create mode 100644 spring-boot-rest/src/main/java/com/baeldung/web/hateoas/event/ResourceCreatedEvent.java rename {spring-rest-full/src/main/java/org => spring-boot-rest/src/main/java/com}/baeldung/web/hateoas/listener/PaginatedResultsRetrievedDiscoverabilityListener.java (96%) create mode 100644 spring-boot-rest/src/main/java/com/baeldung/web/hateoas/listener/ResourceCreatedDiscoverabilityListener.java create mode 100644 spring-boot-rest/src/main/java/com/baeldung/web/util/LinkUtil.java create mode 100644 spring-boot-rest/src/main/java/com/baeldung/web/util/RestPreconditions.java create mode 100644 spring-boot-rest/src/main/resources/persistence-h2.properties create mode 100644 spring-boot-rest/src/main/resources/persistence-mysql.properties create mode 100644 spring-boot-rest/src/main/resources/springDataPersistenceConfig.xml create mode 100644 spring-boot-rest/src/test/java/com/baeldung/Consts.java rename spring-boot-rest/src/test/java/com/baeldung/{web => }/SpringContextIntegrationTest.java (92%) create mode 100644 spring-boot-rest/src/test/java/com/baeldung/common/web/AbstractBasicLiveTest.java create mode 100644 spring-boot-rest/src/test/java/com/baeldung/common/web/AbstractLiveTest.java create mode 100644 spring-boot-rest/src/test/java/com/baeldung/spring/ConfigIntegrationTest.java create mode 100644 spring-boot-rest/src/test/java/com/baeldung/test/IMarshaller.java create mode 100644 spring-boot-rest/src/test/java/com/baeldung/test/JacksonMarshaller.java create mode 100644 spring-boot-rest/src/test/java/com/baeldung/test/TestMarshallerFactory.java create mode 100644 spring-boot-rest/src/test/java/com/baeldung/web/FooLiveTest.java rename {spring-rest-full/src/test/java/org => spring-boot-rest/src/test/java/com}/baeldung/web/FooPageableLiveTest.java (86%) create mode 100644 spring-boot-rest/src/test/java/com/baeldung/web/LiveTestSuiteLiveTest.java create mode 100644 spring-boot-rest/src/test/java/com/baeldung/web/util/HTTPLinkHeaderUtil.java diff --git a/spring-boot-rest/README.md b/spring-boot-rest/README.md index 2b955ddc5b..2c89a64a00 100644 --- a/spring-boot-rest/README.md +++ b/spring-boot-rest/README.md @@ -2,3 +2,4 @@ Module for the articles that are part of the Spring REST E-book: 1. [Bootstrap a Web Application with Spring 5](https://www.baeldung.com/bootstraping-a-web-application-with-spring-and-java-based-configuration) 2. [Error Handling for REST with Spring](http://www.baeldung.com/exception-handling-for-rest-with-spring) +3. [REST Pagination in Spring](http://www.baeldung.com/rest-api-pagination-in-spring) \ No newline at end of file diff --git a/spring-boot-rest/pom.xml b/spring-boot-rest/pom.xml index f05d242072..bcd0381603 100644 --- a/spring-boot-rest/pom.xml +++ b/spring-boot-rest/pom.xml @@ -1,5 +1,6 @@ - 4.0.0 com.baeldung.web @@ -24,7 +25,7 @@ com.fasterxml.jackson.dataformat jackson-dataformat-xml - + org.hibernate hibernate-entitymanager @@ -32,6 +33,30 @@ org.springframework spring-jdbc + + org.springframework.data + spring-data-jpa + + + com.h2database + h2 + + + org.springframework + spring-tx + + + org.springframework.data + spring-data-commons + + + + + + com.google.guava + guava + ${guava.version} + org.springframework.boot @@ -58,5 +83,6 @@ com.baeldung.SpringBootRestApplication 2.32 + 27.0.1-jre diff --git a/spring-boot-rest/src/main/java/com/baeldung/web/SpringBootRestApplication.java b/spring-boot-rest/src/main/java/com/baeldung/SpringBootRestApplication.java similarity index 92% rename from spring-boot-rest/src/main/java/com/baeldung/web/SpringBootRestApplication.java rename to spring-boot-rest/src/main/java/com/baeldung/SpringBootRestApplication.java index c945b20aa1..62aae7619d 100644 --- a/spring-boot-rest/src/main/java/com/baeldung/web/SpringBootRestApplication.java +++ b/spring-boot-rest/src/main/java/com/baeldung/SpringBootRestApplication.java @@ -1,4 +1,4 @@ -package com.baeldung.web; +package com.baeldung; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; diff --git a/spring-boot-rest/src/main/java/com/baeldung/persistence/IOperations.java b/spring-boot-rest/src/main/java/com/baeldung/persistence/IOperations.java new file mode 100644 index 0000000000..d8996ca50d --- /dev/null +++ b/spring-boot-rest/src/main/java/com/baeldung/persistence/IOperations.java @@ -0,0 +1,16 @@ +package com.baeldung.persistence; + +import java.io.Serializable; + +import org.springframework.data.domain.Page; + +public interface IOperations { + + // read - all + + Page findPaginated(int page, int size); + + // write + + T create(final T entity); +} diff --git a/spring-boot-rest/src/main/java/com/baeldung/persistence/dao/IFooDao.java b/spring-boot-rest/src/main/java/com/baeldung/persistence/dao/IFooDao.java new file mode 100644 index 0000000000..59394d0d28 --- /dev/null +++ b/spring-boot-rest/src/main/java/com/baeldung/persistence/dao/IFooDao.java @@ -0,0 +1,9 @@ +package com.baeldung.persistence.dao; + +import org.springframework.data.jpa.repository.JpaRepository; + +import com.baeldung.persistence.model.Foo; + +public interface IFooDao extends JpaRepository { + +} diff --git a/spring-boot-rest/src/main/java/com/baeldung/persistence/model/Foo.java b/spring-boot-rest/src/main/java/com/baeldung/persistence/model/Foo.java new file mode 100644 index 0000000000..9af3d07bed --- /dev/null +++ b/spring-boot-rest/src/main/java/com/baeldung/persistence/model/Foo.java @@ -0,0 +1,83 @@ +package com.baeldung.persistence.model; + +import java.io.Serializable; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; + +@Entity +public class Foo implements Serializable { + + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + private long id; + + @Column(nullable = false) + private String name; + + public Foo() { + super(); + } + + public Foo(final String name) { + super(); + + this.name = name; + } + + // API + + public long getId() { + return id; + } + + public void setId(final long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(final String name) { + this.name = name; + } + + // + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((name == null) ? 0 : name.hashCode()); + return result; + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + final Foo other = (Foo) obj; + if (name == null) { + if (other.name != null) + return false; + } else if (!name.equals(other.name)) + return false; + return true; + } + + @Override + public String toString() { + final StringBuilder builder = new StringBuilder(); + builder.append("Foo [name=").append(name).append("]"); + return builder.toString(); + } + +} diff --git a/spring-boot-rest/src/main/java/com/baeldung/persistence/service/IFooService.java b/spring-boot-rest/src/main/java/com/baeldung/persistence/service/IFooService.java new file mode 100644 index 0000000000..0f165238eb --- /dev/null +++ b/spring-boot-rest/src/main/java/com/baeldung/persistence/service/IFooService.java @@ -0,0 +1,13 @@ +package com.baeldung.persistence.service; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; + +import com.baeldung.persistence.IOperations; +import com.baeldung.persistence.model.Foo; + +public interface IFooService extends IOperations { + + Page findPaginated(Pageable pageable); + +} diff --git a/spring-boot-rest/src/main/java/com/baeldung/persistence/service/common/AbstractService.java b/spring-boot-rest/src/main/java/com/baeldung/persistence/service/common/AbstractService.java new file mode 100644 index 0000000000..871f768895 --- /dev/null +++ b/spring-boot-rest/src/main/java/com/baeldung/persistence/service/common/AbstractService.java @@ -0,0 +1,31 @@ +package com.baeldung.persistence.service.common; + +import java.io.Serializable; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.repository.PagingAndSortingRepository; +import org.springframework.transaction.annotation.Transactional; + +import com.baeldung.persistence.IOperations; + +@Transactional +public abstract class AbstractService implements IOperations { + + // read - all + + @Override + public Page findPaginated(final int page, final int size) { + return getDao().findAll(PageRequest.of(page, size)); + } + + // write + + @Override + public T create(final T entity) { + return getDao().save(entity); + } + + protected abstract PagingAndSortingRepository getDao(); + +} diff --git a/spring-boot-rest/src/main/java/com/baeldung/persistence/service/impl/FooService.java b/spring-boot-rest/src/main/java/com/baeldung/persistence/service/impl/FooService.java new file mode 100644 index 0000000000..9d705f51d3 --- /dev/null +++ b/spring-boot-rest/src/main/java/com/baeldung/persistence/service/impl/FooService.java @@ -0,0 +1,40 @@ +package com.baeldung.persistence.service.impl; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.repository.PagingAndSortingRepository; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.baeldung.persistence.dao.IFooDao; +import com.baeldung.persistence.model.Foo; +import com.baeldung.persistence.service.IFooService; +import com.baeldung.persistence.service.common.AbstractService; + +@Service +@Transactional +public class FooService extends AbstractService implements IFooService { + + @Autowired + private IFooDao dao; + + public FooService() { + super(); + } + + // API + + @Override + protected PagingAndSortingRepository getDao() { + return dao; + } + + // custom methods + + @Override + public Page findPaginated(Pageable pageable) { + return dao.findAll(pageable); + } + +} diff --git a/spring-boot-rest/src/main/java/com/baeldung/spring/PersistenceConfig.java b/spring-boot-rest/src/main/java/com/baeldung/spring/PersistenceConfig.java new file mode 100644 index 0000000000..4a4b9eee3f --- /dev/null +++ b/spring-boot-rest/src/main/java/com/baeldung/spring/PersistenceConfig.java @@ -0,0 +1,85 @@ +package com.baeldung.spring; + +import java.util.Properties; + +import javax.sql.DataSource; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.PropertySource; +import org.springframework.core.env.Environment; +import org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor; +import org.springframework.data.jpa.repository.config.EnableJpaRepositories; +import org.springframework.jdbc.datasource.DriverManagerDataSource; +import org.springframework.orm.jpa.JpaTransactionManager; +import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; +import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +import com.google.common.base.Preconditions; + +@Configuration +@EnableTransactionManagement +@PropertySource({ "classpath:persistence-${envTarget:h2}.properties" }) +@ComponentScan({ "com.baeldung.persistence" }) +// @ImportResource("classpath*:springDataPersistenceConfig.xml") +@EnableJpaRepositories(basePackages = "com.baeldung.persistence.dao") +public class PersistenceConfig { + + @Autowired + private Environment env; + + public PersistenceConfig() { + super(); + } + + @Bean + public LocalContainerEntityManagerFactoryBean entityManagerFactory() { + final LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean(); + em.setDataSource(dataSource()); + em.setPackagesToScan(new String[] { "com.baeldung.persistence.model" }); + + final HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter(); + // vendorAdapter.set + em.setJpaVendorAdapter(vendorAdapter); + em.setJpaProperties(additionalProperties()); + + return em; + } + + @Bean + public DataSource dataSource() { + final DriverManagerDataSource dataSource = new DriverManagerDataSource(); + dataSource.setDriverClassName(Preconditions.checkNotNull(env.getProperty("jdbc.driverClassName"))); + dataSource.setUrl(Preconditions.checkNotNull(env.getProperty("jdbc.url"))); + dataSource.setUsername(Preconditions.checkNotNull(env.getProperty("jdbc.user"))); + dataSource.setPassword(Preconditions.checkNotNull(env.getProperty("jdbc.pass"))); + + return dataSource; + } + + @Bean + public PlatformTransactionManager transactionManager() { + final JpaTransactionManager transactionManager = new JpaTransactionManager(); + transactionManager.setEntityManagerFactory(entityManagerFactory().getObject()); + + return transactionManager; + } + + @Bean + public PersistenceExceptionTranslationPostProcessor exceptionTranslation() { + return new PersistenceExceptionTranslationPostProcessor(); + } + + final Properties additionalProperties() { + final Properties hibernateProperties = new Properties(); + hibernateProperties.setProperty("hibernate.hbm2ddl.auto", env.getProperty("hibernate.hbm2ddl.auto")); + hibernateProperties.setProperty("hibernate.dialect", env.getProperty("hibernate.dialect")); + // hibernateProperties.setProperty("hibernate.globally_quoted_identifiers", "true"); + return hibernateProperties; + } + +} \ No newline at end of file diff --git a/spring-boot-rest/src/main/java/com/baeldung/spring/WebConfig.java b/spring-boot-rest/src/main/java/com/baeldung/spring/WebConfig.java new file mode 100644 index 0000000000..39aade174b --- /dev/null +++ b/spring-boot-rest/src/main/java/com/baeldung/spring/WebConfig.java @@ -0,0 +1,43 @@ +package com.baeldung.spring; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.MediaType; +import org.springframework.web.servlet.ViewResolver; +import org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import org.springframework.web.servlet.view.InternalResourceViewResolver; + +@Configuration +@ComponentScan("com.baeldung.web") +@EnableWebMvc +public class WebConfig implements WebMvcConfigurer { + + public WebConfig() { + super(); + } + + @Bean + public ViewResolver viewResolver() { + final InternalResourceViewResolver viewResolver = new InternalResourceViewResolver(); + viewResolver.setPrefix("/WEB-INF/view/"); + viewResolver.setSuffix(".jsp"); + return viewResolver; + } + + // API + @Override + public void addViewControllers(final ViewControllerRegistry registry) { + registry.addViewController("/graph.html"); + registry.addViewController("/homepage.html"); + } + + @Override + public void configureContentNegotiation(ContentNegotiationConfigurer configurer) { + configurer.defaultContentType(MediaType.APPLICATION_JSON); + } + +} \ No newline at end of file diff --git a/spring-boot-rest/src/main/java/com/baeldung/web/config/MyErrorController.java b/spring-boot-rest/src/main/java/com/baeldung/web/config/MyErrorController.java index e3716ec113..cf3f9c4dbd 100644 --- a/spring-boot-rest/src/main/java/com/baeldung/web/config/MyErrorController.java +++ b/spring-boot-rest/src/main/java/com/baeldung/web/config/MyErrorController.java @@ -27,5 +27,4 @@ public class MyErrorController extends BasicErrorController { HttpStatus status = getStatus(request); return new ResponseEntity<>(body, status); } - } diff --git a/spring-boot-rest/src/main/java/com/baeldung/web/config/WebConfig.java b/spring-boot-rest/src/main/java/com/baeldung/web/config/WebConfig.java deleted file mode 100644 index 808e946218..0000000000 --- a/spring-boot-rest/src/main/java/com/baeldung/web/config/WebConfig.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.baeldung.web.config; - -import org.springframework.context.annotation.Configuration; - -@Configuration -public class WebConfig { - -} \ No newline at end of file diff --git a/spring-boot-rest/src/main/java/com/baeldung/web/controller/FooController.java b/spring-boot-rest/src/main/java/com/baeldung/web/controller/FooController.java new file mode 100644 index 0000000000..b35295cf99 --- /dev/null +++ b/spring-boot-rest/src/main/java/com/baeldung/web/controller/FooController.java @@ -0,0 +1,89 @@ +package com.baeldung.web.controller; + +import java.util.List; + +import javax.servlet.http.HttpServletResponse; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.util.UriComponentsBuilder; + +import com.baeldung.persistence.model.Foo; +import com.baeldung.persistence.service.IFooService; +import com.baeldung.web.exception.MyResourceNotFoundException; +import com.baeldung.web.hateoas.event.PaginatedResultsRetrievedEvent; +import com.baeldung.web.hateoas.event.ResourceCreatedEvent; +import com.google.common.base.Preconditions; + +@Controller +@RequestMapping(value = "/auth/foos") +public class FooController { + + @Autowired + private ApplicationEventPublisher eventPublisher; + + @Autowired + private IFooService service; + + public FooController() { + super(); + } + + // API + + // read - all + + @RequestMapping(params = { "page", "size" }, method = RequestMethod.GET) + @ResponseBody + public List findPaginated(@RequestParam("page") final int page, @RequestParam("size") final int size, + final UriComponentsBuilder uriBuilder, final HttpServletResponse response) { + final Page resultPage = service.findPaginated(page, size); + if (page > resultPage.getTotalPages()) { + throw new MyResourceNotFoundException(); + } + eventPublisher.publishEvent(new PaginatedResultsRetrievedEvent(Foo.class, uriBuilder, response, page, + resultPage.getTotalPages(), size)); + + return resultPage.getContent(); + } + + @GetMapping("/pageable") + @ResponseBody + public List findPaginatedWithPageable(Pageable pageable, final UriComponentsBuilder uriBuilder, + final HttpServletResponse response) { + final Page resultPage = service.findPaginated(pageable); + if (pageable.getPageNumber() > resultPage.getTotalPages()) { + throw new MyResourceNotFoundException(); + } + eventPublisher.publishEvent(new PaginatedResultsRetrievedEvent(Foo.class, uriBuilder, response, + pageable.getPageNumber(), resultPage.getTotalPages(), pageable.getPageSize())); + + return resultPage.getContent(); + } + + // write + + @RequestMapping(method = RequestMethod.POST) + @ResponseStatus(HttpStatus.CREATED) + @ResponseBody + public Foo create(@RequestBody final Foo resource, final HttpServletResponse response) { + Preconditions.checkNotNull(resource); + final Foo foo = service.create(resource); + final Long idOfCreatedResource = foo.getId(); + + eventPublisher.publishEvent(new ResourceCreatedEvent(this, response, idOfCreatedResource)); + + return foo; + } +} diff --git a/spring-boot-rest/src/main/java/com/baeldung/web/controller/RootController.java b/spring-boot-rest/src/main/java/com/baeldung/web/controller/RootController.java new file mode 100644 index 0000000000..436e41e8eb --- /dev/null +++ b/spring-boot-rest/src/main/java/com/baeldung/web/controller/RootController.java @@ -0,0 +1,40 @@ +package com.baeldung.web.controller; + +import java.net.URI; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.util.UriTemplate; + +import com.baeldung.web.util.LinkUtil; + +@Controller +@RequestMapping(value = "/auth/") +public class RootController { + + public RootController() { + super(); + } + + // API + + // discover + + @RequestMapping(value = "admin", method = RequestMethod.GET) + @ResponseStatus(value = HttpStatus.NO_CONTENT) + public void adminRoot(final HttpServletRequest request, final HttpServletResponse response) { + final String rootUri = request.getRequestURL() + .toString(); + + final URI fooUri = new UriTemplate("{rootUri}/{resource}").expand(rootUri, "foo"); + final String linkToFoo = LinkUtil.createLinkHeader(fooUri.toASCIIString(), "collection"); + response.addHeader("Link", linkToFoo); + } + +} diff --git a/spring-rest-full/src/main/java/org/baeldung/web/hateoas/event/PaginatedResultsRetrievedEvent.java b/spring-boot-rest/src/main/java/com/baeldung/web/hateoas/event/PaginatedResultsRetrievedEvent.java similarity index 97% rename from spring-rest-full/src/main/java/org/baeldung/web/hateoas/event/PaginatedResultsRetrievedEvent.java rename to spring-boot-rest/src/main/java/com/baeldung/web/hateoas/event/PaginatedResultsRetrievedEvent.java index 01f7e658f1..f62fbf6247 100644 --- a/spring-rest-full/src/main/java/org/baeldung/web/hateoas/event/PaginatedResultsRetrievedEvent.java +++ b/spring-boot-rest/src/main/java/com/baeldung/web/hateoas/event/PaginatedResultsRetrievedEvent.java @@ -1,4 +1,4 @@ -package org.baeldung.web.hateoas.event; +package com.baeldung.web.hateoas.event; import java.io.Serializable; diff --git a/spring-boot-rest/src/main/java/com/baeldung/web/hateoas/event/ResourceCreatedEvent.java b/spring-boot-rest/src/main/java/com/baeldung/web/hateoas/event/ResourceCreatedEvent.java new file mode 100644 index 0000000000..b602f7ec4b --- /dev/null +++ b/spring-boot-rest/src/main/java/com/baeldung/web/hateoas/event/ResourceCreatedEvent.java @@ -0,0 +1,28 @@ +package com.baeldung.web.hateoas.event; + +import javax.servlet.http.HttpServletResponse; + +import org.springframework.context.ApplicationEvent; + +public class ResourceCreatedEvent extends ApplicationEvent { + private final HttpServletResponse response; + private final long idOfNewResource; + + public ResourceCreatedEvent(final Object source, final HttpServletResponse response, final long idOfNewResource) { + super(source); + + this.response = response; + this.idOfNewResource = idOfNewResource; + } + + // API + + public HttpServletResponse getResponse() { + return response; + } + + public long getIdOfNewResource() { + return idOfNewResource; + } + +} diff --git a/spring-rest-full/src/main/java/org/baeldung/web/hateoas/listener/PaginatedResultsRetrievedDiscoverabilityListener.java b/spring-boot-rest/src/main/java/com/baeldung/web/hateoas/listener/PaginatedResultsRetrievedDiscoverabilityListener.java similarity index 96% rename from spring-rest-full/src/main/java/org/baeldung/web/hateoas/listener/PaginatedResultsRetrievedDiscoverabilityListener.java rename to spring-boot-rest/src/main/java/com/baeldung/web/hateoas/listener/PaginatedResultsRetrievedDiscoverabilityListener.java index 603c91007d..bb60bab171 100644 --- a/spring-rest-full/src/main/java/org/baeldung/web/hateoas/listener/PaginatedResultsRetrievedDiscoverabilityListener.java +++ b/spring-boot-rest/src/main/java/com/baeldung/web/hateoas/listener/PaginatedResultsRetrievedDiscoverabilityListener.java @@ -1,13 +1,13 @@ -package org.baeldung.web.hateoas.listener; +package com.baeldung.web.hateoas.listener; import javax.servlet.http.HttpServletResponse; -import org.baeldung.web.hateoas.event.PaginatedResultsRetrievedEvent; -import org.baeldung.web.util.LinkUtil; import org.springframework.context.ApplicationListener; import org.springframework.stereotype.Component; import org.springframework.web.util.UriComponentsBuilder; +import com.baeldung.web.hateoas.event.PaginatedResultsRetrievedEvent; +import com.baeldung.web.util.LinkUtil; import com.google.common.base.Preconditions; import com.google.common.net.HttpHeaders; diff --git a/spring-boot-rest/src/main/java/com/baeldung/web/hateoas/listener/ResourceCreatedDiscoverabilityListener.java b/spring-boot-rest/src/main/java/com/baeldung/web/hateoas/listener/ResourceCreatedDiscoverabilityListener.java new file mode 100644 index 0000000000..37afcdace4 --- /dev/null +++ b/spring-boot-rest/src/main/java/com/baeldung/web/hateoas/listener/ResourceCreatedDiscoverabilityListener.java @@ -0,0 +1,36 @@ +package com.baeldung.web.hateoas.listener; + +import java.net.URI; + +import javax.servlet.http.HttpServletResponse; + +import org.apache.http.HttpHeaders; +import com.baeldung.web.hateoas.event.ResourceCreatedEvent; +import org.springframework.context.ApplicationListener; +import org.springframework.stereotype.Component; +import org.springframework.web.servlet.support.ServletUriComponentsBuilder; + +import com.google.common.base.Preconditions; + +@Component +class ResourceCreatedDiscoverabilityListener implements ApplicationListener { + + @Override + public void onApplicationEvent(final ResourceCreatedEvent resourceCreatedEvent) { + Preconditions.checkNotNull(resourceCreatedEvent); + + final HttpServletResponse response = resourceCreatedEvent.getResponse(); + final long idOfNewResource = resourceCreatedEvent.getIdOfNewResource(); + + addLinkHeaderOnResourceCreation(response, idOfNewResource); + } + + void addLinkHeaderOnResourceCreation(final HttpServletResponse response, final long idOfNewResource) { + // final String requestUrl = request.getRequestURL().toString(); + // final URI uri = new UriTemplate("{requestUrl}/{idOfNewResource}").expand(requestUrl, idOfNewResource); + + final URI uri = ServletUriComponentsBuilder.fromCurrentRequestUri().path("/{idOfNewResource}").buildAndExpand(idOfNewResource).toUri(); + response.setHeader(HttpHeaders.LOCATION, uri.toASCIIString()); + } + +} \ No newline at end of file diff --git a/spring-boot-rest/src/main/java/com/baeldung/web/util/LinkUtil.java b/spring-boot-rest/src/main/java/com/baeldung/web/util/LinkUtil.java new file mode 100644 index 0000000000..3ebba8ae1c --- /dev/null +++ b/spring-boot-rest/src/main/java/com/baeldung/web/util/LinkUtil.java @@ -0,0 +1,36 @@ +package com.baeldung.web.util; + +import javax.servlet.http.HttpServletResponse; + +/** + * Provides some constants and utility methods to build a Link Header to be stored in the {@link HttpServletResponse} object + */ +public final class LinkUtil { + + public static final String REL_COLLECTION = "collection"; + public static final String REL_NEXT = "next"; + public static final String REL_PREV = "prev"; + public static final String REL_FIRST = "first"; + public static final String REL_LAST = "last"; + + private LinkUtil() { + throw new AssertionError(); + } + + // + + /** + * Creates a Link Header to be stored in the {@link HttpServletResponse} to provide Discoverability features to the user + * + * @param uri + * the base uri + * @param rel + * the relative path + * + * @return the complete url + */ + public static String createLinkHeader(final String uri, final String rel) { + return "<" + uri + ">; rel=\"" + rel + "\""; + } + +} diff --git a/spring-boot-rest/src/main/java/com/baeldung/web/util/RestPreconditions.java b/spring-boot-rest/src/main/java/com/baeldung/web/util/RestPreconditions.java new file mode 100644 index 0000000000..d86aeeebd1 --- /dev/null +++ b/spring-boot-rest/src/main/java/com/baeldung/web/util/RestPreconditions.java @@ -0,0 +1,48 @@ +package com.baeldung.web.util; + +import org.springframework.http.HttpStatus; + +import com.baeldung.web.exception.MyResourceNotFoundException; + +/** + * Simple static methods to be called at the start of your own methods to verify correct arguments and state. If the Precondition fails, an {@link HttpStatus} code is thrown + */ +public final class RestPreconditions { + + private RestPreconditions() { + throw new AssertionError(); + } + + // API + + /** + * Check if some value was found, otherwise throw exception. + * + * @param expression + * has value true if found, otherwise false + * @throws MyResourceNotFoundException + * if expression is false, means value not found. + */ + public static void checkFound(final boolean expression) { + if (!expression) { + throw new MyResourceNotFoundException(); + } + } + + /** + * Check if some value was found, otherwise throw exception. + * + * @param expression + * has value true if found, otherwise false + * @throws MyResourceNotFoundException + * if expression is false, means value not found. + */ + public static T checkFound(final T resource) { + if (resource == null) { + throw new MyResourceNotFoundException(); + } + + return resource; + } + +} diff --git a/spring-boot-rest/src/main/resources/application.properties b/spring-boot-rest/src/main/resources/application.properties index e65440e2b9..a0179f1e4b 100644 --- a/spring-boot-rest/src/main/resources/application.properties +++ b/spring-boot-rest/src/main/resources/application.properties @@ -1,3 +1,6 @@ +server.port=8082 +server.servlet.context-path=/spring-boot-rest + ### Spring Boot default error handling configurations #server.error.whitelabel.enabled=false #server.error.include-stacktrace=always \ No newline at end of file diff --git a/spring-boot-rest/src/main/resources/persistence-h2.properties b/spring-boot-rest/src/main/resources/persistence-h2.properties new file mode 100644 index 0000000000..839a466533 --- /dev/null +++ b/spring-boot-rest/src/main/resources/persistence-h2.properties @@ -0,0 +1,22 @@ +## jdbc.X +#jdbc.driverClassName=com.mysql.jdbc.Driver +#jdbc.url=jdbc:mysql://localhost:3306/spring_hibernate4_01?createDatabaseIfNotExist=true +#jdbc.user=tutorialuser +#jdbc.pass=tutorialmy5ql +# +## hibernate.X +#hibernate.dialect=org.hibernate.dialect.MySQL5Dialect +#hibernate.show_sql=false +#hibernate.hbm2ddl.auto=create-drop + + +# jdbc.X +jdbc.driverClassName=org.h2.Driver +jdbc.url=jdbc:h2:mem:security_permission;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE +jdbc.user=sa +jdbc.pass= + +# hibernate.X +hibernate.dialect=org.hibernate.dialect.H2Dialect +hibernate.show_sql=false +hibernate.hbm2ddl.auto=create-drop diff --git a/spring-boot-rest/src/main/resources/persistence-mysql.properties b/spring-boot-rest/src/main/resources/persistence-mysql.properties new file mode 100644 index 0000000000..8263b0d9ac --- /dev/null +++ b/spring-boot-rest/src/main/resources/persistence-mysql.properties @@ -0,0 +1,10 @@ +# jdbc.X +jdbc.driverClassName=com.mysql.jdbc.Driver +jdbc.url=jdbc:mysql://localhost:3306/spring_hibernate4_01?createDatabaseIfNotExist=true +jdbc.user=tutorialuser +jdbc.pass=tutorialmy5ql + +# hibernate.X +hibernate.dialect=org.hibernate.dialect.MySQL5Dialect +hibernate.show_sql=false +hibernate.hbm2ddl.auto=create-drop diff --git a/spring-boot-rest/src/main/resources/springDataPersistenceConfig.xml b/spring-boot-rest/src/main/resources/springDataPersistenceConfig.xml new file mode 100644 index 0000000000..5ea2d9c05b --- /dev/null +++ b/spring-boot-rest/src/main/resources/springDataPersistenceConfig.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/spring-boot-rest/src/test/java/com/baeldung/Consts.java b/spring-boot-rest/src/test/java/com/baeldung/Consts.java new file mode 100644 index 0000000000..e33efd589e --- /dev/null +++ b/spring-boot-rest/src/test/java/com/baeldung/Consts.java @@ -0,0 +1,5 @@ +package com.baeldung; + +public interface Consts { + int APPLICATION_PORT = 8082; +} diff --git a/spring-boot-rest/src/test/java/com/baeldung/web/SpringContextIntegrationTest.java b/spring-boot-rest/src/test/java/com/baeldung/SpringContextIntegrationTest.java similarity index 92% rename from spring-boot-rest/src/test/java/com/baeldung/web/SpringContextIntegrationTest.java rename to spring-boot-rest/src/test/java/com/baeldung/SpringContextIntegrationTest.java index 1e49df2909..25fbc4cc02 100644 --- a/spring-boot-rest/src/test/java/com/baeldung/web/SpringContextIntegrationTest.java +++ b/spring-boot-rest/src/test/java/com/baeldung/SpringContextIntegrationTest.java @@ -1,4 +1,4 @@ -package com.baeldung.web; +package com.baeldung; import org.junit.Test; import org.junit.runner.RunWith; diff --git a/spring-boot-rest/src/test/java/com/baeldung/common/web/AbstractBasicLiveTest.java b/spring-boot-rest/src/test/java/com/baeldung/common/web/AbstractBasicLiveTest.java new file mode 100644 index 0000000000..61eb9400cc --- /dev/null +++ b/spring-boot-rest/src/test/java/com/baeldung/common/web/AbstractBasicLiveTest.java @@ -0,0 +1,103 @@ +package com.baeldung.common.web; + +import static com.baeldung.web.util.HTTPLinkHeaderUtil.extractURIByRel; +import static org.apache.commons.lang3.RandomStringUtils.randomNumeric; +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertThat; + +import java.io.Serializable; +import java.util.List; + +import org.junit.Test; + +import com.google.common.net.HttpHeaders; + +import io.restassured.RestAssured; +import io.restassured.response.Response; + +public abstract class AbstractBasicLiveTest extends AbstractLiveTest { + + public AbstractBasicLiveTest(final Class clazzToSet) { + super(clazzToSet); + } + + // find - all - paginated + + @Test + public void whenResourcesAreRetrievedPaged_then200IsReceived() { + create(); + + final Response response = RestAssured.get(getURL() + "?page=0&size=10"); + + assertThat(response.getStatusCode(), is(200)); + } + + @Test + public void whenPageOfResourcesAreRetrievedOutOfBounds_then404IsReceived() { + final String url = getURL() + "?page=" + randomNumeric(5) + "&size=10"; + final Response response = RestAssured.get(url); + + assertThat(response.getStatusCode(), is(404)); + } + + @Test + public void givenResourcesExist_whenFirstPageIsRetrieved_thenPageContainsResources() { + create(); + + final Response response = RestAssured.get(getURL() + "?page=0&size=10"); + + assertFalse(response.body().as(List.class).isEmpty()); + } + + @Test + public void whenFirstPageOfResourcesAreRetrieved_thenSecondPageIsNext() { + create(); + create(); + create(); + + final Response response = RestAssured.get(getURL() + "?page=0&size=2"); + + final String uriToNextPage = extractURIByRel(response.getHeader(HttpHeaders.LINK), "next"); + assertEquals(getURL() + "?page=1&size=2", uriToNextPage); + } + + @Test + public void whenFirstPageOfResourcesAreRetrieved_thenNoPreviousPage() { + final Response response = RestAssured.get(getURL() + "?page=0&size=2"); + + final String uriToPrevPage = extractURIByRel(response.getHeader(HttpHeaders.LINK), "prev"); + assertNull(uriToPrevPage); + } + + @Test + public void whenSecondPageOfResourcesAreRetrieved_thenFirstPageIsPrevious() { + create(); + create(); + + final Response response = RestAssured.get(getURL() + "?page=1&size=2"); + + final String uriToPrevPage = extractURIByRel(response.getHeader(HttpHeaders.LINK), "prev"); + assertEquals(getURL() + "?page=0&size=2", uriToPrevPage); + } + + @Test + public void whenLastPageOfResourcesIsRetrieved_thenNoNextPageIsDiscoverable() { + create(); + create(); + create(); + + final Response first = RestAssured.get(getURL() + "?page=0&size=2"); + final String uriToLastPage = extractURIByRel(first.getHeader(HttpHeaders.LINK), "last"); + + final Response response = RestAssured.get(uriToLastPage); + + final String uriToNextPage = extractURIByRel(response.getHeader(HttpHeaders.LINK), "next"); + assertNull(uriToNextPage); + } + + // count + +} diff --git a/spring-boot-rest/src/test/java/com/baeldung/common/web/AbstractLiveTest.java b/spring-boot-rest/src/test/java/com/baeldung/common/web/AbstractLiveTest.java new file mode 100644 index 0000000000..d26632bc38 --- /dev/null +++ b/spring-boot-rest/src/test/java/com/baeldung/common/web/AbstractLiveTest.java @@ -0,0 +1,65 @@ +package com.baeldung.common.web; + +import io.restassured.RestAssured; +import io.restassured.response.Response; + +import static com.baeldung.Consts.APPLICATION_PORT; + +import java.io.Serializable; + +import org.springframework.beans.factory.annotation.Autowired; + +import com.baeldung.test.IMarshaller; +import com.google.common.base.Preconditions; +import com.google.common.net.HttpHeaders; + +public abstract class AbstractLiveTest { + + protected final Class clazz; + + @Autowired + protected IMarshaller marshaller; + + public AbstractLiveTest(final Class clazzToSet) { + super(); + + Preconditions.checkNotNull(clazzToSet); + clazz = clazzToSet; + } + + // template method + + public abstract void create(); + + public abstract String createAsUri(); + + protected final void create(final T resource) { + createAsUri(resource); + } + + protected final String createAsUri(final T resource) { + final Response response = createAsResponse(resource); + Preconditions.checkState(response.getStatusCode() == 201, "create operation: " + response.getStatusCode()); + + final String locationOfCreatedResource = response.getHeader(HttpHeaders.LOCATION); + Preconditions.checkNotNull(locationOfCreatedResource); + return locationOfCreatedResource; + } + + final Response createAsResponse(final T resource) { + Preconditions.checkNotNull(resource); + + final String resourceAsString = marshaller.encode(resource); + return RestAssured.given() + .contentType(marshaller.getMime()) + .body(resourceAsString) + .post(getURL()); + } + + // + + protected String getURL() { + return "http://localhost:" + APPLICATION_PORT + "/spring-boot-rest/auth/foos"; + } + +} diff --git a/spring-boot-rest/src/test/java/com/baeldung/spring/ConfigIntegrationTest.java b/spring-boot-rest/src/test/java/com/baeldung/spring/ConfigIntegrationTest.java new file mode 100644 index 0000000000..da8421ea6c --- /dev/null +++ b/spring-boot-rest/src/test/java/com/baeldung/spring/ConfigIntegrationTest.java @@ -0,0 +1,17 @@ +package com.baeldung.spring; + +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +@Configuration +@ComponentScan("com.baeldung.test") +public class ConfigIntegrationTest implements WebMvcConfigurer { + + public ConfigIntegrationTest() { + super(); + } + + // API + +} \ No newline at end of file diff --git a/spring-boot-rest/src/test/java/com/baeldung/test/IMarshaller.java b/spring-boot-rest/src/test/java/com/baeldung/test/IMarshaller.java new file mode 100644 index 0000000000..e2198ecb59 --- /dev/null +++ b/spring-boot-rest/src/test/java/com/baeldung/test/IMarshaller.java @@ -0,0 +1,15 @@ +package com.baeldung.test; + +import java.util.List; + +public interface IMarshaller { + + String encode(final T entity); + + T decode(final String entityAsString, final Class clazz); + + List decodeList(final String entitiesAsString, final Class clazz); + + String getMime(); + +} diff --git a/spring-boot-rest/src/test/java/com/baeldung/test/JacksonMarshaller.java b/spring-boot-rest/src/test/java/com/baeldung/test/JacksonMarshaller.java new file mode 100644 index 0000000000..23b5d60b6b --- /dev/null +++ b/spring-boot-rest/src/test/java/com/baeldung/test/JacksonMarshaller.java @@ -0,0 +1,81 @@ +package com.baeldung.test; + +import java.io.IOException; +import java.util.List; + +import com.baeldung.persistence.model.Foo; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.MediaType; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.common.base.Preconditions; + +public final class JacksonMarshaller implements IMarshaller { + private final Logger logger = LoggerFactory.getLogger(JacksonMarshaller.class); + + private final ObjectMapper objectMapper; + + public JacksonMarshaller() { + super(); + + objectMapper = new ObjectMapper(); + } + + // API + + @Override + public final String encode(final T resource) { + Preconditions.checkNotNull(resource); + String entityAsJSON = null; + try { + entityAsJSON = objectMapper.writeValueAsString(resource); + } catch (final IOException ioEx) { + logger.error("", ioEx); + } + + return entityAsJSON; + } + + @Override + public final T decode(final String resourceAsString, final Class clazz) { + Preconditions.checkNotNull(resourceAsString); + + T entity = null; + try { + entity = objectMapper.readValue(resourceAsString, clazz); + } catch (final IOException ioEx) { + logger.error("", ioEx); + } + + return entity; + } + + @SuppressWarnings("unchecked") + @Override + public final List decodeList(final String resourcesAsString, final Class clazz) { + Preconditions.checkNotNull(resourcesAsString); + + List entities = null; + try { + if (clazz.equals(Foo.class)) { + entities = objectMapper.readValue(resourcesAsString, new TypeReference>() { + // ... + }); + } else { + entities = objectMapper.readValue(resourcesAsString, List.class); + } + } catch (final IOException ioEx) { + logger.error("", ioEx); + } + + return entities; + } + + @Override + public final String getMime() { + return MediaType.APPLICATION_JSON.toString(); + } + +} diff --git a/spring-boot-rest/src/test/java/com/baeldung/test/TestMarshallerFactory.java b/spring-boot-rest/src/test/java/com/baeldung/test/TestMarshallerFactory.java new file mode 100644 index 0000000000..740ee07839 --- /dev/null +++ b/spring-boot-rest/src/test/java/com/baeldung/test/TestMarshallerFactory.java @@ -0,0 +1,49 @@ +package com.baeldung.test; + +import org.springframework.beans.factory.FactoryBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Profile; +import org.springframework.core.env.Environment; +import org.springframework.stereotype.Component; + +@Component +@Profile("test") +public class TestMarshallerFactory implements FactoryBean { + + @Autowired + private Environment env; + + public TestMarshallerFactory() { + super(); + } + + // API + + @Override + public IMarshaller getObject() { + final String testMime = env.getProperty("test.mime"); + if (testMime != null) { + switch (testMime) { + case "json": + return new JacksonMarshaller(); + case "xml": + // If we need to implement xml marshaller we can include spring-rest-full XStreamMarshaller + throw new IllegalStateException(); + default: + throw new IllegalStateException(); + } + } + + return new JacksonMarshaller(); + } + + @Override + public Class getObjectType() { + return IMarshaller.class; + } + + @Override + public boolean isSingleton() { + return true; + } +} \ No newline at end of file diff --git a/spring-boot-rest/src/test/java/com/baeldung/web/FooLiveTest.java b/spring-boot-rest/src/test/java/com/baeldung/web/FooLiveTest.java new file mode 100644 index 0000000000..f721489eff --- /dev/null +++ b/spring-boot-rest/src/test/java/com/baeldung/web/FooLiveTest.java @@ -0,0 +1,36 @@ +package com.baeldung.web; + +import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic; + +import org.junit.runner.RunWith; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.context.support.AnnotationConfigContextLoader; + +import com.baeldung.common.web.AbstractBasicLiveTest; +import com.baeldung.persistence.model.Foo; +import com.baeldung.spring.ConfigIntegrationTest; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(classes = { ConfigIntegrationTest.class }, loader = AnnotationConfigContextLoader.class) +@ActiveProfiles("test") +public class FooLiveTest extends AbstractBasicLiveTest { + + public FooLiveTest() { + super(Foo.class); + } + + // API + + @Override + public final void create() { + create(new Foo(randomAlphabetic(6))); + } + + @Override + public final String createAsUri() { + return createAsUri(new Foo(randomAlphabetic(6))); + } + +} diff --git a/spring-rest-full/src/test/java/org/baeldung/web/FooPageableLiveTest.java b/spring-boot-rest/src/test/java/com/baeldung/web/FooPageableLiveTest.java similarity index 86% rename from spring-rest-full/src/test/java/org/baeldung/web/FooPageableLiveTest.java rename to spring-boot-rest/src/test/java/com/baeldung/web/FooPageableLiveTest.java index 3f637c5213..359a62a4d8 100644 --- a/spring-rest-full/src/test/java/org/baeldung/web/FooPageableLiveTest.java +++ b/spring-boot-rest/src/test/java/com/baeldung/web/FooPageableLiveTest.java @@ -1,19 +1,14 @@ -package org.baeldung.web; +package com.baeldung.web; +import static com.baeldung.Consts.APPLICATION_PORT; import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic; import static org.apache.commons.lang3.RandomStringUtils.randomNumeric; -import static org.baeldung.Consts.APPLICATION_PORT; import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertThat; -import io.restassured.RestAssured; -import io.restassured.response.Response; import java.util.List; -import org.baeldung.common.web.AbstractBasicLiveTest; -import org.baeldung.persistence.model.Foo; -import org.baeldung.spring.ConfigIntegrationTest; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.test.context.ActiveProfiles; @@ -21,6 +16,13 @@ import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.support.AnnotationConfigContextLoader; +import com.baeldung.common.web.AbstractBasicLiveTest; +import com.baeldung.persistence.model.Foo; +import com.baeldung.spring.ConfigIntegrationTest; + +import io.restassured.RestAssured; +import io.restassured.response.Response; + @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = { ConfigIntegrationTest.class }, loader = AnnotationConfigContextLoader.class) @ActiveProfiles("test") @@ -34,7 +36,7 @@ public class FooPageableLiveTest extends AbstractBasicLiveTest { @Override public final void create() { - create(new Foo(randomAlphabetic(6))); + super.create(new Foo(randomAlphabetic(6))); } @Override @@ -45,6 +47,8 @@ public class FooPageableLiveTest extends AbstractBasicLiveTest { @Override @Test public void whenResourcesAreRetrievedPaged_then200IsReceived() { + this.create(); + final Response response = RestAssured.get(getPageableURL() + "?page=0&size=10"); assertThat(response.getStatusCode(), is(200)); @@ -70,7 +74,7 @@ public class FooPageableLiveTest extends AbstractBasicLiveTest { } protected String getPageableURL() { - return "http://localhost:" + APPLICATION_PORT + "/spring-rest-full/auth/foos/pageable"; + return "http://localhost:" + APPLICATION_PORT + "/spring-boot-rest/auth/foos/pageable"; } } diff --git a/spring-boot-rest/src/test/java/com/baeldung/web/LiveTestSuiteLiveTest.java b/spring-boot-rest/src/test/java/com/baeldung/web/LiveTestSuiteLiveTest.java new file mode 100644 index 0000000000..1e2ddd5ec5 --- /dev/null +++ b/spring-boot-rest/src/test/java/com/baeldung/web/LiveTestSuiteLiveTest.java @@ -0,0 +1,14 @@ +package com.baeldung.web; + +import org.junit.runner.RunWith; +import org.junit.runners.Suite; + +@RunWith(Suite.class) +@Suite.SuiteClasses({ +// @formatter:off + FooLiveTest.class + ,FooPageableLiveTest.class +}) // +public class LiveTestSuiteLiveTest { + +} diff --git a/spring-boot-rest/src/test/java/com/baeldung/web/error/ErrorHandlingLiveTest.java b/spring-boot-rest/src/test/java/com/baeldung/web/error/ErrorHandlingLiveTest.java index ea1b6ab227..3e21af524f 100644 --- a/spring-boot-rest/src/test/java/com/baeldung/web/error/ErrorHandlingLiveTest.java +++ b/spring-boot-rest/src/test/java/com/baeldung/web/error/ErrorHandlingLiveTest.java @@ -6,6 +6,7 @@ import static org.hamcrest.Matchers.hasKey; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.isA; import static org.hamcrest.Matchers.not; +import static com.baeldung.Consts.APPLICATION_PORT; import org.junit.jupiter.api.Test; import org.springframework.http.HttpHeaders; @@ -16,8 +17,8 @@ import com.gargoylesoftware.htmlunit.html.HtmlPage; public class ErrorHandlingLiveTest { - private static final String BASE_URL = "http://localhost:8080"; - private static final String EXCEPTION_ENDPOINT = "/exception"; + private static final String BASE_URL = "http://localhost:" + APPLICATION_PORT + "/spring-boot-rest"; + private static final String EXCEPTION_ENDPOINT = BASE_URL + "/exception"; private static final String ERROR_RESPONSE_KEY_PATH = "error"; private static final String XML_RESPONSE_KEY_PATH = "xmlkey"; @@ -57,7 +58,7 @@ public class ErrorHandlingLiveTest { try (WebClient webClient = new WebClient()) { webClient.getOptions() .setThrowExceptionOnFailingStatusCode(false); - HtmlPage page = webClient.getPage(BASE_URL + EXCEPTION_ENDPOINT); + HtmlPage page = webClient.getPage(EXCEPTION_ENDPOINT); assertThat(page.getBody() .asText()).contains("Whitelabel Error Page"); } diff --git a/spring-boot-rest/src/test/java/com/baeldung/web/util/HTTPLinkHeaderUtil.java b/spring-boot-rest/src/test/java/com/baeldung/web/util/HTTPLinkHeaderUtil.java new file mode 100644 index 0000000000..54d62b64e8 --- /dev/null +++ b/spring-boot-rest/src/test/java/com/baeldung/web/util/HTTPLinkHeaderUtil.java @@ -0,0 +1,36 @@ +package com.baeldung.web.util; + +public final class HTTPLinkHeaderUtil { + + private HTTPLinkHeaderUtil() { + throw new AssertionError(); + } + + // + + public static String extractURIByRel(final String linkHeader, final String rel) { + if (linkHeader == null) { + return null; + } + + String uriWithSpecifiedRel = null; + final String[] links = linkHeader.split(", "); + String linkRelation; + for (final String link : links) { + final int positionOfSeparator = link.indexOf(';'); + linkRelation = link.substring(positionOfSeparator + 1, link.length()).trim(); + if (extractTypeOfRelation(linkRelation).equals(rel)) { + uriWithSpecifiedRel = link.substring(1, positionOfSeparator - 1); + break; + } + } + + return uriWithSpecifiedRel; + } + + private static Object extractTypeOfRelation(final String linkRelation) { + final int positionOfEquals = linkRelation.indexOf('='); + return linkRelation.substring(positionOfEquals + 2, linkRelation.length() - 1).trim(); + } + +} diff --git a/spring-rest-full/README.md b/spring-rest-full/README.md index 3a8d0a727a..2ef3a09e37 100644 --- a/spring-rest-full/README.md +++ b/spring-rest-full/README.md @@ -8,7 +8,6 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring The "Learn Spring Security" Classes: http://github.learnspringsecurity.com ### Relevant Articles: -- [REST Pagination in Spring](http://www.baeldung.com/rest-api-pagination-in-spring) - [HATEOAS for a Spring REST Service](http://www.baeldung.com/rest-api-discoverability-with-spring) - [REST API Discoverability and HATEOAS](http://www.baeldung.com/restful-web-service-discoverability) - [ETags for REST with Spring](http://www.baeldung.com/etags-for-rest-with-spring) diff --git a/spring-rest-full/src/main/java/org/baeldung/persistence/IOperations.java b/spring-rest-full/src/main/java/org/baeldung/persistence/IOperations.java index d4f3f0982c..8c5593c3e8 100644 --- a/spring-rest-full/src/main/java/org/baeldung/persistence/IOperations.java +++ b/spring-rest-full/src/main/java/org/baeldung/persistence/IOperations.java @@ -3,8 +3,6 @@ package org.baeldung.persistence; import java.io.Serializable; import java.util.List; -import org.springframework.data.domain.Page; - public interface IOperations { // read - one @@ -15,8 +13,6 @@ public interface IOperations { List findAll(); - Page findPaginated(int page, int size); - // write T create(final T entity); diff --git a/spring-rest-full/src/main/java/org/baeldung/persistence/service/IFooService.java b/spring-rest-full/src/main/java/org/baeldung/persistence/service/IFooService.java index a3d16d9c15..60d607b9ef 100644 --- a/spring-rest-full/src/main/java/org/baeldung/persistence/service/IFooService.java +++ b/spring-rest-full/src/main/java/org/baeldung/persistence/service/IFooService.java @@ -2,13 +2,9 @@ package org.baeldung.persistence.service; import org.baeldung.persistence.IOperations; import org.baeldung.persistence.model.Foo; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; public interface IFooService extends IOperations { Foo retrieveByName(String name); - - Page findPaginated(Pageable pageable); } diff --git a/spring-rest-full/src/main/java/org/baeldung/persistence/service/common/AbstractService.java b/spring-rest-full/src/main/java/org/baeldung/persistence/service/common/AbstractService.java index 5987bbae5f..59ccea8b12 100644 --- a/spring-rest-full/src/main/java/org/baeldung/persistence/service/common/AbstractService.java +++ b/spring-rest-full/src/main/java/org/baeldung/persistence/service/common/AbstractService.java @@ -4,8 +4,6 @@ import java.io.Serializable; import java.util.List; import org.baeldung.persistence.IOperations; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.PageRequest; import org.springframework.data.repository.PagingAndSortingRepository; import org.springframework.transaction.annotation.Transactional; @@ -30,11 +28,6 @@ public abstract class AbstractService implements IOperat return Lists.newArrayList(getDao().findAll()); } - @Override - public Page findPaginated(final int page, final int size) { - return getDao().findAll(new PageRequest(page, size)); - } - // write @Override diff --git a/spring-rest-full/src/main/java/org/baeldung/persistence/service/impl/FooService.java b/spring-rest-full/src/main/java/org/baeldung/persistence/service/impl/FooService.java index 376082b2d5..d46f1bfe90 100644 --- a/spring-rest-full/src/main/java/org/baeldung/persistence/service/impl/FooService.java +++ b/spring-rest-full/src/main/java/org/baeldung/persistence/service/impl/FooService.java @@ -7,8 +7,6 @@ import org.baeldung.persistence.model.Foo; import org.baeldung.persistence.service.IFooService; import org.baeldung.persistence.service.common.AbstractService; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; import org.springframework.data.repository.PagingAndSortingRepository; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -48,9 +46,4 @@ public class FooService extends AbstractService implements IFooService { return Lists.newArrayList(getDao().findAll()); } - @Override - public Page findPaginated(Pageable pageable) { - return dao.findAll(pageable); - } - } diff --git a/spring-rest-full/src/main/java/org/baeldung/web/controller/FooController.java b/spring-rest-full/src/main/java/org/baeldung/web/controller/FooController.java index 484a59f8ef..443d0908ee 100644 --- a/spring-rest-full/src/main/java/org/baeldung/web/controller/FooController.java +++ b/spring-rest-full/src/main/java/org/baeldung/web/controller/FooController.java @@ -6,27 +6,20 @@ import javax.servlet.http.HttpServletResponse; import org.baeldung.persistence.model.Foo; import org.baeldung.persistence.service.IFooService; -import org.baeldung.web.exception.MyResourceNotFoundException; -import org.baeldung.web.hateoas.event.PaginatedResultsRetrievedEvent; import org.baeldung.web.hateoas.event.ResourceCreatedEvent; import org.baeldung.web.hateoas.event.SingleResourceRetrievedEvent; import org.baeldung.web.util.RestPreconditions; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationEventPublisher; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseStatus; -import org.springframework.web.util.UriComponentsBuilder; import com.google.common.base.Preconditions; @@ -72,30 +65,6 @@ public class FooController { return service.findAll(); } - @RequestMapping(params = { "page", "size" }, method = RequestMethod.GET) - @ResponseBody - public List findPaginated(@RequestParam("page") final int page, @RequestParam("size") final int size, final UriComponentsBuilder uriBuilder, final HttpServletResponse response) { - final Page resultPage = service.findPaginated(page, size); - if (page > resultPage.getTotalPages()) { - throw new MyResourceNotFoundException(); - } - eventPublisher.publishEvent(new PaginatedResultsRetrievedEvent(Foo.class, uriBuilder, response, page, resultPage.getTotalPages(), size)); - - return resultPage.getContent(); - } - - @GetMapping("/pageable") - @ResponseBody - public List findPaginatedWithPageable(Pageable pageable, final UriComponentsBuilder uriBuilder, final HttpServletResponse response) { - final Page resultPage = service.findPaginated(pageable); - if (pageable.getPageNumber() > resultPage.getTotalPages()) { - throw new MyResourceNotFoundException(); - } - eventPublisher.publishEvent(new PaginatedResultsRetrievedEvent(Foo.class, uriBuilder, response, pageable.getPageNumber(), resultPage.getTotalPages(), pageable.getPageSize())); - - return resultPage.getContent(); - } - // write @RequestMapping(method = RequestMethod.POST) diff --git a/spring-rest-full/src/main/java/org/baeldung/web/util/RestPreconditions.java b/spring-rest-full/src/main/java/org/baeldung/web/util/RestPreconditions.java index 18cb8219ec..4e211ccb10 100644 --- a/spring-rest-full/src/main/java/org/baeldung/web/util/RestPreconditions.java +++ b/spring-rest-full/src/main/java/org/baeldung/web/util/RestPreconditions.java @@ -1,8 +1,9 @@ package org.baeldung.web.util; -import org.baeldung.web.exception.MyResourceNotFoundException; import org.springframework.http.HttpStatus; +import org.baeldung.web.exception.MyResourceNotFoundException; + /** * Simple static methods to be called at the start of your own methods to verify correct arguments and state. If the Precondition fails, an {@link HttpStatus} code is thrown */ diff --git a/spring-rest-full/src/test/java/org/baeldung/common/web/AbstractBasicLiveTest.java b/spring-rest-full/src/test/java/org/baeldung/common/web/AbstractBasicLiveTest.java index 4e0007d036..d64807d97f 100644 --- a/spring-rest-full/src/test/java/org/baeldung/common/web/AbstractBasicLiveTest.java +++ b/spring-rest-full/src/test/java/org/baeldung/common/web/AbstractBasicLiveTest.java @@ -1,26 +1,19 @@ package org.baeldung.common.web; import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic; -import static org.apache.commons.lang3.RandomStringUtils.randomNumeric; -import static org.baeldung.web.util.HTTPLinkHeaderUtil.extractURIByRel; -import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; -import io.restassured.RestAssured; -import io.restassured.response.Response; import java.io.Serializable; -import java.util.List; import org.junit.Ignore; import org.junit.Test; import com.google.common.net.HttpHeaders; +import io.restassured.RestAssured; +import io.restassured.response.Response; + public abstract class AbstractBasicLiveTest extends AbstractLiveTest { public AbstractBasicLiveTest(final Class clazzToSet) { @@ -104,71 +97,4 @@ public abstract class AbstractBasicLiveTest extends Abst // find - one // find - all - - // find - all - paginated - - @Test - public void whenResourcesAreRetrievedPaged_then200IsReceived() { - final Response response = RestAssured.get(getURL() + "?page=0&size=10"); - - assertThat(response.getStatusCode(), is(200)); - } - - @Test - public void whenPageOfResourcesAreRetrievedOutOfBounds_then404IsReceived() { - final String url = getURL() + "?page=" + randomNumeric(5) + "&size=10"; - final Response response = RestAssured.get(url); - - assertThat(response.getStatusCode(), is(404)); - } - - @Test - public void givenResourcesExist_whenFirstPageIsRetrieved_thenPageContainsResources() { - create(); - - final Response response = RestAssured.get(getURL() + "?page=0&size=10"); - - assertFalse(response.body().as(List.class).isEmpty()); - } - - @Test - public void whenFirstPageOfResourcesAreRetrieved_thenSecondPageIsNext() { - final Response response = RestAssured.get(getURL() + "?page=0&size=2"); - - final String uriToNextPage = extractURIByRel(response.getHeader(HttpHeaders.LINK), "next"); - assertEquals(getURL() + "?page=1&size=2", uriToNextPage); - } - - @Test - public void whenFirstPageOfResourcesAreRetrieved_thenNoPreviousPage() { - final Response response = RestAssured.get(getURL() + "?page=0&size=2"); - - final String uriToPrevPage = extractURIByRel(response.getHeader(HttpHeaders.LINK), "prev"); - assertNull(uriToPrevPage); - } - - @Test - public void whenSecondPageOfResourcesAreRetrieved_thenFirstPageIsPrevious() { - create(); - create(); - - final Response response = RestAssured.get(getURL() + "?page=1&size=2"); - - final String uriToPrevPage = extractURIByRel(response.getHeader(HttpHeaders.LINK), "prev"); - assertEquals(getURL() + "?page=0&size=2", uriToPrevPage); - } - - @Test - public void whenLastPageOfResourcesIsRetrieved_thenNoNextPageIsDiscoverable() { - final Response first = RestAssured.get(getURL() + "?page=0&size=2"); - final String uriToLastPage = extractURIByRel(first.getHeader(HttpHeaders.LINK), "last"); - - final Response response = RestAssured.get(uriToLastPage); - - final String uriToNextPage = extractURIByRel(response.getHeader(HttpHeaders.LINK), "next"); - assertNull(uriToNextPage); - } - - // count - } diff --git a/spring-rest-full/src/test/java/org/baeldung/common/web/AbstractDiscoverabilityLiveTest.java b/spring-rest-full/src/test/java/org/baeldung/common/web/AbstractDiscoverabilityLiveTest.java index c2dd3d84c7..96d796349a 100644 --- a/spring-rest-full/src/test/java/org/baeldung/common/web/AbstractDiscoverabilityLiveTest.java +++ b/spring-rest-full/src/test/java/org/baeldung/common/web/AbstractDiscoverabilityLiveTest.java @@ -5,8 +5,6 @@ import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertThat; -import io.restassured.RestAssured; -import io.restassured.response.Response; import java.io.Serializable; @@ -18,6 +16,9 @@ import org.springframework.http.MediaType; import com.google.common.net.HttpHeaders; +import io.restassured.RestAssured; +import io.restassured.response.Response; + public abstract class AbstractDiscoverabilityLiveTest extends AbstractLiveTest { public AbstractDiscoverabilityLiveTest(final Class clazzToSet) { diff --git a/spring-rest-full/src/test/java/org/baeldung/web/LiveTestSuiteLiveTest.java b/spring-rest-full/src/test/java/org/baeldung/web/LiveTestSuiteLiveTest.java index 71a61ed338..da736392c4 100644 --- a/spring-rest-full/src/test/java/org/baeldung/web/LiveTestSuiteLiveTest.java +++ b/spring-rest-full/src/test/java/org/baeldung/web/LiveTestSuiteLiveTest.java @@ -8,7 +8,6 @@ import org.junit.runners.Suite; // @formatter:off FooDiscoverabilityLiveTest.class ,FooLiveTest.class - ,FooPageableLiveTest.class }) // public class LiveTestSuiteLiveTest { From 4187df5ce9b2c2b06a68742f97e4639a2274b0c9 Mon Sep 17 00:00:00 2001 From: Trevor Gowing Date: Mon, 24 Dec 2018 17:17:50 +0200 Subject: [PATCH 11/33] QueryByExample (QBE) Examples BAEL-2406 --- .../PassengerRepositoryIntegrationTest.java | 65 ++++++++++++++++++- 1 file changed, 63 insertions(+), 2 deletions(-) diff --git a/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/passenger/PassengerRepositoryIntegrationTest.java b/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/passenger/PassengerRepositoryIntegrationTest.java index c57e771345..59380c1427 100644 --- a/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/passenger/PassengerRepositoryIntegrationTest.java +++ b/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/passenger/PassengerRepositoryIntegrationTest.java @@ -5,6 +5,8 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.data.domain.Example; +import org.springframework.data.domain.ExampleMatcher; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Sort; @@ -13,10 +15,12 @@ import org.springframework.test.context.junit4.SpringRunner; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import java.util.List; +import java.util.Optional; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.contains; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; @DataJpaTest @RunWith(SpringRunner.class) @@ -61,7 +65,8 @@ public class PassengerRepositoryIntegrationTest { public void givenSeveralPassengersWhenFindPageSortedByThenThePassengerInTheFirstFilledSeatIsReturned() { Passenger expected = Passenger.from("Fred", "Bloggs", 22); - Page page = repository.findAll(PageRequest.of(0, 1, Sort.by(Sort.Direction.ASC, "seatNumber"))); + Page page = repository.findAll(PageRequest.of(0, 1, + Sort.by(Sort.Direction.ASC, "seatNumber"))); assertEquals(page.getContent().size(), 1); @@ -94,5 +99,61 @@ public class PassengerRepositoryIntegrationTest { assertThat(passengers, contains(fred, ricki, jill, siya, eve)); } - + + @Test + public void givenPassengers_whenFindByExampleDefaultMatcher_thenExpectedReturned() { + Example example = Example.of(Passenger.from("Fred", "Bloggs", null)); + + Optional actual = repository.findOne(example); + + assertTrue(actual.isPresent()); + assertEquals(actual.get(), Passenger.from("Fred", "Bloggs", 22)); + } + + @Test + public void givenPassengers_whenFindByExampleCaseInsensitiveMatcher_thenExpectedReturned() { + ExampleMatcher caseInsensitiveExampleMatcher = ExampleMatcher.matchingAll().withIgnoreCase(); + Example example = Example.of(Passenger.from("fred", "bloggs", null), + caseInsensitiveExampleMatcher); + + Optional actual = repository.findOne(example); + + assertTrue(actual.isPresent()); + assertEquals(actual.get(), Passenger.from("Fred", "Bloggs", 22)); + } + + @Test + public void givenPassengers_whenFindByExampleCustomMatcher_thenExpectedReturned() { + Passenger jill = Passenger.from("Jill", "Smith", 50); + Passenger eve = Passenger.from("Eve", "Jackson", 95); + Passenger fred = Passenger.from("Fred", "Bloggs", 22); + Passenger siya = Passenger.from("Siya", "Kolisi", 85); + + ExampleMatcher customExampleMatcher = ExampleMatcher.matchingAny().withMatcher("firstName", + ExampleMatcher.GenericPropertyMatchers.contains().ignoreCase()).withMatcher("lastName", + ExampleMatcher.GenericPropertyMatchers.contains().ignoreCase()); + + Example example = Example.of(Passenger.from("e", "s", null), + customExampleMatcher); + + List passengers = repository.findAll(example); + + assertThat(passengers, contains(jill, eve, fred, siya)); + } + +@Test +public void givenPassengers_whenFindByIgnoringMatcher_thenExpectedReturned() { + Passenger fred = Passenger.from("Fred", "Bloggs", 22); + Passenger ricki = Passenger.from("Ricki", "Bobbie", 36); + + ExampleMatcher ignoringExampleMatcher = ExampleMatcher.matchingAny().withMatcher("lastName", + ExampleMatcher.GenericPropertyMatchers.startsWith().ignoreCase()).withIgnorePaths("firstName", "seatNumber"); + + Example example = Example.of(Passenger.from(null, "b", null), + ignoringExampleMatcher); + + List passengers = repository.findAll(example); + + assertThat(passengers, contains(fred, ricki)); +} } From b50ef0b4002f61131de4d6496f869940eb584d16 Mon Sep 17 00:00:00 2001 From: Ger Roza Date: Mon, 21 Jan 2019 23:14:03 -0200 Subject: [PATCH 12/33] improved slightly link generation code --- ...sultsRetrievedDiscoverabilityListener.java | 55 ++++++++++++------- 1 file changed, 34 insertions(+), 21 deletions(-) diff --git a/spring-boot-rest/src/main/java/com/baeldung/web/hateoas/listener/PaginatedResultsRetrievedDiscoverabilityListener.java b/spring-boot-rest/src/main/java/com/baeldung/web/hateoas/listener/PaginatedResultsRetrievedDiscoverabilityListener.java index bb60bab171..31555ef353 100644 --- a/spring-boot-rest/src/main/java/com/baeldung/web/hateoas/listener/PaginatedResultsRetrievedDiscoverabilityListener.java +++ b/spring-boot-rest/src/main/java/com/baeldung/web/hateoas/listener/PaginatedResultsRetrievedDiscoverabilityListener.java @@ -1,5 +1,7 @@ package com.baeldung.web.hateoas.listener; +import java.util.StringJoiner; + import javax.servlet.http.HttpServletResponse; import org.springframework.context.ApplicationListener; @@ -27,32 +29,32 @@ class PaginatedResultsRetrievedDiscoverabilityListener implements ApplicationLis public final void onApplicationEvent(final PaginatedResultsRetrievedEvent ev) { Preconditions.checkNotNull(ev); - addLinkHeaderOnPagedResourceRetrieval(ev.getUriBuilder(), ev.getResponse(), ev.getClazz(), ev.getPage(), ev.getTotalPages(), ev.getPageSize()); + addLinkHeaderOnPagedResourceRetrieval(ev.getUriBuilder(), ev.getResponse(), ev.getClazz(), ev.getPage(), + ev.getTotalPages(), ev.getPageSize()); } // - note: at this point, the URI is transformed into plural (added `s`) in a hardcoded way - this will change in the future - final void addLinkHeaderOnPagedResourceRetrieval(final UriComponentsBuilder uriBuilder, final HttpServletResponse response, final Class clazz, final int page, final int totalPages, final int pageSize) { + final void addLinkHeaderOnPagedResourceRetrieval(final UriComponentsBuilder uriBuilder, + final HttpServletResponse response, final Class clazz, final int page, final int totalPages, + final int pageSize) { plural(uriBuilder, clazz); - final StringBuilder linkHeader = new StringBuilder(); + final StringJoiner linkHeader = new StringJoiner(", "); if (hasNextPage(page, totalPages)) { final String uriForNextPage = constructNextPageUri(uriBuilder, page, pageSize); - linkHeader.append(LinkUtil.createLinkHeader(uriForNextPage, LinkUtil.REL_NEXT)); + linkHeader.add(LinkUtil.createLinkHeader(uriForNextPage, LinkUtil.REL_NEXT)); } if (hasPreviousPage(page)) { final String uriForPrevPage = constructPrevPageUri(uriBuilder, page, pageSize); - appendCommaIfNecessary(linkHeader); - linkHeader.append(LinkUtil.createLinkHeader(uriForPrevPage, LinkUtil.REL_PREV)); + linkHeader.add(LinkUtil.createLinkHeader(uriForPrevPage, LinkUtil.REL_PREV)); } if (hasFirstPage(page)) { final String uriForFirstPage = constructFirstPageUri(uriBuilder, pageSize); - appendCommaIfNecessary(linkHeader); - linkHeader.append(LinkUtil.createLinkHeader(uriForFirstPage, LinkUtil.REL_FIRST)); + linkHeader.add(LinkUtil.createLinkHeader(uriForFirstPage, LinkUtil.REL_FIRST)); } if (hasLastPage(page, totalPages)) { final String uriForLastPage = constructLastPageUri(uriBuilder, totalPages, pageSize); - appendCommaIfNecessary(linkHeader); - linkHeader.append(LinkUtil.createLinkHeader(uriForLastPage, LinkUtil.REL_LAST)); + linkHeader.add(LinkUtil.createLinkHeader(uriForLastPage, LinkUtil.REL_LAST)); } if (linkHeader.length() > 0) { @@ -61,19 +63,35 @@ class PaginatedResultsRetrievedDiscoverabilityListener implements ApplicationLis } final String constructNextPageUri(final UriComponentsBuilder uriBuilder, final int page, final int size) { - return uriBuilder.replaceQueryParam(PAGE, page + 1).replaceQueryParam("size", size).build().encode().toUriString(); + return uriBuilder.replaceQueryParam(PAGE, page + 1) + .replaceQueryParam("size", size) + .build() + .encode() + .toUriString(); } final String constructPrevPageUri(final UriComponentsBuilder uriBuilder, final int page, final int size) { - return uriBuilder.replaceQueryParam(PAGE, page - 1).replaceQueryParam("size", size).build().encode().toUriString(); + return uriBuilder.replaceQueryParam(PAGE, page - 1) + .replaceQueryParam("size", size) + .build() + .encode() + .toUriString(); } final String constructFirstPageUri(final UriComponentsBuilder uriBuilder, final int size) { - return uriBuilder.replaceQueryParam(PAGE, 0).replaceQueryParam("size", size).build().encode().toUriString(); + return uriBuilder.replaceQueryParam(PAGE, 0) + .replaceQueryParam("size", size) + .build() + .encode() + .toUriString(); } final String constructLastPageUri(final UriComponentsBuilder uriBuilder, final int totalPages, final int size) { - return uriBuilder.replaceQueryParam(PAGE, totalPages).replaceQueryParam("size", size).build().encode().toUriString(); + return uriBuilder.replaceQueryParam(PAGE, totalPages) + .replaceQueryParam("size", size) + .build() + .encode() + .toUriString(); } final boolean hasNextPage(final int page, final int totalPages) { @@ -92,16 +110,11 @@ class PaginatedResultsRetrievedDiscoverabilityListener implements ApplicationLis return (totalPages > 1) && hasNextPage(page, totalPages); } - final void appendCommaIfNecessary(final StringBuilder linkHeader) { - if (linkHeader.length() > 0) { - linkHeader.append(", "); - } - } - // template protected void plural(final UriComponentsBuilder uriBuilder, final Class clazz) { - final String resourceName = clazz.getSimpleName().toLowerCase() + "s"; + final String resourceName = clazz.getSimpleName() + .toLowerCase() + "s"; uriBuilder.path("/auth/" + resourceName); } From 2fb3e867d75aa291a53cf69d0d2f75230404c324 Mon Sep 17 00:00:00 2001 From: Urvy Agrawal Date: Tue, 22 Jan 2019 14:28:12 +0530 Subject: [PATCH 13/33] Adding test file for bitwise operators --- .../BitwiseOperatorExample.java | 56 ------------- .../test/BitwiseOperatorUnitTest.java | 81 +++++++++++++++++++ 2 files changed, 81 insertions(+), 56 deletions(-) delete mode 100644 core-java/src/main/java/com/baeldung/bitwiseoperator/BitwiseOperatorExample.java create mode 100644 core-java/src/test/java/com/baeldung/bitwiseoperator/test/BitwiseOperatorUnitTest.java diff --git a/core-java/src/main/java/com/baeldung/bitwiseoperator/BitwiseOperatorExample.java b/core-java/src/main/java/com/baeldung/bitwiseoperator/BitwiseOperatorExample.java deleted file mode 100644 index 4fef92102a..0000000000 --- a/core-java/src/main/java/com/baeldung/bitwiseoperator/BitwiseOperatorExample.java +++ /dev/null @@ -1,56 +0,0 @@ -package com.baeldung.bitwiseoperator; - -public class BitwiseOperatorExample { - - public static void main(String[] args) { - - int value1 = 6; - int value2 = 5; - - // Bitwise AND Operator - int result = value1 & value2; - System.out.println("result : " + result); - - // Bitwise OR Operator - result = value1 | value2; - System.out.println("result : " + result); - - // Bitwise Exclusive OR Operator - result = value1 ^ value2; - System.out.println("result : " + result); - - // Bitwise NOT operator - result = ~value1; - System.out.println("result : " + result); - - // Right Shift Operator with positive number - int value = 12; - int rightShift = value >> 2; - System.out.println("rightShift result with positive number : " + rightShift); - - // Right Shift Operator with negative number - value = -12; - rightShift = value >> 2; - System.out.println("rightShift result with negative number : " + rightShift); - - // Left Shift Operator with positive number - value = 1; - int leftShift = value << 1; - System.out.println("leftShift result with positive number : " + leftShift); - - // Left Shift Operator with negative number - value = -12; - leftShift = value << 2; - System.out.println("leftShift result with negative number : " + leftShift); - - // Unsigned Right Shift Operator with positive number - value = 12; - int unsignedRightShift = value >>> 2; - System.out.println("unsignedRightShift result with positive number : " + unsignedRightShift); - - // Unsigned Right Shift Operator with negative number - value = -12; - unsignedRightShift = value >>> 2; - System.out.println("unsignedRightShift result with negative number : " + unsignedRightShift); - } -} diff --git a/core-java/src/test/java/com/baeldung/bitwiseoperator/test/BitwiseOperatorUnitTest.java b/core-java/src/test/java/com/baeldung/bitwiseoperator/test/BitwiseOperatorUnitTest.java new file mode 100644 index 0000000000..139d3a2512 --- /dev/null +++ b/core-java/src/test/java/com/baeldung/bitwiseoperator/test/BitwiseOperatorUnitTest.java @@ -0,0 +1,81 @@ +package com.baeldung.bitwiseoperator.test; + +import org.junit.Assert; +import org.junit.jupiter.api.Test; + +public class BitwiseOperatorUnitTest { + + @Test + public void givenTwoIntegers_whenAndOperator_thenNewDecimalNumber() { + int value1 = 6; + int value2 = 5; + int result = value1 & value2; + Assert.assertEquals(result, 4); + } + + @Test + public void givenTwoIntegers_whenOrOperator_thenNewDecimalNumber() { + int value1 = 6; + int value2 = 5; + int result = value1 | value2; + Assert.assertEquals(result, 7); + } + + @Test + public void givenTwoIntegers_whenXorOperator_thenNewDecimalNumber() { + int value1 = 6; + int value2 = 5; + int result = value1 ^ value2; + Assert.assertEquals(result, 3); + } + + @Test + public void givenOneInteger_whenNotOperator_thenNewDecimalNumber() { + int value1 = 6; + int result = ~value1; + Assert.assertEquals(result, -7); + } + + @Test + public void givenOnePositiveInteger_whenSignedRightShiftOperator_thenNewDecimalNumber() { + int value = 12; + int rightShift = value >> 2; + Assert.assertEquals(rightShift, 3); + } + + @Test + public void givenOneNegativeInteger_whenSignedRightShiftOperator_thenNewDecimalNumber() { + int value = -12; + int rightShift = value >> 2; + Assert.assertEquals(rightShift, -3); + } + + @Test + public void givenOnePositiveInteger_whenLeftShiftOperator_thenNewDecimalNumber() { + int value = 12; + int leftShift = value << 2; + Assert.assertEquals(leftShift, 48); + } + + @Test + public void givenOneNegativeInteger_whenLeftShiftOperator_thenNewDecimalNumber() { + int value = -12; + int leftShift = value << 2; + Assert.assertEquals(leftShift, -48); + } + + @Test + public void givenOnePositiveInteger_whenUnsignedRightShiftOperator_thenNewDecimalNumber() { + int value = 12; + int unsignedRightShift = value >>> 2; + Assert.assertEquals(unsignedRightShift, 3); + } + + @Test + public void givenOneNegativeInteger_whenUnsignedRightShiftOperator_thenNewDecimalNumber() { + int value = -12; + int unsignedRightShift = value >>> 2; + Assert.assertEquals(unsignedRightShift, 1073741821); + } + +} From 5bbc85c6c1cedb411019e62f506fae42f618bc6d Mon Sep 17 00:00:00 2001 From: enpy Date: Tue, 22 Jan 2019 17:18:11 +0100 Subject: [PATCH 14/33] classes and objects code added (#6173) * classes and objects code added * Car class and test added * fixes and enhancements * code moved to core-java-lang --- .../main/java/com/baeldung/objects/Car.java | 51 +++++++++++++++++++ .../com/baeldung/objects/CarUnitTest.java | 38 ++++++++++++++ 2 files changed, 89 insertions(+) create mode 100644 core-java-lang/src/main/java/com/baeldung/objects/Car.java create mode 100644 core-java-lang/src/test/java/com/baeldung/objects/CarUnitTest.java diff --git a/core-java-lang/src/main/java/com/baeldung/objects/Car.java b/core-java-lang/src/main/java/com/baeldung/objects/Car.java new file mode 100644 index 0000000000..35ef8585b2 --- /dev/null +++ b/core-java-lang/src/main/java/com/baeldung/objects/Car.java @@ -0,0 +1,51 @@ +package com.baeldung.objects; + +public class Car { + + private String type; + private String model; + private String color; + private int speed; + + public Car(String type, String model, String color) { + this.type = type; + this.model = model; + this.color = color; + } + + public String getColor() { + return color; + } + + public void setColor(String color) { + this.color = color; + } + + public int getSpeed() { + return speed; + } + + public int increaseSpeed(int increment) { + if (increment > 0) { + this.speed += increment; + } else { + System.out.println("Increment can't be negative."); + } + return this.speed; + } + + public int decreaseSpeed(int decrement) { + if (decrement > 0 && decrement <= this.speed) { + this.speed -= decrement; + } else { + System.out.println("Decrement can't be negative or greater than current speed."); + } + return this.speed; + } + + @Override + public String toString() { + return "Car [type=" + type + ", model=" + model + ", color=" + color + ", speed=" + speed + "]"; + } + +} diff --git a/core-java-lang/src/test/java/com/baeldung/objects/CarUnitTest.java b/core-java-lang/src/test/java/com/baeldung/objects/CarUnitTest.java new file mode 100644 index 0000000000..a1ef20523e --- /dev/null +++ b/core-java-lang/src/test/java/com/baeldung/objects/CarUnitTest.java @@ -0,0 +1,38 @@ +package com.baeldung.objects; + +import static org.junit.Assert.*; + +import org.junit.Before; +import org.junit.Test; + +public class CarUnitTest { + + private Car car; + + @Before + public void setUp() throws Exception { + car = new Car("Ford", "Focus", "red"); + } + + @Test + public final void when_speedIncreased_then_verifySpeed() { + car.increaseSpeed(30); + assertEquals(30, car.getSpeed()); + + car.increaseSpeed(20); + assertEquals(50, car.getSpeed()); + } + + @Test + public final void when_speedDecreased_then_verifySpeed() { + car.increaseSpeed(50); + assertEquals(50, car.getSpeed()); + + car.decreaseSpeed(30); + assertEquals(20, car.getSpeed()); + + car.decreaseSpeed(20); + assertEquals(0, car.getSpeed()); + } + +} From 39ea408549fbce7be95e1b7160525c3b45f64e09 Mon Sep 17 00:00:00 2001 From: Loredana Crusoveanu Date: Tue, 22 Jan 2019 19:58:57 +0200 Subject: [PATCH 15/33] Update BitwiseOperatorUnitTest.java --- .../test/BitwiseOperatorUnitTest.java | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/core-java/src/test/java/com/baeldung/bitwiseoperator/test/BitwiseOperatorUnitTest.java b/core-java/src/test/java/com/baeldung/bitwiseoperator/test/BitwiseOperatorUnitTest.java index 139d3a2512..d8af4b0833 100644 --- a/core-java/src/test/java/com/baeldung/bitwiseoperator/test/BitwiseOperatorUnitTest.java +++ b/core-java/src/test/java/com/baeldung/bitwiseoperator/test/BitwiseOperatorUnitTest.java @@ -1,6 +1,6 @@ package com.baeldung.bitwiseoperator.test; -import org.junit.Assert; +import static org.junit.Assert.assertEquals; import org.junit.jupiter.api.Test; public class BitwiseOperatorUnitTest { @@ -10,7 +10,7 @@ public class BitwiseOperatorUnitTest { int value1 = 6; int value2 = 5; int result = value1 & value2; - Assert.assertEquals(result, 4); + assertEquals(result, 4); } @Test @@ -18,7 +18,7 @@ public class BitwiseOperatorUnitTest { int value1 = 6; int value2 = 5; int result = value1 | value2; - Assert.assertEquals(result, 7); + assertEquals(result, 7); } @Test @@ -26,56 +26,56 @@ public class BitwiseOperatorUnitTest { int value1 = 6; int value2 = 5; int result = value1 ^ value2; - Assert.assertEquals(result, 3); + assertEquals(result, 3); } @Test public void givenOneInteger_whenNotOperator_thenNewDecimalNumber() { int value1 = 6; int result = ~value1; - Assert.assertEquals(result, -7); + assertEquals(result, -7); } @Test public void givenOnePositiveInteger_whenSignedRightShiftOperator_thenNewDecimalNumber() { int value = 12; int rightShift = value >> 2; - Assert.assertEquals(rightShift, 3); + assertEquals(rightShift, 3); } @Test public void givenOneNegativeInteger_whenSignedRightShiftOperator_thenNewDecimalNumber() { int value = -12; int rightShift = value >> 2; - Assert.assertEquals(rightShift, -3); + assertEquals(rightShift, -3); } @Test public void givenOnePositiveInteger_whenLeftShiftOperator_thenNewDecimalNumber() { int value = 12; int leftShift = value << 2; - Assert.assertEquals(leftShift, 48); + assertEquals(leftShift, 48); } @Test public void givenOneNegativeInteger_whenLeftShiftOperator_thenNewDecimalNumber() { int value = -12; int leftShift = value << 2; - Assert.assertEquals(leftShift, -48); + assertEquals(leftShift, -48); } @Test public void givenOnePositiveInteger_whenUnsignedRightShiftOperator_thenNewDecimalNumber() { int value = 12; int unsignedRightShift = value >>> 2; - Assert.assertEquals(unsignedRightShift, 3); + assertEquals(unsignedRightShift, 3); } @Test public void givenOneNegativeInteger_whenUnsignedRightShiftOperator_thenNewDecimalNumber() { int value = -12; int unsignedRightShift = value >>> 2; - Assert.assertEquals(unsignedRightShift, 1073741821); + assertEquals(unsignedRightShift, 1073741821); } } From 7fa2aba180074969b59b4599a20f9792e76c1dc5 Mon Sep 17 00:00:00 2001 From: Fabian Rivera Date: Tue, 22 Jan 2019 23:54:24 -0600 Subject: [PATCH 16/33] BAEL-2414 Guide to problem-spring-web (#6147) * Fix issue with package name and folder name mismatch * Add problem-spring-web code samples * Use the latest version of the problem-spring-web library. Add spring security exceptions handling samples * Fix issue with security configuration. Fix sample for forbidden operation * Update ProblemDemoConfiguration.java * Add integration tests to validate problems are correctly handled and responses are generated using the problem library --- spring-boot-libraries/pom.xml | 270 +++++++++--------- .../com/baeldung/{ => boot}/Application.java | 2 +- .../problem/SpringProblemApplication.java | 19 ++ .../boot/problem/advice/ExceptionHandler.java | 9 + .../advice/SecurityExceptionHandler.java | 9 + .../ProblemDemoConfiguration.java | 17 ++ .../configuration/SecurityConfiguration.java | 31 ++ .../controller/ProblemDemoController.java | 56 ++++ .../com/baeldung/boot/problem/dto/Task.java | 32 +++ .../problem/problems/TaskNotFoundProblem.java | 16 ++ .../resources/application-problem.properties | 3 + .../ProblemDemoControllerIntegrationTest.java | 75 +++++ 12 files changed, 409 insertions(+), 130 deletions(-) rename spring-boot-libraries/src/main/java/com/baeldung/{ => boot}/Application.java (93%) create mode 100644 spring-boot-libraries/src/main/java/com/baeldung/boot/problem/SpringProblemApplication.java create mode 100644 spring-boot-libraries/src/main/java/com/baeldung/boot/problem/advice/ExceptionHandler.java create mode 100644 spring-boot-libraries/src/main/java/com/baeldung/boot/problem/advice/SecurityExceptionHandler.java create mode 100644 spring-boot-libraries/src/main/java/com/baeldung/boot/problem/configuration/ProblemDemoConfiguration.java create mode 100644 spring-boot-libraries/src/main/java/com/baeldung/boot/problem/configuration/SecurityConfiguration.java create mode 100644 spring-boot-libraries/src/main/java/com/baeldung/boot/problem/controller/ProblemDemoController.java create mode 100644 spring-boot-libraries/src/main/java/com/baeldung/boot/problem/dto/Task.java create mode 100644 spring-boot-libraries/src/main/java/com/baeldung/boot/problem/problems/TaskNotFoundProblem.java create mode 100644 spring-boot-libraries/src/main/resources/application-problem.properties create mode 100644 spring-boot-libraries/src/test/java/com/baeldung/boot/problem/controller/ProblemDemoControllerIntegrationTest.java diff --git a/spring-boot-libraries/pom.xml b/spring-boot-libraries/pom.xml index c28128c5f0..66aa66bdfd 100644 --- a/spring-boot-libraries/pom.xml +++ b/spring-boot-libraries/pom.xml @@ -1,144 +1,156 @@ - 4.0.0 - spring-boot-libraries - war - spring-boot-libraries - This is simple boot application for Spring boot actuator test + 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"> + 4.0.0 + spring-boot-libraries + war + spring-boot-libraries + This is simple boot application for Spring boot actuator test - - parent-boot-2 - com.baeldung - 0.0.1-SNAPSHOT - ../parent-boot-2 - + + parent-boot-2 + com.baeldung + 0.0.1-SNAPSHOT + ../parent-boot-2 + - - - org.springframework.boot - spring-boot-starter-web - - - org.springframework.boot - spring-boot-starter-tomcat - - - org.springframework.boot - spring-boot-starter-test - test - + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-security + + + org.springframework.boot + spring-boot-starter-tomcat + + + org.springframework.boot + spring-boot-starter-test + test + + + + + org.zalando + problem-spring-web + ${problem-spring-web.version} + - - - net.javacrumbs.shedlock - shedlock-spring - 2.1.0 - - - net.javacrumbs.shedlock - shedlock-provider-jdbc-template - 2.1.0 - + + + net.javacrumbs.shedlock + shedlock-spring + 2.1.0 + + + net.javacrumbs.shedlock + shedlock-provider-jdbc-template + 2.1.0 + - + - - spring-boot - - - src/main/resources - true - - + + spring-boot + + + src/main/resources + true + + - + - - org.apache.maven.plugins - maven-war-plugin - + + org.apache.maven.plugins + maven-war-plugin + - - pl.project13.maven - git-commit-id-plugin - ${git-commit-id-plugin.version} - - - get-the-git-infos - - revision - - initialize - - - validate-the-git-infos - - validateRevision - - package - - - - true - ${project.build.outputDirectory}/git.properties - - + + pl.project13.maven + git-commit-id-plugin + ${git-commit-id-plugin.version} + + + get-the-git-infos + + revision + + initialize + + + validate-the-git-infos + + validateRevision + + package + + + + true + ${project.build.outputDirectory}/git.properties + + - + - + - - - autoconfiguration - - - - org.apache.maven.plugins - maven-surefire-plugin - - - integration-test - - test - - - - **/*LiveTest.java - **/*IntegrationTest.java - **/*IntTest.java - - - **/AutoconfigurationTest.java - - - - - - - json - - - - - - - + + + autoconfiguration + + + + org.apache.maven.plugins + maven-surefire-plugin + + + integration-test + + test + + + + **/*LiveTest.java + **/*IntegrationTest.java + **/*IntTest.java + + + **/AutoconfigurationTest.java + + + + + + + json + + + + + + + - - - com.baeldung.intro.App - 8.5.11 - 2.4.1.Final - 1.9.0 - 2.0.0 - 5.0.2 - 5.0.2 - 5.2.4 - 18.0 - 2.2.4 - 2.3.2 - + + + com.baeldung.intro.App + 8.5.11 + 2.4.1.Final + 1.9.0 + 2.0.0 + 5.0.2 + 5.0.2 + 5.2.4 + 18.0 + 2.2.4 + 2.3.2 + 0.23.0 + diff --git a/spring-boot-libraries/src/main/java/com/baeldung/Application.java b/spring-boot-libraries/src/main/java/com/baeldung/boot/Application.java similarity index 93% rename from spring-boot-libraries/src/main/java/com/baeldung/Application.java rename to spring-boot-libraries/src/main/java/com/baeldung/boot/Application.java index c1b6558b26..cb0d0c1532 100644 --- a/spring-boot-libraries/src/main/java/com/baeldung/Application.java +++ b/spring-boot-libraries/src/main/java/com/baeldung/boot/Application.java @@ -1,4 +1,4 @@ -package org.baeldung.boot; +package com.baeldung.boot; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; diff --git a/spring-boot-libraries/src/main/java/com/baeldung/boot/problem/SpringProblemApplication.java b/spring-boot-libraries/src/main/java/com/baeldung/boot/problem/SpringProblemApplication.java new file mode 100644 index 0000000000..7ca9881fb9 --- /dev/null +++ b/spring-boot-libraries/src/main/java/com/baeldung/boot/problem/SpringProblemApplication.java @@ -0,0 +1,19 @@ +package com.baeldung.boot.problem; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration; +import org.springframework.context.annotation.ComponentScan; + +@SpringBootApplication +@EnableAutoConfiguration(exclude = ErrorMvcAutoConfiguration.class) +@ComponentScan("com.baeldung.boot.problem") +public class SpringProblemApplication { + + public static void main(String[] args) { + System.setProperty("spring.profiles.active", "problem"); + SpringApplication.run(SpringProblemApplication.class, args); + } + +} diff --git a/spring-boot-libraries/src/main/java/com/baeldung/boot/problem/advice/ExceptionHandler.java b/spring-boot-libraries/src/main/java/com/baeldung/boot/problem/advice/ExceptionHandler.java new file mode 100644 index 0000000000..7b4cbac7f7 --- /dev/null +++ b/spring-boot-libraries/src/main/java/com/baeldung/boot/problem/advice/ExceptionHandler.java @@ -0,0 +1,9 @@ +package com.baeldung.boot.problem.advice; + +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.zalando.problem.spring.web.advice.ProblemHandling; + +@ControllerAdvice +public class ExceptionHandler implements ProblemHandling { + +} diff --git a/spring-boot-libraries/src/main/java/com/baeldung/boot/problem/advice/SecurityExceptionHandler.java b/spring-boot-libraries/src/main/java/com/baeldung/boot/problem/advice/SecurityExceptionHandler.java new file mode 100644 index 0000000000..8013cbf5c3 --- /dev/null +++ b/spring-boot-libraries/src/main/java/com/baeldung/boot/problem/advice/SecurityExceptionHandler.java @@ -0,0 +1,9 @@ +package com.baeldung.boot.problem.advice; + +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.zalando.problem.spring.web.advice.security.SecurityAdviceTrait; + +@ControllerAdvice +public class SecurityExceptionHandler implements SecurityAdviceTrait { + +} \ No newline at end of file diff --git a/spring-boot-libraries/src/main/java/com/baeldung/boot/problem/configuration/ProblemDemoConfiguration.java b/spring-boot-libraries/src/main/java/com/baeldung/boot/problem/configuration/ProblemDemoConfiguration.java new file mode 100644 index 0000000000..209ff553c7 --- /dev/null +++ b/spring-boot-libraries/src/main/java/com/baeldung/boot/problem/configuration/ProblemDemoConfiguration.java @@ -0,0 +1,17 @@ +package com.baeldung.boot.problem.configuration; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.zalando.problem.ProblemModule; +import org.zalando.problem.validation.ConstraintViolationProblemModule; + +import com.fasterxml.jackson.databind.ObjectMapper; + +@Configuration +public class ProblemDemoConfiguration { + + @Bean + public ObjectMapper objectMapper() { + return new ObjectMapper().registerModules(new ProblemModule(), new ConstraintViolationProblemModule()); + } +} diff --git a/spring-boot-libraries/src/main/java/com/baeldung/boot/problem/configuration/SecurityConfiguration.java b/spring-boot-libraries/src/main/java/com/baeldung/boot/problem/configuration/SecurityConfiguration.java new file mode 100644 index 0000000000..0cb8048981 --- /dev/null +++ b/spring-boot-libraries/src/main/java/com/baeldung/boot/problem/configuration/SecurityConfiguration.java @@ -0,0 +1,31 @@ +package com.baeldung.boot.problem.configuration; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.zalando.problem.spring.web.advice.security.SecurityProblemSupport; + +@Configuration +@EnableWebSecurity +@Import(SecurityProblemSupport.class) +public class SecurityConfiguration extends WebSecurityConfigurerAdapter { + + @Autowired + private SecurityProblemSupport problemSupport; + + @Override + protected void configure(HttpSecurity http) throws Exception { + http.csrf().disable(); + + http.authorizeRequests() + .antMatchers("/") + .permitAll(); + + http.exceptionHandling() + .authenticationEntryPoint(problemSupport) + .accessDeniedHandler(problemSupport); + } +} diff --git a/spring-boot-libraries/src/main/java/com/baeldung/boot/problem/controller/ProblemDemoController.java b/spring-boot-libraries/src/main/java/com/baeldung/boot/problem/controller/ProblemDemoController.java new file mode 100644 index 0000000000..50f1ad5137 --- /dev/null +++ b/spring-boot-libraries/src/main/java/com/baeldung/boot/problem/controller/ProblemDemoController.java @@ -0,0 +1,56 @@ +package com.baeldung.boot.problem.controller; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.springframework.http.MediaType; +import org.springframework.security.access.AccessDeniedException; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.baeldung.boot.problem.dto.Task; +import com.baeldung.boot.problem.problems.TaskNotFoundProblem; + +@RestController +@RequestMapping("/tasks") +public class ProblemDemoController { + + private static final Map MY_TASKS; + + static { + MY_TASKS = new HashMap<>(); + MY_TASKS.put(1L, new Task(1L, "My first task")); + MY_TASKS.put(2L, new Task(2L, "My second task")); + } + + @GetMapping(produces = MediaType.APPLICATION_JSON_VALUE) + public List getTasks() { + return new ArrayList<>(MY_TASKS.values()); + } + + @GetMapping(value = "/{id}", produces = MediaType.APPLICATION_JSON_VALUE) + public Task getTasks(@PathVariable("id") Long taskId) { + if (MY_TASKS.containsKey(taskId)) { + return MY_TASKS.get(taskId); + } else { + throw new TaskNotFoundProblem(taskId); + } + } + + @PutMapping("/{id}") + public void updateTask(@PathVariable("id") Long id) { + throw new UnsupportedOperationException(); + } + + @DeleteMapping("/{id}") + public void deleteTask(@PathVariable("id") Long id) { + throw new AccessDeniedException("You can't delete this task"); + } + +} diff --git a/spring-boot-libraries/src/main/java/com/baeldung/boot/problem/dto/Task.java b/spring-boot-libraries/src/main/java/com/baeldung/boot/problem/dto/Task.java new file mode 100644 index 0000000000..a5f39474e7 --- /dev/null +++ b/spring-boot-libraries/src/main/java/com/baeldung/boot/problem/dto/Task.java @@ -0,0 +1,32 @@ +package com.baeldung.boot.problem.dto; + +public class Task { + + private Long id; + private String description; + + public Task() { + } + + public Task(Long id, String description) { + this.id = id; + this.description = description; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + +} diff --git a/spring-boot-libraries/src/main/java/com/baeldung/boot/problem/problems/TaskNotFoundProblem.java b/spring-boot-libraries/src/main/java/com/baeldung/boot/problem/problems/TaskNotFoundProblem.java new file mode 100644 index 0000000000..cc3f21d4a5 --- /dev/null +++ b/spring-boot-libraries/src/main/java/com/baeldung/boot/problem/problems/TaskNotFoundProblem.java @@ -0,0 +1,16 @@ +package com.baeldung.boot.problem.problems; + +import java.net.URI; + +import org.zalando.problem.AbstractThrowableProblem; +import org.zalando.problem.Status; + +public class TaskNotFoundProblem extends AbstractThrowableProblem { + + private static final URI TYPE = URI.create("https://example.org/not-found"); + + public TaskNotFoundProblem(Long taskId) { + super(TYPE, "Not found", Status.NOT_FOUND, String.format("Task '%s' not found", taskId)); + } + +} diff --git a/spring-boot-libraries/src/main/resources/application-problem.properties b/spring-boot-libraries/src/main/resources/application-problem.properties new file mode 100644 index 0000000000..7d0b0a2720 --- /dev/null +++ b/spring-boot-libraries/src/main/resources/application-problem.properties @@ -0,0 +1,3 @@ +spring.resources.add-mappings=false +spring.mvc.throw-exception-if-no-handler-found=true +spring.http.encoding.force=true diff --git a/spring-boot-libraries/src/test/java/com/baeldung/boot/problem/controller/ProblemDemoControllerIntegrationTest.java b/spring-boot-libraries/src/test/java/com/baeldung/boot/problem/controller/ProblemDemoControllerIntegrationTest.java new file mode 100644 index 0000000000..3b7e43a565 --- /dev/null +++ b/spring-boot-libraries/src/test/java/com/baeldung/boot/problem/controller/ProblemDemoControllerIntegrationTest.java @@ -0,0 +1,75 @@ +package com.baeldung.boot.problem.controller; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.MediaType; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; + +import com.baeldung.boot.problem.SpringProblemApplication; + +@RunWith(SpringRunner.class) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK, classes = SpringProblemApplication.class) +@AutoConfigureMockMvc +public class ProblemDemoControllerIntegrationTest { + + @Autowired + private MockMvc mockMvc; + + @Test + public void whenRequestingAllTasks_thenReturnSuccessfulResponseWithArrayWithTwoTasks() throws Exception { + mockMvc.perform(get("/tasks").contentType(MediaType.APPLICATION_JSON_VALUE)) + .andDo(print()) + .andExpect(jsonPath("$.length()", equalTo(2))) + .andExpect(status().isOk()); + } + + @Test + public void whenRequestingExistingTask_thenReturnSuccessfulResponse() throws Exception { + mockMvc.perform(get("/tasks/1").contentType(MediaType.APPLICATION_JSON_VALUE)) + .andDo(print()) + .andExpect(jsonPath("$.id", equalTo(1))) + .andExpect(status().isOk()); + } + + @Test + public void whenRequestingMissingTask_thenReturnNotFoundProblemResponse() throws Exception { + mockMvc.perform(get("/tasks/5").contentType(MediaType.APPLICATION_PROBLEM_JSON_VALUE)) + .andDo(print()) + .andExpect(jsonPath("$.title", equalTo("Not found"))) + .andExpect(jsonPath("$.status", equalTo(404))) + .andExpect(jsonPath("$.detail", equalTo("Task '5' not found"))) + .andExpect(status().isNotFound()); + } + + @Test + public void whenMakePutCall_thenReturnNotImplementedProblemResponse() throws Exception { + mockMvc.perform(put("/tasks/1").contentType(MediaType.APPLICATION_PROBLEM_JSON_VALUE)) + .andDo(print()) + .andExpect(jsonPath("$.title", equalTo("Not Implemented"))) + .andExpect(jsonPath("$.status", equalTo(501))) + .andExpect(status().isNotImplemented()); + } + + @Test + public void whenMakeDeleteCall_thenReturnForbiddenProblemResponse() throws Exception { + mockMvc.perform(delete("/tasks/2").contentType(MediaType.APPLICATION_PROBLEM_JSON_VALUE)) + .andDo(print()) + .andExpect(jsonPath("$.title", equalTo("Forbidden"))) + .andExpect(jsonPath("$.status", equalTo(403))) + .andExpect(jsonPath("$.detail", equalTo("You can't delete this task"))) + .andExpect(status().isForbidden()); + } + +} From effde80333489fa4b74cb173261c812456de8134 Mon Sep 17 00:00:00 2001 From: Anshul Bansal Date: Wed, 23 Jan 2019 14:19:48 +0200 Subject: [PATCH 17/33] BAEL - 2420 Converting Float to Byte Array and vice-versa in Java (#6194) * Hexagonal Architecture in Java - Spring boot app * create README.md * Update README.md * Update README.md * BAEL-2420 Converting Float to Byte Array and vice-versa in Java * BAEL-2420 Converting Float to Byte Array and vice-versa in Java - conversions package added * Hexagonal architecture code removed --- .../array/conversions/FloatToByteArray.java | 44 ++++++++++++++++++ .../conversions/FloatToByteArrayUnitTest.java | 46 +++++++++++++++++++ 2 files changed, 90 insertions(+) create mode 100644 core-java-arrays/src/main/java/com/baeldung/array/conversions/FloatToByteArray.java create mode 100644 core-java-arrays/src/test/java/com/baeldung/array/conversions/FloatToByteArrayUnitTest.java diff --git a/core-java-arrays/src/main/java/com/baeldung/array/conversions/FloatToByteArray.java b/core-java-arrays/src/main/java/com/baeldung/array/conversions/FloatToByteArray.java new file mode 100644 index 0000000000..b831e436a5 --- /dev/null +++ b/core-java-arrays/src/main/java/com/baeldung/array/conversions/FloatToByteArray.java @@ -0,0 +1,44 @@ +package com.baeldung.array.conversions; + +import java.nio.ByteBuffer; + +public class FloatToByteArray { + + /** + * convert float into byte array using Float API floatToIntBits + * @param value + * @return byte[] + */ + public static byte[] floatToByteArray(float value) { + int intBits = Float.floatToIntBits(value); + return new byte[] {(byte) (intBits >> 24), (byte) (intBits >> 16), (byte) (intBits >> 8), (byte) (intBits) }; + } + + /** + * convert byte array into float using Float API intBitsToFloat + * @param bytes + * @return float + */ + public static float byteArrayToFloat(byte[] bytes) { + int intBits = bytes[0] << 24 | (bytes[1] & 0xFF) << 16 | (bytes[2] & 0xFF) << 8 | (bytes[3] & 0xFF); + return Float.intBitsToFloat(intBits); + } + + /** + * convert float into byte array using ByteBuffer + * @param value + * @return byte[] + */ + public static byte[] floatToByteArrayWithByteBuffer(float value) { + return ByteBuffer.allocate(4).putFloat(value).array(); + } + + /** + * convert byte array into float using ByteBuffer + * @param bytes + * @return float + */ + public static float byteArrayToFloatWithByteBuffer(byte[] bytes) { + return ByteBuffer.wrap(bytes).getFloat(); + } +} diff --git a/core-java-arrays/src/test/java/com/baeldung/array/conversions/FloatToByteArrayUnitTest.java b/core-java-arrays/src/test/java/com/baeldung/array/conversions/FloatToByteArrayUnitTest.java new file mode 100644 index 0000000000..a2cd273f21 --- /dev/null +++ b/core-java-arrays/src/test/java/com/baeldung/array/conversions/FloatToByteArrayUnitTest.java @@ -0,0 +1,46 @@ +package com.baeldung.array.conversions; + +import static com.baeldung.array.conversions.FloatToByteArray.byteArrayToFloat; +import static com.baeldung.array.conversions.FloatToByteArray.byteArrayToFloatWithByteBuffer; +import static com.baeldung.array.conversions.FloatToByteArray.floatToByteArray; +import static com.baeldung.array.conversions.FloatToByteArray.floatToByteArrayWithByteBuffer; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import org.junit.Test; + +public class FloatToByteArrayUnitTest { + + @Test + public void givenAFloat_thenConvertToByteArray() { + assertArrayEquals(new byte[] { 63, -116, -52, -51}, floatToByteArray(1.1f)); + } + + @Test + public void givenAByteArray_thenConvertToFloat() { + assertEquals(1.1f, byteArrayToFloat(new byte[] { 63, -116, -52, -51}), 0); + } + + @Test + public void givenAFloat_thenConvertToByteArrayUsingByteBuffer() { + assertArrayEquals(new byte[] { 63, -116, -52, -51}, floatToByteArrayWithByteBuffer(1.1f)); + } + + @Test + public void givenAByteArray_thenConvertToFloatUsingByteBuffer() { + assertEquals(1.1f, byteArrayToFloatWithByteBuffer(new byte[] { 63, -116, -52, -51}), 0); + } + + @Test + public void givenAFloat_thenConvertToByteArray_thenConvertToFloat() { + float floatToConvert = 200.12f; + byte[] byteArray = floatToByteArray(floatToConvert); + assertEquals(200.12f, byteArrayToFloat(byteArray), 0); + } + + @Test + public void givenAFloat_thenConvertToByteArrayWithByteBuffer_thenConvertToFloatWithByteBuffer() { + float floatToConvert = 30100.42f; + byte[] byteArray = floatToByteArrayWithByteBuffer(floatToConvert); + assertEquals(30100.42f, byteArrayToFloatWithByteBuffer(byteArray), 0); + } +} From 4c7ef02bf3781299a09db3430c2989648f6d5841 Mon Sep 17 00:00:00 2001 From: Andrea Ligios Date: Wed, 23 Jan 2019 18:12:06 +0100 Subject: [PATCH 18/33] BAEL-2294 (#6191) * BAEL-2294 * BAEL-2294 * live tests... * formatting * Live Tests! But not parent pom. Yet. --- blade/README.md | 5 + blade/pom.xml | 189 ++++++++++++++++++ .../java/com/baeldung/blade/sample/App.java | 38 ++++ .../sample/AttributesExampleController.java | 37 ++++ .../blade/sample/LogExampleController.java | 22 ++ .../ParameterInjectionExampleController.java | 71 +++++++ .../blade/sample/RouteExampleController.java | 78 ++++++++ .../configuration/BaeldungException.java | 9 + .../configuration/GlobalExceptionHandler.java | 25 +++ .../sample/configuration/LoadConfig.java | 23 +++ .../sample/configuration/ScheduleExample.java | 15 ++ .../sample/interceptors/BaeldungHook.java | 17 ++ .../interceptors/BaeldungMiddleware.java | 15 ++ .../com/baeldung/blade/sample/vo/User.java | 16 ++ .../src/main/resources/application.properties | 5 + .../src/main/resources/custom-static/icon.png | Bin 0 -> 28893 bytes blade/src/main/resources/favicon.ico | Bin 0 -> 650 bytes blade/src/main/resources/static/app.css | 1 + blade/src/main/resources/static/app.js | 0 .../main/resources/static/file-upload.html | 43 ++++ .../src/main/resources/static/user-post.html | 25 +++ .../main/resources/templates/allmatch.html | 1 + .../src/main/resources/templates/delete.html | 1 + blade/src/main/resources/templates/get.html | 1 + blade/src/main/resources/templates/index.html | 30 +++ .../src/main/resources/templates/my-404.html | 10 + .../src/main/resources/templates/my-500.html | 12 ++ blade/src/main/resources/templates/post.html | 1 + blade/src/main/resources/templates/put.html | 1 + .../templates/template-output-test.html | 1 + .../baeldung/blade/sample/AppLiveTest.java | 56 ++++++ .../AttributesExampleControllerLiveTest.java | 55 +++++ ...terInjectionExampleControllerLiveTest.java | 82 ++++++++ .../RouteExampleControllerLiveTest.java | 117 +++++++++++ pom.xml | 2 + 35 files changed, 1004 insertions(+) create mode 100644 blade/README.md create mode 100644 blade/pom.xml create mode 100644 blade/src/main/java/com/baeldung/blade/sample/App.java create mode 100644 blade/src/main/java/com/baeldung/blade/sample/AttributesExampleController.java create mode 100644 blade/src/main/java/com/baeldung/blade/sample/LogExampleController.java create mode 100644 blade/src/main/java/com/baeldung/blade/sample/ParameterInjectionExampleController.java create mode 100644 blade/src/main/java/com/baeldung/blade/sample/RouteExampleController.java create mode 100644 blade/src/main/java/com/baeldung/blade/sample/configuration/BaeldungException.java create mode 100644 blade/src/main/java/com/baeldung/blade/sample/configuration/GlobalExceptionHandler.java create mode 100644 blade/src/main/java/com/baeldung/blade/sample/configuration/LoadConfig.java create mode 100644 blade/src/main/java/com/baeldung/blade/sample/configuration/ScheduleExample.java create mode 100644 blade/src/main/java/com/baeldung/blade/sample/interceptors/BaeldungHook.java create mode 100644 blade/src/main/java/com/baeldung/blade/sample/interceptors/BaeldungMiddleware.java create mode 100644 blade/src/main/java/com/baeldung/blade/sample/vo/User.java create mode 100644 blade/src/main/resources/application.properties create mode 100644 blade/src/main/resources/custom-static/icon.png create mode 100644 blade/src/main/resources/favicon.ico create mode 100644 blade/src/main/resources/static/app.css create mode 100644 blade/src/main/resources/static/app.js create mode 100644 blade/src/main/resources/static/file-upload.html create mode 100644 blade/src/main/resources/static/user-post.html create mode 100644 blade/src/main/resources/templates/allmatch.html create mode 100644 blade/src/main/resources/templates/delete.html create mode 100644 blade/src/main/resources/templates/get.html create mode 100644 blade/src/main/resources/templates/index.html create mode 100644 blade/src/main/resources/templates/my-404.html create mode 100644 blade/src/main/resources/templates/my-500.html create mode 100644 blade/src/main/resources/templates/post.html create mode 100644 blade/src/main/resources/templates/put.html create mode 100644 blade/src/main/resources/templates/template-output-test.html create mode 100644 blade/src/test/java/com/baeldung/blade/sample/AppLiveTest.java create mode 100644 blade/src/test/java/com/baeldung/blade/sample/AttributesExampleControllerLiveTest.java create mode 100644 blade/src/test/java/com/baeldung/blade/sample/ParameterInjectionExampleControllerLiveTest.java create mode 100644 blade/src/test/java/com/baeldung/blade/sample/RouteExampleControllerLiveTest.java diff --git a/blade/README.md b/blade/README.md new file mode 100644 index 0000000000..d823de775f --- /dev/null +++ b/blade/README.md @@ -0,0 +1,5 @@ +### Relevant Articles: + +- [Blade - A Complete GuideBook](http://www.baeldung.com/blade) + +Run Integration Tests with `mvn integration-test` \ No newline at end of file diff --git a/blade/pom.xml b/blade/pom.xml new file mode 100644 index 0000000000..6bad505f4a --- /dev/null +++ b/blade/pom.xml @@ -0,0 +1,189 @@ + + + 4.0.0 + blade + blade + + + com.baeldung + 1.0.0-SNAPSHOT + + + + + + + + + + 1.8 + 1.8 + + + + + com.bladejava + blade-mvc + 2.0.14.RELEASE + + + + org.webjars + bootstrap + 4.2.1 + + + + org.apache.commons + commons-lang3 + 3.8.1 + + + + + org.projectlombok + lombok + 1.18.4 + provided + + + + + junit + junit + 4.12 + test + + + org.assertj + assertj-core + 3.11.1 + test + + + org.apache.httpcomponents + httpclient + 4.5.6 + test + + + org.apache.httpcomponents + httpmime + 4.5.6 + test + + + org.apache.httpcomponents + httpcore + 4.4.10 + test + + + + sample-blade-app + + + + org.apache.maven.plugins + maven-surefire-plugin + + 3 + true + + **/*LiveTest.java + + + + + + org.apache.maven.plugins + maven-failsafe-plugin + 3.0.0-M3 + + + **/*LiveTest.java + + + + + + integration-test + verify + + + + + + + com.bazaarvoice.maven.plugins + process-exec-maven-plugin + 0.7 + + + + blade-process + pre-integration-test + + start + + + Blade + false + + java + -jar + sample-blade-app.jar + + + + + + + stop-all + post-integration-test + + stop-all + + + + + + + + maven-assembly-plugin + 3.1.0 + + ${project.build.finalName} + false + + + com.baeldung.blade.sample.App + + + + jar-with-dependencies + + + + + make-assembly + package + + single + + + + + + maven-compiler-plugin + + 1.8 + 1.8 + UTF-8 + + + + + diff --git a/blade/src/main/java/com/baeldung/blade/sample/App.java b/blade/src/main/java/com/baeldung/blade/sample/App.java new file mode 100644 index 0000000000..f3f3d4aebd --- /dev/null +++ b/blade/src/main/java/com/baeldung/blade/sample/App.java @@ -0,0 +1,38 @@ +package com.baeldung.blade.sample; + +import com.baeldung.blade.sample.interceptors.BaeldungMiddleware; +import com.blade.Blade; +import com.blade.event.EventType; +import com.blade.mvc.WebContext; +import com.blade.mvc.http.Session; + +public class App { + + private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(App.class); + + public static void main(String[] args) { + + Blade.of() + .get("/", ctx -> ctx.render("index.html")) + .get("/basic-route-example", ctx -> ctx.text("GET called")) + .post("/basic-route-example", ctx -> ctx.text("POST called")) + .put("/basic-route-example", ctx -> ctx.text("PUT called")) + .delete("/basic-route-example", ctx -> ctx.text("DELETE called")) + .addStatics("/custom-static") + // .showFileList(true) + .enableCors(true) + .before("/user/*", ctx -> log.info("[NarrowedHook] Before '/user/*', URL called: " + ctx.uri())) + .on(EventType.SERVER_STARTED, e -> { + String version = WebContext.blade() + .env("app.version") + .orElse("N/D"); + log.info("[Event::serverStarted] Loading 'app.version' from configuration, value: " + version); + }) + .on(EventType.SESSION_CREATED, e -> { + Session session = (Session) e.attribute("session"); + session.attribute("mySessionValue", "Baeldung"); + }) + .use(new BaeldungMiddleware()) + .start(App.class, args); + } +} diff --git a/blade/src/main/java/com/baeldung/blade/sample/AttributesExampleController.java b/blade/src/main/java/com/baeldung/blade/sample/AttributesExampleController.java new file mode 100644 index 0000000000..339ba701f7 --- /dev/null +++ b/blade/src/main/java/com/baeldung/blade/sample/AttributesExampleController.java @@ -0,0 +1,37 @@ +package com.baeldung.blade.sample; + +import com.blade.mvc.annotation.GetRoute; +import com.blade.mvc.annotation.Path; +import com.blade.mvc.http.Request; +import com.blade.mvc.http.Response; +import com.blade.mvc.http.Session; + +@Path +public class AttributesExampleController { + + public final static String REQUEST_VALUE = "Some Request value"; + public final static String SESSION_VALUE = "1337"; + public final static String HEADER = "Some Header"; + + @GetRoute("/request-attribute-example") + public void getRequestAttribute(Request request, Response response) { + request.attribute("request-val", REQUEST_VALUE); + String requestVal = request.attribute("request-val"); + response.text(requestVal); + } + + @GetRoute("/session-attribute-example") + public void getSessionAttribute(Request request, Response response) { + Session session = request.session(); + session.attribute("session-val", SESSION_VALUE); + String sessionVal = session.attribute("session-val"); + response.text(sessionVal); + } + + @GetRoute("/header-example") + public void getHeader(Request request, Response response) { + String headerVal = request.header("a-header", HEADER); + response.header("a-header", headerVal); + } + +} diff --git a/blade/src/main/java/com/baeldung/blade/sample/LogExampleController.java b/blade/src/main/java/com/baeldung/blade/sample/LogExampleController.java new file mode 100644 index 0000000000..f0c22c70dd --- /dev/null +++ b/blade/src/main/java/com/baeldung/blade/sample/LogExampleController.java @@ -0,0 +1,22 @@ +package com.baeldung.blade.sample; + +import com.blade.mvc.annotation.Path; +import com.blade.mvc.annotation.Route; +import com.blade.mvc.http.Response; + +@Path +public class LogExampleController { + + private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LogExampleController.class); + + @Route(value = "/test-logs") + public void testLogs(Response response) { + log.trace("This is a TRACE Message"); + log.debug("This is a DEBUG Message"); + log.info("This is an INFO Message"); + log.warn("This is a WARN Message"); + log.error("This is an ERROR Message"); + response.text("Check in ./logs"); + } + +} diff --git a/blade/src/main/java/com/baeldung/blade/sample/ParameterInjectionExampleController.java b/blade/src/main/java/com/baeldung/blade/sample/ParameterInjectionExampleController.java new file mode 100644 index 0000000000..bc28244022 --- /dev/null +++ b/blade/src/main/java/com/baeldung/blade/sample/ParameterInjectionExampleController.java @@ -0,0 +1,71 @@ +package com.baeldung.blade.sample; + +import java.nio.file.Files; +import java.nio.file.StandardOpenOption; + +import com.baeldung.blade.sample.vo.User; +import com.blade.mvc.annotation.CookieParam; +import com.blade.mvc.annotation.GetRoute; +import com.blade.mvc.annotation.HeaderParam; +import com.blade.mvc.annotation.JSON; +import com.blade.mvc.annotation.MultipartParam; +import com.blade.mvc.annotation.Param; +import com.blade.mvc.annotation.Path; +import com.blade.mvc.annotation.PathParam; +import com.blade.mvc.annotation.PostRoute; +import com.blade.mvc.http.Response; +import com.blade.mvc.multipart.FileItem; +import com.blade.mvc.ui.RestResponse; + +@Path +public class ParameterInjectionExampleController { + + private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(ParameterInjectionExampleController.class); + + @GetRoute("/params/form") + public void formParam(@Param String name, Response response) { + log.info("name: " + name); + response.text(name); + } + + @GetRoute("/params/path/:uid") + public void restfulParam(@PathParam Integer uid, Response response) { + log.info("uid: " + uid); + response.text(String.valueOf(uid)); + } + + @PostRoute("/params-file") // DO NOT USE A SLASH WITHIN THE ROUTE OR IT WILL BREAK (?) + @JSON + public RestResponse fileParam(@MultipartParam FileItem fileItem) throws Exception { + try { + byte[] fileContent = fileItem.getData(); + + log.debug("Saving the uploaded file"); + java.nio.file.Path tempFile = Files.createTempFile("baeldung_tempfiles", ".tmp"); + Files.write(tempFile, fileContent, StandardOpenOption.WRITE); + + return RestResponse.ok(); + } catch (Exception e) { + log.error(e.getMessage(), e); + return RestResponse.fail(e.getMessage()); + } + } + + @GetRoute("/params/header") + public void headerParam(@HeaderParam String customheader, Response response) { + log.info("Custom header: " + customheader); + response.text(customheader); + } + + @GetRoute("/params/cookie") + public void cookieParam(@CookieParam(defaultValue = "default value") String myCookie, Response response) { + log.info("myCookie: " + myCookie); + response.text(myCookie); + } + + @PostRoute("/params/vo") + public void voParam(@Param User user, Response response) { + log.info("user as voParam: " + user.toString()); + response.html(user.toString() + "

Back"); + } +} \ No newline at end of file diff --git a/blade/src/main/java/com/baeldung/blade/sample/RouteExampleController.java b/blade/src/main/java/com/baeldung/blade/sample/RouteExampleController.java new file mode 100644 index 0000000000..7ba2a270a9 --- /dev/null +++ b/blade/src/main/java/com/baeldung/blade/sample/RouteExampleController.java @@ -0,0 +1,78 @@ +package com.baeldung.blade.sample; + +import com.baeldung.blade.sample.configuration.BaeldungException; +import com.blade.mvc.WebContext; +import com.blade.mvc.annotation.DeleteRoute; +import com.blade.mvc.annotation.GetRoute; +import com.blade.mvc.annotation.Path; +import com.blade.mvc.annotation.PostRoute; +import com.blade.mvc.annotation.PutRoute; +import com.blade.mvc.annotation.Route; +import com.blade.mvc.http.HttpMethod; +import com.blade.mvc.http.Request; +import com.blade.mvc.http.Response; + +@Path +public class RouteExampleController { + + private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(RouteExampleController.class); + + @GetRoute("/route-example") + public String get() { + return "get.html"; + } + + @PostRoute("/route-example") + public String post() { + return "post.html"; + } + + @PutRoute("/route-example") + public String put() { + return "put.html"; + } + + @DeleteRoute("/route-example") + public String delete() { + return "delete.html"; + } + + @Route(value = "/another-route-example", method = HttpMethod.GET) + public String anotherGet() { + return "get.html"; + } + + @Route(value = "/allmatch-route-example") + public String allmatch() { + return "allmatch.html"; + } + + @Route(value = "/triggerInternalServerError") + public void triggerInternalServerError() { + int x = 1 / 0; + } + + @Route(value = "/triggerBaeldungException") + public void triggerBaeldungException() throws BaeldungException { + throw new BaeldungException("Foobar Exception to threat differently"); + } + + @Route(value = "/user/foo") + public void urlCoveredByNarrowedWebhook(Response response) { + response.text("Check out for the WebHook covering '/user/*' in the logs"); + } + + @GetRoute("/load-configuration-in-a-route") + public void loadConfigurationInARoute(Response response) { + String authors = WebContext.blade() + .env("app.authors", "Unknown authors"); + log.info("[/load-configuration-in-a-route] Loading 'app.authors' from configuration, value: " + authors); + response.render("index.html"); + } + + @GetRoute("/template-output-test") + public void templateOutputTest(Request request, Response response) { + request.attribute("name", "Blade"); + response.render("template-output-test.html"); + } +} diff --git a/blade/src/main/java/com/baeldung/blade/sample/configuration/BaeldungException.java b/blade/src/main/java/com/baeldung/blade/sample/configuration/BaeldungException.java new file mode 100644 index 0000000000..01a030b7e7 --- /dev/null +++ b/blade/src/main/java/com/baeldung/blade/sample/configuration/BaeldungException.java @@ -0,0 +1,9 @@ +package com.baeldung.blade.sample.configuration; + +public class BaeldungException extends RuntimeException { + + public BaeldungException(String message) { + super(message); + } + +} \ No newline at end of file diff --git a/blade/src/main/java/com/baeldung/blade/sample/configuration/GlobalExceptionHandler.java b/blade/src/main/java/com/baeldung/blade/sample/configuration/GlobalExceptionHandler.java new file mode 100644 index 0000000000..ab7b81c0dc --- /dev/null +++ b/blade/src/main/java/com/baeldung/blade/sample/configuration/GlobalExceptionHandler.java @@ -0,0 +1,25 @@ +package com.baeldung.blade.sample.configuration; + +import com.blade.ioc.annotation.Bean; +import com.blade.mvc.WebContext; +import com.blade.mvc.handler.DefaultExceptionHandler; + +@Bean +public class GlobalExceptionHandler extends DefaultExceptionHandler { + + private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(GlobalExceptionHandler.class); + + @Override + public void handle(Exception e) { + if (e instanceof BaeldungException) { + Exception baeldungException = (BaeldungException) e; + String msg = baeldungException.getMessage(); + log.error("[GlobalExceptionHandler] Intercepted an exception to threat with additional logic. Error message: " + msg); + WebContext.response() + .render("index.html"); + + } else { + super.handle(e); + } + } +} \ No newline at end of file diff --git a/blade/src/main/java/com/baeldung/blade/sample/configuration/LoadConfig.java b/blade/src/main/java/com/baeldung/blade/sample/configuration/LoadConfig.java new file mode 100644 index 0000000000..0f1aab1b52 --- /dev/null +++ b/blade/src/main/java/com/baeldung/blade/sample/configuration/LoadConfig.java @@ -0,0 +1,23 @@ +package com.baeldung.blade.sample.configuration; + +import com.blade.Blade; +import com.blade.ioc.annotation.Bean; +import com.blade.loader.BladeLoader; +import com.blade.mvc.WebContext; + +@Bean +public class LoadConfig implements BladeLoader { + + private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LoadConfig.class); + + @Override + public void load(Blade blade) { + String version = WebContext.blade() + .env("app.version") + .orElse("N/D"); + String authors = WebContext.blade() + .env("app.authors", "Unknown authors"); + + log.info("[LoadConfig] loaded 'app.version' (" + version + ") and 'app.authors' (" + authors + ") in a configuration bean"); + } +} \ No newline at end of file diff --git a/blade/src/main/java/com/baeldung/blade/sample/configuration/ScheduleExample.java b/blade/src/main/java/com/baeldung/blade/sample/configuration/ScheduleExample.java new file mode 100644 index 0000000000..c170975818 --- /dev/null +++ b/blade/src/main/java/com/baeldung/blade/sample/configuration/ScheduleExample.java @@ -0,0 +1,15 @@ +package com.baeldung.blade.sample.configuration; + +import com.blade.ioc.annotation.Bean; +import com.blade.task.annotation.Schedule; + +@Bean +public class ScheduleExample { + + private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(ScheduleExample.class); + + @Schedule(name = "baeldungTask", cron = "0 */1 * * * ?") + public void runScheduledTask() { + log.info("[ScheduleExample] This is a scheduled Task running once per minute."); + } +} diff --git a/blade/src/main/java/com/baeldung/blade/sample/interceptors/BaeldungHook.java b/blade/src/main/java/com/baeldung/blade/sample/interceptors/BaeldungHook.java new file mode 100644 index 0000000000..4d0d178b0d --- /dev/null +++ b/blade/src/main/java/com/baeldung/blade/sample/interceptors/BaeldungHook.java @@ -0,0 +1,17 @@ +package com.baeldung.blade.sample.interceptors; + +import com.blade.ioc.annotation.Bean; +import com.blade.mvc.RouteContext; +import com.blade.mvc.hook.WebHook; + +@Bean +public class BaeldungHook implements WebHook { + + private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(BaeldungHook.class); + + @Override + public boolean before(RouteContext ctx) { + log.info("[BaeldungHook] called before Route method"); + return true; + } +} \ No newline at end of file diff --git a/blade/src/main/java/com/baeldung/blade/sample/interceptors/BaeldungMiddleware.java b/blade/src/main/java/com/baeldung/blade/sample/interceptors/BaeldungMiddleware.java new file mode 100644 index 0000000000..3342cd8b01 --- /dev/null +++ b/blade/src/main/java/com/baeldung/blade/sample/interceptors/BaeldungMiddleware.java @@ -0,0 +1,15 @@ +package com.baeldung.blade.sample.interceptors; + +import com.blade.mvc.RouteContext; +import com.blade.mvc.hook.WebHook; + +public class BaeldungMiddleware implements WebHook { + + private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(BaeldungMiddleware.class); + + @Override + public boolean before(RouteContext context) { + log.info("[BaeldungMiddleware] called before Route method and other WebHooks"); + return true; + } +} \ No newline at end of file diff --git a/blade/src/main/java/com/baeldung/blade/sample/vo/User.java b/blade/src/main/java/com/baeldung/blade/sample/vo/User.java new file mode 100644 index 0000000000..b493dc3663 --- /dev/null +++ b/blade/src/main/java/com/baeldung/blade/sample/vo/User.java @@ -0,0 +1,16 @@ +package com.baeldung.blade.sample.vo; + +import org.apache.commons.lang3.builder.ReflectionToStringBuilder; + +import lombok.Getter; +import lombok.Setter; + +public class User { + @Getter @Setter private String name; + @Getter @Setter private String site; + + @Override + public String toString() { + return ReflectionToStringBuilder.toString(this); + } +} \ No newline at end of file diff --git a/blade/src/main/resources/application.properties b/blade/src/main/resources/application.properties new file mode 100644 index 0000000000..ebf365406a --- /dev/null +++ b/blade/src/main/resources/application.properties @@ -0,0 +1,5 @@ +mvc.statics.show-list=true +mvc.view.404=my-404.html +mvc.view.500=my-500.html +app.version=0.0.1 +app.authors=Andrea Ligios diff --git a/blade/src/main/resources/custom-static/icon.png b/blade/src/main/resources/custom-static/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..59af395afc55f38e5a727a119b4627088753c28e GIT binary patch literal 28893 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 literal 0 HcmV?d00001 diff --git a/blade/src/main/resources/static/app.css b/blade/src/main/resources/static/app.css new file mode 100644 index 0000000000..9fff13d9b6 --- /dev/null +++ b/blade/src/main/resources/static/app.css @@ -0,0 +1 @@ +/* App CSS */ \ No newline at end of file diff --git a/blade/src/main/resources/static/app.js b/blade/src/main/resources/static/app.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/blade/src/main/resources/static/file-upload.html b/blade/src/main/resources/static/file-upload.html new file mode 100644 index 0000000000..b805be81b1 --- /dev/null +++ b/blade/src/main/resources/static/file-upload.html @@ -0,0 +1,43 @@ + + + + +Title + + + + + +

File Upload and download test

+
+ + +
+ +
+ Back + + + + \ No newline at end of file diff --git a/blade/src/main/resources/static/user-post.html b/blade/src/main/resources/static/user-post.html new file mode 100644 index 0000000000..ccfc4e8d0b --- /dev/null +++ b/blade/src/main/resources/static/user-post.html @@ -0,0 +1,25 @@ + + + + +Title + + + + + +

User POJO post test

+ + +
+ Person POJO: + + + +
+ +
+ Back + + + \ No newline at end of file diff --git a/blade/src/main/resources/templates/allmatch.html b/blade/src/main/resources/templates/allmatch.html new file mode 100644 index 0000000000..7a4bfa070f --- /dev/null +++ b/blade/src/main/resources/templates/allmatch.html @@ -0,0 +1 @@ +ALLMATCH called \ No newline at end of file diff --git a/blade/src/main/resources/templates/delete.html b/blade/src/main/resources/templates/delete.html new file mode 100644 index 0000000000..1acb4b0b62 --- /dev/null +++ b/blade/src/main/resources/templates/delete.html @@ -0,0 +1 @@ +DELETE called \ No newline at end of file diff --git a/blade/src/main/resources/templates/get.html b/blade/src/main/resources/templates/get.html new file mode 100644 index 0000000000..2c37aa1058 --- /dev/null +++ b/blade/src/main/resources/templates/get.html @@ -0,0 +1 @@ +GET called \ No newline at end of file diff --git a/blade/src/main/resources/templates/index.html b/blade/src/main/resources/templates/index.html new file mode 100644 index 0000000000..6b7c2e77ad --- /dev/null +++ b/blade/src/main/resources/templates/index.html @@ -0,0 +1,30 @@ + + + + +Baeldung Blade App • Written by Andrea Ligios + + + +

Baeldung Blade App - Showcase

+ +

Manual tests

+

The following are tests which are not covered by integration tests, but that can be run manually in order to check the functionality, either in the browser or in the logs, depending on the case.

+ + + + +

Session value created in App.java

+

mySessionValue = ${mySessionValue}

+ + + + + \ No newline at end of file diff --git a/blade/src/main/resources/templates/my-404.html b/blade/src/main/resources/templates/my-404.html new file mode 100644 index 0000000000..0fa694f241 --- /dev/null +++ b/blade/src/main/resources/templates/my-404.html @@ -0,0 +1,10 @@ + + + + + 404 Not found + + + Custom Error 404 Page + + \ No newline at end of file diff --git a/blade/src/main/resources/templates/my-500.html b/blade/src/main/resources/templates/my-500.html new file mode 100644 index 0000000000..cc8438bfd6 --- /dev/null +++ b/blade/src/main/resources/templates/my-500.html @@ -0,0 +1,12 @@ + + + + + 500 Internal Server Error + + +

Custom Error 500 Page

+

The following error occurred: "${message}"

+
 ${stackTrace} 
+ + \ No newline at end of file diff --git a/blade/src/main/resources/templates/post.html b/blade/src/main/resources/templates/post.html new file mode 100644 index 0000000000..b7a8a931cd --- /dev/null +++ b/blade/src/main/resources/templates/post.html @@ -0,0 +1 @@ +POST called \ No newline at end of file diff --git a/blade/src/main/resources/templates/put.html b/blade/src/main/resources/templates/put.html new file mode 100644 index 0000000000..bdbe6d3285 --- /dev/null +++ b/blade/src/main/resources/templates/put.html @@ -0,0 +1 @@ +PUT called \ No newline at end of file diff --git a/blade/src/main/resources/templates/template-output-test.html b/blade/src/main/resources/templates/template-output-test.html new file mode 100644 index 0000000000..233b12fb88 --- /dev/null +++ b/blade/src/main/resources/templates/template-output-test.html @@ -0,0 +1 @@ +

Hello, ${name}!

\ No newline at end of file diff --git a/blade/src/test/java/com/baeldung/blade/sample/AppLiveTest.java b/blade/src/test/java/com/baeldung/blade/sample/AppLiveTest.java new file mode 100644 index 0000000000..1172e6755f --- /dev/null +++ b/blade/src/test/java/com/baeldung/blade/sample/AppLiveTest.java @@ -0,0 +1,56 @@ +package com.baeldung.blade.sample; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpDelete; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.client.methods.HttpPut; +import org.apache.http.client.methods.HttpUriRequest; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.util.EntityUtils; +import org.junit.Test; + +public class AppLiveTest { + + @Test + public void givenBasicRoute_whenGet_thenCorrectOutput() throws Exception { + final HttpUriRequest request = new HttpGet("http://localhost:9000/basic-route-example"); + try (final CloseableHttpResponse httpResponse = HttpClientBuilder.create() + .build() + .execute(request);) { + assertThat(EntityUtils.toString(httpResponse.getEntity())).isEqualTo("GET called"); + } + } + + @Test + public void givenBasicRoute_whenPost_thenCorrectOutput() throws Exception { + final HttpUriRequest request = new HttpPost("http://localhost:9000/basic-route-example"); + try (final CloseableHttpResponse httpResponse = HttpClientBuilder.create() + .build() + .execute(request);) { + assertThat(EntityUtils.toString(httpResponse.getEntity())).isEqualTo("POST called"); + } + } + + @Test + public void givenBasicRoute_whenPut_thenCorrectOutput() throws Exception { + final HttpUriRequest request = new HttpPut("http://localhost:9000/basic-route-example"); + try (final CloseableHttpResponse httpResponse = HttpClientBuilder.create() + .build() + .execute(request);) { + assertThat(EntityUtils.toString(httpResponse.getEntity())).isEqualTo("PUT called"); + } + } + + @Test + public void givenBasicRoute_whenDelete_thenCorrectOutput() throws Exception { + final HttpUriRequest request = new HttpDelete("http://localhost:9000/basic-route-example"); + try (final CloseableHttpResponse httpResponse = HttpClientBuilder.create() + .build() + .execute(request);) { + assertThat(EntityUtils.toString(httpResponse.getEntity())).isEqualTo("DELETE called"); + } + } +} diff --git a/blade/src/test/java/com/baeldung/blade/sample/AttributesExampleControllerLiveTest.java b/blade/src/test/java/com/baeldung/blade/sample/AttributesExampleControllerLiveTest.java new file mode 100644 index 0000000000..7cf00c2d4b --- /dev/null +++ b/blade/src/test/java/com/baeldung/blade/sample/AttributesExampleControllerLiveTest.java @@ -0,0 +1,55 @@ +package com.baeldung.blade.sample; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpUriRequest; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.util.EntityUtils; +import org.junit.Test; + +public class AttributesExampleControllerLiveTest { + + @Test + public void givenRequestAttribute_whenSet_thenRetrieveWithGet() throws Exception { + final HttpUriRequest request = new HttpGet("http://localhost:9000/request-attribute-example"); + try (final CloseableHttpResponse httpResponse = HttpClientBuilder.create() + .build() + .execute(request);) { + assertThat(EntityUtils.toString(httpResponse.getEntity())).isEqualTo(AttributesExampleController.REQUEST_VALUE); + } + } + + @Test + public void givenSessionAttribute_whenSet_thenRetrieveWithGet() throws Exception { + final HttpUriRequest request = new HttpGet("http://localhost:9000/session-attribute-example"); + try (final CloseableHttpResponse httpResponse = HttpClientBuilder.create() + .build() + .execute(request);) { + assertThat(EntityUtils.toString(httpResponse.getEntity())).isEqualTo(AttributesExampleController.SESSION_VALUE); + } + } + + @Test + public void givenHeader_whenSet_thenRetrieveWithGet() throws Exception { + final HttpUriRequest request = new HttpGet("http://localhost:9000/header-example"); + request.addHeader("a-header","foobar"); + try (final CloseableHttpResponse httpResponse = HttpClientBuilder.create() + .build() + .execute(request);) { + assertThat(httpResponse.getHeaders("a-header")[0].getValue()).isEqualTo("foobar"); + } + } + + @Test + public void givenNoHeader_whenSet_thenRetrieveDefaultValueWithGet() throws Exception { + final HttpUriRequest request = new HttpGet("http://localhost:9000/header-example"); + try (final CloseableHttpResponse httpResponse = HttpClientBuilder.create() + .build() + .execute(request);) { + assertThat(httpResponse.getHeaders("a-header")[0].getValue()).isEqualTo(AttributesExampleController.HEADER); + } + } + +} diff --git a/blade/src/test/java/com/baeldung/blade/sample/ParameterInjectionExampleControllerLiveTest.java b/blade/src/test/java/com/baeldung/blade/sample/ParameterInjectionExampleControllerLiveTest.java new file mode 100644 index 0000000000..fbd5280116 --- /dev/null +++ b/blade/src/test/java/com/baeldung/blade/sample/ParameterInjectionExampleControllerLiveTest.java @@ -0,0 +1,82 @@ +package com.baeldung.blade.sample; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpUriRequest; +import org.apache.http.client.utils.URIBuilder; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.util.EntityUtils; +import org.junit.Test; + +public class ParameterInjectionExampleControllerLiveTest { + + @Test + public void givenFormParam_whenSet_thenRetrieveWithGet() throws Exception { + URIBuilder builder = new URIBuilder("http://localhost:9000/params/form"); + builder.setParameter("name", "Andrea Ligios"); + + final HttpUriRequest request = new HttpGet(builder.build()); + + try (final CloseableHttpResponse httpResponse = HttpClientBuilder.create() + .build() + .execute(request);) { + assertThat(EntityUtils.toString(httpResponse.getEntity())).isEqualTo("Andrea Ligios"); + } + } + + @Test + public void givenPathParam_whenSet_thenRetrieveWithGet() throws Exception { + final HttpUriRequest request = new HttpGet("http://localhost:9000/params/path/1337"); + + try (final CloseableHttpResponse httpResponse = HttpClientBuilder.create() + .build() + .execute(request);) { + assertThat(EntityUtils.toString(httpResponse.getEntity())).isEqualTo("1337"); + } + } + + // @Test + // public void givenFileParam_whenSet_thenRetrieveWithGet() throws Exception { + // + // byte[] data = "this is some temp file content".getBytes("UTF-8"); + // java.nio.file.Path tempFile = Files.createTempFile("baeldung_test_tempfiles", ".tmp"); + // Files.write(tempFile, data, StandardOpenOption.WRITE); + // + // //HttpEntity entity = MultipartEntityBuilder.create().addPart("file", new FileBody(tempFile.toFile())).build(); + // HttpEntity entity = MultipartEntityBuilder.create().addTextBody("field1", "value1") + // .addBinaryBody("fileItem", tempFile.toFile(), ContentType.create("application/octet-stream"), "file1.txt").build(); + // + // final HttpPost post = new HttpPost("http://localhost:9000/params-file"); + // post.setEntity(entity); + // + // try (final CloseableHttpResponse httpResponse = HttpClientBuilder.create().build().execute(post);) { + // assertThat(EntityUtils.toString(httpResponse.getEntity())).isEqualTo("file1.txt"); + // } + // } + + @Test + public void givenHeader_whenSet_thenRetrieveWithGet() throws Exception { + final HttpUriRequest request = new HttpGet("http://localhost:9000/params/header"); + request.addHeader("customheader", "foobar"); + try (final CloseableHttpResponse httpResponse = HttpClientBuilder.create() + .build() + .execute(request);) { + assertThat(EntityUtils.toString(httpResponse.getEntity())).isEqualTo("foobar"); + } + } + + @Test + public void givenNoCookie_whenCalled_thenReadDefaultValue() throws Exception { + + final HttpUriRequest request = new HttpGet("http://localhost:9000/params/cookie"); + try (final CloseableHttpResponse httpResponse = HttpClientBuilder.create() + .build() + .execute(request);) { + assertThat(EntityUtils.toString(httpResponse.getEntity())).isEqualTo("default value"); + } + + } + +} diff --git a/blade/src/test/java/com/baeldung/blade/sample/RouteExampleControllerLiveTest.java b/blade/src/test/java/com/baeldung/blade/sample/RouteExampleControllerLiveTest.java new file mode 100644 index 0000000000..df8e70c461 --- /dev/null +++ b/blade/src/test/java/com/baeldung/blade/sample/RouteExampleControllerLiveTest.java @@ -0,0 +1,117 @@ +package com.baeldung.blade.sample; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpDelete; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.client.methods.HttpPut; +import org.apache.http.client.methods.HttpUriRequest; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.util.EntityUtils; +import org.junit.Test; + +public class RouteExampleControllerLiveTest { + + @Test + public void givenRoute_whenGet_thenCorrectOutput() throws Exception { + final HttpUriRequest request = new HttpGet("http://localhost:9000/route-example"); + try (final CloseableHttpResponse httpResponse = HttpClientBuilder.create() + .build() + .execute(request);) { + assertThat(EntityUtils.toString(httpResponse.getEntity())).isEqualTo("GET called"); + } + } + + @Test + public void givenRoute_whenPost_thenCorrectOutput() throws Exception { + final HttpUriRequest request = new HttpPost("http://localhost:9000/route-example"); + try (final CloseableHttpResponse httpResponse = HttpClientBuilder.create() + .build() + .execute(request);) { + assertThat(EntityUtils.toString(httpResponse.getEntity())).isEqualTo("POST called"); + } + } + + @Test + public void givenRoute_whenPut_thenCorrectOutput() throws Exception { + final HttpUriRequest request = new HttpPut("http://localhost:9000/route-example"); + try (final CloseableHttpResponse httpResponse = HttpClientBuilder.create() + .build() + .execute(request);) { + assertThat(EntityUtils.toString(httpResponse.getEntity())).isEqualTo("PUT called"); + } + } + + @Test + public void givenRoute_whenDelete_thenCorrectOutput() throws Exception { + final HttpUriRequest request = new HttpDelete("http://localhost:9000/route-example"); + try (final CloseableHttpResponse httpResponse = HttpClientBuilder.create() + .build() + .execute(request);) { + assertThat(EntityUtils.toString(httpResponse.getEntity())).isEqualTo("DELETE called"); + } + } + + @Test + public void givenAnotherRoute_whenGet_thenCorrectOutput() throws Exception { + final HttpUriRequest request = new HttpGet("http://localhost:9000/another-route-example"); + try (final CloseableHttpResponse httpResponse = HttpClientBuilder.create() + .build() + .execute(request);) { + assertThat(EntityUtils.toString(httpResponse.getEntity())).isEqualTo("GET called"); + } + } + + @Test + public void givenAllMatchRoute_whenGet_thenCorrectOutput() throws Exception { + final HttpUriRequest request = new HttpGet("http://localhost:9000/allmatch-route-example"); + try (final CloseableHttpResponse httpResponse = HttpClientBuilder.create() + .build() + .execute(request);) { + assertThat(EntityUtils.toString(httpResponse.getEntity())).isEqualTo("ALLMATCH called"); + } + } + + @Test + public void givenAllMatchRoute_whenPost_thenCorrectOutput() throws Exception { + final HttpUriRequest request = new HttpPost("http://localhost:9000/allmatch-route-example"); + try (final CloseableHttpResponse httpResponse = HttpClientBuilder.create() + .build() + .execute(request);) { + assertThat(EntityUtils.toString(httpResponse.getEntity())).isEqualTo("ALLMATCH called"); + } + } + + @Test + public void givenAllMatchRoute_whenPut_thenCorrectOutput() throws Exception { + final HttpUriRequest request = new HttpPut("http://localhost:9000/allmatch-route-example"); + try (final CloseableHttpResponse httpResponse = HttpClientBuilder.create() + .build() + .execute(request);) { + assertThat(EntityUtils.toString(httpResponse.getEntity())).isEqualTo("ALLMATCH called"); + } + } + + @Test + public void givenAllMatchRoute_whenDelete_thenCorrectOutput() throws Exception { + final HttpUriRequest request = new HttpDelete("http://localhost:9000/allmatch-route-example"); + try (final CloseableHttpResponse httpResponse = HttpClientBuilder.create() + .build() + .execute(request);) { + assertThat(EntityUtils.toString(httpResponse.getEntity())).isEqualTo("ALLMATCH called"); + } + } + + @Test + public void givenRequestAttribute_whenRenderedWithTemplate_thenCorrectlyEvaluateIt() throws Exception { + final HttpUriRequest request = new HttpGet("http://localhost:9000/template-output-test"); + try (final CloseableHttpResponse httpResponse = HttpClientBuilder.create() + .build() + .execute(request);) { + assertThat(EntityUtils.toString(httpResponse.getEntity())).isEqualTo("

Hello, Blade!

"); + } + } + +} diff --git a/pom.xml b/pom.xml index 1c0738cafb..d084d0f7af 100644 --- a/pom.xml +++ b/pom.xml @@ -367,6 +367,8 @@ axon azure + blade + bootique cas/cas-secured-app From f2d26dfa38941c9088883ebfc6fd6c5f0877f736 Mon Sep 17 00:00:00 2001 From: Michael Pratt Date: Wed, 23 Jan 2019 17:45:07 -0700 Subject: [PATCH 19/33] Move new code under different module --- pom.xml | 1 - .../scheduling/ScheduleJobsByProfile.java | 0 .../com/baeldung/scheduling/ScheduledJob.java | 0 .../scheduling/ScheduledJobsWithBoolean.java | 0 .../ScheduledJobsWithConditional.java | 0 .../ScheduledJobsWithExpression.java | 0 .../scheduling/SchedulingApplication.java | 0 spring-scheduling/.gitignore | 25 -- .../.mvn/wrapper/maven-wrapper.jar | Bin 48337 -> 0 bytes .../.mvn/wrapper/maven-wrapper.properties | 1 - spring-scheduling/mvnw | 286 ------------------ spring-scheduling/mvnw.cmd | 161 ---------- spring-scheduling/pom.xml | 42 --- .../src/main/resources/application.properties | 0 .../SchedulingApplicationTests.java | 17 -- 15 files changed, 533 deletions(-) rename {spring-scheduling => spring-boot-mvc}/src/main/java/com/baeldung/scheduling/ScheduleJobsByProfile.java (100%) rename {spring-scheduling => spring-boot-mvc}/src/main/java/com/baeldung/scheduling/ScheduledJob.java (100%) rename {spring-scheduling => spring-boot-mvc}/src/main/java/com/baeldung/scheduling/ScheduledJobsWithBoolean.java (100%) rename {spring-scheduling => spring-boot-mvc}/src/main/java/com/baeldung/scheduling/ScheduledJobsWithConditional.java (100%) rename {spring-scheduling => spring-boot-mvc}/src/main/java/com/baeldung/scheduling/ScheduledJobsWithExpression.java (100%) rename {spring-scheduling => spring-boot-mvc}/src/main/java/com/baeldung/scheduling/SchedulingApplication.java (100%) delete mode 100644 spring-scheduling/.gitignore delete mode 100644 spring-scheduling/.mvn/wrapper/maven-wrapper.jar delete mode 100644 spring-scheduling/.mvn/wrapper/maven-wrapper.properties delete mode 100755 spring-scheduling/mvnw delete mode 100644 spring-scheduling/mvnw.cmd delete mode 100644 spring-scheduling/pom.xml delete mode 100644 spring-scheduling/src/main/resources/application.properties delete mode 100644 spring-scheduling/src/test/java/com/baeldung/scheduling/SchedulingApplicationTests.java diff --git a/pom.xml b/pom.xml index 1f25dd0691..1dd2768793 100644 --- a/pom.xml +++ b/pom.xml @@ -714,7 +714,6 @@ spring-rest-simple spring-resttemplate spring-roo - spring-scheduling spring-security-acl spring-security-angular/server spring-security-cache-control diff --git a/spring-scheduling/src/main/java/com/baeldung/scheduling/ScheduleJobsByProfile.java b/spring-boot-mvc/src/main/java/com/baeldung/scheduling/ScheduleJobsByProfile.java similarity index 100% rename from spring-scheduling/src/main/java/com/baeldung/scheduling/ScheduleJobsByProfile.java rename to spring-boot-mvc/src/main/java/com/baeldung/scheduling/ScheduleJobsByProfile.java diff --git a/spring-scheduling/src/main/java/com/baeldung/scheduling/ScheduledJob.java b/spring-boot-mvc/src/main/java/com/baeldung/scheduling/ScheduledJob.java similarity index 100% rename from spring-scheduling/src/main/java/com/baeldung/scheduling/ScheduledJob.java rename to spring-boot-mvc/src/main/java/com/baeldung/scheduling/ScheduledJob.java diff --git a/spring-scheduling/src/main/java/com/baeldung/scheduling/ScheduledJobsWithBoolean.java b/spring-boot-mvc/src/main/java/com/baeldung/scheduling/ScheduledJobsWithBoolean.java similarity index 100% rename from spring-scheduling/src/main/java/com/baeldung/scheduling/ScheduledJobsWithBoolean.java rename to spring-boot-mvc/src/main/java/com/baeldung/scheduling/ScheduledJobsWithBoolean.java diff --git a/spring-scheduling/src/main/java/com/baeldung/scheduling/ScheduledJobsWithConditional.java b/spring-boot-mvc/src/main/java/com/baeldung/scheduling/ScheduledJobsWithConditional.java similarity index 100% rename from spring-scheduling/src/main/java/com/baeldung/scheduling/ScheduledJobsWithConditional.java rename to spring-boot-mvc/src/main/java/com/baeldung/scheduling/ScheduledJobsWithConditional.java diff --git a/spring-scheduling/src/main/java/com/baeldung/scheduling/ScheduledJobsWithExpression.java b/spring-boot-mvc/src/main/java/com/baeldung/scheduling/ScheduledJobsWithExpression.java similarity index 100% rename from spring-scheduling/src/main/java/com/baeldung/scheduling/ScheduledJobsWithExpression.java rename to spring-boot-mvc/src/main/java/com/baeldung/scheduling/ScheduledJobsWithExpression.java diff --git a/spring-scheduling/src/main/java/com/baeldung/scheduling/SchedulingApplication.java b/spring-boot-mvc/src/main/java/com/baeldung/scheduling/SchedulingApplication.java similarity index 100% rename from spring-scheduling/src/main/java/com/baeldung/scheduling/SchedulingApplication.java rename to spring-boot-mvc/src/main/java/com/baeldung/scheduling/SchedulingApplication.java diff --git a/spring-scheduling/.gitignore b/spring-scheduling/.gitignore deleted file mode 100644 index 82eca336e3..0000000000 --- a/spring-scheduling/.gitignore +++ /dev/null @@ -1,25 +0,0 @@ -/target/ -!.mvn/wrapper/maven-wrapper.jar - -### STS ### -.apt_generated -.classpath -.factorypath -.project -.settings -.springBeans -.sts4-cache - -### IntelliJ IDEA ### -.idea -*.iws -*.iml -*.ipr - -### NetBeans ### -/nbproject/private/ -/build/ -/nbbuild/ -/dist/ -/nbdist/ -/.nb-gradle/ \ No newline at end of file diff --git a/spring-scheduling/.mvn/wrapper/maven-wrapper.jar b/spring-scheduling/.mvn/wrapper/maven-wrapper.jar deleted file mode 100644 index 01e67997377a393fd672c7dcde9dccbedf0cb1e9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 48337 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 \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG="`dirname "$PRG"`/$link" - fi - done - - saveddir=`pwd` - - M2_HOME=`dirname "$PRG"`/.. - - # make it fully qualified - M2_HOME=`cd "$M2_HOME" && pwd` - - cd "$saveddir" - # echo Using m2 at $M2_HOME -fi - -# For Cygwin, ensure paths are in UNIX format before anything is touched -if $cygwin ; then - [ -n "$M2_HOME" ] && - M2_HOME=`cygpath --unix "$M2_HOME"` - [ -n "$JAVA_HOME" ] && - JAVA_HOME=`cygpath --unix "$JAVA_HOME"` - [ -n "$CLASSPATH" ] && - CLASSPATH=`cygpath --path --unix "$CLASSPATH"` -fi - -# For Mingw, ensure paths are in UNIX format before anything is touched -if $mingw ; then - [ -n "$M2_HOME" ] && - M2_HOME="`(cd "$M2_HOME"; pwd)`" - [ -n "$JAVA_HOME" ] && - JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" - # TODO classpath? -fi - -if [ -z "$JAVA_HOME" ]; then - javaExecutable="`which javac`" - if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then - # readlink(1) is not available as standard on Solaris 10. - readLink=`which readlink` - if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then - if $darwin ; then - javaHome="`dirname \"$javaExecutable\"`" - javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" - else - javaExecutable="`readlink -f \"$javaExecutable\"`" - fi - javaHome="`dirname \"$javaExecutable\"`" - javaHome=`expr "$javaHome" : '\(.*\)/bin'` - JAVA_HOME="$javaHome" - export JAVA_HOME - fi - fi -fi - -if [ -z "$JAVACMD" ] ; then - if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - else - JAVACMD="`which java`" - fi -fi - -if [ ! -x "$JAVACMD" ] ; then - echo "Error: JAVA_HOME is not defined correctly." >&2 - echo " We cannot execute $JAVACMD" >&2 - exit 1 -fi - -if [ -z "$JAVA_HOME" ] ; then - echo "Warning: JAVA_HOME environment variable is not set." -fi - -CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher - -# traverses directory structure from process work directory to filesystem root -# first directory with .mvn subdirectory is considered project base directory -find_maven_basedir() { - - if [ -z "$1" ] - then - echo "Path not specified to find_maven_basedir" - return 1 - fi - - basedir="$1" - wdir="$1" - while [ "$wdir" != '/' ] ; do - if [ -d "$wdir"/.mvn ] ; then - basedir=$wdir - break - fi - # workaround for JBEAP-8937 (on Solaris 10/Sparc) - if [ -d "${wdir}" ]; then - wdir=`cd "$wdir/.."; pwd` - fi - # end of workaround - done - echo "${basedir}" -} - -# concatenates all lines of a file -concat_lines() { - if [ -f "$1" ]; then - echo "$(tr -s '\n' ' ' < "$1")" - fi -} - -BASE_DIR=`find_maven_basedir "$(pwd)"` -if [ -z "$BASE_DIR" ]; then - exit 1; -fi - -########################################################################################## -# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central -# This allows using the maven wrapper in projects that prohibit checking in binary data. -########################################################################################## -if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found .mvn/wrapper/maven-wrapper.jar" - fi -else - if [ "$MVNW_VERBOSE" = true ]; then - echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." - fi - jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar" - while IFS="=" read key value; do - case "$key" in (wrapperUrl) jarUrl="$value"; break ;; - esac - done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" - if [ "$MVNW_VERBOSE" = true ]; then - echo "Downloading from: $jarUrl" - fi - wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" - - if command -v wget > /dev/null; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found wget ... using wget" - fi - wget "$jarUrl" -O "$wrapperJarPath" - elif command -v curl > /dev/null; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found curl ... using curl" - fi - curl -o "$wrapperJarPath" "$jarUrl" - else - if [ "$MVNW_VERBOSE" = true ]; then - echo "Falling back to using Java to download" - fi - javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" - if [ -e "$javaClass" ]; then - if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then - if [ "$MVNW_VERBOSE" = true ]; then - echo " - Compiling MavenWrapperDownloader.java ..." - fi - # Compiling the Java class - ("$JAVA_HOME/bin/javac" "$javaClass") - fi - if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then - # Running the downloader - if [ "$MVNW_VERBOSE" = true ]; then - echo " - Running MavenWrapperDownloader.java ..." - fi - ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") - fi - fi - fi -fi -########################################################################################## -# End of extension -########################################################################################## - -export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} -if [ "$MVNW_VERBOSE" = true ]; then - echo $MAVEN_PROJECTBASEDIR -fi -MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" - -# For Cygwin, switch paths to Windows format before running java -if $cygwin; then - [ -n "$M2_HOME" ] && - M2_HOME=`cygpath --path --windows "$M2_HOME"` - [ -n "$JAVA_HOME" ] && - JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` - [ -n "$CLASSPATH" ] && - CLASSPATH=`cygpath --path --windows "$CLASSPATH"` - [ -n "$MAVEN_PROJECTBASEDIR" ] && - MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` -fi - -WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain - -exec "$JAVACMD" \ - $MAVEN_OPTS \ - -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ - "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ - ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/spring-scheduling/mvnw.cmd b/spring-scheduling/mvnw.cmd deleted file mode 100644 index e5cfb0ae9e..0000000000 --- a/spring-scheduling/mvnw.cmd +++ /dev/null @@ -1,161 +0,0 @@ -@REM ---------------------------------------------------------------------------- -@REM Licensed to the Apache Software Foundation (ASF) under one -@REM or more contributor license agreements. See the NOTICE file -@REM distributed with this work for additional information -@REM regarding copyright ownership. The ASF licenses this file -@REM to you under the Apache License, Version 2.0 (the -@REM "License"); you may not use this file except in compliance -@REM with the License. You may obtain a copy of the License at -@REM -@REM http://www.apache.org/licenses/LICENSE-2.0 -@REM -@REM Unless required by applicable law or agreed to in writing, -@REM software distributed under the License is distributed on an -@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -@REM KIND, either express or implied. See the License for the -@REM specific language governing permissions and limitations -@REM under the License. -@REM ---------------------------------------------------------------------------- - -@REM ---------------------------------------------------------------------------- -@REM Maven2 Start Up Batch script -@REM -@REM Required ENV vars: -@REM JAVA_HOME - location of a JDK home dir -@REM -@REM Optional ENV vars -@REM M2_HOME - location of maven2's installed home dir -@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands -@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending -@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven -@REM e.g. to debug Maven itself, use -@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files -@REM ---------------------------------------------------------------------------- - -@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' -@echo off -@REM set title of command window -title %0 -@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' -@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% - -@REM set %HOME% to equivalent of $HOME -if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") - -@REM Execute a user defined script before this one -if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre -@REM check for pre script, once with legacy .bat ending and once with .cmd ending -if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" -if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" -:skipRcPre - -@setlocal - -set ERROR_CODE=0 - -@REM To isolate internal variables from possible post scripts, we use another setlocal -@setlocal - -@REM ==== START VALIDATION ==== -if not "%JAVA_HOME%" == "" goto OkJHome - -echo. -echo Error: JAVA_HOME not found in your environment. >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -:OkJHome -if exist "%JAVA_HOME%\bin\java.exe" goto init - -echo. -echo Error: JAVA_HOME is set to an invalid directory. >&2 -echo JAVA_HOME = "%JAVA_HOME%" >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -@REM ==== END VALIDATION ==== - -:init - -@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". -@REM Fallback to current working directory if not found. - -set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% -IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir - -set EXEC_DIR=%CD% -set WDIR=%EXEC_DIR% -:findBaseDir -IF EXIST "%WDIR%"\.mvn goto baseDirFound -cd .. -IF "%WDIR%"=="%CD%" goto baseDirNotFound -set WDIR=%CD% -goto findBaseDir - -:baseDirFound -set MAVEN_PROJECTBASEDIR=%WDIR% -cd "%EXEC_DIR%" -goto endDetectBaseDir - -:baseDirNotFound -set MAVEN_PROJECTBASEDIR=%EXEC_DIR% -cd "%EXEC_DIR%" - -:endDetectBaseDir - -IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig - -@setlocal EnableExtensions EnableDelayedExpansion -for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a -@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% - -:endReadAdditionalConfig - -SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" -set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" -set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain - -set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar" -FOR /F "tokens=1,2 delims==" %%A IN (%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties) DO ( - IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B -) - -@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central -@REM This allows using the maven wrapper in projects that prohibit checking in binary data. -if exist %WRAPPER_JAR% ( - echo Found %WRAPPER_JAR% -) else ( - echo Couldn't find %WRAPPER_JAR%, downloading it ... - echo Downloading from: %DOWNLOAD_URL% - powershell -Command "(New-Object Net.WebClient).DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')" - echo Finished downloading %WRAPPER_JAR% -) -@REM End of extension - -%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* -if ERRORLEVEL 1 goto error -goto end - -:error -set ERROR_CODE=1 - -:end -@endlocal & set ERROR_CODE=%ERROR_CODE% - -if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost -@REM check for post script, once with legacy .bat ending and once with .cmd ending -if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" -if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" -:skipRcPost - -@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' -if "%MAVEN_BATCH_PAUSE%" == "on" pause - -if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% - -exit /B %ERROR_CODE% diff --git a/spring-scheduling/pom.xml b/spring-scheduling/pom.xml deleted file mode 100644 index d739985f7c..0000000000 --- a/spring-scheduling/pom.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - 4.0.0 - - org.springframework.boot - spring-boot-starter-parent - 2.1.2.RELEASE - - - com.baeldung - scheduling - 0.0.1-SNAPSHOT - scheduling - Example of conditionally enabling spring scheduled jobs - - - 1.8 - - - - - org.springframework.boot - spring-boot-starter - - - org.springframework.boot - spring-boot-starter-test - test - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - - diff --git a/spring-scheduling/src/main/resources/application.properties b/spring-scheduling/src/main/resources/application.properties deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/spring-scheduling/src/test/java/com/baeldung/scheduling/SchedulingApplicationTests.java b/spring-scheduling/src/test/java/com/baeldung/scheduling/SchedulingApplicationTests.java deleted file mode 100644 index 60e6d820bb..0000000000 --- a/spring-scheduling/src/test/java/com/baeldung/scheduling/SchedulingApplicationTests.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.baeldung.scheduling; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.junit4.SpringRunner; - -@RunWith(SpringRunner.class) -@SpringBootTest -public class SchedulingApplicationTests { - - @Test - public void contextLoads() { - } - -} - From 24cf6b473d903256b1d906305b47e2f9c88ca066 Mon Sep 17 00:00:00 2001 From: Diego Moreira Date: Thu, 24 Jan 2019 21:32:29 -0300 Subject: [PATCH 20/33] BAEL-2270 Refactor - Moved classes from libraries to libraries-server (#6210) --- libraries-server/pom.xml | 25 +++++++++++++++++++ .../java/com/baeldung/smack/StanzaThread.java | 0 .../baeldung/smack/SmackIntegrationTest.java | 0 libraries/pom.xml | 24 ------------------ 4 files changed, 25 insertions(+), 24 deletions(-) rename {libraries => libraries-server}/src/main/java/com/baeldung/smack/StanzaThread.java (100%) rename {libraries => libraries-server}/src/test/java/com/baeldung/smack/SmackIntegrationTest.java (100%) diff --git a/libraries-server/pom.xml b/libraries-server/pom.xml index 661f5f01d5..f60e664fa7 100644 --- a/libraries-server/pom.xml +++ b/libraries-server/pom.xml @@ -71,6 +71,30 @@ tomcat-catalina ${tomcat.version} + + + org.igniterealtime.smack + smack-tcp + ${smack.version} + + + + org.igniterealtime.smack + smack-im + ${smack.version} + + + + org.igniterealtime.smack + smack-extensions + ${smack.version} + + + + org.igniterealtime.smack + smack-java7 + ${smack.version} + @@ -82,6 +106,7 @@ 4.1 4.12 8.5.24 + 4.3.1 \ No newline at end of file diff --git a/libraries/src/main/java/com/baeldung/smack/StanzaThread.java b/libraries-server/src/main/java/com/baeldung/smack/StanzaThread.java similarity index 100% rename from libraries/src/main/java/com/baeldung/smack/StanzaThread.java rename to libraries-server/src/main/java/com/baeldung/smack/StanzaThread.java diff --git a/libraries/src/test/java/com/baeldung/smack/SmackIntegrationTest.java b/libraries-server/src/test/java/com/baeldung/smack/SmackIntegrationTest.java similarity index 100% rename from libraries/src/test/java/com/baeldung/smack/SmackIntegrationTest.java rename to libraries-server/src/test/java/com/baeldung/smack/SmackIntegrationTest.java diff --git a/libraries/pom.xml b/libraries/pom.xml index 301fa86c8d..d067525315 100644 --- a/libraries/pom.xml +++ b/libraries/pom.xml @@ -676,29 +676,6 @@ test - - org.igniterealtime.smack - smack-tcp - ${smack.version} - - - - org.igniterealtime.smack - smack-im - ${smack.version} - - - - org.igniterealtime.smack - smack-extensions - ${smack.version} - - - - org.igniterealtime.smack - smack-java7 - ${smack.version} - @@ -920,7 +897,6 @@ 1.1.0 2.7.1 3.6 - 4.3.1 From 1293f4e17232fd39d3eb5dd97b141bd98b934533 Mon Sep 17 00:00:00 2001 From: Loredana Date: Fri, 25 Jan 2019 22:40:12 +0200 Subject: [PATCH 21/33] update boot dependencies, config --- spring-boot-rest/pom.xml | 27 ++++---------- .../baeldung/spring/PersistenceConfig.java | 1 - .../java/com/baeldung/spring/WebConfig.java | 35 +------------------ .../resources/springDataPersistenceConfig.xml | 12 ------- 4 files changed, 7 insertions(+), 68 deletions(-) delete mode 100644 spring-boot-rest/src/main/resources/springDataPersistenceConfig.xml diff --git a/spring-boot-rest/pom.xml b/spring-boot-rest/pom.xml index bcd0381603..cf4ac0371b 100644 --- a/spring-boot-rest/pom.xml +++ b/spring-boot-rest/pom.xml @@ -25,31 +25,16 @@ com.fasterxml.jackson.dataformat jackson-dataformat-xml - - org.hibernate - hibernate-entitymanager - - - org.springframework - spring-jdbc - - - org.springframework.data - spring-data-jpa - + com.h2database h2 - - org.springframework - spring-tx - - - org.springframework.data - spring-data-commons - - + + org.springframework.boot + spring-boot-starter-data-jpa + + diff --git a/spring-boot-rest/src/main/java/com/baeldung/spring/PersistenceConfig.java b/spring-boot-rest/src/main/java/com/baeldung/spring/PersistenceConfig.java index 4a4b9eee3f..5179c66978 100644 --- a/spring-boot-rest/src/main/java/com/baeldung/spring/PersistenceConfig.java +++ b/spring-boot-rest/src/main/java/com/baeldung/spring/PersistenceConfig.java @@ -25,7 +25,6 @@ import com.google.common.base.Preconditions; @EnableTransactionManagement @PropertySource({ "classpath:persistence-${envTarget:h2}.properties" }) @ComponentScan({ "com.baeldung.persistence" }) -// @ImportResource("classpath*:springDataPersistenceConfig.xml") @EnableJpaRepositories(basePackages = "com.baeldung.persistence.dao") public class PersistenceConfig { diff --git a/spring-boot-rest/src/main/java/com/baeldung/spring/WebConfig.java b/spring-boot-rest/src/main/java/com/baeldung/spring/WebConfig.java index 39aade174b..80ee975e84 100644 --- a/spring-boot-rest/src/main/java/com/baeldung/spring/WebConfig.java +++ b/spring-boot-rest/src/main/java/com/baeldung/spring/WebConfig.java @@ -1,43 +1,10 @@ package com.baeldung.spring; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; -import org.springframework.http.MediaType; -import org.springframework.web.servlet.ViewResolver; -import org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer; -import org.springframework.web.servlet.config.annotation.EnableWebMvc; -import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; -import org.springframework.web.servlet.view.InternalResourceViewResolver; + @Configuration -@ComponentScan("com.baeldung.web") -@EnableWebMvc public class WebConfig implements WebMvcConfigurer { - public WebConfig() { - super(); - } - - @Bean - public ViewResolver viewResolver() { - final InternalResourceViewResolver viewResolver = new InternalResourceViewResolver(); - viewResolver.setPrefix("/WEB-INF/view/"); - viewResolver.setSuffix(".jsp"); - return viewResolver; - } - - // API - @Override - public void addViewControllers(final ViewControllerRegistry registry) { - registry.addViewController("/graph.html"); - registry.addViewController("/homepage.html"); - } - - @Override - public void configureContentNegotiation(ContentNegotiationConfigurer configurer) { - configurer.defaultContentType(MediaType.APPLICATION_JSON); - } - } \ No newline at end of file diff --git a/spring-boot-rest/src/main/resources/springDataPersistenceConfig.xml b/spring-boot-rest/src/main/resources/springDataPersistenceConfig.xml deleted file mode 100644 index 5ea2d9c05b..0000000000 --- a/spring-boot-rest/src/main/resources/springDataPersistenceConfig.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - \ No newline at end of file From 06023ec09f889214970fdc9615325e92f14769b3 Mon Sep 17 00:00:00 2001 From: Dhawal Kapil Date: Sat, 26 Jan 2019 06:45:40 +0530 Subject: [PATCH 22/33] Feature/bael 2129 (#6182) * BAEL-2129 Added Unit test for Void Type in Kotlin article * BAEL-2129 Updated test case * BAEL-2129 Added comment for commented code --- .../com/baeldung/voidtypes/VoidTypesUnitTest.kt | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/core-kotlin/src/test/kotlin/com/baeldung/voidtypes/VoidTypesUnitTest.kt b/core-kotlin/src/test/kotlin/com/baeldung/voidtypes/VoidTypesUnitTest.kt index 5c285c3135..468352dbed 100644 --- a/core-kotlin/src/test/kotlin/com/baeldung/voidtypes/VoidTypesUnitTest.kt +++ b/core-kotlin/src/test/kotlin/com/baeldung/voidtypes/VoidTypesUnitTest.kt @@ -6,7 +6,19 @@ import kotlin.test.assertTrue class VoidTypesUnitTest { - fun returnTypeAsVoid(): Void? { + // Un-commenting below methods will result into compilation error + // as the syntax used is incorrect and is used for explanation in tutorial. + + // fun returnTypeAsVoidAttempt1(): Void { + // println("Trying with Void as return type") + // } + + // fun returnTypeAsVoidAttempt2(): Void { + // println("Trying with Void as return type") + // return null + // } + + fun returnTypeAsVoidSuccess(): Void? { println("Function can have Void as return type") return null } @@ -36,7 +48,7 @@ class VoidTypesUnitTest { @Test fun givenVoidReturnType_thenReturnsNullOnly() { - assertNull(returnTypeAsVoid()) + assertNull(returnTypeAsVoidSuccess()) } @Test From c6e808348ddbcb70a90045db7b86affdf6ad9e38 Mon Sep 17 00:00:00 2001 From: Loredana Crusoveanu Date: Sat, 26 Jan 2019 10:41:54 +0200 Subject: [PATCH 23/33] Update README.md --- spring-cloud/README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/spring-cloud/README.md b/spring-cloud/README.md index eb2e46c3d0..fede3cc12d 100644 --- a/spring-cloud/README.md +++ b/spring-cloud/README.md @@ -15,8 +15,6 @@ ### Relevant Articles: - [Intro to Spring Cloud Netflix - Hystrix](http://www.baeldung.com/spring-cloud-netflix-hystrix) - [Dockerizing a Spring Boot Application](http://www.baeldung.com/dockerizing-spring-boot-application) -- [Using a Spring Cloud App Starter](http://www.baeldung.com/using-a-spring-cloud-app-starter) -- [Using a Spring Cloud App Starter](http://www.baeldung.com/spring-cloud-app-starter) - [Instance Profile Credentials using Spring Cloud](http://www.baeldung.com/spring-cloud-instance-profiles) - [Running Spring Boot Applications With Minikube](http://www.baeldung.com/spring-boot-minikube) From 2437a265006e4f7a485952d254058914bd2d8d0f Mon Sep 17 00:00:00 2001 From: Loredana Crusoveanu Date: Sat, 26 Jan 2019 10:42:34 +0200 Subject: [PATCH 24/33] Create README.md --- spring-cloud/spring-cloud-stream-starters/README.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 spring-cloud/spring-cloud-stream-starters/README.md diff --git a/spring-cloud/spring-cloud-stream-starters/README.md b/spring-cloud/spring-cloud-stream-starters/README.md new file mode 100644 index 0000000000..761d54abbd --- /dev/null +++ b/spring-cloud/spring-cloud-stream-starters/README.md @@ -0,0 +1,3 @@ +#Revelant Articles: + +- [Using a Spring Cloud App Starter](http://www.baeldung.com/spring-cloud-app-starter) From 630d07277e7851ef2c4b5952ac2206f5fe57107d Mon Sep 17 00:00:00 2001 From: eric-martin Date: Sat, 26 Jan 2019 15:25:41 -0600 Subject: [PATCH 25/33] BAEL-2406: Improve asserts in PassengerRepositoryIntegrationTest --- .../PassengerRepositoryIntegrationTest.java | 70 +++++++++++-------- 1 file changed, 40 insertions(+), 30 deletions(-) diff --git a/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/passenger/PassengerRepositoryIntegrationTest.java b/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/passenger/PassengerRepositoryIntegrationTest.java index 59380c1427..8cd19cec03 100644 --- a/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/passenger/PassengerRepositoryIntegrationTest.java +++ b/persistence-modules/spring-data-jpa/src/test/java/com/baeldung/passenger/PassengerRepositoryIntegrationTest.java @@ -1,5 +1,17 @@ package com.baeldung.passenger; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.core.IsNot.not; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.util.List; +import java.util.Optional; + +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -12,16 +24,6 @@ import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Sort; import org.springframework.test.context.junit4.SpringRunner; -import javax.persistence.EntityManager; -import javax.persistence.PersistenceContext; -import java.util.List; -import java.util.Optional; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.contains; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - @DataJpaTest @RunWith(SpringRunner.class) public class PassengerRepositoryIntegrationTest { @@ -49,7 +51,7 @@ public class PassengerRepositoryIntegrationTest { assertEquals(1, passengers.size()); Passenger actual = passengers.get(0); - assertEquals(actual, expected); + assertEquals(expected, actual); } @Test @@ -58,7 +60,7 @@ public class PassengerRepositoryIntegrationTest { Passenger actual = repository.findFirstByOrderBySeatNumberAsc(); - assertEquals(actual, expected); + assertEquals(expected, actual); } @Test @@ -68,7 +70,7 @@ public class PassengerRepositoryIntegrationTest { Page page = repository.findAll(PageRequest.of(0, 1, Sort.by(Sort.Direction.ASC, "seatNumber"))); - assertEquals(page.getContent().size(), 1); + assertEquals(1, page.getContent().size()); Passenger actual = page.getContent().get(0); assertEquals(expected, actual); @@ -107,7 +109,7 @@ public class PassengerRepositoryIntegrationTest { Optional actual = repository.findOne(example); assertTrue(actual.isPresent()); - assertEquals(actual.get(), Passenger.from("Fred", "Bloggs", 22)); + assertEquals(Passenger.from("Fred", "Bloggs", 22), actual.get()); } @Test @@ -119,7 +121,7 @@ public class PassengerRepositoryIntegrationTest { Optional actual = repository.findOne(example); assertTrue(actual.isPresent()); - assertEquals(actual.get(), Passenger.from("Fred", "Bloggs", 22)); + assertEquals(Passenger.from("Fred", "Bloggs", 22), actual.get()); } @Test @@ -128,6 +130,7 @@ public class PassengerRepositoryIntegrationTest { Passenger eve = Passenger.from("Eve", "Jackson", 95); Passenger fred = Passenger.from("Fred", "Bloggs", 22); Passenger siya = Passenger.from("Siya", "Kolisi", 85); + Passenger ricki = Passenger.from("Ricki", "Bobbie", 36); ExampleMatcher customExampleMatcher = ExampleMatcher.matchingAny().withMatcher("firstName", ExampleMatcher.GenericPropertyMatchers.contains().ignoreCase()).withMatcher("lastName", @@ -139,21 +142,28 @@ public class PassengerRepositoryIntegrationTest { List passengers = repository.findAll(example); assertThat(passengers, contains(jill, eve, fred, siya)); + assertThat(passengers, not(contains(ricki))); } -@Test -public void givenPassengers_whenFindByIgnoringMatcher_thenExpectedReturned() { - Passenger fred = Passenger.from("Fred", "Bloggs", 22); - Passenger ricki = Passenger.from("Ricki", "Bobbie", 36); - - ExampleMatcher ignoringExampleMatcher = ExampleMatcher.matchingAny().withMatcher("lastName", - ExampleMatcher.GenericPropertyMatchers.startsWith().ignoreCase()).withIgnorePaths("firstName", "seatNumber"); - - Example example = Example.of(Passenger.from(null, "b", null), - ignoringExampleMatcher); - - List passengers = repository.findAll(example); - - assertThat(passengers, contains(fred, ricki)); -} + @Test + public void givenPassengers_whenFindByIgnoringMatcher_thenExpectedReturned() { + Passenger jill = Passenger.from("Jill", "Smith", 50); + Passenger eve = Passenger.from("Eve", "Jackson", 95); + Passenger fred = Passenger.from("Fred", "Bloggs", 22); + Passenger siya = Passenger.from("Siya", "Kolisi", 85); + Passenger ricki = Passenger.from("Ricki", "Bobbie", 36); + + ExampleMatcher ignoringExampleMatcher = ExampleMatcher.matchingAny().withMatcher("lastName", + ExampleMatcher.GenericPropertyMatchers.startsWith().ignoreCase()).withIgnorePaths("firstName", "seatNumber"); + + Example example = Example.of(Passenger.from(null, "b", null), + ignoringExampleMatcher); + + List passengers = repository.findAll(example); + + assertThat(passengers, contains(fred, ricki)); + assertThat(passengers, not(contains(jill))); + assertThat(passengers, not(contains(eve))); + assertThat(passengers, not(contains(siya))); + } } From 9a567f95b4be0737af8a9a0cd2b02e09d793bc54 Mon Sep 17 00:00:00 2001 From: PranayVJain Date: Sun, 27 Jan 2019 11:51:13 +0530 Subject: [PATCH 26/33] List files within directory Issue: BAEL-2447 --- .../java/com/baeldung/files/ListFiles.java | 64 +++++++++++++++++++ .../com/baeldung/file/ListFilesUnitTest.java | 46 +++++++++++++ .../listFilesUnitTestFolder/country.txt | 1 + .../listFilesUnitTestFolder/employee.json | 1 + .../listFilesUnitTestFolder/students.json | 1 + .../listFilesUnitTestFolder/test.xml | 1 + 6 files changed, 114 insertions(+) create mode 100644 core-java-io/src/main/java/com/baeldung/files/ListFiles.java create mode 100644 core-java-io/src/test/java/com/baeldung/file/ListFilesUnitTest.java create mode 100644 core-java-io/src/test/resources/listFilesUnitTestFolder/country.txt create mode 100644 core-java-io/src/test/resources/listFilesUnitTestFolder/employee.json create mode 100644 core-java-io/src/test/resources/listFilesUnitTestFolder/students.json create mode 100644 core-java-io/src/test/resources/listFilesUnitTestFolder/test.xml diff --git a/core-java-io/src/main/java/com/baeldung/files/ListFiles.java b/core-java-io/src/main/java/com/baeldung/files/ListFiles.java new file mode 100644 index 0000000000..c5de36270c --- /dev/null +++ b/core-java-io/src/main/java/com/baeldung/files/ListFiles.java @@ -0,0 +1,64 @@ +package com.baeldung.files; + +import java.io.File; +import java.io.IOException; +import java.nio.file.DirectoryStream; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.HashSet; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class ListFiles { + public static final int DEPTH = 1; + + public Set listFilesUsingJavaIO(String dir) { + return Stream.of(new File(dir).listFiles()) + .filter(file -> !file.isDirectory()) + .map(File::getName) + .collect(Collectors.toSet()); + } + + public Set listFilesUsingFileWalk(String dir, int depth) throws IOException { + try (Stream stream = Files.walk(Paths.get(dir), depth)) { + return stream.filter(file -> !Files.isDirectory(file)) + .map(Path::getFileName) + .map(Path::toString) + .collect(Collectors.toSet()); + } + } + + public Set listFilesUsingFileWalkAndVisitor(String dir) throws IOException { + Set fileList = new HashSet<>(); + Files.walkFileTree(Paths.get(dir), new SimpleFileVisitor() { + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { + if (!Files.isDirectory(file)) { + fileList.add(file.getFileName() + .toString()); + } + return FileVisitResult.CONTINUE; + } + }); + return fileList; + } + + public Set listFilesUsingDirectoryStream(String dir) throws IOException { + Set fileList = new HashSet<>(); + try (DirectoryStream stream = Files.newDirectoryStream(Paths.get(dir))) { + for (Path path : stream) { + if (!Files.isDirectory(path)) { + fileList.add(path.getFileName() + .toString()); + } + } + } + return fileList; + } + +} diff --git a/core-java-io/src/test/java/com/baeldung/file/ListFilesUnitTest.java b/core-java-io/src/test/java/com/baeldung/file/ListFilesUnitTest.java new file mode 100644 index 0000000000..65710121cc --- /dev/null +++ b/core-java-io/src/test/java/com/baeldung/file/ListFilesUnitTest.java @@ -0,0 +1,46 @@ +package com.baeldung.file; + +import static org.junit.Assert.assertEquals; + +import java.io.IOException; +import java.util.HashSet; +import java.util.Set; + +import org.junit.Test; + +import com.baeldung.files.ListFiles; + +public class ListFilesUnitTest { + + private ListFiles listFiles = new ListFiles(); + private String DIRECTORY = "src/test/resources/listFilesUnitTestFolder"; + private static final int DEPTH = 1; + private Set EXPECTED_FILE_LIST = new HashSet() { + { + add("test.xml"); + add("employee.json"); + add("students.json"); + add("country.txt"); + } + }; + + @Test + public void givenDir_whenUsingJAVAIO_thenListAllFiles() throws IOException { + assertEquals(EXPECTED_FILE_LIST, listFiles.listFilesUsingJavaIO(DIRECTORY)); + } + + @Test + public void givenDir_whenWalkingTree_thenListAllFiles() throws IOException { + assertEquals(EXPECTED_FILE_LIST, listFiles.listFilesUsingFileWalk(DIRECTORY,DEPTH)); + } + + @Test + public void givenDir_whenWalkingTreeWithVisitor_thenListAllFiles() throws IOException { + assertEquals(EXPECTED_FILE_LIST, listFiles.listFilesUsingFileWalkAndVisitor(DIRECTORY)); + } + + @Test + public void givenDir_whenUsingDirectoryStream_thenListAllFiles() throws IOException { + assertEquals(EXPECTED_FILE_LIST, listFiles.listFilesUsingDirectoryStream(DIRECTORY)); + } +} diff --git a/core-java-io/src/test/resources/listFilesUnitTestFolder/country.txt b/core-java-io/src/test/resources/listFilesUnitTestFolder/country.txt new file mode 100644 index 0000000000..45bfe896dc --- /dev/null +++ b/core-java-io/src/test/resources/listFilesUnitTestFolder/country.txt @@ -0,0 +1 @@ +This is a sample txt file for unit test ListFilesUnitTest \ No newline at end of file diff --git a/core-java-io/src/test/resources/listFilesUnitTestFolder/employee.json b/core-java-io/src/test/resources/listFilesUnitTestFolder/employee.json new file mode 100644 index 0000000000..9e26dfeeb6 --- /dev/null +++ b/core-java-io/src/test/resources/listFilesUnitTestFolder/employee.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/core-java-io/src/test/resources/listFilesUnitTestFolder/students.json b/core-java-io/src/test/resources/listFilesUnitTestFolder/students.json new file mode 100644 index 0000000000..9e26dfeeb6 --- /dev/null +++ b/core-java-io/src/test/resources/listFilesUnitTestFolder/students.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/core-java-io/src/test/resources/listFilesUnitTestFolder/test.xml b/core-java-io/src/test/resources/listFilesUnitTestFolder/test.xml new file mode 100644 index 0000000000..19b16cc72c --- /dev/null +++ b/core-java-io/src/test/resources/listFilesUnitTestFolder/test.xml @@ -0,0 +1 @@ + \ No newline at end of file From 4bd87241ce8cc99f98446b3703cb8ddfba9c2dca Mon Sep 17 00:00:00 2001 From: rodolforfq <31481067+rodolforfq@users.noreply.github.com> Date: Sun, 27 Jan 2019 02:38:38 -0400 Subject: [PATCH 27/33] BAEL-2524 (#6206) * BAEL-2524 Uploading article examples. * Fixing build error Used List.of, which is not available on java 8 (running java 11 on my PC) --- .../java8/lambda/methodreference/Bicycle.java | 29 ++++++++ .../methodreference/BicycleComparator.java | 13 ++++ .../MethodReferenceExamples.java | 70 +++++++++++++++++++ 3 files changed, 112 insertions(+) create mode 100644 core-java-8/src/test/java/com/baeldung/java8/lambda/methodreference/Bicycle.java create mode 100644 core-java-8/src/test/java/com/baeldung/java8/lambda/methodreference/BicycleComparator.java create mode 100644 core-java-8/src/test/java/com/baeldung/java8/lambda/methodreference/MethodReferenceExamples.java diff --git a/core-java-8/src/test/java/com/baeldung/java8/lambda/methodreference/Bicycle.java b/core-java-8/src/test/java/com/baeldung/java8/lambda/methodreference/Bicycle.java new file mode 100644 index 0000000000..760a24d7c2 --- /dev/null +++ b/core-java-8/src/test/java/com/baeldung/java8/lambda/methodreference/Bicycle.java @@ -0,0 +1,29 @@ +package com.baeldung.java8.lambda.methodreference; + +public class Bicycle { + + private String brand; + private Integer frameSize; + + public Bicycle(String brand, Integer frameSize) { + this.brand = brand; + this.frameSize = frameSize; + } + + public String getBrand() { + return brand; + } + + public void setBrand(String brand) { + this.brand = brand; + } + + public Integer getFrameSize() { + return frameSize; + } + + public void setFrameSize(Integer frameSize) { + this.frameSize = frameSize; + } + +} diff --git a/core-java-8/src/test/java/com/baeldung/java8/lambda/methodreference/BicycleComparator.java b/core-java-8/src/test/java/com/baeldung/java8/lambda/methodreference/BicycleComparator.java new file mode 100644 index 0000000000..153a7d105a --- /dev/null +++ b/core-java-8/src/test/java/com/baeldung/java8/lambda/methodreference/BicycleComparator.java @@ -0,0 +1,13 @@ +package com.baeldung.java8.lambda.methodreference; + +import java.util.Comparator; + +public class BicycleComparator implements Comparator { + + @Override + public int compare(Bicycle a, Bicycle b) { + return a.getFrameSize() + .compareTo(b.getFrameSize()); + } + +} diff --git a/core-java-8/src/test/java/com/baeldung/java8/lambda/methodreference/MethodReferenceExamples.java b/core-java-8/src/test/java/com/baeldung/java8/lambda/methodreference/MethodReferenceExamples.java new file mode 100644 index 0000000000..3b9a5ec6ff --- /dev/null +++ b/core-java-8/src/test/java/com/baeldung/java8/lambda/methodreference/MethodReferenceExamples.java @@ -0,0 +1,70 @@ +package com.baeldung.java8.lambda.methodreference; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.function.BiFunction; + +import org.junit.Test; + +public class MethodReferenceExamples { + + private static void doNothingAtAll(Object... o) { + } + + ; + + @Test + public void referenceToStaticMethod() { + List messages = Arrays.asList("Hello", "Baeldung", "readers!"); + messages.forEach((word) -> { + System.out.println(word); + }); + messages.forEach(System.out::println); + } + + @Test + public void referenceToInstanceMethodOfParticularObject() { + BicycleComparator bikeFrameSizeComparator = new BicycleComparator(); + createBicyclesList().stream() + .sorted((a, b) -> bikeFrameSizeComparator.compare(a, b)); + createBicyclesList().stream() + .sorted(bikeFrameSizeComparator::compare); + } + + @Test + public void referenceToInstanceMethodOfArbitratyObjectOfParticularType() { + List numbers = Arrays.asList(5, 3, 50, 24, 40, 2, 9, 18); + numbers.stream() + .sorted((a, b) -> Integer.compare(a, b)); + numbers.stream() + .sorted(Integer::compare); + } + + @Test + public void referenceToConstructor() { + BiFunction bikeCreator = (brand, frameSize) -> new Bicycle(brand, frameSize); + BiFunction bikeCreatorMethodReference = Bicycle::new; + List bikes = new ArrayList<>(); + bikes.add(bikeCreator.apply("Giant", 50)); + bikes.add(bikeCreator.apply("Scott", 20)); + bikes.add(bikeCreatorMethodReference.apply("Trek", 35)); + bikes.add(bikeCreatorMethodReference.apply("GT", 40)); + } + + @Test + public void limitationsAndAdditionalExamples() { + createBicyclesList().forEach(b -> System.out.printf("Bike brand is '%s' and frame size is '%d'%n", b.getBrand(), b.getFrameSize())); + createBicyclesList().forEach((o) -> this.doNothingAtAll(o)); + } + + private List createBicyclesList() { + List bikes = new ArrayList<>(); + bikes.add(new Bicycle("Giant", 50)); + bikes.add(new Bicycle("Scott", 20)); + bikes.add(new Bicycle("Trek", 35)); + bikes.add(new Bicycle("GT", 40)); + return bikes; + } + +} From 8ccec9a413ee3e36eb73d0d1e2294596b2b3681f Mon Sep 17 00:00:00 2001 From: pcoates33 Date: Sun, 27 Jan 2019 06:55:25 +0000 Subject: [PATCH 28/33] BAEL-2510 Add nested properties section (#6212) Add nested properties section to ConfigurationProperties article. --- .../baeldung/properties/ConfigProperties.java | 62 +++++-------------- .../org/baeldung/properties/Credentials.java | 37 +++++++++++ .../src/main/resources/configprops.properties | 2 +- .../ConfigPropertiesIntegrationTest.java | 31 +++++++--- .../resources/configprops-test.properties | 2 +- 5 files changed, 75 insertions(+), 59 deletions(-) create mode 100644 spring-boot/src/main/java/org/baeldung/properties/Credentials.java diff --git a/spring-boot/src/main/java/org/baeldung/properties/ConfigProperties.java b/spring-boot/src/main/java/org/baeldung/properties/ConfigProperties.java index 2d3e56100c..3698d8ef30 100644 --- a/spring-boot/src/main/java/org/baeldung/properties/ConfigProperties.java +++ b/spring-boot/src/main/java/org/baeldung/properties/ConfigProperties.java @@ -8,7 +8,6 @@ import javax.validation.constraints.Min; import javax.validation.constraints.NotBlank; import javax.validation.constraints.Pattern; -import org.hibernate.validator.constraints.Length; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource; @@ -20,41 +19,8 @@ import org.springframework.validation.annotation.Validated; @Validated public class ConfigProperties { - @Validated - public static class Credentials { - - @Length(max = 4, min = 1) - private String authMethod; - private String username; - private String password; - - public String getAuthMethod() { - return authMethod; - } - - public void setAuthMethod(String authMethod) { - this.authMethod = authMethod; - } - - public String getUsername() { - return username; - } - - public void setUsername(String username) { - this.username = username; - } - - public String getPassword() { - return password; - } - - public void setPassword(String password) { - this.password = password; - } - } - @NotBlank - private String host; + private String hostName; @Min(1025) @Max(65536) @@ -63,16 +29,16 @@ public class ConfigProperties { @Pattern(regexp = "^[a-z0-9._%+-]+@[a-z0-9.-]+\\.[a-z]{2,6}$") private String from; - private Credentials credentials; private List defaultRecipients; private Map additionalHeaders; + private Credentials credentials; - public String getHost() { - return host; + public String getHostName() { + return hostName; } - public void setHost(String host) { - this.host = host; + public void setHostName(String hostName) { + this.hostName = hostName; } public int getPort() { @@ -91,14 +57,6 @@ public class ConfigProperties { this.from = from; } - public Credentials getCredentials() { - return credentials; - } - - public void setCredentials(Credentials credentials) { - this.credentials = credentials; - } - public List getDefaultRecipients() { return defaultRecipients; } @@ -114,4 +72,12 @@ public class ConfigProperties { public void setAdditionalHeaders(Map additionalHeaders) { this.additionalHeaders = additionalHeaders; } + + public Credentials getCredentials() { + return credentials; + } + + public void setCredentials(Credentials credentials) { + this.credentials = credentials; + } } diff --git a/spring-boot/src/main/java/org/baeldung/properties/Credentials.java b/spring-boot/src/main/java/org/baeldung/properties/Credentials.java new file mode 100644 index 0000000000..2d8ac76e62 --- /dev/null +++ b/spring-boot/src/main/java/org/baeldung/properties/Credentials.java @@ -0,0 +1,37 @@ +package org.baeldung.properties; + +import org.hibernate.validator.constraints.Length; +import org.springframework.validation.annotation.Validated; + +@Validated +public class Credentials { + + @Length(max = 4, min = 1) + private String authMethod; + private String username; + private String password; + + public String getAuthMethod() { + return authMethod; + } + + public void setAuthMethod(String authMethod) { + this.authMethod = authMethod; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } +} diff --git a/spring-boot/src/main/resources/configprops.properties b/spring-boot/src/main/resources/configprops.properties index e5d9ae621d..2dad11f9cc 100644 --- a/spring-boot/src/main/resources/configprops.properties +++ b/spring-boot/src/main/resources/configprops.properties @@ -1,5 +1,5 @@ #Simple properties -mail.host=mailer@mail.com +mail.hostname=host@mail.com mail.port=9000 mail.from=mailer@mail.com diff --git a/spring-boot/src/test/java/org/baeldung/properties/ConfigPropertiesIntegrationTest.java b/spring-boot/src/test/java/org/baeldung/properties/ConfigPropertiesIntegrationTest.java index 3f3b558db9..4ba6bf29d8 100644 --- a/spring-boot/src/test/java/org/baeldung/properties/ConfigPropertiesIntegrationTest.java +++ b/spring-boot/src/test/java/org/baeldung/properties/ConfigPropertiesIntegrationTest.java @@ -1,5 +1,8 @@ package org.baeldung.properties; +import java.util.List; +import java.util.Map; + import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; @@ -18,26 +21,36 @@ public class ConfigPropertiesIntegrationTest { @Test public void whenSimplePropertyQueriedthenReturnsProperty() throws Exception { - Assert.assertTrue("From address is read as null!", properties.getFrom() != null); + Assert.assertEquals("Incorrectly bound hostName property", "host@mail.com", properties.getHostName()); + Assert.assertEquals("Incorrectly bound port property", 9000, properties.getPort()); + Assert.assertEquals("Incorrectly bound from property", "mailer@mail.com", properties.getFrom()); } @Test public void whenListPropertyQueriedthenReturnsProperty() throws Exception { - Assert.assertTrue("Couldn't bind list property!", properties.getDefaultRecipients().size() == 2); - Assert.assertTrue("Incorrectly bound list property. Expected 2 entries!", properties.getDefaultRecipients().size() == 2); + List defaultRecipients = properties.getDefaultRecipients(); + Assert.assertTrue("Couldn't bind list property!", defaultRecipients.size() == 2); + Assert.assertTrue("Incorrectly bound list property. Expected 2 entries!", defaultRecipients.size() == 2); + Assert.assertEquals("Incorrectly bound list[0] property", "admin@mail.com", defaultRecipients.get(0)); + Assert.assertEquals("Incorrectly bound list[1] property", "owner@mail.com", defaultRecipients.get(1)); } @Test public void whenMapPropertyQueriedthenReturnsProperty() throws Exception { - Assert.assertTrue("Couldn't bind map property!", properties.getAdditionalHeaders() != null); - Assert.assertTrue("Incorrectly bound map property. Expected 3 Entries!", properties.getAdditionalHeaders().size() == 3); + Map additionalHeaders = properties.getAdditionalHeaders(); + Assert.assertTrue("Couldn't bind map property!", additionalHeaders != null); + Assert.assertTrue("Incorrectly bound map property. Expected 3 Entries!", additionalHeaders.size() == 3); + Assert.assertEquals("Incorrectly bound map[redelivery] property", "true", additionalHeaders.get("redelivery")); + Assert.assertEquals("Incorrectly bound map[secure] property", "true", additionalHeaders.get("secure")); + Assert.assertEquals("Incorrectly bound map[p3] property", "value", additionalHeaders.get("p3")); } @Test public void whenObjectPropertyQueriedthenReturnsProperty() throws Exception { - Assert.assertTrue("Couldn't bind map property!", properties.getCredentials() != null); - Assert.assertTrue("Incorrectly bound object property!", properties.getCredentials().getAuthMethod().equals("SHA1")); - Assert.assertTrue("Incorrectly bound object property!", properties.getCredentials().getUsername().equals("john")); - Assert.assertTrue("Incorrectly bound object property!", properties.getCredentials().getPassword().equals("password")); + Credentials credentials = properties.getCredentials(); + Assert.assertTrue("Couldn't bind map property!", credentials != null); + Assert.assertEquals("Incorrectly bound object property, authMethod", "SHA1", credentials.getAuthMethod()); + Assert.assertEquals("Incorrectly bound object property, username", "john", credentials.getUsername()); + Assert.assertEquals("Incorrectly bound object property, password", "password", credentials.getPassword()); } } diff --git a/spring-boot/src/test/resources/configprops-test.properties b/spring-boot/src/test/resources/configprops-test.properties index b27cf2107a..697771ae6e 100644 --- a/spring-boot/src/test/resources/configprops-test.properties +++ b/spring-boot/src/test/resources/configprops-test.properties @@ -1,5 +1,5 @@ #Simple properties -mail.host=mailer@mail.com +mail.hostname=host@mail.com mail.port=9000 mail.from=mailer@mail.com From 2e733c38675d49f250861cae91166d5c4b18495b Mon Sep 17 00:00:00 2001 From: Eugen Paraschiv Date: Sun, 27 Jan 2019 14:25:36 +0200 Subject: [PATCH 29/33] minor formatting cleanup --- .../java/com/baeldung/config/DbConfig.java | 16 +++--- .../java/com/baeldung/config/MvcConfig.java | 8 +-- .../java/com/baeldung/config/RestConfig.java | 5 +- .../config/ValidatorEventRegister.java | 8 +-- .../baeldung/events/AuthorEventHandler.java | 49 +++++++++--------- .../com/baeldung/events/BookEventHandler.java | 23 +++++---- .../RestResponseEntityExceptionHandler.java | 7 +-- .../java/com/baeldung/models/Address.java | 2 +- .../main/java/com/baeldung/models/Author.java | 2 +- .../main/java/com/baeldung/models/Book.java | 7 ++- .../java/com/baeldung/models/Library.java | 2 +- .../java/com/baeldung/models/Subject.java | 2 +- .../com/baeldung/projections/CustomBook.java | 10 ++-- .../baeldung/repositories/BookRepository.java | 3 +- .../repositories/SubjectRepository.java | 4 +- .../events/AuthorEventHandlerUnitTest.java | 28 +++++------ .../events/BookEventHandlerUnitTest.java | 28 +++++------ .../SpringDataProjectionLiveTest.java | 50 +++++++++---------- 18 files changed, 122 insertions(+), 132 deletions(-) diff --git a/spring-data-rest/src/main/java/com/baeldung/config/DbConfig.java b/spring-data-rest/src/main/java/com/baeldung/config/DbConfig.java index 05fa27bbff..3ca728ec94 100644 --- a/spring-data-rest/src/main/java/com/baeldung/config/DbConfig.java +++ b/spring-data-rest/src/main/java/com/baeldung/config/DbConfig.java @@ -20,7 +20,7 @@ import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter; // @PropertySource("persistence-h2.properties") // @PropertySource("persistence-hsqldb.properties") // @PropertySource("persistence-derby.properties") -//@PropertySource("persistence-sqlite.properties") +// @PropertySource("persistence-sqlite.properties") public class DbConfig { @Autowired @@ -65,21 +65,23 @@ public class DbConfig { @Configuration @Profile("h2") @PropertySource("classpath:persistence-h2.properties") -class H2Config {} +class H2Config { +} @Configuration @Profile("hsqldb") @PropertySource("classpath:persistence-hsqldb.properties") -class HsqldbConfig {} - +class HsqldbConfig { +} @Configuration @Profile("derby") @PropertySource("classpath:persistence-derby.properties") -class DerbyConfig {} - +class DerbyConfig { +} @Configuration @Profile("sqlite") @PropertySource("classpath:persistence-sqlite.properties") -class SqliteConfig {} +class SqliteConfig { +} diff --git a/spring-data-rest/src/main/java/com/baeldung/config/MvcConfig.java b/spring-data-rest/src/main/java/com/baeldung/config/MvcConfig.java index e5748f2f55..9d0d3a6687 100644 --- a/spring-data-rest/src/main/java/com/baeldung/config/MvcConfig.java +++ b/spring-data-rest/src/main/java/com/baeldung/config/MvcConfig.java @@ -11,11 +11,11 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration @EnableWebMvc public class MvcConfig implements WebMvcConfigurer { - - public MvcConfig(){ + + public MvcConfig() { super(); } - + @Override public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) { configurer.enable(); @@ -27,7 +27,7 @@ public class MvcConfig implements WebMvcConfigurer { } @Bean - BookEventHandler bookEventHandler(){ + BookEventHandler bookEventHandler() { return new BookEventHandler(); } diff --git a/spring-data-rest/src/main/java/com/baeldung/config/RestConfig.java b/spring-data-rest/src/main/java/com/baeldung/config/RestConfig.java index 39f90e867b..47cb95693b 100644 --- a/spring-data-rest/src/main/java/com/baeldung/config/RestConfig.java +++ b/spring-data-rest/src/main/java/com/baeldung/config/RestConfig.java @@ -12,10 +12,9 @@ import org.springframework.http.HttpMethod; public class RestConfig implements RepositoryRestConfigurer { @Override - public void configureRepositoryRestConfiguration(RepositoryRestConfiguration repositoryRestConfiguration){ + public void configureRepositoryRestConfiguration(RepositoryRestConfiguration repositoryRestConfiguration) { repositoryRestConfiguration.getProjectionConfiguration().addProjection(CustomBook.class); ExposureConfiguration config = repositoryRestConfiguration.getExposureConfiguration(); - config.forDomainType(WebsiteUser.class).withItemExposure((metadata, httpMethods) -> - httpMethods.disable(HttpMethod.PATCH)); + config.forDomainType(WebsiteUser.class).withItemExposure((metadata, httpMethods) -> httpMethods.disable(HttpMethod.PATCH)); } } diff --git a/spring-data-rest/src/main/java/com/baeldung/config/ValidatorEventRegister.java b/spring-data-rest/src/main/java/com/baeldung/config/ValidatorEventRegister.java index 8f14d6c1c6..632ad9183a 100644 --- a/spring-data-rest/src/main/java/com/baeldung/config/ValidatorEventRegister.java +++ b/spring-data-rest/src/main/java/com/baeldung/config/ValidatorEventRegister.java @@ -24,13 +24,7 @@ public class ValidatorEventRegister implements InitializingBean { List events = Arrays.asList("beforeCreate", "afterCreate", "beforeSave", "afterSave", "beforeLinkSave", "afterLinkSave", "beforeDelete", "afterDelete"); for (Map.Entry entry : validators.entrySet()) { - events - .stream() - .filter(p -> entry - .getKey() - .startsWith(p)) - .findFirst() - .ifPresent(p -> validatingRepositoryEventListener.addValidator(p, entry.getValue())); + events.stream().filter(p -> entry.getKey().startsWith(p)).findFirst().ifPresent(p -> validatingRepositoryEventListener.addValidator(p, entry.getValue())); } } } diff --git a/spring-data-rest/src/main/java/com/baeldung/events/AuthorEventHandler.java b/spring-data-rest/src/main/java/com/baeldung/events/AuthorEventHandler.java index 5a8ae05c08..485dc8e221 100644 --- a/spring-data-rest/src/main/java/com/baeldung/events/AuthorEventHandler.java +++ b/spring-data-rest/src/main/java/com/baeldung/events/AuthorEventHandler.java @@ -8,33 +8,34 @@ import java.util.logging.Logger; @RepositoryEventHandler public class AuthorEventHandler { - Logger logger = Logger.getLogger("Class AuthorEventHandler"); - public AuthorEventHandler(){ - super(); - } + Logger logger = Logger.getLogger("Class AuthorEventHandler"); - @HandleBeforeCreate - public void handleAuthorBeforeCreate(Author author){ - logger.info("Inside Author Before Create...."); - String name = author.getName(); - } + public AuthorEventHandler() { + super(); + } - @HandleAfterCreate - public void handleAuthorAfterCreate(Author author){ - logger.info("Inside Author After Create ...."); - String name = author.getName(); - } + @HandleBeforeCreate + public void handleAuthorBeforeCreate(Author author) { + logger.info("Inside Author Before Create...."); + String name = author.getName(); + } - @HandleBeforeDelete - public void handleAuthorBeforeDelete(Author author){ - logger.info("Inside Author Before Delete ...."); - String name = author.getName(); - } + @HandleAfterCreate + public void handleAuthorAfterCreate(Author author) { + logger.info("Inside Author After Create ...."); + String name = author.getName(); + } - @HandleAfterDelete - public void handleAuthorAfterDelete(Author author){ - logger.info("Inside Author After Delete ...."); - String name = author.getName(); - } + @HandleBeforeDelete + public void handleAuthorBeforeDelete(Author author) { + logger.info("Inside Author Before Delete ...."); + String name = author.getName(); + } + + @HandleAfterDelete + public void handleAuthorAfterDelete(Author author) { + logger.info("Inside Author After Delete ...."); + String name = author.getName(); + } } diff --git a/spring-data-rest/src/main/java/com/baeldung/events/BookEventHandler.java b/spring-data-rest/src/main/java/com/baeldung/events/BookEventHandler.java index 3953e6ce0d..36ae62b926 100644 --- a/spring-data-rest/src/main/java/com/baeldung/events/BookEventHandler.java +++ b/spring-data-rest/src/main/java/com/baeldung/events/BookEventHandler.java @@ -10,17 +10,18 @@ import org.springframework.data.rest.core.annotation.RepositoryEventHandler; @RepositoryEventHandler public class BookEventHandler { - Logger logger = Logger.getLogger("Class BookEventHandler"); - @HandleBeforeCreate - public void handleBookBeforeCreate(Book book){ + Logger logger = Logger.getLogger("Class BookEventHandler"); - logger.info("Inside Book Before Create ...."); - book.getAuthors(); - } + @HandleBeforeCreate + public void handleBookBeforeCreate(Book book) { - @HandleBeforeCreate - public void handleAuthorBeforeCreate(Author author){ - logger.info("Inside Author Before Create ...."); - author.getBooks(); - } + logger.info("Inside Book Before Create ...."); + book.getAuthors(); + } + + @HandleBeforeCreate + public void handleAuthorBeforeCreate(Author author) { + logger.info("Inside Author Before Create ...."); + author.getBooks(); + } } diff --git a/spring-data-rest/src/main/java/com/baeldung/exception/handlers/RestResponseEntityExceptionHandler.java b/spring-data-rest/src/main/java/com/baeldung/exception/handlers/RestResponseEntityExceptionHandler.java index aa24fccac7..a3ef91f6d6 100644 --- a/spring-data-rest/src/main/java/com/baeldung/exception/handlers/RestResponseEntityExceptionHandler.java +++ b/spring-data-rest/src/main/java/com/baeldung/exception/handlers/RestResponseEntityExceptionHandler.java @@ -19,12 +19,7 @@ public class RestResponseEntityExceptionHandler extends ResponseEntityExceptionH public ResponseEntity handleAccessDeniedException(Exception ex, WebRequest request) { RepositoryConstraintViolationException nevEx = (RepositoryConstraintViolationException) ex; - String errors = nevEx - .getErrors() - .getAllErrors() - .stream() - .map(ObjectError::toString) - .collect(Collectors.joining("\n")); + String errors = nevEx.getErrors().getAllErrors().stream().map(ObjectError::toString).collect(Collectors.joining("\n")); return new ResponseEntity<>(errors, new HttpHeaders(), HttpStatus.NOT_ACCEPTABLE); } diff --git a/spring-data-rest/src/main/java/com/baeldung/models/Address.java b/spring-data-rest/src/main/java/com/baeldung/models/Address.java index 82e3783f3e..713af58ae6 100644 --- a/spring-data-rest/src/main/java/com/baeldung/models/Address.java +++ b/spring-data-rest/src/main/java/com/baeldung/models/Address.java @@ -11,7 +11,7 @@ import javax.persistence.OneToOne; public class Address { @Id - @GeneratedValue(strategy=GenerationType.IDENTITY) + @GeneratedValue(strategy = GenerationType.IDENTITY) private long id; @Column(nullable = false) diff --git a/spring-data-rest/src/main/java/com/baeldung/models/Author.java b/spring-data-rest/src/main/java/com/baeldung/models/Author.java index cdd04cbdcf..3f43af9c47 100644 --- a/spring-data-rest/src/main/java/com/baeldung/models/Author.java +++ b/spring-data-rest/src/main/java/com/baeldung/models/Author.java @@ -16,7 +16,7 @@ import javax.persistence.ManyToMany; public class Author { @Id - @GeneratedValue(strategy=GenerationType.IDENTITY) + @GeneratedValue(strategy = GenerationType.IDENTITY) private long id; @Column(nullable = false) diff --git a/spring-data-rest/src/main/java/com/baeldung/models/Book.java b/spring-data-rest/src/main/java/com/baeldung/models/Book.java index 002a64e738..07b0d08b84 100644 --- a/spring-data-rest/src/main/java/com/baeldung/models/Book.java +++ b/spring-data-rest/src/main/java/com/baeldung/models/Book.java @@ -16,14 +16,14 @@ import javax.persistence.ManyToOne; public class Book { @Id - @GeneratedValue(strategy=GenerationType.IDENTITY) + @GeneratedValue(strategy = GenerationType.IDENTITY) private long id; @Column(nullable = false) private String title; - + private String isbn; - + @ManyToOne @JoinColumn(name = "library_id") private Library library; @@ -63,7 +63,6 @@ public class Book { this.isbn = isbn; } - public Library getLibrary() { return library; } diff --git a/spring-data-rest/src/main/java/com/baeldung/models/Library.java b/spring-data-rest/src/main/java/com/baeldung/models/Library.java index c27512d0e4..091975f5d0 100644 --- a/spring-data-rest/src/main/java/com/baeldung/models/Library.java +++ b/spring-data-rest/src/main/java/com/baeldung/models/Library.java @@ -17,7 +17,7 @@ import org.springframework.data.rest.core.annotation.RestResource; public class Library { @Id - @GeneratedValue(strategy=GenerationType.IDENTITY) + @GeneratedValue(strategy = GenerationType.IDENTITY) private long id; @Column diff --git a/spring-data-rest/src/main/java/com/baeldung/models/Subject.java b/spring-data-rest/src/main/java/com/baeldung/models/Subject.java index b3b9a5b0a0..4e5fa82148 100644 --- a/spring-data-rest/src/main/java/com/baeldung/models/Subject.java +++ b/spring-data-rest/src/main/java/com/baeldung/models/Subject.java @@ -10,7 +10,7 @@ import javax.persistence.Id; public class Subject { @Id - @GeneratedValue(strategy=GenerationType.IDENTITY) + @GeneratedValue(strategy = GenerationType.IDENTITY) private long id; @Column(nullable = false) diff --git a/spring-data-rest/src/main/java/com/baeldung/projections/CustomBook.java b/spring-data-rest/src/main/java/com/baeldung/projections/CustomBook.java index 1cd9c01383..3dc6938f5c 100644 --- a/spring-data-rest/src/main/java/com/baeldung/projections/CustomBook.java +++ b/spring-data-rest/src/main/java/com/baeldung/projections/CustomBook.java @@ -8,15 +8,15 @@ import org.springframework.data.rest.core.config.Projection; import com.baeldung.models.Author; import com.baeldung.models.Book; -@Projection(name = "customBook", types = { Book.class }) +@Projection(name = "customBook", types = { Book.class }) public interface CustomBook { @Value("#{target.id}") - long getId(); - + long getId(); + String getTitle(); - + List getAuthors(); - + @Value("#{target.getAuthors().size()}") int getAuthorCount(); } diff --git a/spring-data-rest/src/main/java/com/baeldung/repositories/BookRepository.java b/spring-data-rest/src/main/java/com/baeldung/repositories/BookRepository.java index 34019a9d91..eee44f35d4 100644 --- a/spring-data-rest/src/main/java/com/baeldung/repositories/BookRepository.java +++ b/spring-data-rest/src/main/java/com/baeldung/repositories/BookRepository.java @@ -7,4 +7,5 @@ import com.baeldung.models.Book; import com.baeldung.projections.CustomBook; @RepositoryRestResource(excerptProjection = CustomBook.class) -public interface BookRepository extends CrudRepository {} +public interface BookRepository extends CrudRepository { +} diff --git a/spring-data-rest/src/main/java/com/baeldung/repositories/SubjectRepository.java b/spring-data-rest/src/main/java/com/baeldung/repositories/SubjectRepository.java index a91ae2d505..76e34b0799 100644 --- a/spring-data-rest/src/main/java/com/baeldung/repositories/SubjectRepository.java +++ b/spring-data-rest/src/main/java/com/baeldung/repositories/SubjectRepository.java @@ -8,8 +8,8 @@ import org.springframework.data.rest.core.annotation.RestResource; import com.baeldung.models.Subject; public interface SubjectRepository extends PagingAndSortingRepository { - + @RestResource(path = "nameContains") public Page findByNameContaining(@Param("name") String name, Pageable p); - + } \ No newline at end of file diff --git a/spring-data-rest/src/test/java/com/baeldung/events/AuthorEventHandlerUnitTest.java b/spring-data-rest/src/test/java/com/baeldung/events/AuthorEventHandlerUnitTest.java index 6db536c40c..c01d5882a0 100644 --- a/spring-data-rest/src/test/java/com/baeldung/events/AuthorEventHandlerUnitTest.java +++ b/spring-data-rest/src/test/java/com/baeldung/events/AuthorEventHandlerUnitTest.java @@ -9,21 +9,21 @@ import static org.mockito.Mockito.mock; public class AuthorEventHandlerUnitTest { - @Test - public void whenCreateAuthorThenSuccess() { - Author author = mock(Author.class); - AuthorEventHandler authorEventHandler = new AuthorEventHandler(); - authorEventHandler.handleAuthorBeforeCreate(author); - Mockito.verify(author,Mockito.times(1)).getName(); + @Test + public void whenCreateAuthorThenSuccess() { + Author author = mock(Author.class); + AuthorEventHandler authorEventHandler = new AuthorEventHandler(); + authorEventHandler.handleAuthorBeforeCreate(author); + Mockito.verify(author, Mockito.times(1)).getName(); - } + } - @Test - public void whenDeleteAuthorThenSuccess() { - Author author = mock(Author.class); - AuthorEventHandler authorEventHandler = new AuthorEventHandler(); - authorEventHandler.handleAuthorAfterDelete(author); - Mockito.verify(author,Mockito.times(1)).getName(); + @Test + public void whenDeleteAuthorThenSuccess() { + Author author = mock(Author.class); + AuthorEventHandler authorEventHandler = new AuthorEventHandler(); + authorEventHandler.handleAuthorAfterDelete(author); + Mockito.verify(author, Mockito.times(1)).getName(); - } + } } diff --git a/spring-data-rest/src/test/java/com/baeldung/events/BookEventHandlerUnitTest.java b/spring-data-rest/src/test/java/com/baeldung/events/BookEventHandlerUnitTest.java index 28f0b91e1c..d6b8b3b25e 100644 --- a/spring-data-rest/src/test/java/com/baeldung/events/BookEventHandlerUnitTest.java +++ b/spring-data-rest/src/test/java/com/baeldung/events/BookEventHandlerUnitTest.java @@ -8,21 +8,21 @@ import org.mockito.Mockito; import static org.mockito.Mockito.mock; public class BookEventHandlerUnitTest { - @Test - public void whenCreateBookThenSuccess() { - Book book = mock(Book.class); - BookEventHandler bookEventHandler = new BookEventHandler(); - bookEventHandler.handleBookBeforeCreate(book); - Mockito.verify(book,Mockito.times(1)).getAuthors(); + @Test + public void whenCreateBookThenSuccess() { + Book book = mock(Book.class); + BookEventHandler bookEventHandler = new BookEventHandler(); + bookEventHandler.handleBookBeforeCreate(book); + Mockito.verify(book, Mockito.times(1)).getAuthors(); - } + } - @Test - public void whenCreateAuthorThenSuccess() { - Author author = mock(Author.class); - BookEventHandler bookEventHandler = new BookEventHandler(); - bookEventHandler.handleAuthorBeforeCreate(author); - Mockito.verify(author,Mockito.times(1)).getBooks(); + @Test + public void whenCreateAuthorThenSuccess() { + Author author = mock(Author.class); + BookEventHandler bookEventHandler = new BookEventHandler(); + bookEventHandler.handleAuthorBeforeCreate(author); + Mockito.verify(author, Mockito.times(1)).getBooks(); - } + } } diff --git a/spring-data-rest/src/test/java/com/baeldung/projection/SpringDataProjectionLiveTest.java b/spring-data-rest/src/test/java/com/baeldung/projection/SpringDataProjectionLiveTest.java index 702c1521da..ad219ccd53 100644 --- a/spring-data-rest/src/test/java/com/baeldung/projection/SpringDataProjectionLiveTest.java +++ b/spring-data-rest/src/test/java/com/baeldung/projection/SpringDataProjectionLiveTest.java @@ -29,16 +29,15 @@ public class SpringDataProjectionLiveTest { private static final String BOOK_ENDPOINT = "http://localhost:8080/books"; private static final String AUTHOR_ENDPOINT = "http://localhost:8080/authors"; - @Autowired private BookRepository bookRepo; @Autowired private AuthorRepository authorRepo; - + @Before - public void setup(){ - if(bookRepo.findById(1L) == null){ + public void setup() { + if (bookRepo.findById(1L) == null) { Book book = new Book("Animal Farm"); book.setIsbn("978-1943138425"); book = bookRepo.save(book); @@ -48,45 +47,44 @@ public class SpringDataProjectionLiveTest { author = authorRepo.save(author); } } - + @Test - public void whenGetBook_thenOK(){ - final Response response = RestAssured.get(BOOK_ENDPOINT+"/1"); - + public void whenGetBook_thenOK() { + final Response response = RestAssured.get(BOOK_ENDPOINT + "/1"); + assertEquals(200, response.getStatusCode()); assertTrue(response.asString().contains("isbn")); assertFalse(response.asString().contains("authorCount")); -// System.out.println(response.asString()); + // System.out.println(response.asString()); } - - + @Test - public void whenGetBookProjection_thenOK(){ - final Response response = RestAssured.get(BOOK_ENDPOINT+"/1?projection=customBook"); - + public void whenGetBookProjection_thenOK() { + final Response response = RestAssured.get(BOOK_ENDPOINT + "/1?projection=customBook"); + assertEquals(200, response.getStatusCode()); assertFalse(response.asString().contains("isbn")); - assertTrue(response.asString().contains("authorCount")); -// System.out.println(response.asString()); + assertTrue(response.asString().contains("authorCount")); + // System.out.println(response.asString()); } - + @Test - public void whenGetAllBooks_thenOK(){ + public void whenGetAllBooks_thenOK() { final Response response = RestAssured.get(BOOK_ENDPOINT); - + assertEquals(200, response.getStatusCode()); assertFalse(response.asString().contains("isbn")); - assertTrue(response.asString().contains("authorCount")); - // System.out.println(response.asString()); + assertTrue(response.asString().contains("authorCount")); + // System.out.println(response.asString()); } - + @Test - public void whenGetAuthorBooks_thenOK(){ - final Response response = RestAssured.get(AUTHOR_ENDPOINT+"/1/books"); - + public void whenGetAuthorBooks_thenOK() { + final Response response = RestAssured.get(AUTHOR_ENDPOINT + "/1/books"); + assertEquals(200, response.getStatusCode()); assertFalse(response.asString().contains("isbn")); - assertTrue(response.asString().contains("authorCount")); + assertTrue(response.asString().contains("authorCount")); System.out.println(response.asString()); } } From 2e8d2a7c1e6d827263b3c380e93a49fbb63a59b5 Mon Sep 17 00:00:00 2001 From: Loredana Crusoveanu Date: Sun, 27 Jan 2019 15:08:16 +0200 Subject: [PATCH 30/33] Update README.md --- lombok/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lombok/README.md b/lombok/README.md index bd6282fd18..e3d08d4e26 100644 --- a/lombok/README.md +++ b/lombok/README.md @@ -5,3 +5,5 @@ - [Lombok @Builder with Inheritance](https://www.baeldung.com/lombok-builder-inheritance) - [Lombok Builder with Default Value](https://www.baeldung.com/lombok-builder-default-value) - [Lombok Builder with Custom Setter](https://www.baeldung.com/lombok-builder-custom-setter) +- [Setting up Lombok with Eclipse and Intellij](https://www.baeldung.com/lombok-ide) + From 4845bd82a17f61db82e48e68937fb1887c4eb533 Mon Sep 17 00:00:00 2001 From: Sam Millington Date: Sun, 27 Jan 2019 14:18:13 +0000 Subject: [PATCH 31/33] added solid code (#6226) --- patterns/principles/solid/pom.xml | 23 ++++++++++++++++ .../main/java/com/baeldung/d/Keyboard.java | 4 +++ .../src/main/java/com/baeldung/d/Monitor.java | 6 +++++ .../java/com/baeldung/d/Windows98Machine.java | 15 +++++++++++ .../com/baeldung/d/Windows98MachineDI.java | 12 +++++++++ .../main/java/com/baeldung/i/BearCarer.java | 12 +++++++++ .../main/java/com/baeldung/i/BearCleaner.java | 5 ++++ .../main/java/com/baeldung/i/BearFeeder.java | 5 ++++ .../main/java/com/baeldung/i/BearKeeper.java | 9 +++++++ .../main/java/com/baeldung/i/BearPetter.java | 5 ++++ .../main/java/com/baeldung/i/CrazyPerson.java | 8 ++++++ .../src/main/java/com/baeldung/l/Car.java | 8 ++++++ .../main/java/com/baeldung/l/ElectricCar.java | 12 +++++++++ .../src/main/java/com/baeldung/l/Engine.java | 13 +++++++++ .../main/java/com/baeldung/l/MotorCar.java | 18 +++++++++++++ .../src/main/java/com/baeldung/o/Guitar.java | 10 +++++++ .../baeldung/o/SuperCoolGuitarWithFlames.java | 9 +++++++ .../src/main/java/com/baeldung/s/BadBook.java | 27 +++++++++++++++++++ .../main/java/com/baeldung/s/BookPrinter.java | 13 +++++++++ .../main/java/com/baeldung/s/GoodBook.java | 20 ++++++++++++++ 20 files changed, 234 insertions(+) create mode 100644 patterns/principles/solid/pom.xml create mode 100644 patterns/principles/solid/src/main/java/com/baeldung/d/Keyboard.java create mode 100644 patterns/principles/solid/src/main/java/com/baeldung/d/Monitor.java create mode 100644 patterns/principles/solid/src/main/java/com/baeldung/d/Windows98Machine.java create mode 100644 patterns/principles/solid/src/main/java/com/baeldung/d/Windows98MachineDI.java create mode 100644 patterns/principles/solid/src/main/java/com/baeldung/i/BearCarer.java create mode 100644 patterns/principles/solid/src/main/java/com/baeldung/i/BearCleaner.java create mode 100644 patterns/principles/solid/src/main/java/com/baeldung/i/BearFeeder.java create mode 100644 patterns/principles/solid/src/main/java/com/baeldung/i/BearKeeper.java create mode 100644 patterns/principles/solid/src/main/java/com/baeldung/i/BearPetter.java create mode 100644 patterns/principles/solid/src/main/java/com/baeldung/i/CrazyPerson.java create mode 100644 patterns/principles/solid/src/main/java/com/baeldung/l/Car.java create mode 100644 patterns/principles/solid/src/main/java/com/baeldung/l/ElectricCar.java create mode 100644 patterns/principles/solid/src/main/java/com/baeldung/l/Engine.java create mode 100644 patterns/principles/solid/src/main/java/com/baeldung/l/MotorCar.java create mode 100644 patterns/principles/solid/src/main/java/com/baeldung/o/Guitar.java create mode 100644 patterns/principles/solid/src/main/java/com/baeldung/o/SuperCoolGuitarWithFlames.java create mode 100644 patterns/principles/solid/src/main/java/com/baeldung/s/BadBook.java create mode 100644 patterns/principles/solid/src/main/java/com/baeldung/s/BookPrinter.java create mode 100644 patterns/principles/solid/src/main/java/com/baeldung/s/GoodBook.java diff --git a/patterns/principles/solid/pom.xml b/patterns/principles/solid/pom.xml new file mode 100644 index 0000000000..825c7730a5 --- /dev/null +++ b/patterns/principles/solid/pom.xml @@ -0,0 +1,23 @@ + + + 4.0.0 + + com.baeldung + solid/artifactId> + 1.0-SNAPSHOT + + + + + + junit + junit + 4.12 + test + + + + + diff --git a/patterns/principles/solid/src/main/java/com/baeldung/d/Keyboard.java b/patterns/principles/solid/src/main/java/com/baeldung/d/Keyboard.java new file mode 100644 index 0000000000..acb50cedb4 --- /dev/null +++ b/patterns/principles/solid/src/main/java/com/baeldung/d/Keyboard.java @@ -0,0 +1,4 @@ +package com.baeldung.d; + +public class Keyboard { +} diff --git a/patterns/principles/solid/src/main/java/com/baeldung/d/Monitor.java b/patterns/principles/solid/src/main/java/com/baeldung/d/Monitor.java new file mode 100644 index 0000000000..c0ab7a53b2 --- /dev/null +++ b/patterns/principles/solid/src/main/java/com/baeldung/d/Monitor.java @@ -0,0 +1,6 @@ +package com.baeldung.d; + +public class Monitor { + + +} diff --git a/patterns/principles/solid/src/main/java/com/baeldung/d/Windows98Machine.java b/patterns/principles/solid/src/main/java/com/baeldung/d/Windows98Machine.java new file mode 100644 index 0000000000..a9f130aedb --- /dev/null +++ b/patterns/principles/solid/src/main/java/com/baeldung/d/Windows98Machine.java @@ -0,0 +1,15 @@ +package com.baeldung.d; + +public class Windows98Machine { + + private final Keyboard keyboard; + private final Monitor monitor; + + public Windows98Machine() { + + monitor = new Monitor(); + keyboard = new Keyboard(); + + } + +} diff --git a/patterns/principles/solid/src/main/java/com/baeldung/d/Windows98MachineDI.java b/patterns/principles/solid/src/main/java/com/baeldung/d/Windows98MachineDI.java new file mode 100644 index 0000000000..2a6fd74a41 --- /dev/null +++ b/patterns/principles/solid/src/main/java/com/baeldung/d/Windows98MachineDI.java @@ -0,0 +1,12 @@ +package com.baeldung.d; + +public class Windows98MachineDI { + + private final Keyboard keyboard; + private final Monitor monitor; + + public Windows98MachineDI(Keyboard keyboard, Monitor monitor) { + this.keyboard = keyboard; + this.monitor = monitor; + } +} diff --git a/patterns/principles/solid/src/main/java/com/baeldung/i/BearCarer.java b/patterns/principles/solid/src/main/java/com/baeldung/i/BearCarer.java new file mode 100644 index 0000000000..3d69211674 --- /dev/null +++ b/patterns/principles/solid/src/main/java/com/baeldung/i/BearCarer.java @@ -0,0 +1,12 @@ +package com.baeldung.i; + +public class BearCarer implements BearCleaner, BearFeeder { + + public void washTheBear() { + //I think we missed a spot.. + } + + public void feedTheBear() { + //Tuna tuesdays.. + } +} diff --git a/patterns/principles/solid/src/main/java/com/baeldung/i/BearCleaner.java b/patterns/principles/solid/src/main/java/com/baeldung/i/BearCleaner.java new file mode 100644 index 0000000000..e2b71b2ce8 --- /dev/null +++ b/patterns/principles/solid/src/main/java/com/baeldung/i/BearCleaner.java @@ -0,0 +1,5 @@ +package com.baeldung.i; + +public interface BearCleaner { + void washTheBear(); +} diff --git a/patterns/principles/solid/src/main/java/com/baeldung/i/BearFeeder.java b/patterns/principles/solid/src/main/java/com/baeldung/i/BearFeeder.java new file mode 100644 index 0000000000..5d0ba7cd29 --- /dev/null +++ b/patterns/principles/solid/src/main/java/com/baeldung/i/BearFeeder.java @@ -0,0 +1,5 @@ +package com.baeldung.i; + +public interface BearFeeder { + void feedTheBear(); +} diff --git a/patterns/principles/solid/src/main/java/com/baeldung/i/BearKeeper.java b/patterns/principles/solid/src/main/java/com/baeldung/i/BearKeeper.java new file mode 100644 index 0000000000..f09774a5ff --- /dev/null +++ b/patterns/principles/solid/src/main/java/com/baeldung/i/BearKeeper.java @@ -0,0 +1,9 @@ +package com.baeldung.i; + +public interface BearKeeper { + + void washTheBear(); + void feedTheBear(); + void petTheBear(); + +} diff --git a/patterns/principles/solid/src/main/java/com/baeldung/i/BearPetter.java b/patterns/principles/solid/src/main/java/com/baeldung/i/BearPetter.java new file mode 100644 index 0000000000..a913cf3d8a --- /dev/null +++ b/patterns/principles/solid/src/main/java/com/baeldung/i/BearPetter.java @@ -0,0 +1,5 @@ +package com.baeldung.i; + +public interface BearPetter { + void petTheBear(); +} diff --git a/patterns/principles/solid/src/main/java/com/baeldung/i/CrazyPerson.java b/patterns/principles/solid/src/main/java/com/baeldung/i/CrazyPerson.java new file mode 100644 index 0000000000..aae0d4c11b --- /dev/null +++ b/patterns/principles/solid/src/main/java/com/baeldung/i/CrazyPerson.java @@ -0,0 +1,8 @@ +package com.baeldung.i; + +public class CrazyPerson implements BearPetter { + + public void petTheBear() { + //Good luck with that! + } +} diff --git a/patterns/principles/solid/src/main/java/com/baeldung/l/Car.java b/patterns/principles/solid/src/main/java/com/baeldung/l/Car.java new file mode 100644 index 0000000000..b3481f894a --- /dev/null +++ b/patterns/principles/solid/src/main/java/com/baeldung/l/Car.java @@ -0,0 +1,8 @@ +package com.baeldung.l; + +public interface Car { + + void turnOnEngine(); + void accelerate(); + +} diff --git a/patterns/principles/solid/src/main/java/com/baeldung/l/ElectricCar.java b/patterns/principles/solid/src/main/java/com/baeldung/l/ElectricCar.java new file mode 100644 index 0000000000..fd919c5659 --- /dev/null +++ b/patterns/principles/solid/src/main/java/com/baeldung/l/ElectricCar.java @@ -0,0 +1,12 @@ +package com.baeldung.l; + +public class ElectricCar implements Car { + + public void turnOnEngine() { + throw new AssertionError("I don't have an engine!"); + } + + public void accelerate() { + //this acceleration is crazy! + } +} diff --git a/patterns/principles/solid/src/main/java/com/baeldung/l/Engine.java b/patterns/principles/solid/src/main/java/com/baeldung/l/Engine.java new file mode 100644 index 0000000000..a8e38b8877 --- /dev/null +++ b/patterns/principles/solid/src/main/java/com/baeldung/l/Engine.java @@ -0,0 +1,13 @@ +package com.baeldung.l; + +public class Engine { + + public void on(){ + //vroom. + } + + public void powerOn(int amount){ + //do something + } + +} diff --git a/patterns/principles/solid/src/main/java/com/baeldung/l/MotorCar.java b/patterns/principles/solid/src/main/java/com/baeldung/l/MotorCar.java new file mode 100644 index 0000000000..638f315475 --- /dev/null +++ b/patterns/principles/solid/src/main/java/com/baeldung/l/MotorCar.java @@ -0,0 +1,18 @@ +package com.baeldung.l; + +public class MotorCar implements Car { + + private Engine engine; + + //Constructors, getters + setters + + public void turnOnEngine() { + //turn on the engine! + engine.on(); + } + + public void accelerate() { + //move forward! + engine.powerOn(1000); + } +} diff --git a/patterns/principles/solid/src/main/java/com/baeldung/o/Guitar.java b/patterns/principles/solid/src/main/java/com/baeldung/o/Guitar.java new file mode 100644 index 0000000000..baab006b5b --- /dev/null +++ b/patterns/principles/solid/src/main/java/com/baeldung/o/Guitar.java @@ -0,0 +1,10 @@ +package com.baeldung.o; + +public class Guitar { + + private String make; + private String model; + private int volume; + + //Constructors, getters & setters +} diff --git a/patterns/principles/solid/src/main/java/com/baeldung/o/SuperCoolGuitarWithFlames.java b/patterns/principles/solid/src/main/java/com/baeldung/o/SuperCoolGuitarWithFlames.java new file mode 100644 index 0000000000..b69e3be74a --- /dev/null +++ b/patterns/principles/solid/src/main/java/com/baeldung/o/SuperCoolGuitarWithFlames.java @@ -0,0 +1,9 @@ +package com.baeldung.o; + +public class SuperCoolGuitarWithFlames extends Guitar { + + private String flameColour; + + //constructor, getters + setters + +} diff --git a/patterns/principles/solid/src/main/java/com/baeldung/s/BadBook.java b/patterns/principles/solid/src/main/java/com/baeldung/s/BadBook.java new file mode 100644 index 0000000000..03c8fcd488 --- /dev/null +++ b/patterns/principles/solid/src/main/java/com/baeldung/s/BadBook.java @@ -0,0 +1,27 @@ +package com.baeldung.s; + +public class BadBook { + + private String name; + private String author; + private String text; + + //constructor, getters and setters + + + //methods that directly relate to the book properties + public String replaceWordInText(String word){ + return text.replaceAll(word, text); + } + + public boolean isWordInText(String word){ + return text.contains(word); + } + + //methods for outputting text to console - should this really be here? + void printTextToConsole(){ + //our code for formatting and printing the text + } + + +} diff --git a/patterns/principles/solid/src/main/java/com/baeldung/s/BookPrinter.java b/patterns/principles/solid/src/main/java/com/baeldung/s/BookPrinter.java new file mode 100644 index 0000000000..0c8ef62e01 --- /dev/null +++ b/patterns/principles/solid/src/main/java/com/baeldung/s/BookPrinter.java @@ -0,0 +1,13 @@ +package com.baeldung.s; + +public class BookPrinter { + + //methods for outputting text + void printTextToConsole(String text){ + //our code for formatting and printing the text + } + + void printTextToAnotherMedium(String text){ + //code for writing to any other location.. + } +} diff --git a/patterns/principles/solid/src/main/java/com/baeldung/s/GoodBook.java b/patterns/principles/solid/src/main/java/com/baeldung/s/GoodBook.java new file mode 100644 index 0000000000..b0993aca2b --- /dev/null +++ b/patterns/principles/solid/src/main/java/com/baeldung/s/GoodBook.java @@ -0,0 +1,20 @@ +package com.baeldung.s; + +public class GoodBook { + + private String name; + private String author; + private String text; + + //constructor, getters and setters + + //methods that directly relate to the book properties + public String replaceWordInText(String word){ + return text.replaceAll(word, text); + } + + public boolean isWordInText(String word){ + return text.contains(word); + } + +} From e67915213a38cf82c0213f617d3c68ec812603b4 Mon Sep 17 00:00:00 2001 From: anuraggoyal1 Date: Sun, 27 Jan 2019 20:42:18 +0530 Subject: [PATCH 32/33] [BAEL-2471] Guide to Apache Commons MultiValuedMap (#6155) * [BAEL-2471] Guide to Apache Commons MultiValuedMap * Update MultiValuedMapUnitTest.java * added empty lines --- .../java/map/MultiValuedMapUnitTest.java | 204 ++++++++++++++++++ 1 file changed, 204 insertions(+) create mode 100644 java-collections-maps/src/test/java/com/baeldung/java/map/MultiValuedMapUnitTest.java diff --git a/java-collections-maps/src/test/java/com/baeldung/java/map/MultiValuedMapUnitTest.java b/java-collections-maps/src/test/java/com/baeldung/java/map/MultiValuedMapUnitTest.java new file mode 100644 index 0000000000..67e4a5b0a0 --- /dev/null +++ b/java-collections-maps/src/test/java/com/baeldung/java/map/MultiValuedMapUnitTest.java @@ -0,0 +1,204 @@ +package com.baeldung.java.map; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Map; +import java.util.Map.Entry; + +import org.apache.commons.collections4.MultiMapUtils; +import org.apache.commons.collections4.MultiValuedMap; +import org.apache.commons.collections4.multimap.ArrayListValuedHashMap; +import org.apache.commons.collections4.multimap.HashSetValuedHashMap; +import org.junit.Test; + +public class MultiValuedMapUnitTest { + + @Test + public void givenMultiValuesMap_whenPuttingMultipleValuesUsingPutMethod_thenReturningAllValues() { + MultiValuedMap map = new ArrayListValuedHashMap<>(); + + map.put("key", "value1"); + map.put("key", "value2"); + map.put("key", "value2"); + + assertThat((Collection) map.get("key")).containsExactly("value1", "value2", "value2"); + } + + @Test + public void givenMultiValuesMap_whenPuttingMultipleValuesUsingPutAllMethod_thenReturningAllValues() { + MultiValuedMap map = new ArrayListValuedHashMap<>(); + + map.putAll("key", Arrays.asList("value1", "value2", "value2")); + + assertThat((Collection) map.get("key")).containsExactly("value1", "value2", "value2"); + } + + @Test + public void givenMultiValuesMap_whenGettingValueUsingGetMethod_thenReturningValue() { + MultiValuedMap map = new ArrayListValuedHashMap<>(); + map.put("key", "value"); + + assertThat((Collection) map.get("key")).containsExactly("value"); + } + + @Test + public void givenMultiValuesMap_whenUsingEntriesMethod_thenReturningMappings() { + MultiValuedMap map = new ArrayListValuedHashMap<>(); + map.put("key", "value1"); + map.put("key", "value2"); + + Collection> entries = (Collection>) map.entries(); + + for(Map.Entry entry : entries) { + assertThat(entry.getKey()).contains("key"); + assertTrue(entry.getValue().equals("value1") || entry.getValue().equals("value2") ); + } + } + + @Test + public void givenMultiValuesMap_whenUsingKeysMethod_thenReturningAllKeys() { + MultiValuedMap map = new ArrayListValuedHashMap<>(); + map.put("key", "value"); + map.put("key1", "value1"); + map.put("key2", "value2"); + + assertThat(((Collection) map.keys())).contains("key", "key1", "key2"); + } + + @Test + public void givenMultiValuesMap_whenUsingKeySetMethod_thenReturningAllKeys() { + MultiValuedMap map = new ArrayListValuedHashMap<>(); + map.put("key", "value"); + map.put("key1", "value1"); + map.put("key2", "value2"); + + assertThat((Collection) map.keySet()).contains("key", "key1", "key2"); + } + + @Test + public void givenMultiValuesMap_whenUsingValuesMethod_thenReturningAllValues() { + MultiValuedMap map = new ArrayListValuedHashMap<>(); + map.put("key", "value"); + map.put("key1", "value1"); + map.put("key2", "value2"); + + assertThat(((Collection) map.values())).contains("value", "value1", "value2"); + } + + @Test + public void givenMultiValuesMap_whenUsingRemoveMethod_thenReturningUpdatedMap() { + MultiValuedMap map = new ArrayListValuedHashMap<>(); + map.put("key", "value"); + map.put("key1", "value1"); + map.put("key2", "value2"); + assertThat(((Collection) map.values())).contains("value", "value1", "value2"); + + map.remove("key"); + + assertThat(((Collection) map.values())).contains("value1", "value2"); + } + + @Test + public void givenMultiValuesMap_whenUsingRemoveMappingMethod_thenReturningUpdatedMapAfterMappingRemoved() { + MultiValuedMap map = new ArrayListValuedHashMap<>(); + map.put("key", "value"); + map.put("key1", "value1"); + map.put("key2", "value2"); + assertThat(((Collection) map.values())).contains("value", "value1", "value2"); + + map.removeMapping("key", "value"); + + assertThat(((Collection) map.values())).contains("value1", "value2"); + } + + @Test + public void givenMultiValuesMap_whenUsingClearMethod_thenReturningEmptyMap() { + MultiValuedMap map = new ArrayListValuedHashMap<>(); + map.put("key", "value"); + map.put("key1", "value1"); + map.put("key2", "value2"); + assertThat(((Collection) map.values())).contains("value", "value1", "value2"); + + map.clear(); + + assertTrue(map.isEmpty()); + } + + @Test + public void givenMultiValuesMap_whenUsingContainsKeyMethod_thenReturningTrue() { + MultiValuedMap map = new ArrayListValuedHashMap<>(); + map.put("key", "value"); + map.put("key1", "value1"); + map.put("key2", "value2"); + + assertTrue(map.containsKey("key")); + } + + @Test + public void givenMultiValuesMap_whenUsingContainsValueMethod_thenReturningTrue() { + MultiValuedMap map = new ArrayListValuedHashMap<>(); + map.put("key", "value"); + map.put("key1", "value1"); + map.put("key2", "value2"); + + assertTrue(map.containsValue("value")); + } + + @Test + public void givenMultiValuesMap_whenUsingIsEmptyMethod_thenReturningFalse() { + MultiValuedMap map = new ArrayListValuedHashMap<>(); + map.put("key", "value"); + map.put("key1", "value1"); + map.put("key2", "value2"); + + assertFalse(map.isEmpty()); + } + + @Test + public void givenMultiValuesMap_whenUsingSizeMethod_thenReturningElementCount() { + MultiValuedMap map = new ArrayListValuedHashMap<>(); + map.put("key", "value"); + map.put("key1", "value1"); + map.put("key2", "value2"); + + assertEquals(3, map.size()); + } + + @Test + public void givenArrayListValuedHashMap_whenPuttingDoubleValues_thenReturningAllValues() { + MultiValuedMap map = new ArrayListValuedHashMap<>(); + + map.put("key", "value1"); + map.put("key", "value2"); + map.put("key", "value2"); + + assertThat((Collection) map.get("key")).containsExactly("value1", "value2", "value2"); + } + + @Test + public void givenHashSetValuedHashMap_whenPuttingTwiceTheSame_thenReturningOneValue() { + MultiValuedMap map = new HashSetValuedHashMap<>(); + + map.put("key1", "value1"); + map.put("key1", "value1"); + + assertThat((Collection) map.get("key1")).containsExactly("value1"); + } + + @Test(expected = UnsupportedOperationException.class) + public void givenUnmodifiableMultiValuedMap_whenInserting_thenThrowingException() { + MultiValuedMap map = new ArrayListValuedHashMap<>(); + map.put("key", "value1"); + map.put("key", "value2"); + MultiValuedMap immutableMap = MultiMapUtils.unmodifiableMultiValuedMap(map); + + immutableMap.put("key", "value3"); + } + + +} From f3faf9234e1d365c8bc9ac4a11316795b4b67b2b Mon Sep 17 00:00:00 2001 From: Alejandro Gervasio Date: Mon, 28 Jan 2019 00:27:43 -0300 Subject: [PATCH 33/33] Initial Commit (#6202) --- .../validation/application/Application.java | 27 ++++++++ .../controllers/UserController.java | 52 ++++++++++++++ .../validation/application/entities/User.java | 50 ++++++++++++++ .../repositories/UserRepository.java | 8 +++ .../tests/UserControllerIntegrationTest.java | 69 +++++++++++++++++++ 5 files changed, 206 insertions(+) create mode 100644 spring-boot/src/main/java/com/baeldung/validation/application/Application.java create mode 100644 spring-boot/src/main/java/com/baeldung/validation/application/controllers/UserController.java create mode 100644 spring-boot/src/main/java/com/baeldung/validation/application/entities/User.java create mode 100644 spring-boot/src/main/java/com/baeldung/validation/application/repositories/UserRepository.java create mode 100644 spring-boot/src/test/java/com/baeldung/validation/tests/UserControllerIntegrationTest.java diff --git a/spring-boot/src/main/java/com/baeldung/validation/application/Application.java b/spring-boot/src/main/java/com/baeldung/validation/application/Application.java new file mode 100644 index 0000000000..af8f768193 --- /dev/null +++ b/spring-boot/src/main/java/com/baeldung/validation/application/Application.java @@ -0,0 +1,27 @@ +package com.baeldung.validation.application; + +import com.baeldung.validation.application.entities.User; +import com.baeldung.validation.application.repositories.UserRepository; +import org.springframework.boot.CommandLineRunner; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; + +@SpringBootApplication +public class Application { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } + + @Bean + public CommandLineRunner run(UserRepository userRepository) throws Exception { + return (String[] args) -> { + User user1 = new User("Bob", "bob@domain.com"); + User user2 = new User("Jenny", "jenny@domain.com"); + userRepository.save(user1); + userRepository.save(user2); + userRepository.findAll().forEach(System.out::println); + }; + } +} diff --git a/spring-boot/src/main/java/com/baeldung/validation/application/controllers/UserController.java b/spring-boot/src/main/java/com/baeldung/validation/application/controllers/UserController.java new file mode 100644 index 0000000000..a4aeefb70b --- /dev/null +++ b/spring-boot/src/main/java/com/baeldung/validation/application/controllers/UserController.java @@ -0,0 +1,52 @@ +package com.baeldung.validation.application.controllers; + +import com.baeldung.validation.application.entities.User; +import com.baeldung.validation.application.repositories.UserRepository; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import javax.validation.Valid; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.validation.FieldError; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class UserController { + + private final UserRepository userRepository; + + @Autowired + public UserController(UserRepository userRepository) { + this.userRepository = userRepository; + } + + @GetMapping("/users") + public List getUsers() { + return (List) userRepository.findAll(); + } + + @PostMapping("/users") + ResponseEntity addUser(@Valid @RequestBody User user) { + return ResponseEntity.ok("User is valid"); + } + + @ResponseStatus(HttpStatus.BAD_REQUEST) + @ExceptionHandler(MethodArgumentNotValidException.class) + public Map handleValidationExceptions(MethodArgumentNotValidException ex) { + Map errors = new HashMap<>(); + ex.getBindingResult().getAllErrors().forEach((error) -> { + String fieldName = ((FieldError) error).getField(); + String errorMessage = error.getDefaultMessage(); + errors.put(fieldName, errorMessage); + }); + return errors; + } +} diff --git a/spring-boot/src/main/java/com/baeldung/validation/application/entities/User.java b/spring-boot/src/main/java/com/baeldung/validation/application/entities/User.java new file mode 100644 index 0000000000..529368f132 --- /dev/null +++ b/spring-boot/src/main/java/com/baeldung/validation/application/entities/User.java @@ -0,0 +1,50 @@ +package com.baeldung.validation.application.entities; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; +import javax.validation.constraints.NotBlank; + +@Entity +public class User { + + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + private long id; + + @NotBlank(message = "Name is mandatory") + private String name; + + @NotBlank(message = "Email is mandatory") + private String email; + + public User(){} + + public User(String name, String email) { + this.name = name; + this.email = email; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + @Override + public String toString() { + return "User{" + "id=" + id + ", name=" + name + ", email=" + email + '}'; + } +} diff --git a/spring-boot/src/main/java/com/baeldung/validation/application/repositories/UserRepository.java b/spring-boot/src/main/java/com/baeldung/validation/application/repositories/UserRepository.java new file mode 100644 index 0000000000..b579addcaa --- /dev/null +++ b/spring-boot/src/main/java/com/baeldung/validation/application/repositories/UserRepository.java @@ -0,0 +1,8 @@ +package com.baeldung.validation.application.repositories; + +import com.baeldung.validation.application.entities.User; +import org.springframework.data.repository.CrudRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface UserRepository extends CrudRepository {} diff --git a/spring-boot/src/test/java/com/baeldung/validation/tests/UserControllerIntegrationTest.java b/spring-boot/src/test/java/com/baeldung/validation/tests/UserControllerIntegrationTest.java new file mode 100644 index 0000000000..265c4ec22c --- /dev/null +++ b/spring-boot/src/test/java/com/baeldung/validation/tests/UserControllerIntegrationTest.java @@ -0,0 +1,69 @@ +package com.baeldung.validation.tests; + +import com.baeldung.validation.application.controllers.UserController; +import com.baeldung.validation.application.repositories.UserRepository; +import java.nio.charset.Charset; +import static org.assertj.core.api.Assertions.assertThat; +import org.hamcrest.core.Is; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.MediaType; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.test.web.servlet.result.MockMvcResultMatchers; + +@RunWith(SpringRunner.class) +@WebMvcTest +@AutoConfigureMockMvc +public class UserControllerIntegrationTest { + + @MockBean + private UserRepository userRepository; + + @Autowired + UserController userController; + + @Autowired + private MockMvc mockMvc; + + @Test + public void whenUserControllerInjected_thenNotNull() throws Exception { + assertThat(userController).isNotNull(); + } + + @Test + public void whenGetRequestToUsers_thenCorrectResponse() throws Exception { + mockMvc.perform(MockMvcRequestBuilders.get("/users") + .contentType(MediaType.APPLICATION_JSON_UTF8)) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON_UTF8)); + + } + + @Test + public void whenPostRequestToUsersAndValidUser_thenCorrectResponse() throws Exception { + MediaType textPlainUtf8 = new MediaType(MediaType.TEXT_PLAIN, Charset.forName("UTF-8")); + String user = "{\"name\": \"bob\", \"email\" : \"bob@domain.com\"}"; + mockMvc.perform(MockMvcRequestBuilders.post("/users") + .content(user) + .contentType(MediaType.APPLICATION_JSON_UTF8)) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(textPlainUtf8)); + } + + @Test + public void whenPostRequestToUsersAndInValidUser_thenCorrectReponse() throws Exception { + String user = "{\"name\": \"\", \"email\" : \"bob@domain.com\"}"; + mockMvc.perform(MockMvcRequestBuilders.post("/users") + .content(user) + .contentType(MediaType.APPLICATION_JSON_UTF8)) + .andExpect(MockMvcResultMatchers.status().isBadRequest()) + .andExpect(MockMvcResultMatchers.jsonPath("$.name", Is.is("Name is mandatory"))) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON_UTF8)); + } +}