diff --git a/algorithms-miscellaneous-6/src/main/java/com/baeldung/algorithms/linkedlist/LinkedListReversal.java b/algorithms-miscellaneous-6/src/main/java/com/baeldung/algorithms/linkedlist/LinkedListReversal.java new file mode 100644 index 0000000000..93402133ff --- /dev/null +++ b/algorithms-miscellaneous-6/src/main/java/com/baeldung/algorithms/linkedlist/LinkedListReversal.java @@ -0,0 +1,30 @@ +package com.baeldung.algorithms.linkedlist; + +public class LinkedListReversal { + + ListNode reverseList(ListNode head) { + ListNode previous = null; + ListNode current = head; + while (current != null) { + ListNode nextElement = current.getNext(); + current.setNext(previous); + previous = current; + current = nextElement; + } + return previous; + } + + ListNode reverseListRecursive(ListNode head) { + if (head == null) { + return null; + } + if (head.getNext() == null) { + return head; + } + ListNode node = reverseListRecursive(head.getNext()); + head.getNext().setNext(head); + head.setNext(null); + return node; + } + +} diff --git a/algorithms-miscellaneous-6/src/main/java/com/baeldung/algorithms/linkedlist/ListNode.java b/algorithms-miscellaneous-6/src/main/java/com/baeldung/algorithms/linkedlist/ListNode.java new file mode 100644 index 0000000000..de2e93a65c --- /dev/null +++ b/algorithms-miscellaneous-6/src/main/java/com/baeldung/algorithms/linkedlist/ListNode.java @@ -0,0 +1,28 @@ +package com.baeldung.algorithms.linkedlist; + +public class ListNode { + + private int data; + private ListNode next; + + ListNode(int data) { + this.data = data; + this.next = null; + } + + public int getData() { + return data; + } + + public ListNode getNext() { + return next; + } + + public void setData(int data) { + this.data = data; + } + + public void setNext(ListNode next) { + this.next = next; + } +} diff --git a/algorithms-miscellaneous-6/src/test/java/com/baeldung/algorithms/linkedlist/LinkedListReversalUnitTest.java b/algorithms-miscellaneous-6/src/test/java/com/baeldung/algorithms/linkedlist/LinkedListReversalUnitTest.java new file mode 100644 index 0000000000..0940677959 --- /dev/null +++ b/algorithms-miscellaneous-6/src/test/java/com/baeldung/algorithms/linkedlist/LinkedListReversalUnitTest.java @@ -0,0 +1,59 @@ +package com.baeldung.algorithms.linkedlist; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +public class LinkedListReversalUnitTest { + @Test + public void givenLinkedList_whenIterativeReverse_thenOutputCorrectResult() { + ListNode head = constructLinkedList(); + ListNode node = head; + for (int i = 1; i <= 5; i++) { + assertNotNull(node); + assertEquals(i, node.getData()); + node = node.getNext(); + } + LinkedListReversal reversal = new LinkedListReversal(); + node = reversal.reverseList(head); + for (int i = 5; i >= 1; i--) { + assertNotNull(node); + assertEquals(i, node.getData()); + node = node.getNext(); + } + } + + @Test + public void givenLinkedList_whenRecursiveReverse_thenOutputCorrectResult() { + ListNode head = constructLinkedList(); + ListNode node = head; + for (int i = 1; i <= 5; i++) { + assertNotNull(node); + assertEquals(i, node.getData()); + node = node.getNext(); + } + LinkedListReversal reversal = new LinkedListReversal(); + node = reversal.reverseListRecursive(head); + for (int i = 5; i >= 1; i--) { + assertNotNull(node); + assertEquals(i, node.getData()); + node = node.getNext(); + } + } + + private ListNode constructLinkedList() { + ListNode head = null; + ListNode tail = null; + for (int i = 1; i <= 5; i++) { + ListNode node = new ListNode(i); + if (head == null) { + head = node; + } else { + tail.setNext(node); + } + tail = node; + } + return head; + } +} diff --git a/core-groovy-strings/README.md b/core-groovy-strings/README.md new file mode 100644 index 0000000000..2f49f47cf9 --- /dev/null +++ b/core-groovy-strings/README.md @@ -0,0 +1,3 @@ +### Relevant Articles: + +- [How to Remove a Prefix From Strings in Groovy](https://www.baeldung.com/groovy-remove-string-prefix) diff --git a/core-java-modules/core-java-io-3/src/main/java/com/baeldung/lastmodifiedfile/LastModifiedFileApp.java b/core-java-modules/core-java-io-3/src/main/java/com/baeldung/lastmodifiedfile/LastModifiedFileApp.java new file mode 100644 index 0000000000..d2aace184f --- /dev/null +++ b/core-java-modules/core-java-io-3/src/main/java/com/baeldung/lastmodifiedfile/LastModifiedFileApp.java @@ -0,0 +1,61 @@ +package com.baeldung.lastmodifiedfile; + +import java.io.File; +import java.io.FileFilter; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.Optional; + +import org.apache.commons.io.comparator.LastModifiedFileComparator; +import org.apache.commons.io.filefilter.FileFilterUtils; + +public class LastModifiedFileApp { + + public static File findUsingIOApi(String sdir) { + File dir = new File(sdir); + if (dir.isDirectory()) { + Optional opFile = Arrays.stream(dir.listFiles(File::isFile)) + .max((f1, f2) -> Long.compare(f1.lastModified(), f2.lastModified())); + + if (opFile.isPresent()) { + return opFile.get(); + } + } + + return null; + } + + public static Path findUsingNIOApi(String sdir) throws IOException { + Path dir = Paths.get(sdir); + if (Files.isDirectory(dir)) { + Optional opPath = Files.list(dir) + .filter(p -> !Files.isDirectory(p)) + .sorted((p1, p2) -> Long.valueOf(p2.toFile().lastModified()) + .compareTo(p1.toFile().lastModified())) + .findFirst(); + + if (opPath.isPresent()) { + return opPath.get(); + } + } + + return null; + } + + public static File findUsingCommonsIO(String sdir) { + File dir = new File(sdir); + if (dir.isDirectory()) { + File[] dirFiles = dir.listFiles((FileFilter) FileFilterUtils.fileFileFilter()); + if (dirFiles != null && dirFiles.length > 0) { + Arrays.sort(dirFiles, LastModifiedFileComparator.LASTMODIFIED_REVERSE); + return dirFiles[0]; + } + } + + return null; + } + +} diff --git a/core-java-modules/core-java-io-3/src/test/java/com/baeldung/lastmodifiedfile/LastModifiedFileAppUnitTest.java b/core-java-modules/core-java-io-3/src/test/java/com/baeldung/lastmodifiedfile/LastModifiedFileAppUnitTest.java new file mode 100644 index 0000000000..fe704c3c40 --- /dev/null +++ b/core-java-modules/core-java-io-3/src/test/java/com/baeldung/lastmodifiedfile/LastModifiedFileAppUnitTest.java @@ -0,0 +1,78 @@ +package com.baeldung.lastmodifiedfile; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +import org.apache.commons.io.FileUtils; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +public class LastModifiedFileAppUnitTest { + + private final static String SOURCEDIRECTORY = "src/test/resources/lastmodfiles"; + + @BeforeAll + public static void setUpFiles() throws IOException, InterruptedException { + File srcDir = new File(SOURCEDIRECTORY); + if (!srcDir.exists()) { + srcDir.mkdir(); + } + + FileUtils.cleanDirectory(srcDir); + + File file01 = new File(SOURCEDIRECTORY + "/file01.txt"); + file01.createNewFile(); + + Thread.sleep(2000); + + File file02 = new File(SOURCEDIRECTORY + "/file02.txt"); + file02.createNewFile(); + + Thread.sleep(2000); + + File file03 = new File(SOURCEDIRECTORY + "/file03.txt"); + file03.createNewFile(); + + Thread.sleep(2000); + + Files.write(Paths.get(SOURCEDIRECTORY + "/file02.txt"), "Hello File02".getBytes()); + + } + + @Test + public void givenDirectory_whenUsingIoApi_thenFindLastModfile() throws IOException { + File lastModFile = LastModifiedFileApp.findUsingIOApi(SOURCEDIRECTORY); + + assertThat(lastModFile).isNotNull(); + assertThat(lastModFile.getName()).isEqualTo("file02.txt"); + } + + @Test + public void givenDirectory_whenUsingNioApi_thenFindLastModfile() throws IOException { + Path lastModPath = LastModifiedFileApp.findUsingNIOApi(SOURCEDIRECTORY); + + assertThat(lastModPath).isNotNull(); + assertThat(lastModPath.toFile().getName()).isEqualTo("file02.txt"); + } + + @Test + public void givenDirectory_whenUsingApacheCommons_thenFindLastModfile() throws IOException { + File lastModFile = LastModifiedFileApp.findUsingCommonsIO(SOURCEDIRECTORY); + + assertThat(lastModFile).isNotNull(); + assertThat(lastModFile.getName()).isEqualTo("file02.txt"); + } + + @AfterAll + public static void cleanUp() throws IOException { + File srcDir = new File(SOURCEDIRECTORY); + FileUtils.deleteDirectory(srcDir); + } + +} \ No newline at end of file diff --git a/core-java-modules/core-java-lang-3/src/main/java/com/baeldung/getclassobject/Animal.java b/core-java-modules/core-java-lang-3/src/main/java/com/baeldung/getclassobject/Animal.java new file mode 100644 index 0000000000..426f1403af --- /dev/null +++ b/core-java-modules/core-java-lang-3/src/main/java/com/baeldung/getclassobject/Animal.java @@ -0,0 +1,5 @@ +package com.baeldung.getclassobject; + +public class Animal { + protected int numberOfEyes; +} diff --git a/core-java-modules/core-java-lang-3/src/main/java/com/baeldung/getclassobject/Monkey.java b/core-java-modules/core-java-lang-3/src/main/java/com/baeldung/getclassobject/Monkey.java new file mode 100644 index 0000000000..76ad8a96e3 --- /dev/null +++ b/core-java-modules/core-java-lang-3/src/main/java/com/baeldung/getclassobject/Monkey.java @@ -0,0 +1,4 @@ +package com.baeldung.getclassobject; + +public class Monkey extends Animal { +} diff --git a/core-java-modules/core-java-lang-3/src/main/java/com/baeldung/getclassobject/SomeAbstractClass.java b/core-java-modules/core-java-lang-3/src/main/java/com/baeldung/getclassobject/SomeAbstractClass.java new file mode 100644 index 0000000000..7ee34cf62a --- /dev/null +++ b/core-java-modules/core-java-lang-3/src/main/java/com/baeldung/getclassobject/SomeAbstractClass.java @@ -0,0 +1,4 @@ +package com.baeldung.getclassobject; + +public abstract class SomeAbstractClass { +} diff --git a/core-java-modules/core-java-lang-3/src/main/java/com/baeldung/getclassobject/SomeInterface.java b/core-java-modules/core-java-lang-3/src/main/java/com/baeldung/getclassobject/SomeInterface.java new file mode 100644 index 0000000000..eec8048481 --- /dev/null +++ b/core-java-modules/core-java-lang-3/src/main/java/com/baeldung/getclassobject/SomeInterface.java @@ -0,0 +1,4 @@ +package com.baeldung.getclassobject; + +interface SomeInterface { +} diff --git a/core-java-modules/core-java-lang-3/src/main/java/com/baeldung/getclassobject/SomeUtils.java b/core-java-modules/core-java-lang-3/src/main/java/com/baeldung/getclassobject/SomeUtils.java new file mode 100644 index 0000000000..294ef5bc9e --- /dev/null +++ b/core-java-modules/core-java-lang-3/src/main/java/com/baeldung/getclassobject/SomeUtils.java @@ -0,0 +1,9 @@ +package com.baeldung.getclassobject; + +public class SomeUtils { + private SomeUtils() { + throw new RuntimeException("This Util class is not allowed to be instantiated!"); + } + // public static utilMethods + // ... +} diff --git a/core-java-modules/core-java-lang-3/src/test/java/com/baeldung/getclassobject/GetClassObjectUnitTest.java b/core-java-modules/core-java-lang-3/src/test/java/com/baeldung/getclassobject/GetClassObjectUnitTest.java new file mode 100644 index 0000000000..20b5b8e0c8 --- /dev/null +++ b/core-java-modules/core-java-lang-3/src/test/java/com/baeldung/getclassobject/GetClassObjectUnitTest.java @@ -0,0 +1,55 @@ +package com.baeldung.getclassobject; + +import org.junit.Test; + +import static org.junit.Assert.*; + +public class GetClassObjectUnitTest { + @Test + public void givenObjectAndType_whenGettingClassObject_thenTwoMethodsHaveTheSameResult() { + String str = "I am an object of the String class"; + Class fromStrObject = str.getClass(); + Class clazz = String.class; + assertSame(fromStrObject, clazz); + } + + @Test + public void givenClassInheritance_whenGettingRuntimeTypeAndStaticType_thenGetDifferentResult() { + Animal animal = new Monkey(); + Class runtimeType = animal.getClass(); + Class staticType = Animal.class; + //Not equals + assertNotEquals(staticType, runtimeType); + + Class monkeyClass = Monkey.class; + assertSame(runtimeType, monkeyClass); + } + + @Test + public void givenPrimitiveType_whenGettingClassObject_thenOnlyStaticTypeWorks() { + int number = 7; + // Class numberClass = number.getClass(); <-- compilation error + Class intType = int.class; + + assertNotNull(intType); + assertEquals("int", intType.getName()); + assertTrue(intType.isPrimitive()); + } + + @Test + public void givenTypeCannotInstantiate_whenGetTypeStatically_thenGetTypesSuccefully() { + Class interfaceType = SomeInterface.class; + Class abstractClassType = SomeAbstractClass.class; + Class utilClassType = SomeUtils.class; + + assertNotNull(interfaceType); + assertTrue(interfaceType.isInterface()); + assertEquals("SomeInterface", interfaceType.getSimpleName()); + + assertNotNull(abstractClassType); + assertEquals("SomeAbstractClass", abstractClassType.getSimpleName()); + + assertNotNull(utilClassType); + assertEquals("SomeUtils", utilClassType.getSimpleName()); + } +} diff --git a/core-java-modules/core-java-lang-oop-methods/README.md b/core-java-modules/core-java-lang-oop-methods/README.md index afceaded9a..43eab24003 100644 --- a/core-java-modules/core-java-lang-oop-methods/README.md +++ b/core-java-modules/core-java-lang-oop-methods/README.md @@ -9,3 +9,4 @@ This module contains articles about methods in Java - [Java equals() and hashCode() Contracts](https://www.baeldung.com/java-equals-hashcode-contracts) - [Guide to hashCode() in Java](https://www.baeldung.com/java-hashcode) - [The Covariant Return Type in Java](https://www.baeldung.com/java-covariant-return-type) +- [Does a Method’s Signature Include the Return Type in Java?](https://www.baeldung.com/java-method-signature-return-type) diff --git a/core-java-modules/core-java-networking-2/README.md b/core-java-modules/core-java-networking-2/README.md index dbda8bdc7c..fa49c35bf8 100644 --- a/core-java-modules/core-java-networking-2/README.md +++ b/core-java-modules/core-java-networking-2/README.md @@ -13,4 +13,5 @@ This module contains articles about networking in Java - [Download a File from an URL in Java](https://www.baeldung.com/java-download-file) - [Handling java.net.ConnectException](https://www.baeldung.com/java-net-connectexception) - [Getting MAC addresses in Java](https://www.baeldung.com/java-mac-address) +- [Sending Emails with Attachments in Java](https://www.baeldung.com/java-send-emails-attachments) - [[<-- Prev]](/core-java-modules/core-java-networking) diff --git a/core-java-modules/core-java-reflection-2/README.md b/core-java-modules/core-java-reflection-2/README.md index e5ddb7a8b8..1668eeade3 100644 --- a/core-java-modules/core-java-reflection-2/README.md +++ b/core-java-modules/core-java-reflection-2/README.md @@ -2,3 +2,4 @@ - [Reading the Value of ‘private’ Fields from a Different Class in Java](https://www.baeldung.com/java-reflection-read-private-field-value) - [Set Field Value With Reflection](https://www.baeldung.com/java-set-private-field-value) +- [Checking If a Method is Static Using Reflection in Java](https://www.baeldung.com/java-check-method-is-static) diff --git a/gradle/gradle-wrapper/gradle/wrapper/README.md b/gradle/gradle-wrapper/gradle/wrapper/README.md new file mode 100644 index 0000000000..892f7a23cb --- /dev/null +++ b/gradle/gradle-wrapper/gradle/wrapper/README.md @@ -0,0 +1,35 @@ +The files in this project were generated using gradle wrapper command. +`gradle wrapper` + +To test, download this project on your machine and run the following: +`./wrapper tasks` + +This should generate output similar to: +``` +> Task :tasks + +------------------------------------------------------------ +Tasks runnable from root project +------------------------------------------------------------ + +Build Setup tasks +----------------- +init - Initializes a new Gradle build. +wrapper - Generates Gradle wrapper files. + +Help tasks +---------- +buildEnvironment - Displays all buildscript dependencies declared in root project 'gradle-wrapper'. +components - Displays the components produced by root project 'gradle-wrapper'. [incubating] +dependencies - Displays all dependencies declared in root project 'gradle-wrapper'. +dependencyInsight - Displays the insight into a specific dependency in root project 'gradle-wrapper'. +dependentComponents - Displays the dependent components of components in root project 'gradle-wrapper'. [incubating] +help - Displays a help message. +model - Displays the configuration model of root project 'gradle-wrapper'. [incubating] +outgoingVariants - Displays the outgoing variants of root project 'gradle-wrapper'. +projects - Displays the sub-projects of root project 'gradle-wrapper'. +properties - Displays the properties of root project 'gradle-wrapper'. +tasks - Displays the tasks runnable from root project 'gradle-wrapper'. + +To see all tasks and more detail, run gradlew tasks --all +``` \ No newline at end of file diff --git a/gradle/gradle-wrapper/gradle/wrapper/gradle-wrapper.properties b/gradle/gradle-wrapper/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000000..a4b4429748 --- /dev/null +++ b/gradle/gradle-wrapper/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-6.3-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradle/gradle-wrapper/gradlew b/gradle/gradle-wrapper/gradlew new file mode 100755 index 0000000000..2fe81a7d95 --- /dev/null +++ b/gradle/gradle-wrapper/gradlew @@ -0,0 +1,183 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +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 + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=`expr $i + 1` + done + case $i in + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=`save "$@"` + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +exec "$JAVACMD" "$@" diff --git a/gradle/gradle-wrapper/gradlew.bat b/gradle/gradle-wrapper/gradlew.bat new file mode 100644 index 0000000000..9109989e3c --- /dev/null +++ b/gradle/gradle-wrapper/gradlew.bat @@ -0,0 +1,103 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/httpclient-2/.gitignore b/httpclient-2/.gitignore new file mode 100644 index 0000000000..83c05e60c8 --- /dev/null +++ b/httpclient-2/.gitignore @@ -0,0 +1,13 @@ +*.class + +#folders# +/target +/neoDb* +/data +/src/main/webapp/WEB-INF/classes +*/META-INF/* + +# Packaged files # +*.jar +*.war +*.ear \ No newline at end of file diff --git a/httpclient-2/README.md b/httpclient-2/README.md new file mode 100644 index 0000000000..52d8b8fcff --- /dev/null +++ b/httpclient-2/README.md @@ -0,0 +1,12 @@ +## HttpClient 4.x + +This module contains articles about HttpClient 4.x + +### The Course + +The "REST With Spring" Classes: http://bit.ly/restwithspring + +### Relevant Articles: + +- [How to Set TLS Version in Apache HttpClient](https://www.baeldung.com/TODO) +- More articles: [[<-- prev]](../httpclient) diff --git a/httpclient-2/pom.xml b/httpclient-2/pom.xml new file mode 100644 index 0000000000..1a27d9b5fe --- /dev/null +++ b/httpclient-2/pom.xml @@ -0,0 +1,43 @@ + + + 4.0.0 + httpclient-2 + 0.1-SNAPSHOT + + + com.baeldung + parent-java + 0.0.1-SNAPSHOT + ../parent-java + + + + + org.apache.httpcomponents + httpclient + ${httpclient.version} + + + commons-logging + commons-logging + + + + + + + httpclient-2 + + + src/main/resources + true + + + + + + 4.5.8 + + + \ No newline at end of file diff --git a/httpclient-2/src/main/java/com/baeldung/tlsversion/ClientTlsVersionExamples.java b/httpclient-2/src/main/java/com/baeldung/tlsversion/ClientTlsVersionExamples.java new file mode 100644 index 0000000000..c58763b1c0 --- /dev/null +++ b/httpclient-2/src/main/java/com/baeldung/tlsversion/ClientTlsVersionExamples.java @@ -0,0 +1,64 @@ +package com.baeldung.tlsversion; + +import javax.net.ssl.SSLSocket; + +import org.apache.http.HttpEntity; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.conn.ssl.SSLConnectionSocketFactory; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.ssl.SSLContexts; +import org.apache.http.util.EntityUtils; + +import java.io.IOException; + +public class ClientTlsVersionExamples { + + public static CloseableHttpClient setViaSocketFactory() { + SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory( + SSLContexts.createDefault(), + new String[] { "TLSv1.2", "TLSv1.3" }, + null, + SSLConnectionSocketFactory.getDefaultHostnameVerifier()); + + return HttpClients.custom().setSSLSocketFactory(sslsf).build(); + } + + public static CloseableHttpClient setTlsVersionPerConnection() { + SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(SSLContexts.createDefault()) { + + @Override + protected void prepareSocket(SSLSocket socket) { + String hostname = socket.getInetAddress().getHostName(); + if (hostname.endsWith("internal.system.com")) { + socket.setEnabledProtocols(new String[] { "TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3" }); + } else { + socket.setEnabledProtocols(new String[] { "TLSv1.3" }); + } + } + }; + + return HttpClients.custom().setSSLSocketFactory(sslsf).build(); + } + + // To configure the TLS versions for the client, set the https.protocols system property during runtime. + // For example: java -Dhttps.protocols=TLSv1.1,TLSv1.2,TLSv1.3 -jar webClient.jar + public static CloseableHttpClient setViaSystemProperties() { + return HttpClients.createSystem(); + // Alternatively: + // return HttpClients.custom().useSystemProperties().build(); + } + + public static void main(String[] args) throws IOException { + // Alternatively: + // CloseableHttpClient httpClient = setTlsVersionPerConnection(); + // CloseableHttpClient httpClient = setViaSystemProperties(); + try (CloseableHttpClient httpClient = setViaSocketFactory(); + CloseableHttpResponse response = httpClient.execute(new HttpGet("https://httpbin.org/"))) { + + HttpEntity entity = response.getEntity(); + EntityUtils.consume(entity); + } + } +} \ No newline at end of file diff --git a/httpclient/README.md b/httpclient/README.md index d88739e901..23fe7c7271 100644 --- a/httpclient/README.md +++ b/httpclient/README.md @@ -18,3 +18,4 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring - [Advanced HttpClient Configuration](https://www.baeldung.com/httpclient-advanced-config) - [HttpClient 4 – Do Not Follow Redirects](https://www.baeldung.com/httpclient-stop-follow-redirect) - [Custom User-Agent in HttpClient 4](https://www.baeldung.com/httpclient-user-agent-header) +- More articles: [[next -->]](../httpclient-2) diff --git a/java-collections-conversions-2/README.md b/java-collections-conversions-2/README.md index 9d0ba88cbf..628421b0e2 100644 --- a/java-collections-conversions-2/README.md +++ b/java-collections-conversions-2/README.md @@ -7,4 +7,5 @@ This module contains articles about conversions among Collection types and array - [Array to String Conversions](https://www.baeldung.com/java-array-to-string) - [Mapping Lists with ModelMapper](https://www.baeldung.com/java-modelmapper-lists) - [Converting List to Map With a Custom Supplier](https://www.baeldung.com/list-to-map-supplier) +- [Arrays.asList vs new ArrayList(Arrays.asList())](https://www.baeldung.com/java-arrays-aslist-vs-new-arraylist) - More articles: [[<-- prev]](../java-collections-conversions) diff --git a/json/README.md b/json/README.md index 0e50dcfddb..6ad4c8a29d 100644 --- a/json/README.md +++ b/json/README.md @@ -13,3 +13,4 @@ This module contains articles about JSON. - [Get a Value by Key in a JSONArray](https://www.baeldung.com/java-jsonarray-get-value-by-key) - [Iterating Over an Instance of org.json.JSONObject](https://www.baeldung.com/jsonobject-iteration) - [Escape JSON String in Java](https://www.baeldung.com/java-json-escaping) +- [Reducing JSON Data Size](https://www.baeldung.com/json-reduce-data-size) diff --git a/mapstruct/pom.xml b/mapstruct/pom.xml index 9fe6ab6485..9b416177e7 100644 --- a/mapstruct/pom.xml +++ b/mapstruct/pom.xml @@ -71,7 +71,7 @@ - 1.4.0.Beta1 + 1.3.1.Final 4.3.4.RELEASE 1.8 1.8 diff --git a/mapstruct/src/main/java/com/baeldung/mapstruct/mappingCollections/mapper/CompanyMapperAdderPreferred.java b/mapstruct/src/main/java/com/baeldung/mapstruct/mappingCollections/mapper/CompanyMapperAdderPreferred.java index e5cc43074e..094d87351a 100644 --- a/mapstruct/src/main/java/com/baeldung/mapstruct/mappingCollections/mapper/CompanyMapperAdderPreferred.java +++ b/mapstruct/src/main/java/com/baeldung/mapstruct/mappingCollections/mapper/CompanyMapperAdderPreferred.java @@ -5,7 +5,8 @@ import com.baeldung.mapstruct.mappingCollections.model.Company; import org.mapstruct.CollectionMappingStrategy; import org.mapstruct.Mapper; -@Mapper(collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERRED) +@Mapper(collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERRED, + uses = EmployeeMapper.class) public interface CompanyMapperAdderPreferred { CompanyDTO map(Company company); diff --git a/mapstruct/src/main/java/com/baeldung/mapstruct/mappingCollections/mapper/EmployeeMapper.java b/mapstruct/src/main/java/com/baeldung/mapstruct/mappingCollections/mapper/EmployeeMapper.java index 45bf76c5a4..4a723f049a 100644 --- a/mapstruct/src/main/java/com/baeldung/mapstruct/mappingCollections/mapper/EmployeeMapper.java +++ b/mapstruct/src/main/java/com/baeldung/mapstruct/mappingCollections/mapper/EmployeeMapper.java @@ -11,6 +11,8 @@ import java.util.Set; @Mapper public interface EmployeeMapper { + EmployeeDTO map(Employee employee); + List map(List employees); Set map(Set employees); diff --git a/persistence-modules/jooq/pom.xml b/persistence-modules/jooq/pom.xml new file mode 100644 index 0000000000..f0c5a27a96 --- /dev/null +++ b/persistence-modules/jooq/pom.xml @@ -0,0 +1,46 @@ + + + 4.0.0 + jooq + 0.0.1-SNAPSHOT + jooq-examples + jar + jOOQ Examples + + + com.baeldung + persistence-modules + 1.0.0-SNAPSHOT + + + + + org.jooq + jooq + 3.13.4 + + + org.jooq + jooq-meta + 3.13.4 + + + org.jooq + jooq-codegen + 3.13.4 + + + org.postgresql + postgresql + 42.2.16 + + + com.h2database + h2 + 1.4.200 + + + + diff --git a/persistence-modules/jooq/src/main/java/com/baeldung/jooq/Crud.java b/persistence-modules/jooq/src/main/java/com/baeldung/jooq/Crud.java new file mode 100644 index 0000000000..0427b71c25 --- /dev/null +++ b/persistence-modules/jooq/src/main/java/com/baeldung/jooq/Crud.java @@ -0,0 +1,57 @@ +package com.baeldung.jooq; + +import org.jooq.Condition; +import org.jooq.DSLContext; +import org.jooq.Field; +import org.jooq.Record; +import org.jooq.Result; +import org.jooq.SelectFieldOrAsterisk; +import org.jooq.Table; +import org.jooq.UpdatableRecord; + +import java.util.Map; + +public class Crud { + + public static > void save(UpdatableRecord record) { + record.store(); + } + + public static Result getAll(DSLContext context, Table table) { + return context.select() + .from(table) + .fetch(); + } + + public static Result getFields(DSLContext context, Table table, SelectFieldOrAsterisk... fields) { + return context.select(fields) + .from(table) + .fetch(); + } + + public static R getOne(DSLContext context, Table table, Condition condition) { + return context.fetchOne(table, condition); + } + + public static void update(DSLContext context, Table table, Map, T> values, Condition condition) { + context.update(table) + .set(values) + .where(condition) + .execute(); + } + + public static > void update(UpdatableRecord record) { + record.update(); + } + + public static void delete(DSLContext context, Table table, Condition condition) { + context.delete(table) + .where(condition) + .execute(); + } + + public static > void delete(UpdatableRecord record) { + record.delete(); + } + +} diff --git a/persistence-modules/jooq/src/main/java/com/baeldung/jooq/CrudExamples.java b/persistence-modules/jooq/src/main/java/com/baeldung/jooq/CrudExamples.java new file mode 100644 index 0000000000..87a7b6439e --- /dev/null +++ b/persistence-modules/jooq/src/main/java/com/baeldung/jooq/CrudExamples.java @@ -0,0 +1,117 @@ +package com.baeldung.jooq; + +import com.baeldung.jooq.model.tables.Article; +import com.baeldung.jooq.model.tables.Author; +import com.baeldung.jooq.model.tables.records.ArticleRecord; +import com.baeldung.jooq.model.tables.records.AuthorRecord; +import org.jooq.DSLContext; +import org.jooq.Field; +import org.jooq.Record; +import org.jooq.Result; +import org.jooq.SQLDialect; +import org.jooq.impl.DSL; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; +import java.util.HashMap; + +import static com.baeldung.jooq.Crud.delete; +import static com.baeldung.jooq.Crud.getAll; +import static com.baeldung.jooq.Crud.getFields; +import static com.baeldung.jooq.Crud.getOne; +import static com.baeldung.jooq.Crud.save; +import static com.baeldung.jooq.Crud.update; + +public class CrudExamples { + + public void crudExamples() throws SQLException { + String userName = "username"; + String password = "password"; + String url = "jdbc:postgresql://db_url:5432/baeldung_database"; + + Connection conn = DriverManager.getConnection(url, userName, password); + DSLContext context = DSL.using(conn, SQLDialect.POSTGRES); + + createValues(context); + readValues(context); + updateValues(context); + deleteValues(context); + } + + private void createValues(DSLContext context) { + ArticleRecord article = context.newRecord(Article.ARTICLE); + + article.setId(2); + article.setTitle("jOOQ examples"); + article.setDescription("A few examples of jOOQ CRUD operations"); + article.setAuthorId(1); + + save(article); + + AuthorRecord author = context.newRecord(Author.AUTHOR); + author.setId(1); + author.setFirstName("John"); + author.setLastName("Smith"); + author.setAge(40); + + save(author); + } + + private void readValues(DSLContext context) { + Result authors = getAll( + context, + Author.AUTHOR + ); + + authors.forEach(author -> { + Integer id = author.getValue(Author.AUTHOR.ID); + String firstName = author.getValue(Author.AUTHOR.FIRST_NAME); + String lastName = author.getValue(Author.AUTHOR.LAST_NAME); + Integer age = author.getValue(Author.AUTHOR.AGE); + System.out.printf("Author %s %s has id: %d and age: %d%n", firstName, lastName, id, age); + }); + + Result articles = getFields( + context, + Author.AUTHOR, + Article.ARTICLE.ID, Article.ARTICLE.TITLE + ); + + AuthorRecord author = getOne( + context, + Author.AUTHOR, + Author.AUTHOR.ID.eq(1) + ); + } + + private void updateValues(DSLContext context) { + HashMap, String> fieldsToUpdate = new HashMap<>(); + fieldsToUpdate.put(Author.AUTHOR.FIRST_NAME, "David"); + fieldsToUpdate.put(Author.AUTHOR.LAST_NAME, "Brown"); + update( + context, + Author.AUTHOR, + fieldsToUpdate, + Author.AUTHOR.ID.eq(1) + ); + + ArticleRecord article = context.fetchOne(Article.ARTICLE, Article.ARTICLE.ID.eq(1)); + article.setTitle("A New Article Title"); + update( + article + ); + } + + private void deleteValues(DSLContext context) { + delete( + context, + Article.ARTICLE, + Article.ARTICLE.ID.eq(1) + ); + + AuthorRecord author = context.fetchOne(Author.AUTHOR, Author.AUTHOR.ID.eq(1)); + delete(author); + } + +} diff --git a/persistence-modules/jooq/src/main/java/com/baeldung/jooq/model/DefaultCatalog.java b/persistence-modules/jooq/src/main/java/com/baeldung/jooq/model/DefaultCatalog.java new file mode 100644 index 0000000000..b18484877a --- /dev/null +++ b/persistence-modules/jooq/src/main/java/com/baeldung/jooq/model/DefaultCatalog.java @@ -0,0 +1,44 @@ +/* + * This file is generated by jOOQ. + */ +package com.baeldung.jooq.model; + + +import org.jooq.Schema; +import org.jooq.impl.CatalogImpl; + +import java.util.Arrays; +import java.util.List; + + +/** + * This class is generated by jOOQ. + */ +@SuppressWarnings({ "all", "unchecked", "rawtypes" }) +public class DefaultCatalog extends CatalogImpl { + + private static final long serialVersionUID = 1035293962; + + /** + * The reference instance of DEFAULT_CATALOG + */ + public static final DefaultCatalog DEFAULT_CATALOG = new DefaultCatalog(); + + /** + * The schema public. + */ + public final Public PUBLIC = Public.PUBLIC; + + /** + * No further instances allowed + */ + private DefaultCatalog() { + super(""); + } + + @Override + public final List getSchemas() { + return Arrays.asList( + Public.PUBLIC); + } +} diff --git a/persistence-modules/jooq/src/main/java/com/baeldung/jooq/model/Keys.java b/persistence-modules/jooq/src/main/java/com/baeldung/jooq/model/Keys.java new file mode 100644 index 0000000000..461ffb58c7 --- /dev/null +++ b/persistence-modules/jooq/src/main/java/com/baeldung/jooq/model/Keys.java @@ -0,0 +1,48 @@ +/* + * This file is generated by jOOQ. + */ +package com.baeldung.jooq.model; + + +import com.baeldung.jooq.model.tables.Article; +import com.baeldung.jooq.model.tables.Author; +import com.baeldung.jooq.model.tables.records.ArticleRecord; +import com.baeldung.jooq.model.tables.records.AuthorRecord; +import org.jooq.ForeignKey; +import org.jooq.TableField; +import org.jooq.UniqueKey; +import org.jooq.impl.Internal; + + +/** + * A class modelling foreign key relationships and constraints of tables of + * the public schema. + */ +@SuppressWarnings({"all", "unchecked", "rawtypes"}) +public class Keys { + + // ------------------------------------------------------------------------- + // UNIQUE and PRIMARY KEY definitions + // ------------------------------------------------------------------------- + + public static final UniqueKey ARTICLE_PKEY = UniqueKeys0.ARTICLE_PKEY; + public static final UniqueKey AUTHOR_PKEY = UniqueKeys0.AUTHOR_PKEY; + + // ------------------------------------------------------------------------- + // FOREIGN KEY definitions + // ------------------------------------------------------------------------- + public static final ForeignKey ARTICLE__XXX = ForeignKeys0.ARTICLE__XXX; + + // ------------------------------------------------------------------------- + // [#1459] distribute members to avoid static initialisers > 64kb + // ------------------------------------------------------------------------- + + private static class UniqueKeys0 { + public static final UniqueKey ARTICLE_PKEY = Internal.createUniqueKey(Article.ARTICLE, "article_pkey", new TableField[]{Article.ARTICLE.ID}, true); + public static final UniqueKey AUTHOR_PKEY = Internal.createUniqueKey(Author.AUTHOR, "author_pkey", new TableField[]{Author.AUTHOR.ID}, true); + } + + private static class ForeignKeys0 { + public static final ForeignKey ARTICLE__XXX = Internal.createForeignKey(Keys.AUTHOR_PKEY, Article.ARTICLE, "xxx", new TableField[]{Article.ARTICLE.AUTHOR_ID}, true); + } +} diff --git a/persistence-modules/jooq/src/main/java/com/baeldung/jooq/model/Public.java b/persistence-modules/jooq/src/main/java/com/baeldung/jooq/model/Public.java new file mode 100644 index 0000000000..02c664522b --- /dev/null +++ b/persistence-modules/jooq/src/main/java/com/baeldung/jooq/model/Public.java @@ -0,0 +1,59 @@ +/* + * This file is generated by jOOQ. + */ +package com.baeldung.jooq.model; + +import com.baeldung.jooq.model.tables.Article; +import com.baeldung.jooq.model.tables.Author; +import org.jooq.Catalog; +import org.jooq.Table; +import org.jooq.impl.SchemaImpl; + +import java.util.Arrays; +import java.util.List; + + +/** + * This class is generated by jOOQ. + */ +@SuppressWarnings({"all", "unchecked", "rawtypes"}) +public class Public extends SchemaImpl { + + private static final long serialVersionUID = -2049410122; + + /** + * The reference instance of public + */ + public static final Public PUBLIC = new Public(); + + /** + * The table public.article. + */ + public final Article ARTICLE = Article.ARTICLE; + + /** + * The table public.author. + */ + public final Author AUTHOR = Author.AUTHOR; + + /** + * No further instances allowed + */ + private Public() { + super("public", null); + } + + + @Override + public Catalog getCatalog() { + return DefaultCatalog.DEFAULT_CATALOG; + } + + @Override + public final List> getTables() { + return Arrays.>asList( + Article.ARTICLE, + Author.AUTHOR + ); + } +} diff --git a/persistence-modules/jooq/src/main/java/com/baeldung/jooq/model/Tables.java b/persistence-modules/jooq/src/main/java/com/baeldung/jooq/model/Tables.java new file mode 100644 index 0000000000..eb1f14e05a --- /dev/null +++ b/persistence-modules/jooq/src/main/java/com/baeldung/jooq/model/Tables.java @@ -0,0 +1,25 @@ +/* + * This file is generated by jOOQ. + */ +package com.baeldung.jooq.model; + +import com.baeldung.jooq.model.tables.Article; +import com.baeldung.jooq.model.tables.Author; + +/** + * Convenience access to all tables in public + */ +@SuppressWarnings({"all", "unchecked", "rawtypes"}) +public class Tables { + + /** + * The table public.article. + */ + public static final Article ARTICLE = Article.ARTICLE; + + /** + * The table public.author. + */ + public static final Author AUTHOR = Author.AUTHOR; + +} diff --git a/persistence-modules/jooq/src/main/java/com/baeldung/jooq/model/tables/Article.java b/persistence-modules/jooq/src/main/java/com/baeldung/jooq/model/tables/Article.java new file mode 100644 index 0000000000..3159c91aa8 --- /dev/null +++ b/persistence-modules/jooq/src/main/java/com/baeldung/jooq/model/tables/Article.java @@ -0,0 +1,159 @@ +/* + * This file is generated by jOOQ. + */ +package com.baeldung.jooq.model.tables; + + +import com.baeldung.jooq.model.Keys; +import com.baeldung.jooq.model.Public; +import com.baeldung.jooq.model.tables.records.ArticleRecord; +import org.jooq.Field; +import org.jooq.ForeignKey; +import org.jooq.Name; +import org.jooq.Record; +import org.jooq.Row4; +import org.jooq.Schema; +import org.jooq.Table; +import org.jooq.TableField; +import org.jooq.TableOptions; +import org.jooq.UniqueKey; +import org.jooq.impl.DSL; +import org.jooq.impl.TableImpl; + +import java.util.Arrays; +import java.util.List; + + +/** + * This class is generated by jOOQ. + */ +@SuppressWarnings({ "all", "unchecked", "rawtypes" }) +public class Article extends TableImpl { + + private static final long serialVersionUID = -1401275800; + + /** + * The reference instance of public.article + */ + public static final Article ARTICLE = new Article(); + + /** + * The class holding records for this type + */ + @Override + public Class getRecordType() { + return ArticleRecord.class; + } + + /** + * The column public.article.id. + */ + public final TableField ID = createField(DSL.name("id"), org.jooq.impl.SQLDataType.INTEGER.nullable(false), this, ""); + + /** + * The column public.article.title. + */ + public final TableField TITLE = createField(DSL.name("title"), org.jooq.impl.SQLDataType.VARCHAR(255).nullable(false), this, ""); + + /** + * The column public.article.description. + */ + public final TableField DESCRIPTION = createField(DSL.name("description"), org.jooq.impl.SQLDataType.VARCHAR(255), this, ""); + + /** + * The column public.article.author_id. + */ + public final TableField AUTHOR_ID = createField(DSL.name("author_id"), org.jooq.impl.SQLDataType.INTEGER, this, ""); + + /** + * Create a public.article table reference + */ + public Article() { + this(DSL.name("article"), null); + } + + /** + * Create an aliased public.article table reference + */ + public Article(String alias) { + this(DSL.name(alias), ARTICLE); + } + + /** + * Create an aliased public.article table reference + */ + public Article(Name alias) { + this(alias, ARTICLE); + } + + private Article(Name alias, Table aliased) { + this(alias, aliased, null); + } + + private Article(Name alias, Table aliased, Field[] parameters) { + super(alias, null, aliased, parameters, DSL.comment(""), TableOptions.table()); + } + + public Article(Table child, ForeignKey key) { + super(child, key, ARTICLE); + } + + @Override + public Schema getSchema() { + return Public.PUBLIC; + } + + @Override + public UniqueKey getPrimaryKey() { + return Keys.ARTICLE_PKEY; + } + + @Override + public List> getKeys() { + return Arrays.>asList(Keys.ARTICLE_PKEY); + } + + @Override + public List> getReferences() { + return Arrays.>asList(Keys.ARTICLE__XXX); + } + + public Author author() { + return new Author(this, Keys.ARTICLE__XXX); + } + + @Override + public Article as(String alias) { + return new Article(DSL.name(alias), this); + } + + @Override + public Article as(Name alias) { + return new Article(alias, this); + } + + /** + * Rename this table + */ + @Override + public Article rename(String name) { + return new Article(DSL.name(name), null); + } + + /** + * Rename this table + */ + @Override + public Article rename(Name name) { + return new Article(name, null); + } + + // ------------------------------------------------------------------------- + // Row4 type methods + // ------------------------------------------------------------------------- + + @Override + public Row4 fieldsRow() { + return (Row4) super.fieldsRow(); + } +} diff --git a/persistence-modules/jooq/src/main/java/com/baeldung/jooq/model/tables/Author.java b/persistence-modules/jooq/src/main/java/com/baeldung/jooq/model/tables/Author.java new file mode 100644 index 0000000000..9da9415109 --- /dev/null +++ b/persistence-modules/jooq/src/main/java/com/baeldung/jooq/model/tables/Author.java @@ -0,0 +1,149 @@ +/* + * This file is generated by jOOQ. + */ +package com.baeldung.jooq.model.tables; + +import com.baeldung.jooq.model.Keys; +import com.baeldung.jooq.model.Public; +import com.baeldung.jooq.model.tables.records.AuthorRecord; +import org.jooq.Field; +import org.jooq.ForeignKey; +import org.jooq.Name; +import org.jooq.Record; +import org.jooq.Row4; +import org.jooq.Schema; +import org.jooq.Table; +import org.jooq.TableField; +import org.jooq.TableOptions; +import org.jooq.UniqueKey; +import org.jooq.impl.DSL; +import org.jooq.impl.TableImpl; + +import java.util.Arrays; +import java.util.List; + + +/** + * This class is generated by jOOQ. + */ +@SuppressWarnings({ "all", "unchecked", "rawtypes" }) +public class Author extends TableImpl { + + private static final long serialVersionUID = -798376522; + + /** + * The reference instance of public.author + */ + public static final Author AUTHOR = new Author(); + + /** + * The class holding records for this type + */ + @Override + public Class getRecordType() { + return AuthorRecord.class; + } + + /** + * The column public.author.id. + */ + public final TableField ID = createField(DSL.name("id"), org.jooq.impl.SQLDataType.INTEGER.nullable(false), AUTHOR, ""); + + /** + * The column public.author.first_name. + */ + public final TableField FIRST_NAME = createField(DSL.name("first_name"), org.jooq.impl.SQLDataType.VARCHAR(255), this, ""); + + /** + * The column public.author.last_name. + */ + public final TableField LAST_NAME = createField(DSL.name("last_name"), org.jooq.impl.SQLDataType.VARCHAR(255), this, ""); + + /** + * The column public.author.age. + */ + public final TableField AGE = createField(DSL.name("age"), org.jooq.impl.SQLDataType.INTEGER, this, ""); + + /** + * Create a public.author table reference + */ + public Author() { + this(DSL.name("author"), null); + } + + /** + * Create an aliased public.author table reference + */ + public Author(String alias) { + this(DSL.name(alias), AUTHOR); + } + + /** + * Create an aliased public.author table reference + */ + public Author(Name alias) { + this(alias, AUTHOR); + } + + private Author(Name alias, Table aliased) { + this(alias, aliased, null); + } + + private Author(Name alias, Table aliased, Field[] parameters) { + super(alias, null, aliased, parameters, DSL.comment(""), TableOptions.table()); + } + + public Author(Table child, ForeignKey key) { + super(child, key, AUTHOR); + } + + @Override + public Schema getSchema() { + return Public.PUBLIC; + } + + @Override + public UniqueKey getPrimaryKey() { + return Keys.AUTHOR_PKEY; + } + + @Override + public List> getKeys() { + return Arrays.>asList(Keys.AUTHOR_PKEY); + } + + @Override + public Author as(String alias) { + return new Author(DSL.name(alias), this); + } + + @Override + public Author as(Name alias) { + return new Author(alias, this); + } + + /** + * Rename this table + */ + @Override + public Author rename(String name) { + return new Author(DSL.name(name), null); + } + + /** + * Rename this table + */ + @Override + public Author rename(Name name) { + return new Author(name, null); + } + + // ------------------------------------------------------------------------- + // Row4 type methods + // ------------------------------------------------------------------------- + + @Override + public Row4 fieldsRow() { + return (Row4) super.fieldsRow(); + } +} diff --git a/persistence-modules/jooq/src/main/java/com/baeldung/jooq/model/tables/records/ArticleRecord.java b/persistence-modules/jooq/src/main/java/com/baeldung/jooq/model/tables/records/ArticleRecord.java new file mode 100644 index 0000000000..cee17fe716 --- /dev/null +++ b/persistence-modules/jooq/src/main/java/com/baeldung/jooq/model/tables/records/ArticleRecord.java @@ -0,0 +1,218 @@ +/* + * This file is generated by jOOQ. + */ +package com.baeldung.jooq.model.tables.records; + + +import com.baeldung.jooq.model.tables.Article; + +import org.jooq.Field; +import org.jooq.Record1; +import org.jooq.Record4; +import org.jooq.Row4; +import org.jooq.impl.UpdatableRecordImpl; + + +/** + * This class is generated by jOOQ. + */ +@SuppressWarnings({ "all", "unchecked", "rawtypes" }) +public class ArticleRecord extends UpdatableRecordImpl implements Record4 { + + private static final long serialVersionUID = 1297442421; + + /** + * Setter for public.article.id. + */ + public void setId(Integer value) { + set(0, value); + } + + /** + * Getter for public.article.id. + */ + public Integer getId() { + return (Integer) get(0); + } + + /** + * Setter for public.article.title. + */ + public void setTitle(String value) { + set(1, value); + } + + /** + * Getter for public.article.title. + */ + public String getTitle() { + return (String) get(1); + } + + /** + * Setter for public.article.description. + */ + public void setDescription(String value) { + set(2, value); + } + + /** + * Getter for public.article.description. + */ + public String getDescription() { + return (String) get(2); + } + + /** + * Setter for public.article.author_id. + */ + public void setAuthorId(Integer value) { + set(3, value); + } + + /** + * Getter for public.article.author_id. + */ + public Integer getAuthorId() { + return (Integer) get(3); + } + + // ------------------------------------------------------------------------- + // Primary key information + // ------------------------------------------------------------------------- + + @Override + public Record1 key() { + return (Record1) super.key(); + } + + // ------------------------------------------------------------------------- + // Record4 type implementation + // ------------------------------------------------------------------------- + + @Override + public Row4 fieldsRow() { + return (Row4) super.fieldsRow(); + } + + @Override + public Row4 valuesRow() { + return (Row4) super.valuesRow(); + } + + @Override + public Field field1() { + return Article.ARTICLE.ID; + } + + @Override + public Field field2() { + return Article.ARTICLE.TITLE; + } + + @Override + public Field field3() { + return Article.ARTICLE.DESCRIPTION; + } + + @Override + public Field field4() { + return Article.ARTICLE.AUTHOR_ID; + } + + @Override + public Integer component1() { + return getId(); + } + + @Override + public String component2() { + return getTitle(); + } + + @Override + public String component3() { + return getDescription(); + } + + @Override + public Integer component4() { + return getAuthorId(); + } + + @Override + public Integer value1() { + return getId(); + } + + @Override + public String value2() { + return getTitle(); + } + + @Override + public String value3() { + return getDescription(); + } + + @Override + public Integer value4() { + return getAuthorId(); + } + + @Override + public ArticleRecord value1(Integer value) { + setId(value); + return this; + } + + @Override + public ArticleRecord value2(String value) { + setTitle(value); + return this; + } + + @Override + public ArticleRecord value3(String value) { + setDescription(value); + return this; + } + + @Override + public ArticleRecord value4(Integer value) { + setAuthorId(value); + return this; + } + + @Override + public ArticleRecord values(Integer value1, String value2, String value3, Integer value4) { + value1(value1); + value2(value2); + value3(value3); + value4(value4); + return this; + } + + // ------------------------------------------------------------------------- + // Constructors + // ------------------------------------------------------------------------- + + /** + * Create a detached ArticleRecord + */ + public ArticleRecord() { + super(Article.ARTICLE); + } + + /** + * Create a detached, initialised ArticleRecord + */ + public ArticleRecord(Integer id, String title, String description, Integer authorId) { + super(Article.ARTICLE); + + set(0, id); + set(1, title); + set(2, description); + set(3, authorId); + } +} diff --git a/persistence-modules/jooq/src/main/java/com/baeldung/jooq/model/tables/records/AuthorRecord.java b/persistence-modules/jooq/src/main/java/com/baeldung/jooq/model/tables/records/AuthorRecord.java new file mode 100644 index 0000000000..365de20747 --- /dev/null +++ b/persistence-modules/jooq/src/main/java/com/baeldung/jooq/model/tables/records/AuthorRecord.java @@ -0,0 +1,217 @@ +/* + * This file is generated by jOOQ. + */ +package com.baeldung.jooq.model.tables.records; + + +import com.baeldung.jooq.model.tables.Author; +import org.jooq.Field; +import org.jooq.Record1; +import org.jooq.Record4; +import org.jooq.Row4; +import org.jooq.impl.UpdatableRecordImpl; + + +/** + * This class is generated by jOOQ. + */ +@SuppressWarnings({ "all", "unchecked", "rawtypes" }) +public class AuthorRecord extends UpdatableRecordImpl implements Record4 { + + private static final long serialVersionUID = -2120822720; + + /** + * Setter for public.author.id. + */ + public void setId(Integer value) { + set(0, value); + } + + /** + * Getter for public.author.id. + */ + public Integer getId() { + return (Integer) get(0); + } + + /** + * Setter for public.author.first_name. + */ + public void setFirstName(String value) { + set(1, value); + } + + /** + * Getter for public.author.first_name. + */ + public String getFirstName() { + return (String) get(1); + } + + /** + * Setter for public.author.last_name. + */ + public void setLastName(String value) { + set(2, value); + } + + /** + * Getter for public.author.last_name. + */ + public String getLastName() { + return (String) get(2); + } + + /** + * Setter for public.author.age. + */ + public void setAge(Integer value) { + set(3, value); + } + + /** + * Getter for public.author.age. + */ + public Integer getAge() { + return (Integer) get(3); + } + + // ------------------------------------------------------------------------- + // Primary key information + // ------------------------------------------------------------------------- + + @Override + public Record1 key() { + return (Record1) super.key(); + } + + // ------------------------------------------------------------------------- + // Record4 type implementation + // ------------------------------------------------------------------------- + + @Override + public Row4 fieldsRow() { + return (Row4) super.fieldsRow(); + } + + @Override + public Row4 valuesRow() { + return (Row4) super.valuesRow(); + } + + @Override + public Field field1() { + return Author.AUTHOR.ID; + } + + @Override + public Field field2() { + return Author.AUTHOR.FIRST_NAME; + } + + @Override + public Field field3() { + return Author.AUTHOR.LAST_NAME; + } + + @Override + public Field field4() { + return Author.AUTHOR.AGE; + } + + @Override + public Integer component1() { + return getId(); + } + + @Override + public String component2() { + return getFirstName(); + } + + @Override + public String component3() { + return getLastName(); + } + + @Override + public Integer component4() { + return getAge(); + } + + @Override + public Integer value1() { + return getId(); + } + + @Override + public String value2() { + return getFirstName(); + } + + @Override + public String value3() { + return getLastName(); + } + + @Override + public Integer value4() { + return getAge(); + } + + @Override + public AuthorRecord value1(Integer value) { + setId(value); + return this; + } + + @Override + public AuthorRecord value2(String value) { + setFirstName(value); + return this; + } + + @Override + public AuthorRecord value3(String value) { + setLastName(value); + return this; + } + + @Override + public AuthorRecord value4(Integer value) { + setAge(value); + return this; + } + + @Override + public AuthorRecord values(Integer value1, String value2, String value3, Integer value4) { + value1(value1); + value2(value2); + value3(value3); + value4(value4); + return this; + } + + // ------------------------------------------------------------------------- + // Constructors + // ------------------------------------------------------------------------- + + /** + * Create a detached AuthorRecord + */ + public AuthorRecord() { + super(Author.AUTHOR); + } + + /** + * Create a detached, initialised AuthorRecord + */ + public AuthorRecord(Integer id, String firstName, String lastName, Integer age) { + super(Author.AUTHOR); + + set(0, id); + set(1, firstName); + set(2, lastName); + set(3, age); + } +} diff --git a/persistence-modules/jooq/src/test/java/com/baeldung/jooq/CrudLiveTest.java b/persistence-modules/jooq/src/test/java/com/baeldung/jooq/CrudLiveTest.java new file mode 100644 index 0000000000..d41344c08e --- /dev/null +++ b/persistence-modules/jooq/src/test/java/com/baeldung/jooq/CrudLiveTest.java @@ -0,0 +1,257 @@ +package com.baeldung.jooq; + +import com.baeldung.jooq.model.tables.Article; +import com.baeldung.jooq.model.tables.Author; +import com.baeldung.jooq.model.tables.records.ArticleRecord; +import org.jooq.DSLContext; +import org.jooq.Field; +import org.jooq.Record; +import org.jooq.Result; +import org.jooq.SQLDialect; +import org.jooq.impl.DSL; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; +import java.util.HashMap; + +import static com.baeldung.jooq.Crud.delete; +import static com.baeldung.jooq.Crud.getAll; +import static com.baeldung.jooq.Crud.getFields; +import static com.baeldung.jooq.Crud.getOne; +import static com.baeldung.jooq.Crud.save; +import static com.baeldung.jooq.Crud.update; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +public class CrudLiveTest { + + static DSLContext context; + + @BeforeClass + public static void setup() throws SQLException { + Connection conn = DriverManager.getConnection("jdbc:h2:mem:tes;INIT=CREATE SCHEMA IF NOT EXISTS \"public\""); + context = DSL.using(conn, SQLDialect.H2); + + context.createTable(Author.AUTHOR) + .columns( + Author.AUTHOR.ID, + Author.AUTHOR.FIRST_NAME, + Author.AUTHOR.LAST_NAME, + Author.AUTHOR.AGE + ) + .execute(); + context.createTable(Article.ARTICLE) + .columns( + Article.ARTICLE.ID, + Article.ARTICLE.TITLE, + Article.ARTICLE.DESCRIPTION, + Article.ARTICLE.AUTHOR_ID + ) + .execute(); + } + + @Before + public void cleanup() { + context.truncateTable(Article.ARTICLE) + .execute(); + context.truncateTable(Author.AUTHOR) + .execute(); + } + + @Test + public void givenArticleRecord_whenSave_thenNewRecordInDb() { + // given + ArticleRecord article = article(); + + // when + save(article); + + // then + ArticleRecord savedArticle = getOne( + context, + Article.ARTICLE, + Article.ARTICLE.ID.eq(1) + ); + assertEquals(savedArticle.getId().intValue(), 1); + assertEquals(savedArticle.getTitle(), "jOOQ examples"); + assertEquals(savedArticle.getDescription(), "A few examples of jOOQ CRUD operations"); + assertEquals(savedArticle.getAuthorId().intValue(), 1); + } + + @Test + public void givenArticleRecord_whenGetAll_thenValidOneRecord() { + // given + ArticleRecord article = article(); + save(article); + + // when + Result articles = getAll( + context, + Article.ARTICLE + ); + + // then + assertEquals(articles.size(), 1); + + Record record = articles.get(0); + ArticleRecord savedArticle = record.into(Article.ARTICLE); + + assertEquals(savedArticle.getId().intValue(), 1); + assertEquals(savedArticle.getTitle(), "jOOQ examples"); + assertEquals(savedArticle.getDescription(), "A few examples of jOOQ CRUD operations"); + assertEquals(savedArticle.getAuthorId().intValue(), 1); + } + + @Test + public void givenArticleRecord_whenGetOnlyTitles_thenValidOneValue() { + // given + ArticleRecord article = article(); + save(article); + + // when + Result articles = getFields( + context, + Article.ARTICLE, + Article.ARTICLE.TITLE + ); + + // then + assertEquals(articles.size(), 1); + + Record record = articles.get(0); + ArticleRecord savedArticle = record.into(Article.ARTICLE); + + assertNull(savedArticle.getId()); + assertEquals(savedArticle.getTitle(), "jOOQ examples"); + assertNull(savedArticle.getDescription()); + assertNull(savedArticle.getAuthorId()); + } + + @Test + public void givenArticleRecord_whenGetOne_thenValidRecord() { + // given + ArticleRecord article = article(); + save(article); + + // when + ArticleRecord savedArticle = getOne( + context, + Article.ARTICLE, + Article.ARTICLE.ID.eq(1) + ); + + // then + assertEquals(savedArticle.getId().intValue(), 1); + assertEquals(savedArticle.getTitle(), "jOOQ examples"); + assertEquals(savedArticle.getDescription(), "A few examples of jOOQ CRUD operations"); + assertEquals(savedArticle.getAuthorId().intValue(), 1); + } + + @Test + public void givenArticleRecord_whenUpdateById_thenChangedValuesDbTable() { + // given + ArticleRecord article = article(); + save(article); + + HashMap, String> updateFields = new HashMap<>(); + updateFields.put(Article.ARTICLE.TITLE, "new title"); + updateFields.put(Article.ARTICLE.DESCRIPTION, "new description"); + + // when + update( + context, + Article.ARTICLE, + updateFields, + Article.ARTICLE.ID.eq(1) + ); + + // then + ArticleRecord updatedArticle = getOne( + context, + Article.ARTICLE, + Article.ARTICLE.ID.eq(1) + ); + assertEquals(updatedArticle.getId().intValue(), 1); + assertEquals(updatedArticle.getTitle(), "new title"); + assertEquals(updatedArticle.getDescription(), "new description"); + assertEquals(updatedArticle.getAuthorId().intValue(), 1); + } + + @Test + public void givenArticleRecord_whenUpdate_thenChangedValuesDbTable() { + // given + ArticleRecord article = article(); + save(article); + + article.setTitle("new title"); + article.setDescription("new description"); + + // when + update(article); + + // then + ArticleRecord updatedArticle = getOne( + context, + Article.ARTICLE, + Article.ARTICLE.ID.eq(1) + ); + assertEquals(updatedArticle.getId().intValue(), 1); + assertEquals(updatedArticle.getTitle(), "new title"); + assertEquals(updatedArticle.getDescription(), "new description"); + assertEquals(updatedArticle.getAuthorId().intValue(), 1); + } + + @Test + public void givenArticleRecord_whenDelete_thenEmptyDbTable() { + // given + ArticleRecord article = article(); + save(article); + + // when + delete(article); + + // then + Result articles = getAll( + context, + Article.ARTICLE + ); + assertTrue(articles.isEmpty()); + } + + @Test + public void givenArticleRecord_whenDeleteById_thenEmptyDbTable() { + // given + ArticleRecord article = article(); + save(article); + + // when + delete( + context, + Article.ARTICLE, + Article.ARTICLE.ID.eq(1) + ); + + // then + Result articles = getAll( + context, + Article.ARTICLE + ); + assertTrue(articles.isEmpty()); + } + + private ArticleRecord article() { + ArticleRecord article = context.newRecord(Article.ARTICLE); + article.setId(1); + article.setTitle("jOOQ examples"); + article.setDescription("A few examples of jOOQ CRUD operations"); + article.setAuthorId(1); + + return article; + } + +} diff --git a/persistence-modules/pom.xml b/persistence-modules/pom.xml index def2deb941..590e5da76e 100644 --- a/persistence-modules/pom.xml +++ b/persistence-modules/pom.xml @@ -39,6 +39,7 @@ java-jpa-2 java-mongodb jnosql + jooq jpa-hibernate-cascade-type liquibase orientdb diff --git a/persistence-modules/spring-data-jpa-enterprise/pom.xml b/persistence-modules/spring-data-jpa-enterprise/pom.xml index 6d9fc41df6..9ecab5feaa 100644 --- a/persistence-modules/spring-data-jpa-enterprise/pom.xml +++ b/persistence-modules/spring-data-jpa-enterprise/pom.xml @@ -95,10 +95,6 @@ - 2.1.9.RELEASE - com.baeldung.springdatageode.app.ClientCacheApp - 1.1.1.RELEASE - 2.1.9.RELEASE 1.3.1.Final 21.0 1.12.2 diff --git a/persistence-modules/spring-jpa-2/pom.xml b/persistence-modules/spring-jpa-2/pom.xml index 1c21f6b98d..8d8dfe3a7b 100644 --- a/persistence-modules/spring-jpa-2/pom.xml +++ b/persistence-modules/spring-jpa-2/pom.xml @@ -66,6 +66,11 @@ guava ${guava.version} + + net.bytebuddy + byte-buddy + ${byte-buddy.version} + @@ -85,13 +90,14 @@ 5.1.5.RELEASE + 2.2.6.RELEASE 9.0.0.M26 21.0 - 2.2.6.RELEASE + 1.10.16 \ No newline at end of file diff --git a/pom.xml b/pom.xml index 6553716d63..065d6abbdd 100644 --- a/pom.xml +++ b/pom.xml @@ -424,6 +424,7 @@ hazelcast helidon httpclient + httpclient-2 httpclient-simple hystrix @@ -935,6 +936,7 @@ hazelcast helidon httpclient + httpclient-2 httpclient-simple hystrix diff --git a/spring-boot-modules/pom.xml b/spring-boot-modules/pom.xml index 527f7dcad8..fa70a9f058 100644 --- a/spring-boot-modules/pom.xml +++ b/spring-boot-modules/pom.xml @@ -46,6 +46,7 @@ spring-boot-jasypt spring-boot-keycloak spring-boot-libraries + spring-boot-libraries-2 spring-boot-logging-log4j2 spring-boot-kotlin spring-boot-mvc diff --git a/spring-boot-modules/spring-boot-environment/src/main/java/com/baeldung/serverport/GetServerPortApplication.java b/spring-boot-modules/spring-boot-environment/src/main/java/com/baeldung/serverport/GetServerPortApplication.java new file mode 100644 index 0000000000..d7658ad8d5 --- /dev/null +++ b/spring-boot-modules/spring-boot-environment/src/main/java/com/baeldung/serverport/GetServerPortApplication.java @@ -0,0 +1,12 @@ +package com.baeldung.serverport; + + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class GetServerPortApplication { + public static void main(String[] args) { + SpringApplication.run(GetServerPortApplication.class, args); + } +} diff --git a/spring-boot-modules/spring-boot-environment/src/main/java/com/baeldung/serverport/ServerPortService.java b/spring-boot-modules/spring-boot-environment/src/main/java/com/baeldung/serverport/ServerPortService.java new file mode 100644 index 0000000000..59c0a0f333 --- /dev/null +++ b/spring-boot-modules/spring-boot-environment/src/main/java/com/baeldung/serverport/ServerPortService.java @@ -0,0 +1,20 @@ +package com.baeldung.serverport; + +import org.springframework.boot.web.servlet.context.ServletWebServerInitializedEvent; +import org.springframework.context.event.EventListener; +import org.springframework.stereotype.Service; + +@Service +public class ServerPortService { + private int port; + + public int getPort() { + return port; + } + + @EventListener + public void onApplicationEvent(final ServletWebServerInitializedEvent event) { + port = event.getWebServer().getPort(); + } + +} \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-environment/src/test/java/com/baeldung/serverport/GetServerFixedPortUnitTest.java b/spring-boot-modules/spring-boot-environment/src/test/java/com/baeldung/serverport/GetServerFixedPortUnitTest.java new file mode 100644 index 0000000000..81e663b7a1 --- /dev/null +++ b/spring-boot-modules/spring-boot-environment/src/test/java/com/baeldung/serverport/GetServerFixedPortUnitTest.java @@ -0,0 +1,37 @@ +package com.baeldung.serverport; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.web.ServerProperties; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.junit4.SpringRunner; + +import static org.junit.Assert.assertEquals; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = GetServerPortApplication.class, webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT) +@ActiveProfiles("fixedport") +public class GetServerFixedPortUnitTest { + private final static int EXPECTED_PORT = 7777; + + @Value("${server.port}") + private int serverPort; + + @Autowired + private ServerProperties serverProperties; + + @Test + public void givenFixedPortAsServerPort_whenReadServerPort_thenGetThePort() { + assertEquals("Reading fixed port by @Value(\"${server.port}\") will get the port.", EXPECTED_PORT, serverPort); + } + + @Test + public void givenFixedPortAsServerPort_whenReadServerProps_thenGetThePort() { + int port = serverProperties.getPort(); + assertEquals("Reading fixed port from serverProperties will get the port.", EXPECTED_PORT, port); + } + +} diff --git a/spring-boot-modules/spring-boot-environment/src/test/java/com/baeldung/serverport/GetServerRandomPortUnitTest.java b/spring-boot-modules/spring-boot-environment/src/test/java/com/baeldung/serverport/GetServerRandomPortUnitTest.java new file mode 100644 index 0000000000..3ad7e0fdf1 --- /dev/null +++ b/spring-boot-modules/spring-boot-environment/src/test/java/com/baeldung/serverport/GetServerRandomPortUnitTest.java @@ -0,0 +1,55 @@ +package com.baeldung.serverport; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.web.ServerProperties; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.junit4.SpringRunner; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = GetServerPortApplication.class, webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT) +@ActiveProfiles("randomport") +public class GetServerRandomPortUnitTest { + + @Value("${server.port}") + private int randomServerPort; + + @Autowired + private ServerPortService serverPortService; + + @Autowired + private ServerProperties serverProperties; + + @Autowired + private ServletWebServerApplicationContext webServerAppCtxt; + + @Test + public void given0AsServerPort_whenReadServerPort_thenGet0() { + assertEquals("Reading random port by @Value(\"${server.port}\") will get 0.", 0, randomServerPort); + } + + @Test + public void given0AsServerPort_whenReadServerProps_thenGet0() { + int port = serverProperties.getPort(); + assertEquals("Reading random port by serverProperties will get 0.", 0, port); + } + + @Test + public void given0AsServerPort_whenReadWebAppCtxt_thenGetThePort() { + int port = webServerAppCtxt.getWebServer().getPort(); + assertTrue("The random port should be greater than 1023", port > 1023); + } + + @Test + public void given0AsServerPort_whenReadFromListener_thenGetThePort() { + int port = serverPortService.getPort(); + assertTrue("The random port should be greater than 1023", port > 1023); + } +} diff --git a/spring-boot-modules/spring-boot-environment/src/test/resources/application-fixedport.properties b/spring-boot-modules/spring-boot-environment/src/test/resources/application-fixedport.properties new file mode 100644 index 0000000000..0c5e84f3a2 --- /dev/null +++ b/spring-boot-modules/spring-boot-environment/src/test/resources/application-fixedport.properties @@ -0,0 +1 @@ +server.port=7777 diff --git a/spring-boot-modules/spring-boot-environment/src/test/resources/application-randomport.properties b/spring-boot-modules/spring-boot-environment/src/test/resources/application-randomport.properties new file mode 100644 index 0000000000..cbe617ef03 --- /dev/null +++ b/spring-boot-modules/spring-boot-environment/src/test/resources/application-randomport.properties @@ -0,0 +1 @@ +server.port=0 diff --git a/spring-boot-modules/spring-boot-libraries-2/README.md b/spring-boot-modules/spring-boot-libraries-2/README.md new file mode 100644 index 0000000000..b0840798e3 --- /dev/null +++ b/spring-boot-modules/spring-boot-libraries-2/README.md @@ -0,0 +1,7 @@ +## Spring Boot Libraries + +This module contains articles about various Spring Boot libraries + +### Relevant Articles: + +- Running background jobs in Spring with JobRunr diff --git a/spring-boot-modules/spring-boot-libraries-2/pom.xml b/spring-boot-modules/spring-boot-libraries-2/pom.xml new file mode 100644 index 0000000000..2633c8fad3 --- /dev/null +++ b/spring-boot-modules/spring-boot-libraries-2/pom.xml @@ -0,0 +1,46 @@ + + + + spring-boot-modules + com.baeldung.spring-boot-modules + 1.0.0-SNAPSHOT + + 4.0.0 + + spring-boot-libraries-2 + + + + org.springframework.boot + spring-boot-starter-web + + + + + org.jobrunr + jobrunr-spring-boot-starter + ${jobrunr.version} + + + + org.springframework.boot + spring-boot-starter-test + test + + + + org.awaitility + awaitility + ${awaitility.version} + test + + + + + 1.0.0 + 4.0.3 + + + \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/jobrunr/JobRunrSpringBootApp.java b/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/jobrunr/JobRunrSpringBootApp.java new file mode 100644 index 0000000000..d72e9464d9 --- /dev/null +++ b/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/jobrunr/JobRunrSpringBootApp.java @@ -0,0 +1,37 @@ +package com.baeldung.jobrunr; + +import com.baeldung.jobrunr.service.SampleJobService; +import org.jobrunr.jobs.mappers.JobMapper; +import org.jobrunr.scheduling.JobScheduler; +import org.jobrunr.scheduling.cron.Cron; +import org.jobrunr.storage.InMemoryStorageProvider; +import org.jobrunr.storage.StorageProvider; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; + +import javax.annotation.PostConstruct; + +@SpringBootApplication +public class JobRunrSpringBootApp { + + @Autowired + private JobScheduler jobScheduler; + + public static void main(String[] args) { + SpringApplication.run(JobRunrSpringBootApp.class, args); + } + + @Bean + public StorageProvider storageProvider(JobMapper jobMapper) { + InMemoryStorageProvider storageProvider = new InMemoryStorageProvider(); + storageProvider.setJobMapper(jobMapper); + return storageProvider; + } + + @PostConstruct + public void scheduleRecurrently() { + jobScheduler.scheduleRecurrently(x -> x.executeSampleJob("a recurring job"), Cron.every5minutes()); + } +} diff --git a/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/jobrunr/controller/JobRunrController.java b/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/jobrunr/controller/JobRunrController.java new file mode 100644 index 0000000000..af5f0b1196 --- /dev/null +++ b/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/jobrunr/controller/JobRunrController.java @@ -0,0 +1,43 @@ +package com.baeldung.jobrunr.controller; + +import com.baeldung.jobrunr.service.SampleJobService; +import org.jobrunr.scheduling.JobScheduler; +import org.springframework.boot.context.properties.bind.DefaultValue; +import org.springframework.format.annotation.DateTimeFormat; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.time.LocalDateTime; + +@RestController +@RequestMapping("/jobrunr") +public class JobRunrController { + + private JobScheduler jobScheduler; + private SampleJobService sampleJobService; + + private JobRunrController(JobScheduler jobScheduler, SampleJobService sampleJobService) { + this.jobScheduler = jobScheduler; + this.sampleJobService = sampleJobService; + } + + @GetMapping(value = "/enqueue/{input}", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity enqueue(@PathVariable("input") @DefaultValue("default-input") String input) { + jobScheduler.enqueue(() -> sampleJobService.executeSampleJob(input)); + return okResponse("job enqueued successfully"); + } + + @GetMapping(value = "/schedule/{input}", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity schedule( + @PathVariable("input") @DefaultValue("default-input") String input, + @RequestParam("scheduleAt") @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime scheduleAt) { + jobScheduler.schedule(() -> sampleJobService.executeSampleJob(input), scheduleAt); + return okResponse("job scheduled successfully"); + } + + private ResponseEntity okResponse(String feedback) { + return new ResponseEntity<>(feedback, HttpStatus.OK); + } +} diff --git a/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/jobrunr/service/SampleJobService.java b/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/jobrunr/service/SampleJobService.java new file mode 100644 index 0000000000..dff4309374 --- /dev/null +++ b/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/jobrunr/service/SampleJobService.java @@ -0,0 +1,36 @@ +package com.baeldung.jobrunr.service; + +import org.jobrunr.jobs.annotations.Job; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; + +import java.util.concurrent.atomic.AtomicInteger; + +@Service +public class SampleJobService { + + public static final long EXECUTION_TIME = 5000L; + + private Logger logger = LoggerFactory.getLogger(getClass()); + + private AtomicInteger count = new AtomicInteger(); + + @Job(name = "The sample job with variable %0", retries = 2) + public void executeSampleJob(String variable) { + + logger.info("The sample job has begun. The variable you passed is {}", variable); + try { + Thread.sleep(EXECUTION_TIME); + } catch (InterruptedException e) { + logger.error("Error while executing sample job", e); + } finally { + count.incrementAndGet(); + logger.info("Sample job has finished..."); + } + } + + public int getNumberOfInvocations() { + return count.get(); + } +} diff --git a/spring-boot-modules/spring-boot-libraries-2/src/main/resources/application.properties b/spring-boot-modules/spring-boot-libraries-2/src/main/resources/application.properties new file mode 100644 index 0000000000..69f5a7356e --- /dev/null +++ b/spring-boot-modules/spring-boot-libraries-2/src/main/resources/application.properties @@ -0,0 +1,2 @@ +org.jobrunr.background_job_server=true +org.jobrunr.dashboard=true diff --git a/spring-boot-modules/spring-boot-libraries-2/src/test/java/com/baeldung/jobrunr/JobRunrLiveTest.java b/spring-boot-modules/spring-boot-libraries-2/src/test/java/com/baeldung/jobrunr/JobRunrLiveTest.java new file mode 100644 index 0000000000..83222e7726 --- /dev/null +++ b/spring-boot-modules/spring-boot-libraries-2/src/test/java/com/baeldung/jobrunr/JobRunrLiveTest.java @@ -0,0 +1,46 @@ +package com.baeldung.jobrunr; + +import org.awaitility.Awaitility; +import org.jobrunr.jobs.states.StateName; +import org.jobrunr.storage.StorageProvider; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.test.context.junit4.SpringRunner; + +import java.net.URI; +import java.util.concurrent.TimeUnit; + +import static org.awaitility.Awaitility.await; +import static org.junit.Assert.assertEquals; +import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.DEFINED_PORT; + +@RunWith(SpringRunner.class) +@SpringBootTest(webEnvironment = DEFINED_PORT, classes = JobRunrSpringBootApp.class) +public class JobRunrLiveTest { + + @Autowired + TestRestTemplate restTemplate; + + @Autowired + StorageProvider storageProvider; + + @Test + public void givenEndpoint_whenJobEnqueued_thenJobIsProcessedWithin30Seconds() { + String response = enqueueJobViaRest("some-input"); + assertEquals("job enqueued successfully", response); + + await().atMost(30, TimeUnit.SECONDS).until(() -> storageProvider.countJobs(StateName.SUCCEEDED) == 1); + } + + private String enqueueJobViaRest(String input) { + try { + return restTemplate.getForObject(new URI("http://localhost:8080/jobrunr/enqueue/" + input), String.class); + } catch (Exception ignored) { + ignored.printStackTrace(); + } + return null; + } +} diff --git a/spring-boot-modules/spring-boot-mvc-3/README.md b/spring-boot-modules/spring-boot-mvc-3/README.md index 6627bd8eea..796ab72425 100644 --- a/spring-boot-modules/spring-boot-mvc-3/README.md +++ b/spring-boot-modules/spring-boot-mvc-3/README.md @@ -7,4 +7,5 @@ This module contains articles about Spring Web MVC in Spring Boot projects. - [Circular View Path Error](https://www.baeldung.com/spring-circular-view-path-error) - [Download an Image or a File with Spring MVC](https://www.baeldung.com/spring-controller-return-image-file) - [Spring MVC Async vs Spring WebFlux](https://www.baeldung.com/spring-mvc-async-vs-webflux) +- [Differences in @Valid and @Validated Annotations in Spring](https://www.baeldung.com/spring-valid-vs-validated) - More articles: [[prev -->]](/spring-boot-modules/spring-boot-mvc-2) diff --git a/testing-modules/testing-libraries-2/README.md b/testing-modules/testing-libraries-2/README.md new file mode 100644 index 0000000000..3325600b5e --- /dev/null +++ b/testing-modules/testing-libraries-2/README.md @@ -0,0 +1,3 @@ +### Relevant Articles: + +- [Guide to the System Rules Library](https://www.baeldung.com/java-system-rules-junit)